Branch data Line data Source code
1 : : /* mechtools.c --- Helper functions available for use by any mechanism.
2 : : * Copyright (C) 2010-2012 Simon Josefsson
3 : : *
4 : : * This file is part of GNU SASL Library.
5 : : *
6 : : * GNU SASL Library is free software; you can redistribute it and/or
7 : : * modify it under the terms of the GNU Lesser General Public License
8 : : * as published by the Free Software Foundation; either version 2.1 of
9 : : * the License, or (at your option) any later version.
10 : : *
11 : : * GNU SASL Library is distributed in the hope that it will be useful,
12 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : : * Lesser General Public License for more details.
15 : : *
16 : : * You should have received a copy of the GNU Lesser General Public
17 : : * License along with GNU SASL Library; if not, write to the Free
18 : : * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 : : * Boston, MA 02110-1301, USA.
20 : : *
21 : : */
22 : :
23 : : #ifdef HAVE_CONFIG_H
24 : : #include "config.h"
25 : : #endif
26 : :
27 : : /* Get specification. */
28 : : #include "mechtools.h"
29 : :
30 : : /* Get strcmp. */
31 : : #include <string.h>
32 : :
33 : : /* Get malloc, free. */
34 : : #include <stdlib.h>
35 : :
36 : : /* Get asprintf. */
37 : : #include <stdio.h>
38 : :
39 : : /* Get error codes. */
40 : : #include <gsasl.h>
41 : :
42 : : /* Create in AUTHZID a newly allocated copy of STR where =2C is
43 : : replaced with , and =3D is replaced with =. Return GSASL_OK on
44 : : success, GSASL_MALLOC_ERROR on memory errors, GSASL_PARSE_ERRORS if
45 : : string contains any unencoded ',' or incorrectly encoded
46 : : sequence. */
47 : : static int
48 : 3 : unescape_authzid (const char *str, size_t len, char **authzid)
49 : : {
50 : : char *p;
51 : :
52 [ - + ]: 3 : if (memchr (str, ',', len) != NULL)
53 : 0 : return GSASL_MECHANISM_PARSE_ERROR;
54 : :
55 : 3 : p = *authzid = malloc (len + 1);
56 [ - + ]: 3 : if (!p)
57 : 0 : return GSASL_MALLOC_ERROR;
58 : :
59 [ + + ][ + - ]: 15 : while (len > 0 && *str)
60 : : {
61 [ + + ][ - + ]: 12 : if (len >= 3 && str[0] == '=' && str[1] == '2' && str[2] == 'C')
[ # # ][ # # ]
62 : : {
63 : 0 : *p++ = ',';
64 : 0 : str += 3;
65 : 0 : len -= 3;
66 : : }
67 [ + + ][ - + ]: 12 : else if (len >= 3 && str[0] == '=' && str[1] == '3' && str[2] == 'D')
[ # # ][ # # ]
68 : : {
69 : 0 : *p++ = '=';
70 : 0 : str += 3;
71 : 0 : len -= 3;
72 : : }
73 [ - + ]: 12 : else if (str[0] == '=')
74 : : {
75 : 0 : free (*authzid);
76 : 0 : *authzid = NULL;
77 : 0 : return GSASL_MECHANISM_PARSE_ERROR;
78 : : }
79 : : else
80 : : {
81 : 12 : *p++ = *str;
82 : 12 : str++;
83 : 12 : len--;
84 : : }
85 : : }
86 : 3 : *p = '\0';
87 : :
88 : 3 : return GSASL_OK;
89 : : }
90 : :
91 : : /* Parse the GS2 header containing flags and authorization identity.
92 : : Put authorization identity (or NULL) in AUTHZID and length of
93 : : header in HEADERLEN. Return GSASL_OK on success or an error
94 : : code.*/
95 : : int
96 : 14 : _gsasl_parse_gs2_header (const char *data, size_t len,
97 : : char **authzid, size_t * headerlen)
98 : : {
99 : : char *authzid_endptr;
100 : :
101 [ + + ]: 14 : if (len < 3)
102 : 4 : return GSASL_MECHANISM_PARSE_ERROR;
103 : :
104 [ + + ]: 10 : if (strncmp (data, "n,,", 3) == 0)
105 : : {
106 : 3 : *headerlen = 3;
107 : 3 : *authzid = NULL;
108 : : }
109 [ + + ][ + - ]: 7 : else if (strncmp (data, "n,a=", 4) == 0 &&
110 : 3 : (authzid_endptr = memchr (data + 4, ',', len - 4)))
111 : 3 : {
112 : : int res;
113 : :
114 [ - + ]: 3 : if (authzid_endptr == NULL)
115 : 0 : return GSASL_MECHANISM_PARSE_ERROR;
116 : :
117 : 3 : res = unescape_authzid (data + 4, authzid_endptr - (data + 4), authzid);
118 [ - + ]: 3 : if (res != GSASL_OK)
119 : 0 : return res;
120 : :
121 : 3 : *headerlen = authzid_endptr - data + 1;
122 : : }
123 : : else
124 : 4 : return GSASL_MECHANISM_PARSE_ERROR;
125 : :
126 : 14 : return GSASL_OK;
127 : : }
128 : :
129 : : /* Return newly allocated copy of STR with all occurrences of ','
130 : : replaced with =2C and '=' with '=3D', or return NULL on memory
131 : : allocation errors. */
132 : : static char *
133 : 3 : escape_authzid (const char *str)
134 : : {
135 : 3 : char *out = malloc (strlen (str) * 3 + 1);
136 : 3 : char *p = out;
137 : :
138 [ - + ]: 3 : if (!out)
139 : 0 : return NULL;
140 : :
141 [ + + ]: 15 : while (*str)
142 : : {
143 [ - + ]: 12 : if (*str == ',')
144 : : {
145 : 0 : memcpy (p, "=2C", 3);
146 : 0 : p += 3;
147 : : }
148 [ - + ]: 12 : else if (*str == '=')
149 : : {
150 : 0 : memcpy (p, "=3D", 3);
151 : 0 : p += 3;
152 : : }
153 : : else
154 : : {
155 : 12 : *p = *str;
156 : 12 : p++;
157 : : }
158 : 12 : str++;
159 : : }
160 : 3 : *p = '\0';
161 : :
162 : 3 : return out;
163 : : }
164 : :
165 : : /* Generate a newly allocated GS2 header, escaping authzid
166 : : appropriately, and appending EXTRA. */
167 : : int
168 : 6 : _gsasl_gs2_generate_header (bool nonstd, char cbflag,
169 : : const char *cbname, const char *authzid,
170 : : size_t extralen, const char *extra,
171 : : char **gs2h, size_t * gs2hlen)
172 : : {
173 : 6 : int elen = extralen;
174 : : char *gs2cbflag;
175 : : int len;
176 : :
177 [ - + ]: 6 : if (cbflag == 'p')
178 : 0 : len = asprintf (&gs2cbflag, "p=%s", cbname);
179 [ + - ]: 6 : else if (cbflag == 'n')
180 : 6 : len = asprintf (&gs2cbflag, "n");
181 [ # # ]: 0 : else if (cbflag == 'y')
182 : 0 : len = asprintf (&gs2cbflag, "y");
183 : : else
184 : : /* internal caller error */
185 : 0 : return GSASL_MECHANISM_PARSE_ERROR;
186 : :
187 [ + - ][ - + ]: 6 : if (len <= 0 || gs2cbflag == NULL)
188 : 0 : return GSASL_MALLOC_ERROR;
189 : :
190 [ + + ]: 6 : if (authzid)
191 : : {
192 : 3 : char *escaped_authzid = escape_authzid (authzid);
193 : :
194 [ - + ]: 3 : if (!escaped_authzid)
195 : : {
196 : 0 : free (gs2cbflag);
197 : 0 : return GSASL_MALLOC_ERROR;
198 : : }
199 : :
200 [ - + ]: 3 : len = asprintf (gs2h, "%s%s,a=%s,%.*s", nonstd ? "F," : "",
201 : : gs2cbflag, escaped_authzid, elen, extra);
202 : :
203 : 3 : free (escaped_authzid);
204 : : }
205 : : else
206 [ - + ]: 3 : len = asprintf (gs2h, "%s%s,,%.*s", nonstd ? "F," : "", gs2cbflag,
207 : : elen, extra);
208 : :
209 : 6 : free (gs2cbflag);
210 : :
211 [ + - ][ - + ]: 6 : if (len <= 0 || gs2h == NULL)
212 : 0 : return GSASL_MALLOC_ERROR;
213 : :
214 : 6 : *gs2hlen = len;
215 : :
216 : 6 : return GSASL_OK;
217 : : }
|