Update gnulib files.
[shishi.git] / lib / principal.c
blobaeaae0dc9bed565571f60a327114bb43f649e65a
1 /* principal.c --- Get and set default principal.
2 * Copyright (C) 2002, 2003, 2004, 2006, 2007 Simon Josefsson
4 * This file is part of Shishi.
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.
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.
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
23 #include "internal.h"
25 /**
26 * shishi_principal_default_guess:
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".
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 shishi_principal_default_guess (void)
38 char *envuser;
40 envuser = getenv ("SHISHI_USER");
41 if (!envuser)
42 envuser = getenv ("USER");
43 if (!envuser)
44 envuser = "user";
46 return xstrdup (envuser);
50 /**
51 * shishi_principal_default:
52 * @handle: Shishi library handle create by shishi_init().
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.
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 shishi_principal_default (Shishi * handle)
64 if (!handle->default_principal)
66 char *p;
67 p = shishi_principal_default_guess ();
68 shishi_principal_default_set (handle, p);
69 free (p);
72 return handle->default_principal;
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.
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 shishi_principal_default_set (Shishi * handle, const char *principal)
88 if (handle->default_principal)
89 free (handle->default_principal);
90 if (principal)
91 handle->default_principal = xstrdup (principal);
92 else
93 handle->default_principal = NULL;
96 /**
97 * shishi_parse_name:
98 * @handle: Shishi library handle create by shishi_init().
99 * @name: Input principal name string, e.g. imap/mail.gnu.org@GNU.ORG.
100 * @principal: newly allocated output string with principal name.
101 * @realm: newly allocated output string with realm name.
103 * Split up principal name (e.g., "simon@JOSEFSSON.ORG") into two
104 * newly allocated strings, the principal ("simon") and realm
105 * ("JOSEFSSON.ORG"). If there is no realm part in NAME, REALM is set
106 * to NULL.
108 * Return value: Returns SHISHI_INVALID_PRINCIPAL_NAME if NAME is NULL
109 * or ends with the escape character "\", or SHISHI_OK iff
110 * successful
113 shishi_parse_name (Shishi * handle, const char *name,
114 char **principal, char **realm)
116 const char *p = name;
117 const char *q;
118 int escaped = 0;
120 if (!name)
121 return SHISHI_INVALID_PRINCIPAL_NAME;
123 while (*p && (*p != '@' || escaped))
124 if (escaped)
125 escaped = 0;
126 else if (*p++ == '\\')
127 escaped = 1;
129 if (escaped)
130 return SHISHI_INVALID_PRINCIPAL_NAME;
132 if (principal)
134 *principal = xstrndup (name, p - name + 1);
135 (*principal)[p - name] = '\0';
138 if (*p)
140 q = ++p;
142 while (*q)
143 if (escaped)
144 escaped = 0;
145 else if (*q++ == '\\')
146 escaped = 1;
148 if (escaped)
149 return SHISHI_INVALID_PRINCIPAL_NAME;
151 if (realm)
152 *realm = xstrdup (p);
154 else if (realm)
155 *realm = NULL;
157 return SHISHI_OK;
161 * shishi_principal_name:
162 * @handle: Shishi library handle create by shishi_init().
163 * @namenode: ASN.1 structure with principal in @namefield.
164 * @namefield: name of field in @namenode containing principal name.
165 * @out: pointer to newly allocated zero terminated string containing
166 * principal name. May be %NULL (to only populate @outlen).
167 * @outlen: pointer to length of @out on output, excluding terminating
168 * zero. May be %NULL (to only populate @out).
170 * Represent principal name in ASN.1 structure as zero-terminated
171 * string. The string is allocate by this function, and it is the
172 * responsibility of the caller to deallocate it. Note that the
173 * output length @outlen does not include the terminating zero.
175 * Return value: Returns SHISHI_OK iff successful.
178 shishi_principal_name (Shishi * handle,
179 Shishi_asn1 namenode,
180 const char *namefield, char **out, size_t * outlen)
182 char *format;
183 size_t i, j, n;
184 char *name = NULL;
185 size_t namelen = 0;
186 int res;
188 asprintf (&format, "%s.name-string", namefield);
189 res = shishi_asn1_number_of_elements (handle, namenode, format, &n);
190 free (format);
191 if (res != SHISHI_OK)
192 return res;
194 for (i = 1; i <= n; i++)
196 char *tmp;
197 size_t tmplen;
198 size_t safetmplen;
200 asprintf (&format, "%s.name-string.?%d", namefield, i);
201 res = shishi_asn1_read (handle, namenode, format, &tmp, &tmplen);
202 free (format);
203 if (res != SHISHI_OK)
204 return res;
206 safetmplen = tmplen;
207 for (j = 0; j < tmplen; j++)
208 if (tmp[j] == '@' || tmp[j] == '/' || tmp[j] == '\\')
209 safetmplen++;
210 if (i < n)
211 safetmplen++;
213 name = xrealloc (name, namelen + safetmplen);
215 for (j = 0; j < tmplen; j++)
217 if (tmp[j] == '@' || tmp[j] == '/' || tmp[j] == '\\')
218 name[namelen++] = '\\';
219 name[namelen++] = tmp[j];
222 if (i < n)
223 name[namelen++] = '/';
225 free (tmp);
228 name = xrealloc (name, namelen + 1);
229 name[namelen] = '\0';
231 if (out)
232 *out = name;
233 else
234 free (name);
235 if (outlen)
236 *outlen = namelen;
238 return SHISHI_OK;
242 * shishi_principal_name_realm:
243 * @handle: Shishi library handle create by shishi_init().
244 * @namenode: ASN.1 structure with principal name in @namefield.
245 * @namefield: name of field in @namenode containing principal name.
246 * @realmnode: ASN.1 structure with principal realm in @realmfield.
247 * @realmfield: name of field in @realmnode containing principal realm.
248 * @out: pointer to newly allocated zero terminated string containing
249 * principal name. May be %NULL (to only populate @outlen).
250 * @outlen: pointer to length of @out on output, excluding terminating
251 * zero. May be %NULL (to only populate @out).
253 * Represent principal name and realm in ASN.1 structure as
254 * zero-terminated string. The string is allocate by this function,
255 * and it is the responsibility of the caller to deallocate it. Note
256 * that the output length @outlen does not include the terminating
257 * zero.
259 * Return value: Returns SHISHI_OK iff successful.
262 shishi_principal_name_realm (Shishi * handle,
263 Shishi_asn1 namenode,
264 const char *namefield,
265 Shishi_asn1 realmnode,
266 const char *realmfield,
267 char **out, size_t * outlen)
269 char *tmp;
270 size_t tmplen;
271 int rc;
273 rc = shishi_principal_name (handle, namenode, namefield, &tmp, &tmplen);
274 if (rc != SHISHI_OK)
275 return rc;
277 if (realmnode == NULL && realmfield)
279 size_t realmfieldlen = strlen (realmfield);
281 tmp = xrealloc (tmp, tmplen + 1 + realmfieldlen + 1);
283 tmp[tmplen] = '@';
284 memcpy (tmp + tmplen + 1, realmfield, realmfieldlen);
286 tmplen += 1 + realmfieldlen;
288 tmp[tmplen] = '\0';
290 else if (realmnode != NULL)
292 char *realm;
293 size_t realmlen;
295 rc = shishi_asn1_read (handle, realmnode, realmfield,
296 &realm, &realmlen);
297 if (rc != SHISHI_OK)
299 free (tmp);
300 return rc;
303 tmp = xrealloc (tmp, tmplen + 1 + realmlen + 1);
305 tmp[tmplen] = '@';
306 memcpy (tmp + tmplen + 1, realm, realmlen);
308 tmplen += 1 + realmlen;
310 tmp[tmplen] = '\0';
312 free (realm);
315 *out = tmp;
316 if (outlen)
317 *outlen = tmplen;
319 return SHISHI_OK;
323 * shishi_principal_name_set:
324 * @handle: shishi handle as allocated by shishi_init().
325 * @namenode: ASN.1 structure with principal in @namefield.
326 * @namefield: name of field in namenode containing principal name.
327 * @name_type: type of principial, see Shishi_name_type, usually
328 * SHISHI_NT_UNKNOWN.
329 * @name: zero-terminated input array with principal name.
331 * Set the given principal name field to given name.
333 * Return value: Returns SHISHI_OK iff successful.
336 shishi_principal_name_set (Shishi * handle,
337 Shishi_asn1 namenode,
338 const char *namefield,
339 Shishi_name_type name_type, const char *name[])
341 int res;
342 char *asn1name;
343 int i;
345 asprintf (&asn1name, "%s.name-type", namefield);
346 res = shishi_asn1_write_int32 (handle, namenode, asn1name, name_type);
347 free (asn1name);
348 if (res != SHISHI_OK)
349 return res;
351 asprintf (&asn1name, "%s.name-string", namefield);
352 res = shishi_asn1_write (handle, namenode, asn1name, NULL, 0);
353 free (asn1name);
354 if (res != SHISHI_OK)
355 return res;
357 i = 1;
358 while (name[i - 1])
360 asprintf (&asn1name, "%s.name-string", namefield);
361 res = shishi_asn1_write (handle, namenode, asn1name, "NEW", 1);
362 free (asn1name);
363 if (res != SHISHI_OK)
364 return res;
366 asprintf (&asn1name, "%s.name-string.?%d", namefield, i);
367 res = shishi_asn1_write (handle, namenode, asn1name, name[i - 1], 0);
368 free (asn1name);
369 if (res != SHISHI_OK)
370 return res;
372 i++;
375 return SHISHI_OK;
379 * shishi_principal_set:
380 * @handle: shishi handle as allocated by shishi_init().
381 * @namenode: ASN.1 structure with principal in @namefield.
382 * @namefield: name of field in namenode containing principal name.
383 * @name: zero-terminated string with principal name on RFC 1964 form.
385 * Set principal name field in ASN.1 structure to given name.
387 * Return value: Returns SHISHI_OK iff successful.
390 shishi_principal_set (Shishi * handle,
391 Shishi_asn1 namenode,
392 const char *namefield, const char *name)
394 char *tmpname;
395 const char **namebuf;
396 char *tokptr;
397 int res;
398 int i;
400 tmpname = xstrdup (name);
401 namebuf = xmalloc (sizeof (*namebuf));
403 for (i = 0;
404 (namebuf[i] = strtok_r (i == 0 ? tmpname : NULL, "/", &tokptr)); i++)
406 namebuf = xrealloc (namebuf, (i + 2) * sizeof (*namebuf));
409 res = shishi_principal_name_set (handle, namenode, namefield,
410 SHISHI_NT_UNKNOWN, namebuf);
411 free (namebuf);
412 free (tmpname);
413 if (res != SHISHI_OK)
415 shishi_error_printf (handle, _("Could not set principal name: %s\n"),
416 shishi_strerror (res));
417 return res;
420 return SHISHI_OK;
424 * shishi_derive_default_salt:
425 * @handle: shishi handle as allocated by shishi_init().
426 * @name: principal name of user.
427 * @salt: output variable with newly allocated salt string.
429 * Derive the default salt from a principal. The default salt is the
430 * concatenation of the decoded realm and principal.
432 * Return value: Return SHISHI_OK if successful.
435 shishi_derive_default_salt (Shishi * handle,
436 const char *name,
437 char **salt)
439 char *principal;
440 char *realm;
441 int rc;
443 rc = shishi_parse_name (handle, name, &principal, &realm);
444 if (rc != SHISHI_OK)
445 return rc;
447 if (!principal || !realm)
449 if (realm)
450 free (realm);
451 if (principal)
452 free (principal);
453 return SHISHI_INVALID_PRINCIPAL_NAME;
456 *salt = xasprintf ("%s%s", realm, principal);
458 free (realm);
459 free (principal);
461 return SHISHI_OK;
465 * shishi_server_for_local_service:
466 * @handle: shishi handle as allocated by shishi_init().
467 * @service: zero terminated string with name of service, e.g., "host".
469 * Construct a service principal (e.g., "imap/yxa.extuno.com") based
470 * on supplied service name (i.e., "imap") and the system hostname as
471 * returned by hostname() (i.e., "yxa.extundo.com"). The string must
472 * be deallocated by the caller.
474 * Return value: Return newly allocated service name string.
476 char *
477 shishi_server_for_local_service (Shishi * handle, const char *service)
479 char *hostname;
480 char *server;
482 hostname = xgethostname ();
484 asprintf (&server, "%s/%s", service, hostname);
486 free (hostname);
488 return server;