No need for getline.h.
[shishi.git] / lib / cfg.c
blobf447fa94adf080d3c0fb126ced3805cfbebc9b3f
1 /* cfg.h --- Configuration file functions.
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 /* Get prototypes. */
26 #include "cfg.h"
28 #define KDC_SERVICE_PORT "\x6b\x65\x72\x62\x65\x72\x6f\x73"
30 enum
32 DEFAULT_REALM_OPTION = 0,
33 DEFAULT_PRINCIPAL_OPTION,
34 CLIENT_KDC_ETYPES_OPTION,
35 REALM_KDC_OPTION,
36 SERVER_REALM_OPTION,
37 KDC_TIMEOUT_OPTION,
38 KDC_RETRIES_OPTION,
39 TICKET_LIFE_OPTION,
40 RENEW_LIFE_OPTION,
41 AUTHORIZATION_TYPES_OPTION,
42 VERBOSE_CRYPTO_NOISE_OPTION,
43 VERBOSE_CRYPTO_OPTION,
44 VERBOSE_ASN1_OPTION,
45 VERBOSE_NOISE_OPTION,
46 VERBOSE_OPTION,
47 STRINGPROCESS_OPTION,
48 THE_END
51 static const char *_shishi_opts[] = {
52 /* [DEFAULT_REALM_OPTION] = */ "default-realm",
53 /* [DEFAULT_PRINCIPAL_OPTION] = */ "default-principal",
54 /* [CLIENT_KDC_ETYPES_OPTION] = */ "client-kdc-etypes",
55 /* [REALM_KDC_OPTION] = */ "realm-kdc",
56 /* [SERVER_REALM_OPTION] = */ "server-realm",
57 /* [KDC_TIMEOUT_OPTION] = */ "kdc-timeout",
58 /* [KDC_RETRIES_OPTION] = */ "kdc-retries",
59 /* [TICKET_LIFE_OPTION] = */ "ticket-life",
60 /* [RENEW_LIFE_OPTION] = */ "renew-life",
61 /* [AUTHORIZATION_TYPES_OPTION] = */ "authorization-types",
62 /* [VERBOSE_CRYPTO_NOISE_OPTION] = */ "verbose-crypto-noise",
63 /* [VERBOSE_CRYPTO_OPTION] = */ "verbose-crypto",
64 /* [VERBOSE_ASN1_OPTION] = */ "verbose-asn1",
65 /* [VERBOSE_NOISE_OPTION] = */ "verbose-noise",
66 /* [VERBOSE_OPTION] = */ "verbose",
67 /* [STRINGPROCESS_OPTION] = */ "stringprocess",
68 /* [THE_END] = */ NULL
71 struct Shishi_realminfo *
72 _shishi_realminfo (Shishi * handle, const char *realm)
74 size_t i;
76 for (i = 0; i < handle->nrealminfos; i++)
77 if (strcmp (realm, handle->realminfos[i].name) == 0)
78 return &handle->realminfos[i];
80 return NULL;
83 struct Shishi_realminfo *
84 _shishi_realminfo_new (Shishi * handle, char *realm)
86 struct Shishi_realminfo *ri;
88 ri = _shishi_realminfo (handle, realm);
89 if (ri)
90 return ri;
92 handle->realminfos = xrealloc (handle->realminfos,
93 (++handle->nrealminfos) *
94 sizeof (*handle->realminfos));
96 ri = &handle->realminfos[handle->nrealminfos - 1];
97 memset (ri, 0, sizeof (*ri));
98 ri->name = realm;
100 return ri;
104 * shishi_cfg:
105 * @handle: Shishi library handle create by shishi_init().
106 * @option: string with shishi library option.
108 * Configure shishi library with given option.
110 * Return Value: Returns SHISHI_OK if option was valid.
113 shishi_cfg (Shishi * handle, char *option)
115 char *value;
116 char *realm = NULL;
117 int res;
118 size_t i;
120 while (option != NULL && *option != '\0')
122 switch (getsubopt (&option, _shishi_opts, &value))
124 case KDC_TIMEOUT_OPTION:
125 if (value && atoi (value) > 0)
126 handle->kdctimeout = atoi (value);
127 else if (value)
128 shishi_warn (handle, "Invalid KDC timeout value: `%s'", value);
129 else
130 shishi_warn (handle, "Missing KDC timeout value");
131 break;
133 case KDC_RETRIES_OPTION:
134 if (value && atoi (value) > 0)
135 handle->kdcretries = atoi (value);
136 else if (value)
137 shishi_warn (handle, "Invalid KDC retries value: `%s'", value);
138 else
139 shishi_warn (handle, "Missing KDC retries value");
140 break;
142 case TICKET_LIFE_OPTION:
144 time_t now = time (NULL);
145 time_t then = shishi_get_date (value, &now);
146 int diff = difftime (then, now);
148 if (value && then != -1 && diff > 0)
149 handle->ticketlife = diff;
150 else if (diff <= 0 && diff + 60 * 60 * 24 > 0)
151 /* Hack to support "17:00" as always meaning the next 17:00. */
152 handle->ticketlife = 60 * 60 * 24 + diff;
153 else if (diff <= 0)
154 shishi_warn (handle, "Negative ticket life date: `%s'", value);
155 else if (then == -1)
156 shishi_warn (handle, "Invalid ticket life date: `%s'", value);
157 else
158 shishi_warn (handle, "Missing ticket life value");
160 break;
162 case RENEW_LIFE_OPTION:
164 time_t now = time (NULL);
165 time_t then = shishi_get_date (value, &now);
166 int diff = difftime (then, now);
168 if (value && then != -1 && diff > 0)
169 handle->renewlife = diff;
170 else if (diff <= 0)
171 shishi_warn (handle, "Negative renew life date: `%s'", value);
172 else if (then == -1)
173 shishi_warn (handle, "Invalid renew life date: `%s'", value);
174 else
175 shishi_warn (handle, "Missing renew life value");
177 break;
179 case REALM_KDC_OPTION:
180 realm = xstrdup (value);
181 for (i = 0; i < handle->nrealminfos; i++)
182 if (strcmp (realm, handle->realminfos[i].name) == 0)
184 if (handle->realminfos[i].nkdcaddresses > 0 ||
185 handle->realminfos[i].kdcaddresses)
187 if (handle->realminfos[i].kdcaddresses)
188 free (handle->realminfos[i].kdcaddresses);
189 handle->realminfos[i].kdcaddresses = NULL;
190 handle->realminfos[i].nkdcaddresses = 0;
192 break;
194 handle->realminfos = xrealloc (handle->realminfos,
195 (handle->nrealminfos + 1) *
196 sizeof (*handle->realminfos));
197 memset (&handle->realminfos[handle->nrealminfos], 0,
198 sizeof (handle->realminfos[handle->nrealminfos]));
199 handle->realminfos[handle->nrealminfos].name = realm;
200 handle->nrealminfos++;
201 break;
203 case SERVER_REALM_OPTION:
205 struct Shishi_realminfo *ri;
206 ri = _shishi_realminfo_new (handle, value);
207 ri->serverwildcards = xrealloc (ri->serverwildcards,
208 ++ri->nserverwildcards *
209 sizeof (*ri->serverwildcards));
210 ri->serverwildcards[ri->nserverwildcards - 1] = xstrdup (value);
212 break;
214 case DEFAULT_REALM_OPTION:
215 handle->default_realm = xstrdup (value);
216 break;
218 case DEFAULT_PRINCIPAL_OPTION:
219 handle->default_principal = xstrdup (value);
220 break;
222 case CLIENT_KDC_ETYPES_OPTION:
223 res = shishi_cfg_clientkdcetype_set (handle, value);
224 if (res != SHISHI_OK)
225 return res;
226 break;
228 case AUTHORIZATION_TYPES_OPTION:
229 res = shishi_cfg_authorizationtype_set (handle, value);
230 if (res != SHISHI_OK)
231 return res;
232 break;
234 case STRINGPROCESS_OPTION:
235 if (handle->stringprocess)
236 free (handle->stringprocess);
237 handle->stringprocess = xstrdup (value);
238 break;
240 case VERBOSE_OPTION:
241 handle->verbose = value && atoi (value) ? atoi (value) :
242 ~0 & ~VERBOSES;
243 break;
245 case VERBOSE_CRYPTO_NOISE_OPTION:
246 handle->verbose |= SHISHI_VERBOSE_CRYPTO_NOISE;
247 break;
249 case VERBOSE_CRYPTO_OPTION:
250 handle->verbose |= SHISHI_VERBOSE_CRYPTO;
251 break;
253 case VERBOSE_ASN1_OPTION:
254 handle->verbose |= SHISHI_VERBOSE_ASN1;
255 break;
257 case VERBOSE_NOISE_OPTION:
258 handle->verbose |= SHISHI_VERBOSE_NOISE;
259 break;
261 case -1:
262 if (!value)
263 break;
264 for (i = 0; i < handle->nrealminfos; i++)
265 if (realm && handle->realminfos[i].name == realm)
267 struct Shishi_realminfo *ri = &handle->realminfos[i];
268 struct sockaddr_in *sinaddr;
269 struct hostent *he;
270 struct servent *se;
271 char *p;
272 int protocol = UDP;
273 int port = -1;
275 if ((p = strchr (value, '/')))
277 *p = '\0';
278 p++;
279 if (strcasecmp (p, "udp") == 0)
280 protocol = UDP;
281 else if (strcasecmp (p, "tcp") == 0)
282 protocol = TCP;
283 else if (strcasecmp (p, "tls") == 0)
284 protocol = TLS;
285 else
286 shishi_warn (handle,
287 "Ignoring unknown KDC parameter: %s", p);
290 if ((p = strchr (value, ':')))
292 *p = '\0';
293 p++;
294 port = atoi (p);
297 he = gethostbyname (value); /* XXX move to netio.c */
298 if (he == NULL ||
299 he->h_addr_list[0] == NULL || he->h_addrtype != AF_INET)
301 shishi_warn (handle,
302 "Unknown KDC host `%s' (h_errno %d)",
303 value, h_errno);
304 break;
307 ri->kdcaddresses = xrealloc (ri->kdcaddresses,
308 (ri->nkdcaddresses + 1) *
309 sizeof (*ri->kdcaddresses));
310 ri->kdcaddresses[ri->nkdcaddresses].name = xstrdup (value);
311 ri->kdcaddresses[ri->nkdcaddresses].protocol = protocol;
312 sinaddr = (struct sockaddr_in *)
313 &ri->kdcaddresses[ri->nkdcaddresses].sockaddress;
314 memset (sinaddr, 0, sizeof (struct sockaddr));
315 ri->nkdcaddresses++;
317 sinaddr->sin_family = he->h_addrtype;
318 memcpy (&sinaddr->sin_addr, he->h_addr_list[0], he->h_length);
319 if (port == -1)
321 se = getservbyname (KDC_SERVICE_PORT, NULL);
322 if (se)
323 sinaddr->sin_port = se->s_port;
324 else
325 sinaddr->sin_port = htons (88);
327 else
328 sinaddr->sin_port = htons (port);
330 if (realm)
331 break;
332 /* fall through */
334 default:
335 shishi_warn (handle, "Unknown option: `%s'", value);
336 break;
340 return SHISHI_OK;
344 * shishi_cfg_from_file:
345 * @handle: Shishi library handle create by shishi_init().
346 * @cfg: filename to read configuration from.
348 * Configure shishi library using configuration file.
350 * Return Value: Returns SHISHI_OK iff succesful.
353 shishi_cfg_from_file (Shishi * handle, const char *cfg)
355 char *line = NULL;
356 size_t len = 0;
357 FILE *fh;
359 if (cfg == NULL)
360 return SHISHI_OK;
362 fh = fopen (cfg, "r");
363 if (fh == NULL)
365 shishi_warn (handle, "`%s': %s", cfg, strerror (errno));
366 return SHISHI_FOPEN_ERROR;
369 while (!feof (fh))
371 ssize_t n = getline (&line, &len, fh);
372 char *p = line;
373 char *q;
375 if (n <= 0)
376 /* End of file or error. */
377 break;
379 while (strlen (p) > 0 && (p[strlen (p) - 1] == '\n' ||
380 p[strlen (p) - 1] == '\r'))
381 p[strlen (p) - 1] = '\0';
383 while (*p && strchr (" \t\r\n", *p))
384 p++;
386 if (*p == '\0' || *p == '#')
387 continue;
389 q = strchr (p, ' ');
390 if (q && (strchr (p, '=') == NULL || q < strchr (p, '=')))
391 *q = '=';
393 shishi_cfg (handle, p);
396 if (line)
397 free (line);
399 if (ferror (fh))
400 shishi_error_printf (handle, "Error reading configuration file");
402 if (fclose (fh) != 0)
403 return SHISHI_IO_ERROR;
405 return SHISHI_OK;
409 * shishi_cfg_print:
410 * @handle: Shishi library handle create by shishi_init().
411 * @fh: file descriptor opened for writing.
413 * Print library configuration status, mostly for debugging purposes.
415 * Return Value: Returns SHISHI_OK.
418 shishi_cfg_print (Shishi * handle, FILE * fh)
420 size_t i, j;
421 time_t tmp, now = time (NULL);
423 fprintf (fh, "Shishi initial library configuration:\n");
424 fprintf (fh, "\tDefault realm: %s\n",
425 handle->default_realm ? handle->default_realm : "(NULL)");
426 fprintf (fh, "\tDefault principal: %s\n",
427 handle->default_principal ? handle->default_principal : "(NULL)");
428 fprintf (fh, "\tClient KDC etypes:");
429 for (i = 0; i < handle->nclientkdcetypes; i++)
430 fprintf (fh, " %s", shishi_cipher_name (handle->clientkdcetypes[i]));
431 fprintf (fh, "\n");
432 fprintf (fh, "\tKDC: %s\n", handle->kdc ? handle->kdc : "(NULL)");
433 fprintf (fh, "\tVerbose: %d\n", handle->verbose);
434 tmp = now + handle->ticketlife;
435 fprintf (fh, "\tTicket life: %d seconds. %s",
436 handle->ticketlife, ctime (&tmp));
437 tmp = now + handle->renewlife;
438 fprintf (fh, "\tRenew life: %d seconds. %s",
439 handle->renewlife, ctime (&tmp));
440 for (i = 0; i < handle->nrealminfos; i++)
442 fprintf (fh, "\tRealm %s's KDCs:", handle->realminfos[i].name);
443 for (j = 0; j < handle->realminfos[i].nkdcaddresses; j++)
444 fprintf (fh, " %s (%s)", handle->realminfos[i].kdcaddresses[j].name,
445 inet_ntoa (((struct sockaddr_in *) &handle->realminfos[i].
446 kdcaddresses[j].sockaddress)->sin_addr));
447 fprintf (fh, "\n");
450 return SHISHI_OK;
454 * shishi_cfg_default_systemfile:
455 * @handle: Shishi library handle create by shishi_init().
457 * The system configuration file name is decided at compile-time, but
458 * may be overridden by the environment variable SHISHI_CONFIG.
460 * Return value: Return system configuration file name.
462 const char *
463 shishi_cfg_default_systemfile (Shishi * handle)
465 char *file;
467 file = getenv ("SHISHI_CONFIG");
468 if (file)
469 return file;
471 return SYSTEMCFGFILE;
474 #define BASE_DIR "/.shishi"
477 * shishi_cfg_default_userdirectory:
478 * @handle: Shishi library handle create by shishi_init().
480 * The default user directory (used for, e.g. Shishi ticket cache) is
481 * normally computed by appending BASE_DIR ("/.shishi") to the content
482 * of the environment variable $HOME, but can be overridden by
483 * specifying the complete path in the environment variable
484 * SHISHI_HOME.
486 * Return value: Return directory with configuration files etc.
488 const char *
489 shishi_cfg_default_userdirectory (Shishi * handle)
491 char *home;
492 char *envdir;
494 envdir = getenv ("SHISHI_HOME");
495 if (envdir)
496 return envdir;
498 if (!handle->userdirectory)
500 home = getenv ("HOME");
502 asprintf (&handle->userdirectory, "%s%s", home ? home : "", BASE_DIR);
505 return handle->userdirectory;
509 * shishi_cfg_userdirectory_file:
510 * @handle: Shishi library handle create by shishi_init().
511 * @file: basename of file to find in user directory.
513 * Get the full path to specified @file in the users' configuration
514 * directory.
516 * Return value: Return full path to given relative filename, relative
517 * to the user specific Shishi configuration directory as returned
518 * by shishi_cfg_default_userdirectory() (typically $HOME/.shishi).
520 char *
521 shishi_cfg_userdirectory_file (Shishi * handle, const char *file)
523 char *out;
525 asprintf (&out, "%s/%s", shishi_cfg_default_userdirectory (handle), file);
527 return out;
530 #define USERCFG_FILE "shishi.conf"
533 * shishi_cfg_default_userfile:
534 * @handle: Shishi library handle create by shishi_init().
536 * Get filename of default user configuration file, typically
537 * $HOME/shishi.conf.
539 * Return value: Return user configuration filename.
541 const char *
542 shishi_cfg_default_userfile (Shishi * handle)
544 if (!handle->usercfgfile)
545 handle->usercfgfile =
546 shishi_cfg_userdirectory_file (handle, USERCFG_FILE);
548 return handle->usercfgfile;
552 * shishi_cfg_clientkdcetype:
553 * @handle: Shishi library handle create by shishi_init().
554 * @etypes: output array with encryption types.
556 * Set the etypes variable to the array of preferred client etypes.
558 * Return value: Return the number of encryption types in the array,
559 * 0 means none.
562 shishi_cfg_clientkdcetype (Shishi * handle, int32_t ** etypes)
564 *etypes = handle->clientkdcetypes;
565 return handle->nclientkdcetypes;
569 * shishi_cfg_clientkdcetype_fast:
570 * @handle: Shishi library handle create by shishi_init().
572 * Extract the default etype from the list of preferred client etypes.
574 * Return value: Return the default encryption types.
576 int32_t
577 shishi_cfg_clientkdcetype_fast (Shishi * handle)
579 if (handle->nclientkdcetypes > 0)
580 return handle->clientkdcetypes[0];
581 else
582 return SHISHI_AES256_CTS_HMAC_SHA1_96;
586 * shishi_cfg_clientkdcetype_set:
587 * @handle: Shishi library handle create by shishi_init().
588 * @value: string with encryption types.
590 * Set the "client-kdc-etypes" configuration option from given string.
591 * The string contains encryption types (integer or names) separated
592 * by comma or whitespace, e.g. "aes256-cts-hmac-sha1-96
593 * des3-cbc-sha1-kd des-cbc-md5".
595 * Return value: Return SHISHI_OK iff successful.
598 shishi_cfg_clientkdcetype_set (Shishi * handle, char *value)
600 char *ptrptr;
601 char *val;
602 int i;
603 int tot = 0;
605 if (value == NULL || *value == '\0')
606 return SHISHI_OK;
608 for (i = 0; (val = strtok_r (i == 0 ? value : NULL, ", \t", &ptrptr)); i++)
610 int etype = shishi_cipher_parse (val);
612 if (etype == -1)
613 shishi_warn (handle, "Ignoring unknown encryption type: `%s'", val);
614 else
616 int *new;
618 tot++;
619 new = xrealloc (handle->clientkdcetypes,
620 tot * sizeof (*handle->clientkdcetypes));
621 handle->clientkdcetypes = new;
622 handle->clientkdcetypes[tot - 1] = etype;
623 handle->nclientkdcetypes = tot;
627 return SHISHI_OK;
631 * shishi_cfg_authorizationtype_set:
632 * @handle: Shishi library handle create by shishi_init().
633 * @value: string with authorization types.
635 * Set the "authorization-types" configuration option from given string.
636 * The string contains authorization types (integer or names) separated
637 * by comma or whitespace, e.g. "basic k5login".
639 * Return value: Return SHISHI_OK iff successful.
642 shishi_cfg_authorizationtype_set (Shishi * handle, char *value)
644 char *ptrptr;
645 char *val;
646 int i;
647 int tot = 0;
649 if (value == NULL || *value == '\0')
650 return SHISHI_OK;
652 for (i = 0; (val = strtok_r (i == 0 ? value : NULL, ", \t", &ptrptr)); i++)
654 int atype = shishi_authorization_parse (val);
656 if (atype == -1)
657 shishi_warn (handle, "Ignoring unknown authorization type: `%s'",
658 val);
659 else
661 int *new;
663 tot++;
664 new = xrealloc (handle->authorizationtypes,
665 tot * sizeof (*handle->authorizationtypes));
666 handle->authorizationtypes = new;
667 handle->authorizationtypes[tot - 1] = atype;
668 handle->nauthorizationtypes = tot;
672 return SHISHI_OK;