move up roken-common.h again.
[heimdal.git] / kadmin / util.c
blobe2fb166fb4620a3cd48e0c517b87d54b1c3f6648
1 /*
2 * Copyright (c) 1997, 1998, 1999 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$");
40 * util.c - functions for parsing, unparsing, and editing different
41 * types of data used in kadmin.
45 * attributes
48 struct units kdb_attrs[] = {
49 { "new-princ", KRB5_KDB_NEW_PRINC },
50 { "support-desmd5", KRB5_KDB_SUPPORT_DESMD5 },
51 { "pwchange-service", KRB5_KDB_PWCHANGE_SERVICE },
52 { "disallow-svr", KRB5_KDB_DISALLOW_SVR },
53 { "requires-pw-change", KRB5_KDB_REQUIRES_PWCHANGE },
54 { "requires-hw-auth", KRB5_KDB_REQUIRES_HW_AUTH },
55 { "requires-pre-auth", KRB5_KDB_REQUIRES_PRE_AUTH },
56 { "disallow-all-tix", KRB5_KDB_DISALLOW_ALL_TIX },
57 { "disallow-dup-skey", KRB5_KDB_DISALLOW_DUP_SKEY },
58 { "disallow-proxiable", KRB5_KDB_DISALLOW_PROXIABLE },
59 { "disallow-renewable", KRB5_KDB_DISALLOW_RENEWABLE },
60 { "disallow-tgt-based", KRB5_KDB_DISALLOW_TGT_BASED },
61 { "disallow-forwardable", KRB5_KDB_DISALLOW_FORWARDABLE },
62 { "disallow-postdated", KRB5_KDB_DISALLOW_POSTDATED },
63 { NULL }
67 * convert the attributes in `attributes' into a printable string
68 * in `str, len'
71 void
72 attributes2str(krb5_flags attributes, char *str, size_t len)
74 unparse_flags (attributes, kdb_attrs, str, len);
78 * convert the string in `str' into attributes in `flags'
79 * return 0 if parsed ok, else -1.
82 int
83 str2attributes(const char *str, krb5_flags *flags)
85 int res;
87 res = parse_flags (str, kdb_attrs, *flags);
88 if (res < 0)
89 return res;
90 else {
91 *flags = res;
92 return 0;
97 * try to parse the string `resp' into attributes in `attr', also
98 * setting the `bit' in `mask' if attributes are given and valid.
102 parse_attributes (const char *resp, krb5_flags *attr, int *mask, int bit)
104 krb5_flags tmp = *attr;
106 if (resp[0] == '\0')
107 return 0;
108 else if (str2attributes(resp, &tmp) == 0) {
109 *attr = tmp;
110 if (mask)
111 *mask |= bit;
112 return 0;
113 } else if(*resp == '?') {
114 print_flags_table (kdb_attrs, stderr);
115 } else {
116 fprintf (stderr, "Unable to parse '%s'\n", resp);
118 return -1;
122 * allow the user to edit the attributes in `attr', prompting with `prompt'
126 edit_attributes (const char *prompt, krb5_flags *attr, int *mask, int bit)
128 char buf[1024], resp[1024];
130 if (mask && (*mask & bit))
131 return 0;
133 attributes2str(*attr, buf, sizeof(buf));
134 for (;;) {
135 get_response("Attributes", buf, resp, sizeof(resp));
136 if (parse_attributes (resp, attr, mask, bit) == 0)
137 break;
139 return 0;
143 * time_t
144 * the special value 0 means ``never''
148 * Convert the time `t' to a string representation in `str' (of max
149 * size `len'). If include_time also include time, otherwise just
150 * date.
153 void
154 time_t2str(time_t t, char *str, size_t len, int include_time)
156 if(t) {
157 if(include_time)
158 strftime(str, len, "%Y-%m-%d %H:%M:%S UTC", gmtime(&t));
159 else
160 strftime(str, len, "%Y-%m-%d", gmtime(&t));
161 } else
162 snprintf(str, len, "never");
166 * Convert the time representation in `str' to a time in `time'.
167 * Return 0 if succesful, else -1.
171 str2time_t (const char *str, time_t *time)
173 const char *p;
174 struct tm tm;
176 memset (&tm, 0, sizeof (tm));
178 if(strcasecmp(str, "never") == 0) {
179 *time = 0;
180 return 0;
183 p = strptime (str, "%Y-%m-%d", &tm);
185 if (p == NULL)
186 return -1;
188 /* Do it on the end of the day */
189 tm.tm_hour = 23;
190 tm.tm_min = 59;
191 tm.tm_sec = 59;
193 strptime (p, "%H:%M:%S", &tm);
195 *time = tm2time (tm, 0);
196 return 0;
200 * try to parse the time in `resp' storing it in `value'
204 parse_timet (const char *resp, krb5_timestamp *value, int *mask, int bit)
206 time_t tmp;
208 if (str2time_t(resp, &tmp) == 0) {
209 *value = tmp;
210 if(mask)
211 *mask |= bit;
212 return 0;
213 } else if(*resp == '?') {
214 printf ("Print date on format YYYY-mm-dd [hh:mm:ss]\n");
215 } else {
216 fprintf (stderr, "Unable to parse time '%s'\n", resp);
218 return -1;
222 * allow the user to edit the time in `value'
226 edit_timet (const char *prompt, krb5_timestamp *value, int *mask, int bit)
228 char buf[1024], resp[1024];
230 if (mask && (*mask & bit))
231 return 0;
233 time_t2str (*value, buf, sizeof (buf), 0);
235 for (;;) {
236 get_response(prompt, buf, resp, sizeof(resp));
237 if (parse_timet (resp, value, mask, bit) == 0)
238 break;
240 return 0;
244 * deltat
245 * the special value 0 means ``unlimited''
249 * convert the delta_t value in `t' into a printable form in `str, len'
252 void
253 deltat2str(unsigned t, char *str, size_t len)
255 if(t)
256 unparse_time(t, str, len);
257 else
258 snprintf(str, len, "unlimited");
262 * parse the delta value in `str', storing result in `*delta'
263 * return 0 if ok, else -1
267 str2deltat(const char *str, krb5_deltat *delta)
269 int res;
271 if(strcasecmp(str, "unlimited") == 0) {
272 *delta = 0;
273 return 0;
275 res = parse_time(str, "day");
276 if (res < 0)
277 return res;
278 else {
279 *delta = res;
280 return 0;
285 * try to parse the string in `resp' into a deltad in `value'
286 * `mask' will get the bit `bit' set if a value was given.
290 parse_deltat (const char *resp, krb5_deltat *value, int *mask, int bit)
292 krb5_deltat tmp;
294 if (str2deltat(resp, &tmp) == 0) {
295 *value = tmp;
296 if (mask)
297 *mask |= bit;
298 return 0;
299 } else if(*resp == '?') {
300 print_time_table (stderr);
301 } else {
302 fprintf (stderr, "Unable to parse time '%s'\n", resp);
304 return -1;
308 * allow the user to edit the deltat in `value'
312 edit_deltat (const char *prompt, krb5_deltat *value, int *mask, int bit)
314 char buf[1024], resp[1024];
316 if (mask && (*mask & bit))
317 return 0;
319 deltat2str(*value, buf, sizeof(buf));
320 for (;;) {
321 get_response(prompt, buf, resp, sizeof(resp));
322 if (parse_deltat (resp, value, mask, bit) == 0)
323 break;
325 return 0;
329 * allow the user to edit `ent'
333 edit_entry(kadm5_principal_ent_t ent, int *mask,
334 kadm5_principal_ent_t default_ent, int default_mask)
336 if (default_ent && (default_mask & KADM5_MAX_LIFE))
337 ent->max_life = default_ent->max_life;
338 edit_deltat ("Max ticket life", &ent->max_life, mask,
339 KADM5_MAX_LIFE);
341 if (default_ent && (default_mask & KADM5_MAX_RLIFE))
342 ent->max_renewable_life = default_ent->max_renewable_life;
343 edit_deltat ("Max renewable life", &ent->max_renewable_life, mask,
344 KADM5_MAX_RLIFE);
346 if (default_ent && (default_mask & KADM5_PRINC_EXPIRE_TIME))
347 ent->princ_expire_time = default_ent->princ_expire_time;
348 edit_timet ("Principal expiration time", &ent->princ_expire_time, mask,
349 KADM5_PRINC_EXPIRE_TIME);
351 if (default_ent && (default_mask & KADM5_PW_EXPIRATION))
352 ent->pw_expiration = default_ent->pw_expiration;
353 edit_timet ("Password expiration time", &ent->pw_expiration, mask,
354 KADM5_PW_EXPIRATION);
356 if (default_ent && (default_mask & KADM5_ATTRIBUTES))
357 ent->attributes = default_ent->attributes & ~KRB5_KDB_DISALLOW_ALL_TIX;
358 edit_attributes ("Attributes", &ent->attributes, mask,
359 KADM5_ATTRIBUTES);
360 return 0;
364 * Parse the arguments, set the fields in `ent' and the `mask' for the
365 * entries having been set.
366 * Return 1 on failure and 0 on success.
370 set_entry(krb5_context context,
371 kadm5_principal_ent_t ent,
372 int *mask,
373 const char *max_ticket_life,
374 const char *max_renewable_life,
375 const char *expiration,
376 const char *pw_expiration,
377 const char *attributes)
379 if (max_ticket_life != NULL) {
380 if (parse_deltat (max_ticket_life, &ent->max_life,
381 mask, KADM5_MAX_LIFE)) {
382 krb5_warnx (context, "unable to parse `%s'", max_ticket_life);
383 return 1;
386 if (max_renewable_life != NULL) {
387 if (parse_deltat (max_renewable_life, &ent->max_renewable_life,
388 mask, KADM5_MAX_RLIFE)) {
389 krb5_warnx (context, "unable to parse `%s'", max_renewable_life);
390 return 1;
394 if (expiration) {
395 if (parse_timet (expiration, &ent->princ_expire_time,
396 mask, KADM5_PRINC_EXPIRE_TIME)) {
397 krb5_warnx (context, "unable to parse `%s'", expiration);
398 return 1;
401 if (pw_expiration) {
402 if (parse_timet (pw_expiration, &ent->pw_expiration,
403 mask, KADM5_PW_EXPIRATION)) {
404 krb5_warnx (context, "unable to parse `%s'", pw_expiration);
405 return 1;
408 if (attributes != NULL) {
409 if (parse_attributes (attributes, &ent->attributes,
410 mask, KADM5_ATTRIBUTES)) {
411 krb5_warnx (context, "unable to parse `%s'", attributes);
412 return 1;
415 return 0;
419 * Does `string' contain any globing characters?
422 static int
423 is_expression(const char *string)
425 const char *p;
426 int quote = 0;
428 for(p = string; *p; p++) {
429 if(quote) {
430 quote = 0;
431 continue;
433 if(*p == '\\')
434 quote++;
435 else if(strchr("[]*?", *p) != NULL)
436 return 1;
438 return 0;
441 /* loop over all principals matching exp */
443 foreach_principal(const char *exp,
444 int (*func)(krb5_principal, void*),
445 void *data)
447 char **princs;
448 int num_princs;
449 int i;
450 krb5_error_code ret;
451 krb5_principal princ_ent;
452 int is_expr;
454 /* if this isn't an expression, there is no point in wading
455 through the whole database looking for matches */
456 is_expr = is_expression(exp);
457 if(is_expr)
458 ret = kadm5_get_principals(kadm_handle, exp, &princs, &num_princs);
459 if(!is_expr || ret == KADM5_AUTH_LIST) {
460 /* we might be able to perform the requested opreration even
461 if we're not allowed to list principals */
462 num_princs = 1;
463 princs = malloc(sizeof(*princs));
464 if(princs == NULL)
465 return ENOMEM;
466 princs[0] = strdup(exp);
467 if(princs[0] == NULL){
468 free(princs);
469 return ENOMEM;
471 } else if(ret) {
472 krb5_warn(context, ret, "kadm5_get_principals");
473 return ret;
475 for(i = 0; i < num_princs; i++) {
476 ret = krb5_parse_name(context, princs[i], &princ_ent);
477 if(ret){
478 krb5_warn(context, ret, "krb5_parse_name(%s)", princs[i]);
479 continue;
481 ret = (*func)(princ_ent, data);
482 if(ret) {
483 char *tmp;
484 krb5_error_code ret2;
486 ret2 = krb5_unparse_name(context, princ_ent, &tmp);
487 if(ret2) {
488 krb5_warn(context, ret2, "krb5_unparse_name");
489 krb5_warn(context, ret, "<unknown principal>");
490 } else {
491 krb5_warn(context, ret, "%s", tmp);
492 free(tmp);
495 krb5_free_principal(context, princ_ent);
497 kadm5_free_name_list(kadm_handle, princs, &num_princs);
498 return 0;
502 * prompt with `prompt' and default value `def', and store the reply
503 * in `buf, len'
506 void
507 get_response(const char *prompt, const char *def, char *buf, size_t len)
509 char *p;
511 printf("%s [%s]:", prompt, def);
512 if(fgets(buf, len, stdin) == NULL)
513 *buf = '\0';
514 p = strchr(buf, '\n');
515 if(p)
516 *p = '\0';
517 if(strcmp(buf, "") == 0)
518 strncpy(buf, def, len);
519 buf[len-1] = 0;