MFC r1.6 r1.15 (HEAD)
[dragonfly.git] / crypto / heimdal-0.6.3 / kadmin / util.c
blobb25bf2a60ca2294b0005f50690a36faa81cfcc6c
1 /*
2 * Copyright (c) 1997 - 2002 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
34 #include "kadmin_locl.h"
35 #include <parse_units.h>
37 RCSID("$Id: util.c,v 1.39 2003/04/14 11:55:27 lha Exp $");
40 * util.c - functions for parsing, unparsing, and editing different
41 * types of data used in kadmin.
44 static int
45 get_response(const char *prompt, const char *def, char *buf, size_t len);
48 * attributes
51 struct units kdb_attrs[] = {
52 { "new-princ", KRB5_KDB_NEW_PRINC },
53 { "support-desmd5", KRB5_KDB_SUPPORT_DESMD5 },
54 { "pwchange-service", KRB5_KDB_PWCHANGE_SERVICE },
55 { "disallow-svr", KRB5_KDB_DISALLOW_SVR },
56 { "requires-pw-change", KRB5_KDB_REQUIRES_PWCHANGE },
57 { "requires-hw-auth", KRB5_KDB_REQUIRES_HW_AUTH },
58 { "requires-pre-auth", KRB5_KDB_REQUIRES_PRE_AUTH },
59 { "disallow-all-tix", KRB5_KDB_DISALLOW_ALL_TIX },
60 { "disallow-dup-skey", KRB5_KDB_DISALLOW_DUP_SKEY },
61 { "disallow-proxiable", KRB5_KDB_DISALLOW_PROXIABLE },
62 { "disallow-renewable", KRB5_KDB_DISALLOW_RENEWABLE },
63 { "disallow-tgt-based", KRB5_KDB_DISALLOW_TGT_BASED },
64 { "disallow-forwardable", KRB5_KDB_DISALLOW_FORWARDABLE },
65 { "disallow-postdated", KRB5_KDB_DISALLOW_POSTDATED },
66 { NULL }
70 * convert the attributes in `attributes' into a printable string
71 * in `str, len'
74 void
75 attributes2str(krb5_flags attributes, char *str, size_t len)
77 unparse_flags (attributes, kdb_attrs, str, len);
81 * convert the string in `str' into attributes in `flags'
82 * return 0 if parsed ok, else -1.
85 int
86 str2attributes(const char *str, krb5_flags *flags)
88 int res;
90 res = parse_flags (str, kdb_attrs, *flags);
91 if (res < 0)
92 return res;
93 else {
94 *flags = res;
95 return 0;
100 * try to parse the string `resp' into attributes in `attr', also
101 * setting the `bit' in `mask' if attributes are given and valid.
105 parse_attributes (const char *resp, krb5_flags *attr, int *mask, int bit)
107 krb5_flags tmp = *attr;
109 if (str2attributes(resp, &tmp) == 0) {
110 *attr = tmp;
111 if (mask)
112 *mask |= bit;
113 return 0;
114 } else if(*resp == '?') {
115 print_flags_table (kdb_attrs, stderr);
116 } else {
117 fprintf (stderr, "Unable to parse '%s'\n", resp);
119 return -1;
123 * allow the user to edit the attributes in `attr', prompting with `prompt'
127 edit_attributes (const char *prompt, krb5_flags *attr, int *mask, int bit)
129 char buf[1024], resp[1024];
131 if (mask && (*mask & bit))
132 return 0;
134 attributes2str(*attr, buf, sizeof(buf));
135 for (;;) {
136 if(get_response("Attributes", buf, resp, sizeof(resp)) != 0)
137 return 1;
138 if (resp[0] == '\0')
139 break;
140 if (parse_attributes (resp, attr, mask, bit) == 0)
141 break;
143 return 0;
147 * time_t
148 * the special value 0 means ``never''
152 * Convert the time `t' to a string representation in `str' (of max
153 * size `len'). If include_time also include time, otherwise just
154 * date.
157 void
158 time_t2str(time_t t, char *str, size_t len, int include_time)
160 if(t) {
161 if(include_time)
162 strftime(str, len, "%Y-%m-%d %H:%M:%S UTC", gmtime(&t));
163 else
164 strftime(str, len, "%Y-%m-%d", gmtime(&t));
165 } else
166 snprintf(str, len, "never");
170 * Convert the time representation in `str' to a time in `time'.
171 * Return 0 if succesful, else -1.
175 str2time_t (const char *str, time_t *t)
177 const char *p;
178 struct tm tm, tm2;
180 memset (&tm, 0, sizeof (tm));
182 if(strcasecmp(str, "never") == 0) {
183 *t = 0;
184 return 0;
187 if(strcasecmp(str, "now") == 0) {
188 *t = time(NULL);
189 return 0;
192 p = strptime (str, "%Y-%m-%d", &tm);
194 if (p == NULL)
195 return -1;
197 /* Do it on the end of the day */
198 tm2.tm_hour = 23;
199 tm2.tm_min = 59;
200 tm2.tm_sec = 59;
202 if(strptime (p, "%H:%M:%S", &tm2) != NULL) {
203 tm.tm_hour = tm2.tm_hour;
204 tm.tm_min = tm2.tm_min;
205 tm.tm_sec = tm2.tm_sec;
208 *t = tm2time (tm, 0);
209 return 0;
213 * try to parse the time in `resp' storing it in `value'
217 parse_timet (const char *resp, krb5_timestamp *value, int *mask, int bit)
219 time_t tmp;
221 if (str2time_t(resp, &tmp) == 0) {
222 *value = tmp;
223 if(mask)
224 *mask |= bit;
225 return 0;
226 } else if(*resp == '?') {
227 printf ("Print date on format YYYY-mm-dd [hh:mm:ss]\n");
228 } else {
229 fprintf (stderr, "Unable to parse time '%s'\n", resp);
231 return -1;
235 * allow the user to edit the time in `value'
239 edit_timet (const char *prompt, krb5_timestamp *value, int *mask, int bit)
241 char buf[1024], resp[1024];
243 if (mask && (*mask & bit))
244 return 0;
246 time_t2str (*value, buf, sizeof (buf), 0);
248 for (;;) {
249 if(get_response(prompt, buf, resp, sizeof(resp)) != 0)
250 return 1;
251 if (parse_timet (resp, value, mask, bit) == 0)
252 break;
254 return 0;
258 * deltat
259 * the special value 0 means ``unlimited''
263 * convert the delta_t value in `t' into a printable form in `str, len'
266 void
267 deltat2str(unsigned t, char *str, size_t len)
269 if(t == 0 || t == INT_MAX)
270 snprintf(str, len, "unlimited");
271 else
272 unparse_time(t, str, len);
276 * parse the delta value in `str', storing result in `*delta'
277 * return 0 if ok, else -1
281 str2deltat(const char *str, krb5_deltat *delta)
283 int res;
285 if(strcasecmp(str, "unlimited") == 0) {
286 *delta = 0;
287 return 0;
289 res = parse_time(str, "day");
290 if (res < 0)
291 return res;
292 else {
293 *delta = res;
294 return 0;
299 * try to parse the string in `resp' into a deltad in `value'
300 * `mask' will get the bit `bit' set if a value was given.
304 parse_deltat (const char *resp, krb5_deltat *value, int *mask, int bit)
306 krb5_deltat tmp;
308 if (str2deltat(resp, &tmp) == 0) {
309 *value = tmp;
310 if (mask)
311 *mask |= bit;
312 return 0;
313 } else if(*resp == '?') {
314 print_time_table (stderr);
315 } else {
316 fprintf (stderr, "Unable to parse time '%s'\n", resp);
318 return -1;
322 * allow the user to edit the deltat in `value'
326 edit_deltat (const char *prompt, krb5_deltat *value, int *mask, int bit)
328 char buf[1024], resp[1024];
330 if (mask && (*mask & bit))
331 return 0;
333 deltat2str(*value, buf, sizeof(buf));
334 for (;;) {
335 if(get_response(prompt, buf, resp, sizeof(resp)) != 0)
336 return 1;
337 if (parse_deltat (resp, value, mask, bit) == 0)
338 break;
340 return 0;
344 * allow the user to edit `ent'
347 void
348 set_defaults(kadm5_principal_ent_t ent, int *mask,
349 kadm5_principal_ent_t default_ent, int default_mask)
351 if (default_ent
352 && (default_mask & KADM5_MAX_LIFE)
353 && !(*mask & KADM5_MAX_LIFE))
354 ent->max_life = default_ent->max_life;
356 if (default_ent
357 && (default_mask & KADM5_MAX_RLIFE)
358 && !(*mask & KADM5_MAX_RLIFE))
359 ent->max_renewable_life = default_ent->max_renewable_life;
361 if (default_ent
362 && (default_mask & KADM5_PRINC_EXPIRE_TIME)
363 && !(*mask & KADM5_PRINC_EXPIRE_TIME))
364 ent->princ_expire_time = default_ent->princ_expire_time;
366 if (default_ent
367 && (default_mask & KADM5_PW_EXPIRATION)
368 && !(*mask & KADM5_PW_EXPIRATION))
369 ent->pw_expiration = default_ent->pw_expiration;
371 if (default_ent
372 && (default_mask & KADM5_ATTRIBUTES)
373 && !(*mask & KADM5_ATTRIBUTES))
374 ent->attributes = default_ent->attributes & ~KRB5_KDB_DISALLOW_ALL_TIX;
378 edit_entry(kadm5_principal_ent_t ent, int *mask,
379 kadm5_principal_ent_t default_ent, int default_mask)
382 set_defaults(ent, mask, default_ent, default_mask);
384 if(edit_deltat ("Max ticket life", &ent->max_life, mask,
385 KADM5_MAX_LIFE) != 0)
386 return 1;
388 if(edit_deltat ("Max renewable life", &ent->max_renewable_life, mask,
389 KADM5_MAX_RLIFE) != 0)
390 return 1;
392 if(edit_timet ("Principal expiration time", &ent->princ_expire_time, mask,
393 KADM5_PRINC_EXPIRE_TIME) != 0)
394 return 1;
396 if(edit_timet ("Password expiration time", &ent->pw_expiration, mask,
397 KADM5_PW_EXPIRATION) != 0)
398 return 1;
400 if(edit_attributes ("Attributes", &ent->attributes, mask,
401 KADM5_ATTRIBUTES) != 0)
402 return 1;
404 return 0;
408 * Parse the arguments, set the fields in `ent' and the `mask' for the
409 * entries having been set.
410 * Return 1 on failure and 0 on success.
414 set_entry(krb5_context context,
415 kadm5_principal_ent_t ent,
416 int *mask,
417 const char *max_ticket_life,
418 const char *max_renewable_life,
419 const char *expiration,
420 const char *pw_expiration,
421 const char *attributes)
423 if (max_ticket_life != NULL) {
424 if (parse_deltat (max_ticket_life, &ent->max_life,
425 mask, KADM5_MAX_LIFE)) {
426 krb5_warnx (context, "unable to parse `%s'", max_ticket_life);
427 return 1;
430 if (max_renewable_life != NULL) {
431 if (parse_deltat (max_renewable_life, &ent->max_renewable_life,
432 mask, KADM5_MAX_RLIFE)) {
433 krb5_warnx (context, "unable to parse `%s'", max_renewable_life);
434 return 1;
438 if (expiration) {
439 if (parse_timet (expiration, &ent->princ_expire_time,
440 mask, KADM5_PRINC_EXPIRE_TIME)) {
441 krb5_warnx (context, "unable to parse `%s'", expiration);
442 return 1;
445 if (pw_expiration) {
446 if (parse_timet (pw_expiration, &ent->pw_expiration,
447 mask, KADM5_PW_EXPIRATION)) {
448 krb5_warnx (context, "unable to parse `%s'", pw_expiration);
449 return 1;
452 if (attributes != NULL) {
453 if (parse_attributes (attributes, &ent->attributes,
454 mask, KADM5_ATTRIBUTES)) {
455 krb5_warnx (context, "unable to parse `%s'", attributes);
456 return 1;
459 return 0;
463 * Does `string' contain any globing characters?
466 static int
467 is_expression(const char *string)
469 const char *p;
470 int quote = 0;
472 for(p = string; *p; p++) {
473 if(quote) {
474 quote = 0;
475 continue;
477 if(*p == '\\')
478 quote++;
479 else if(strchr("[]*?", *p) != NULL)
480 return 1;
482 return 0;
485 /* loop over all principals matching exp */
487 foreach_principal(const char *exp,
488 int (*func)(krb5_principal, void*),
489 const char *funcname,
490 void *data)
492 char **princs;
493 int num_princs;
494 int i;
495 krb5_error_code ret;
496 krb5_principal princ_ent;
497 int is_expr;
499 /* if this isn't an expression, there is no point in wading
500 through the whole database looking for matches */
501 is_expr = is_expression(exp);
502 if(is_expr)
503 ret = kadm5_get_principals(kadm_handle, exp, &princs, &num_princs);
504 if(!is_expr || ret == KADM5_AUTH_LIST) {
505 /* we might be able to perform the requested opreration even
506 if we're not allowed to list principals */
507 num_princs = 1;
508 princs = malloc(sizeof(*princs));
509 if(princs == NULL)
510 return ENOMEM;
511 princs[0] = strdup(exp);
512 if(princs[0] == NULL){
513 free(princs);
514 return ENOMEM;
516 } else if(ret) {
517 krb5_warn(context, ret, "kadm5_get_principals");
518 return ret;
520 for(i = 0; i < num_princs; i++) {
521 ret = krb5_parse_name(context, princs[i], &princ_ent);
522 if(ret){
523 krb5_warn(context, ret, "krb5_parse_name(%s)", princs[i]);
524 continue;
526 ret = (*func)(princ_ent, data);
527 if(ret)
528 krb5_warn(context, ret, "%s %s", funcname, princs[i]);
529 krb5_free_principal(context, princ_ent);
531 kadm5_free_name_list(kadm_handle, princs, &num_princs);
532 return 0;
536 * prompt with `prompt' and default value `def', and store the reply
537 * in `buf, len'
540 #include <setjmp.h>
542 static jmp_buf jmpbuf;
544 static void
545 interrupt(int sig)
547 longjmp(jmpbuf, 1);
550 static int
551 get_response(const char *prompt, const char *def, char *buf, size_t len)
553 char *p;
554 void (*osig)(int);
556 osig = signal(SIGINT, interrupt);
557 if(setjmp(jmpbuf)) {
558 signal(SIGINT, osig);
559 printf("\n");
560 return 1;
563 printf("%s [%s]:", prompt, def);
564 if(fgets(buf, len, stdin) == NULL) {
565 int save_errno = errno;
566 if(ferror(stdin))
567 krb5_err(context, 1, save_errno, "<stdin>");
568 signal(SIGINT, osig);
569 return 1;
571 p = strchr(buf, '\n');
572 if(p)
573 *p = '\0';
574 if(strcmp(buf, "") == 0)
575 strlcpy(buf, def, len);
576 signal(SIGINT, osig);
577 return 0;
581 * return [0, 16) or -1
584 static int
585 hex2n (char c)
587 static char hexdigits[] = "0123456789abcdef";
588 const char *p;
590 p = strchr (hexdigits, tolower((unsigned char)c));
591 if (p == NULL)
592 return -1;
593 else
594 return p - hexdigits;
598 * convert a key in a readable format into a keyblock.
599 * return 0 iff succesful, otherwise `err' should point to an error message
603 parse_des_key (const char *key_string, krb5_key_data *key_data,
604 const char **err)
606 const char *p = key_string;
607 unsigned char bits[8];
608 int i;
610 if (strlen (key_string) != 16) {
611 *err = "bad length, should be 16 for DES key";
612 return 1;
614 for (i = 0; i < 8; ++i) {
615 int d1, d2;
617 d1 = hex2n(p[2 * i]);
618 d2 = hex2n(p[2 * i + 1]);
619 if (d1 < 0 || d2 < 0) {
620 *err = "non-hex character";
621 return 1;
623 bits[i] = (d1 << 4) | d2;
625 for (i = 0; i < 3; ++i) {
626 key_data[i].key_data_ver = 2;
627 key_data[i].key_data_kvno = 0;
628 /* key */
629 key_data[i].key_data_type[0] = ETYPE_DES_CBC_CRC;
630 key_data[i].key_data_length[0] = 8;
631 key_data[i].key_data_contents[0] = malloc(8);
632 memcpy (key_data[i].key_data_contents[0], bits, 8);
633 /* salt */
634 key_data[i].key_data_type[1] = KRB5_PW_SALT;
635 key_data[i].key_data_length[1] = 0;
636 key_data[i].key_data_contents[1] = NULL;
638 key_data[0].key_data_type[0] = ETYPE_DES_CBC_MD5;
639 key_data[1].key_data_type[0] = ETYPE_DES_CBC_MD4;
640 return 0;