Branch data Line data Source code
1 : : /* principal.c --- Get and set default principal.
2 : : * Copyright (C) 2002, 2003, 2004, 2006, 2007, 2008, 2010 Simon Josefsson
3 : : *
4 : : * This file is part of Shishi.
5 : : *
6 : : * Shishi is free software; you can redistribute it and/or modify it
7 : : * under the terms of the GNU General Public License as published by
8 : : * the Free Software Foundation; either version 3 of the License, or
9 : : * (at your option) any later version.
10 : : *
11 : : * Shishi is distributed in the hope that it will be useful, but
12 : : * WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : : * GNU General Public License for more details.
15 : : *
16 : : * You should have received a copy of the GNU General Public License
17 : : * along with Shishi; if not, see http://www.gnu.org/licenses or write
18 : : * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
19 : : * Floor, Boston, MA 02110-1301, USA
20 : : *
21 : : */
22 : :
23 : : #include "internal.h"
24 : :
25 : : /**
26 : : * shishi_principal_default_guess:
27 : : *
28 : : * Guesses the principal name for the user, looking at environment
29 : : * variables SHISHI_USER and USER, or if that fails, returns the
30 : : * string "user".
31 : : *
32 : : * Return value: Returns guessed default principal for user as a
33 : : * string that has to be deallocated with free() by the caller.
34 : : **/
35 : : char *
36 : 1 : shishi_principal_default_guess (void)
37 : : {
38 : : const char *envuser;
39 : :
40 : 1 : envuser = getenv ("SHISHI_USER");
41 [ + - ]: 1 : if (!envuser)
42 : 1 : envuser = getenv ("USER");
43 [ - + ]: 1 : if (!envuser)
44 : 0 : envuser = "user";
45 : :
46 : 1 : return xstrdup (envuser);
47 : : }
48 : :
49 : :
50 : : /**
51 : : * shishi_principal_default:
52 : : * @handle: Shishi library handle create by shishi_init().
53 : : *
54 : : * The default principal name is the name in the environment variable
55 : : * USER, but can be overridden by specifying the environment variable
56 : : * SHISHI_USER.
57 : : *
58 : : * Return value: Returns the default principal name used in the
59 : : * library. (Not a copy of it, so don't modify or deallocate it.)
60 : : **/
61 : : const char *
62 : 1 : shishi_principal_default (Shishi * handle)
63 : : {
64 [ + - ]: 1 : if (!handle->default_principal)
65 : : {
66 : : char *p;
67 : 1 : p = shishi_principal_default_guess ();
68 : 1 : shishi_principal_default_set (handle, p);
69 : 1 : free (p);
70 : : }
71 : :
72 : 1 : return handle->default_principal;
73 : : }
74 : :
75 : : /**
76 : : * shishi_principal_default_set:
77 : : * @handle: Shishi library handle create by shishi_init().
78 : : * @principal: string with new default principal name, or NULL to
79 : : * reset to default.
80 : : *
81 : : * Set the default realm used in the library. The string is copied
82 : : * into the library, so you can dispose of the variable immediately
83 : : * after calling this function.
84 : : **/
85 : : void
86 : 15 : shishi_principal_default_set (Shishi * handle, const char *principal)
87 : : {
88 : 15 : free (handle->default_principal);
89 [ + + ]: 15 : if (principal)
90 : 1 : handle->default_principal = xstrdup (principal);
91 : : else
92 : 14 : handle->default_principal = NULL;
93 : 15 : }
94 : :
95 : : /**
96 : : * shishi_parse_name:
97 : : * @handle: Shishi library handle create by shishi_init().
98 : : * @name: Input principal name string, e.g. imap/mail.gnu.org@GNU.ORG.
99 : : * @principal: newly allocated output string with principal name.
100 : : * @realm: newly allocated output string with realm name.
101 : : *
102 : : * Split up principal name (e.g., "simon@JOSEFSSON.ORG") into two
103 : : * newly allocated strings, the principal ("simon") and realm
104 : : * ("JOSEFSSON.ORG"). If there is no realm part in NAME, REALM is set
105 : : * to NULL.
106 : : *
107 : : * Return value: Returns SHISHI_INVALID_PRINCIPAL_NAME if NAME is NULL
108 : : * or ends with the escape character "\", or SHISHI_OK iff
109 : : * successful
110 : : **/
111 : : int
112 : 0 : shishi_parse_name (Shishi * handle, const char *name,
113 : : char **principal, char **realm)
114 : : {
115 : 0 : const char *p = name;
116 : : const char *q;
117 : 0 : int escaped = 0;
118 : :
119 [ # # ]: 0 : if (!name)
120 : 0 : return SHISHI_INVALID_PRINCIPAL_NAME;
121 : :
122 [ # # ][ # # ]: 0 : while (*p && (*p != '@' || escaped))
[ # # ]
123 [ # # ]: 0 : if (escaped)
124 : 0 : escaped = 0;
125 [ # # ]: 0 : else if (*p++ == '\\')
126 : 0 : escaped = 1;
127 : :
128 [ # # ]: 0 : if (escaped)
129 : 0 : return SHISHI_INVALID_PRINCIPAL_NAME;
130 : :
131 [ # # ]: 0 : if (principal)
132 : : {
133 : 0 : *principal = xstrndup (name, p - name + 1);
134 : 0 : (*principal)[p - name] = '\0';
135 : : }
136 : :
137 [ # # ]: 0 : if (*p)
138 : : {
139 : 0 : q = ++p;
140 : :
141 [ # # ]: 0 : while (*q)
142 [ # # ]: 0 : if (escaped)
143 : 0 : escaped = 0;
144 [ # # ]: 0 : else if (*q++ == '\\')
145 : 0 : escaped = 1;
146 : :
147 [ # # ]: 0 : if (escaped)
148 : 0 : return SHISHI_INVALID_PRINCIPAL_NAME;
149 : :
150 [ # # ]: 0 : if (realm)
151 : 0 : *realm = xstrdup (p);
152 : : }
153 [ # # ]: 0 : else if (realm)
154 : 0 : *realm = NULL;
155 : :
156 : 0 : return SHISHI_OK;
157 : : }
158 : :
159 : : /**
160 : : * shishi_principal_name:
161 : : * @handle: Shishi library handle create by shishi_init().
162 : : * @namenode: ASN.1 structure with principal in @namefield.
163 : : * @namefield: name of field in @namenode containing principal name.
164 : : * @out: pointer to newly allocated zero terminated string containing
165 : : * principal name. May be %NULL (to only populate @outlen).
166 : : * @outlen: pointer to length of @out on output, excluding terminating
167 : : * zero. May be %NULL (to only populate @out).
168 : : *
169 : : * Represent principal name in ASN.1 structure as zero-terminated
170 : : * string. The string is allocate by this function, and it is the
171 : : * responsibility of the caller to deallocate it. Note that the
172 : : * output length @outlen does not include the terminating zero.
173 : : *
174 : : * Return value: Returns SHISHI_OK iff successful.
175 : : **/
176 : : int
177 : 16 : shishi_principal_name (Shishi * handle,
178 : : Shishi_asn1 namenode,
179 : : const char *namefield, char **out, size_t * outlen)
180 : : {
181 : : char *format;
182 : : size_t i, j, n;
183 : 16 : char *name = NULL;
184 : 16 : size_t namelen = 0;
185 : : int res;
186 : :
187 : 16 : asprintf (&format, "%s.name-string", namefield);
188 : 16 : res = shishi_asn1_number_of_elements (handle, namenode, format, &n);
189 : 16 : free (format);
190 [ - + ]: 16 : if (res != SHISHI_OK)
191 : 0 : return res;
192 : :
193 [ + + ]: 42 : for (i = 1; i <= n; i++)
194 : : {
195 : : char *tmp;
196 : : size_t tmplen;
197 : : size_t safetmplen;
198 : :
199 : 26 : asprintf (&format, "%s.name-string.?%d", namefield, i);
200 : 26 : res = shishi_asn1_read (handle, namenode, format, &tmp, &tmplen);
201 : 26 : free (format);
202 [ - + ]: 26 : if (res != SHISHI_OK)
203 : 0 : return res;
204 : :
205 : 26 : safetmplen = tmplen;
206 [ + + ]: 208 : for (j = 0; j < tmplen; j++)
207 [ + - ][ + - ]: 182 : if (tmp[j] == '@' || tmp[j] == '/' || tmp[j] == '\\')
[ - + ]
208 : 0 : safetmplen++;
209 [ + + ]: 26 : if (i < n)
210 : 10 : safetmplen++;
211 : :
212 : 26 : name = xrealloc (name, namelen + safetmplen);
213 : :
214 [ + + ]: 208 : for (j = 0; j < tmplen; j++)
215 : : {
216 [ + - ][ + - ]: 182 : if (tmp[j] == '@' || tmp[j] == '/' || tmp[j] == '\\')
[ - + ]
217 : 0 : name[namelen++] = '\\';
218 : 182 : name[namelen++] = tmp[j];
219 : : }
220 : :
221 [ + + ]: 26 : if (i < n)
222 : 10 : name[namelen++] = '/';
223 : :
224 : 26 : free (tmp);
225 : : }
226 : :
227 : 16 : name = xrealloc (name, namelen + 1);
228 : 16 : name[namelen] = '\0';
229 : :
230 [ + - ]: 16 : if (out)
231 : 16 : *out = name;
232 : : else
233 : 0 : free (name);
234 [ + + ]: 16 : if (outlen)
235 : 8 : *outlen = namelen;
236 : :
237 : 16 : return SHISHI_OK;
238 : : }
239 : :
240 : : /**
241 : : * shishi_principal_name_realm:
242 : : * @handle: Shishi library handle create by shishi_init().
243 : : * @namenode: ASN.1 structure with principal name in @namefield.
244 : : * @namefield: name of field in @namenode containing principal name.
245 : : * @realmnode: ASN.1 structure with principal realm in @realmfield.
246 : : * @realmfield: name of field in @realmnode containing principal realm.
247 : : * @out: pointer to newly allocated zero terminated string containing
248 : : * principal name. May be %NULL (to only populate @outlen).
249 : : * @outlen: pointer to length of @out on output, excluding terminating
250 : : * zero. May be %NULL (to only populate @out).
251 : : *
252 : : * Represent principal name and realm in ASN.1 structure as
253 : : * zero-terminated string. The string is allocate by this function,
254 : : * and it is the responsibility of the caller to deallocate it. Note
255 : : * that the output length @outlen does not include the terminating
256 : : * zero.
257 : : *
258 : : * Return value: Returns SHISHI_OK iff successful.
259 : : **/
260 : : int
261 : 3 : shishi_principal_name_realm (Shishi * handle,
262 : : Shishi_asn1 namenode,
263 : : const char *namefield,
264 : : Shishi_asn1 realmnode,
265 : : const char *realmfield,
266 : : char **out, size_t * outlen)
267 : : {
268 : : char *tmp;
269 : : size_t tmplen;
270 : : int rc;
271 : :
272 : 3 : rc = shishi_principal_name (handle, namenode, namefield, &tmp, &tmplen);
273 [ - + ]: 3 : if (rc != SHISHI_OK)
274 : 0 : return rc;
275 : :
276 [ - + ][ # # ]: 3 : if (realmnode == NULL && realmfield)
277 : : {
278 : 0 : size_t realmfieldlen = strlen (realmfield);
279 : :
280 : 0 : tmp = xrealloc (tmp, tmplen + 1 + realmfieldlen + 1);
281 : :
282 : 0 : tmp[tmplen] = '@';
283 : 0 : memcpy (tmp + tmplen + 1, realmfield, realmfieldlen);
284 : :
285 : 0 : tmplen += 1 + realmfieldlen;
286 : :
287 : 0 : tmp[tmplen] = '\0';
288 : : }
289 [ + - ]: 3 : else if (realmnode != NULL)
290 : : {
291 : : char *realm;
292 : : size_t realmlen;
293 : :
294 : 3 : rc = shishi_asn1_read (handle, realmnode, realmfield,
295 : : &realm, &realmlen);
296 [ - + ]: 3 : if (rc != SHISHI_OK)
297 : : {
298 : 0 : free (tmp);
299 : 0 : return rc;
300 : : }
301 : :
302 : 3 : tmp = xrealloc (tmp, tmplen + 1 + realmlen + 1);
303 : :
304 : 3 : tmp[tmplen] = '@';
305 : 3 : memcpy (tmp + tmplen + 1, realm, realmlen);
306 : :
307 : 3 : tmplen += 1 + realmlen;
308 : :
309 : 3 : tmp[tmplen] = '\0';
310 : :
311 : 3 : free (realm);
312 : : }
313 : :
314 : 3 : *out = tmp;
315 [ + - ]: 3 : if (outlen)
316 : 3 : *outlen = tmplen;
317 : :
318 : 3 : return SHISHI_OK;
319 : : }
320 : :
321 : : /**
322 : : * shishi_principal_name_set:
323 : : * @handle: shishi handle as allocated by shishi_init().
324 : : * @namenode: ASN.1 structure with principal in @namefield.
325 : : * @namefield: name of field in namenode containing principal name.
326 : : * @name_type: type of principial, see Shishi_name_type, usually
327 : : * SHISHI_NT_UNKNOWN.
328 : : * @name: zero-terminated input array with principal name.
329 : : *
330 : : * Set the given principal name field to given name.
331 : : *
332 : : * Return value: Returns SHISHI_OK iff successful.
333 : : **/
334 : : int
335 : 5 : shishi_principal_name_set (Shishi * handle,
336 : : Shishi_asn1 namenode,
337 : : const char *namefield,
338 : : Shishi_name_type name_type, const char *name[])
339 : : {
340 : : int res;
341 : : char *asn1name;
342 : : int i;
343 : :
344 : 5 : asprintf (&asn1name, "%s.name-type", namefield);
345 : 5 : res = shishi_asn1_write_int32 (handle, namenode, asn1name, name_type);
346 : 5 : free (asn1name);
347 [ - + ]: 5 : if (res != SHISHI_OK)
348 : 0 : return res;
349 : :
350 : 5 : asprintf (&asn1name, "%s.name-string", namefield);
351 : 5 : res = shishi_asn1_write (handle, namenode, asn1name, NULL, 0);
352 : 5 : free (asn1name);
353 [ - + ]: 5 : if (res != SHISHI_OK)
354 : 0 : return res;
355 : :
356 : 5 : i = 1;
357 [ + + ]: 12 : while (name[i - 1])
358 : : {
359 : 7 : asprintf (&asn1name, "%s.name-string", namefield);
360 : 7 : res = shishi_asn1_write (handle, namenode, asn1name, "NEW", 1);
361 : 7 : free (asn1name);
362 [ - + ]: 7 : if (res != SHISHI_OK)
363 : 0 : return res;
364 : :
365 : 7 : asprintf (&asn1name, "%s.name-string.?%d", namefield, i);
366 : 7 : res = shishi_asn1_write (handle, namenode, asn1name, name[i - 1], 0);
367 : 7 : free (asn1name);
368 [ - + ]: 7 : if (res != SHISHI_OK)
369 : 0 : return res;
370 : :
371 : 7 : i++;
372 : : }
373 : :
374 : 5 : return SHISHI_OK;
375 : : }
376 : :
377 : : /**
378 : : * shishi_principal_set:
379 : : * @handle: shishi handle as allocated by shishi_init().
380 : : * @namenode: ASN.1 structure with principal in @namefield.
381 : : * @namefield: name of field in namenode containing principal name.
382 : : * @name: zero-terminated string with principal name on RFC 1964 form.
383 : : *
384 : : * Set principal name field in ASN.1 structure to given name.
385 : : *
386 : : * Return value: Returns SHISHI_OK iff successful.
387 : : **/
388 : : int
389 : 3 : shishi_principal_set (Shishi * handle,
390 : : Shishi_asn1 namenode,
391 : : const char *namefield, const char *name)
392 : : {
393 : : char *tmpname;
394 : : const char **namebuf;
395 : 3 : char *tokptr = NULL;
396 : : int res;
397 : : int i;
398 : :
399 : 3 : tmpname = xstrdup (name);
400 : 3 : namebuf = xmalloc (sizeof (*namebuf));
401 : :
402 [ + + ]: 11 : for (i = 0;
403 [ + + ]: 8 : (namebuf[i] = strtok_r (i == 0 ? tmpname : NULL, "/", &tokptr)); i++)
404 : : {
405 : 5 : namebuf = xrealloc (namebuf, (i + 2) * sizeof (*namebuf));
406 : : }
407 : :
408 : 3 : res = shishi_principal_name_set (handle, namenode, namefield,
409 : : SHISHI_NT_UNKNOWN, namebuf);
410 : 3 : free (namebuf);
411 : 3 : free (tmpname);
412 [ - + ]: 3 : if (res != SHISHI_OK)
413 : : {
414 : 0 : shishi_error_printf (handle, _("Could not set principal name: %s\n"),
415 : : shishi_strerror (res));
416 : 0 : return res;
417 : : }
418 : :
419 : 3 : return SHISHI_OK;
420 : : }
421 : :
422 : : /**
423 : : * shishi_derive_default_salt:
424 : : * @handle: shishi handle as allocated by shishi_init().
425 : : * @name: principal name of user.
426 : : * @salt: output variable with newly allocated salt string.
427 : : *
428 : : * Derive the default salt from a principal. The default salt is the
429 : : * concatenation of the decoded realm and principal.
430 : : *
431 : : * Return value: Return SHISHI_OK if successful.
432 : : **/
433 : : int
434 : 0 : shishi_derive_default_salt (Shishi * handle, const char *name, char **salt)
435 : : {
436 : : char *principal;
437 : : char *realm;
438 : : int rc;
439 : :
440 : 0 : rc = shishi_parse_name (handle, name, &principal, &realm);
441 [ # # ]: 0 : if (rc != SHISHI_OK)
442 : 0 : return rc;
443 : :
444 [ # # ][ # # ]: 0 : if (!principal || !realm)
445 : : {
446 : 0 : free (realm);
447 : 0 : free (principal);
448 : 0 : return SHISHI_INVALID_PRINCIPAL_NAME;
449 : : }
450 : :
451 : 0 : *salt = xasprintf ("%s%s", realm, principal);
452 : :
453 : 0 : free (realm);
454 : 0 : free (principal);
455 : :
456 : 0 : return SHISHI_OK;
457 : : }
458 : :
459 : : /**
460 : : * shishi_server_for_local_service:
461 : : * @handle: shishi handle as allocated by shishi_init().
462 : : * @service: zero terminated string with name of service, e.g., "host".
463 : : *
464 : : * Construct a service principal (e.g., "imap/yxa.extuno.com") based
465 : : * on supplied service name (i.e., "imap") and the system hostname as
466 : : * returned by hostname() (i.e., "yxa.extundo.com"). The string must
467 : : * be deallocated by the caller.
468 : : *
469 : : * Return value: Return newly allocated service name string.
470 : : **/
471 : : char *
472 : 0 : shishi_server_for_local_service (Shishi * handle, const char *service)
473 : : {
474 : : char *hostname;
475 : : char *server;
476 : :
477 : 0 : hostname = xgethostname ();
478 : :
479 : 0 : asprintf (&server, "%s/%s", service, hostname);
480 : :
481 : 0 : free (hostname);
482 : :
483 : 0 : return server;
484 : : }
|