Bump versions.
[shishi.git] / lib / principal.c
blobd271cc6a684487e0dd5d630e2b62741975490f89
1 /* principal.c --- Get and set default principal.
2 * Copyright (C) 2002, 2003, 2004, 2006 Simon Josefsson
4 * This file is part of Shishi.
6 * Shishi is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * Shishi 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
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, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "internal.h"
24 /**
25 * shishi_principal_default_guess:
27 * Guesses the principal name for the user, looking at environment
28 * variables SHISHI_USER and USER, or if that fails, returns the
29 * string "user".
31 * Return value: Returns guessed default principal for user as a
32 * string that has to be deallocated with free() by the caller.
33 **/
34 char *
35 shishi_principal_default_guess (void)
37 char *envuser;
39 envuser = getenv ("SHISHI_USER");
40 if (!envuser)
41 envuser = getenv ("USER");
42 if (!envuser)
43 envuser = "user";
45 return xstrdup (envuser);
49 /**
50 * shishi_principal_default:
51 * @handle: Shishi library handle create by shishi_init().
53 * The default principal name is the name in the environment variable
54 * USER, but can be overridden by specifying the environment variable
55 * SHISHI_USER.
57 * Return value: Returns the default principal name used in the
58 * library. (Not a copy of it, so don't modify or deallocate it.)
59 **/
60 const char *
61 shishi_principal_default (Shishi * handle)
63 if (!handle->default_principal)
65 char *p;
66 p = shishi_principal_default_guess ();
67 shishi_principal_default_set (handle, p);
68 free (p);
71 return handle->default_principal;
74 /**
75 * shishi_principal_default_set:
76 * @handle: Shishi library handle create by shishi_init().
77 * @principal: string with new default principal name, or NULL to
78 * reset to default.
80 * Set the default realm used in the library. The string is copied
81 * into the library, so you can dispose of the variable immediately
82 * after calling this function.
83 **/
84 void
85 shishi_principal_default_set (Shishi * handle, const char *principal)
87 if (handle->default_principal)
88 free (handle->default_principal);
89 if (principal)
90 handle->default_principal = xstrdup (principal);
91 else
92 handle->default_principal = NULL;
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.
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.
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
112 shishi_parse_name (Shishi * handle, const char *name,
113 char **principal, char **realm)
115 const char *p = name;
116 const char *q;
117 int escaped = 0;
119 if (!name)
120 return SHISHI_INVALID_PRINCIPAL_NAME;
122 while (*p && (*p != '@' || escaped))
123 if (escaped)
124 escaped = 0;
125 else if (*p++ == '\\')
126 escaped = 1;
128 if (escaped)
129 return SHISHI_INVALID_PRINCIPAL_NAME;
131 if (principal)
133 *principal = xstrndup (name, p - name + 1);
134 (*principal)[p - name] = '\0';
137 if (*p)
139 q = ++p;
141 while (*q)
142 if (escaped)
143 escaped = 0;
144 else if (*q++ == '\\')
145 escaped = 1;
147 if (escaped)
148 return SHISHI_INVALID_PRINCIPAL_NAME;
150 if (realm)
151 *realm = xstrdup (p);
153 else if (realm)
154 *realm = NULL;
156 return SHISHI_OK;
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).
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.
174 * Return value: Returns SHISHI_OK iff successful.
177 shishi_principal_name (Shishi * handle,
178 Shishi_asn1 namenode,
179 const char *namefield, char **out, size_t * outlen)
181 char *format;
182 size_t i, j, n;
183 char *name = NULL;
184 size_t namelen = 0;
185 int res;
187 asprintf (&format, "%s.name-string", namefield);
188 res = shishi_asn1_number_of_elements (handle, namenode, format, &n);
189 free (format);
190 if (res != SHISHI_OK)
191 return res;
193 for (i = 1; i <= n; i++)
195 char *tmp;
196 size_t tmplen;
197 size_t safetmplen;
199 asprintf (&format, "%s.name-string.?%d", namefield, i);
200 res = shishi_asn1_read (handle, namenode, format, &tmp, &tmplen);
201 free (format);
202 if (res != SHISHI_OK)
203 return res;
205 safetmplen = tmplen;
206 for (j = 0; j < tmplen; j++)
207 if (tmp[j] == '@' || tmp[j] == '/' || tmp[j] == '\\')
208 safetmplen++;
209 if (i < n)
210 safetmplen++;
212 name = xrealloc (name, namelen + safetmplen);
214 for (j = 0; j < tmplen; j++)
216 if (tmp[j] == '@' || tmp[j] == '/' || tmp[j] == '\\')
217 name[namelen++] = '\\';
218 name[namelen++] = tmp[j];
221 if (i < n)
222 name[namelen++] = '/';
224 free (tmp);
227 name = xrealloc (name, namelen + 1);
228 name[namelen] = '\0';
230 if (out)
231 *out = name;
232 else
233 free (name);
234 if (outlen)
235 *outlen = namelen;
237 return SHISHI_OK;
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).
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.
258 * Return value: Returns SHISHI_OK iff successful.
261 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)
268 char *tmp;
269 size_t tmplen;
270 int rc;
272 rc = shishi_principal_name (handle, namenode, namefield, &tmp, &tmplen);
273 if (rc != SHISHI_OK)
274 return rc;
276 if (realmnode == NULL && realmfield)
278 size_t realmfieldlen = strlen (realmfield);
280 tmp = xrealloc (tmp, tmplen + 1 + realmfieldlen + 1);
282 tmp[tmplen] = '@';
283 memcpy (tmp + tmplen + 1, realmfield, realmfieldlen);
285 tmplen += 1 + realmfieldlen;
287 tmp[tmplen] = '\0';
289 else if (realmnode != NULL)
291 char *realm;
292 size_t realmlen;
294 rc = shishi_asn1_read (handle, realmnode, realmfield,
295 &realm, &realmlen);
296 if (rc != SHISHI_OK)
298 free (tmp);
299 return rc;
302 tmp = xrealloc (tmp, tmplen + 1 + realmlen + 1);
304 tmp[tmplen] = '@';
305 memcpy (tmp + tmplen + 1, realm, realmlen);
307 tmplen += 1 + realmlen;
309 tmp[tmplen] = '\0';
311 free (realm);
314 *out = tmp;
315 if (outlen)
316 *outlen = tmplen;
318 return SHISHI_OK;
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.
330 * Set the given principal name field to given name.
332 * Return value: Returns SHISHI_OK iff successful.
335 shishi_principal_name_set (Shishi * handle,
336 Shishi_asn1 namenode,
337 const char *namefield,
338 Shishi_name_type name_type, const char *name[])
340 int res;
341 char *asn1name;
342 int i;
344 asprintf (&asn1name, "%s.name-type", namefield);
345 res = shishi_asn1_write_int32 (handle, namenode, asn1name, name_type);
346 free (asn1name);
347 if (res != SHISHI_OK)
348 return res;
350 asprintf (&asn1name, "%s.name-string", namefield);
351 res = shishi_asn1_write (handle, namenode, asn1name, NULL, 0);
352 free (asn1name);
353 if (res != SHISHI_OK)
354 return res;
356 i = 1;
357 while (name[i - 1])
359 asprintf (&asn1name, "%s.name-string", namefield);
360 res = shishi_asn1_write (handle, namenode, asn1name, "NEW", 1);
361 free (asn1name);
362 if (res != SHISHI_OK)
363 return res;
365 asprintf (&asn1name, "%s.name-string.?%d", namefield, i);
366 res = shishi_asn1_write (handle, namenode, asn1name, name[i - 1], 0);
367 free (asn1name);
368 if (res != SHISHI_OK)
369 return res;
371 i++;
374 return SHISHI_OK;
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.
384 * Set principal name field in ASN.1 structure to given name.
386 * Return value: Returns SHISHI_OK iff successful.
389 shishi_principal_set (Shishi * handle,
390 Shishi_asn1 namenode,
391 const char *namefield, const char *name)
393 char *tmpname;
394 const char **namebuf;
395 char *tokptr;
396 int res;
397 int i;
399 tmpname = xstrdup (name);
400 namebuf = xmalloc (sizeof (*namebuf));
402 for (i = 0;
403 (namebuf[i] = strtok_r (i == 0 ? tmpname : NULL, "/", &tokptr)); i++)
405 namebuf = xrealloc (namebuf, (i + 2) * sizeof (*namebuf));
408 res = shishi_principal_name_set (handle, namenode, namefield,
409 SHISHI_NT_UNKNOWN, namebuf);
410 free (namebuf);
411 free (tmpname);
412 if (res != SHISHI_OK)
414 shishi_error_printf (handle, _("Could not set principal name: %s\n"),
415 shishi_strerror (res));
416 return res;
419 return SHISHI_OK;
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.
428 * Derive the default salt from a principal. The default salt is the
429 * concatenation of the decoded realm and principal.
431 * Return value: Return SHISHI_OK if successful.
434 shishi_derive_default_salt (Shishi * handle,
435 const char *name,
436 char **salt)
438 char *principal;
439 char *realm;
440 int rc;
442 rc = shishi_parse_name (handle, name, &principal, &realm);
443 if (rc != SHISHI_OK)
444 return rc;
446 if (!principal || !realm)
448 if (realm)
449 free (realm);
450 if (principal)
451 free (principal);
452 return SHISHI_INVALID_PRINCIPAL_NAME;
455 *salt = xasprintf ("%s%s", realm, principal);
457 free (realm);
458 free (principal);
460 return SHISHI_OK;
464 * shishi_server_for_local_service:
465 * @handle: shishi handle as allocated by shishi_init().
466 * @service: zero terminated string with name of service, e.g., "host".
468 * Construct a service principal (e.g., "imap/yxa.extuno.com") based
469 * on supplied service name (i.e., "imap") and the system hostname as
470 * returned by hostname() (i.e., "yxa.extundo.com"). The string must
471 * be deallocated by the caller.
473 * Return value: Return newly allocated service name string.
475 char *
476 shishi_server_for_local_service (Shishi * handle, const char *service)
478 char *hostname;
479 char *server;
481 hostname = xgethostname ();
483 asprintf (&server, "%s/%s", service, hostname);
485 free (hostname);
487 return server;