dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / krb5 / kadmin / cli / kadmin.c
blob6817c10921fdd82fcdeaa866e09ebe9ddbc48fa4
1 /*
2 * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
3 */
5 /*
6 * Copyright 1994 by the Massachusetts Institute of Technology.
7 * All Rights Reserved.
9 * Export of this software from the United States of America may
10 * require a specific license from the United States Government.
11 * It is the responsibility of any person or organization contemplating
12 * export to obtain such a license before exporting.
14 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
15 * distribute this software and its documentation for any purpose and
16 * without fee is hereby granted, provided that the above copyright
17 * notice appear in all copies and that both that copyright notice and
18 * this permission notice appear in supporting documentation, and that
19 * the name of M.I.T. not be used in advertising or publicity pertaining
20 * to distribution of the software without specific, written prior
21 * permission. Furthermore if you modify this software you must label
22 * your software as modified software and not distribute it in such a
23 * fashion that it might be confused with the original M.I.T. software.
24 * M.I.T. makes no representations about the suitability of
25 * this software for any purpose. It is provided "as is" without express
26 * or implied warranty.
28 * kadmin.c: base functions for a kadmin command line interface using
29 * the OVSecure library
32 #include <kadm5/admin.h>
33 #include <krb5/adm_proto.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <sys/types.h>
37 #include <math.h>
38 #include <unistd.h>
39 #include <pwd.h>
40 /* #include <sys/timeb.h> */
41 #include <time.h>
42 #include "kadmin.h"
43 #include <libintl.h>
44 #include <krb5.h>
47 * Solaris: the following are needed for paging
49 #include <signal.h>
50 #include <sys/wait.h>
52 /* command name when called "locally" (i.e. non-networked client ) */
53 #define KADMIN_LOCAL_NAME "kadmin.local"
55 /* functions defined in remote/local specific files */
56 extern void usage(const char *);
58 /* special struct to convert flag names for principals
59 to actual krb5_flags for a principal */
60 struct pflag {
61 char *flagname; /* name of flag as typed to CLI */
62 int flaglen; /* length of string (not counting -,+) */
63 krb5_flags theflag; /* actual principal flag to set/clear */
64 int set; /* 0 means clear, 1 means set (on '-') */
67 static struct pflag flags[] = {
68 {"allow_postdated", 15, KRB5_KDB_DISALLOW_POSTDATED, 1},
69 {"allow_forwardable", 17, KRB5_KDB_DISALLOW_FORWARDABLE, 1},
70 {"allow_tgs_req", 13, KRB5_KDB_DISALLOW_TGT_BASED, 1},
71 {"allow_renewable", 15, KRB5_KDB_DISALLOW_RENEWABLE, 1},
72 {"allow_proxiable", 15, KRB5_KDB_DISALLOW_PROXIABLE, 1},
73 {"allow_dup_skey", 14, KRB5_KDB_DISALLOW_DUP_SKEY, 1},
74 {"allow_tix", 9, KRB5_KDB_DISALLOW_ALL_TIX, 1},
75 {"requires_preauth", 16, KRB5_KDB_REQUIRES_PRE_AUTH, 0},
76 {"requires_hwauth", 15, KRB5_KDB_REQUIRES_HW_AUTH, 0},
77 {"needchange", 10, KRB5_KDB_REQUIRES_PWCHANGE, 0},
78 {"allow_svr", 9, KRB5_KDB_DISALLOW_SVR, 1},
79 {"password_changing_service", 25, KRB5_KDB_PWCHANGE_SERVICE, 0 },
80 {"support_desmd5", 14, KRB5_KDB_SUPPORT_DESMD5, 0 }
83 static char *prflags[] = {
84 "DISALLOW_POSTDATED", /* 0x00000001 */
85 "DISALLOW_FORWARDABLE", /* 0x00000002 */
86 "DISALLOW_TGT_BASED", /* 0x00000004 */
87 "DISALLOW_RENEWABLE", /* 0x00000008 */
88 "DISALLOW_PROXIABLE", /* 0x00000010 */
89 "DISALLOW_DUP_SKEY", /* 0x00000020 */
90 "DISALLOW_ALL_TIX", /* 0x00000040 */
91 "REQUIRES_PRE_AUTH", /* 0x00000080 */
92 "REQUIRES_HW_AUTH", /* 0x00000100 */
93 "REQUIRES_PWCHANGE", /* 0x00000200 */
94 "UNKNOWN_0x00000400", /* 0x00000400 */
95 "UNKNOWN_0x00000800", /* 0x00000800 */
96 "DISALLOW_SVR", /* 0x00001000 */
97 "PWCHANGE_SERVICE", /* 0x00002000 */
98 "SUPPORT_DESMD5", /* 0x00004000 */
99 "NEW_PRINC", /* 0x00008000 */
102 char *getenv();
103 int exit_status = 0;
104 char *def_realm = NULL;
105 char *whoami = NULL;
107 void *handle = NULL;
108 krb5_context context;
109 char *ccache_name = NULL;
111 int locked = 0;
112 static char *strdur(duration)
113 time_t duration;
115 static char out[50];
116 int neg, days, hours, minutes, seconds;
118 if (duration < 0) {
119 duration *= -1;
120 neg = 1;
121 } else
122 neg = 0;
123 days = duration / (24 * 3600);
124 duration %= 24 * 3600;
125 hours = duration / 3600;
126 duration %= 3600;
127 minutes = duration / 60;
128 duration %= 60;
129 seconds = duration;
130 snprintf(out, sizeof (out), "%s%d %s %02d:%02d:%02d", neg ? "-" : "",
131 days, days == 1 ? gettext("day") : gettext("days"),
132 hours, minutes, seconds);
133 return out;
136 static char *strdate(when)
137 krb5_timestamp when;
139 struct tm *tm;
140 static char out[40];
142 time_t lcltim = when;
143 tm = localtime(&lcltim);
144 strftime(out, sizeof(out), gettext("%a %b %d %H:%M:%S %Z %Y"), tm);
145 return out;
148 /* this is a wrapper to go around krb5_parse_principal so we can set
149 the default realm up properly */
150 static krb5_error_code
151 kadmin_parse_name(name, principal)
152 char *name;
153 krb5_principal *principal;
155 char *cp, *fullname;
156 krb5_error_code retval;
158 if (name == NULL)
159 return (EINVAL);
161 /* assumes def_realm is initialized! */
162 fullname = (char *)malloc(strlen(name) + 1 + strlen(def_realm) + 1);
163 if (fullname == NULL)
164 return ENOMEM;
165 strcpy(fullname, name);
166 cp = strchr(fullname, '@');
167 while (cp) {
168 if (cp - fullname && *(cp - 1) != '\\')
169 break;
170 else
171 cp = strchr(cp + 1, '@');
173 if (cp == NULL) {
174 strcat(fullname, "@");
175 strcat(fullname, def_realm);
177 retval = krb5_parse_name(context, fullname, principal);
178 free(fullname);
179 return retval;
182 static void extended_com_err_fn (const char *myprog, errcode_t code,
183 const char *fmt, va_list args)
185 if (code) {
186 const char *emsg;
187 emsg = krb5_get_error_message (context, code);
188 fprintf (stderr, "%s: %s ", myprog, emsg);
189 krb5_free_error_message (context, emsg);
190 } else {
191 fprintf (stderr, "%s: ", myprog);
193 vfprintf (stderr, fmt, args);
194 fprintf (stderr, "\n");
196 char *kadmin_startup(argc, argv)
197 int argc;
198 char *argv[];
200 extern char *optarg;
201 char *princstr = NULL, *keytab_name = NULL, *query = NULL;
202 char *password = NULL;
203 char *luser, *canon, *cp;
204 int optchar, freeprinc = 0, use_keytab = 0;
205 struct passwd *pw;
206 kadm5_ret_t retval;
207 krb5_ccache cc;
208 krb5_principal princ;
209 kadm5_config_params params;
210 char **db_args = NULL;
211 int db_args_size = 0;
212 char *db_name = NULL;
213 char *svcname = NULL;
215 memset((char *) &params, 0, sizeof(params));
217 if (strcmp (whoami, "kadmin.local") == 0)
218 set_com_err_hook(extended_com_err_fn);
220 retval = kadm5_init_krb5_context(&context);
221 if (retval) {
222 com_err(whoami, retval, gettext("while initializing krb5 library"));
223 exit(1);
226 while ((optchar = getopt(argc, argv, "x:r:p:kq:w:d:s:mc:t:e:ON")) != EOF) {
227 switch (optchar) {
228 case 'x':
229 db_args_size++;
231 char **temp = reallocarray(db_args, db_args_size + 1,
232 sizeof (char *));
233 if (temp == NULL) {
234 fprintf(stderr, gettext("%s: Cannot initialize. Not enough memory\n"),
235 argv[0]);
236 exit(1);
239 db_args = temp;
241 db_args[db_args_size-1] = optarg;
242 db_args[db_args_size] = NULL;
243 break;
245 case 'r':
246 def_realm = optarg;
247 break;
248 case 'p':
249 princstr = optarg;
250 break;
251 case 'c':
252 ccache_name = optarg;
253 break;
254 case 'k':
255 use_keytab++;
256 break;
257 case 't':
258 keytab_name = optarg;
259 break;
260 case 'w':
261 password = optarg;
262 break;
263 case 'q':
264 query = optarg;
265 break;
266 case 'd':
267 /* now db_name is not a seperate argument. It has to be passed as part of the db_args */
268 if (!db_name) {
269 db_name = malloc(strlen(optarg) + sizeof("dbname="));
270 } else {
271 db_name = realloc(db_name, strlen(optarg) + sizeof("dbname="));
274 strcpy(db_name, "dbname=");
275 strcat(db_name, optarg);
277 db_args_size++;
279 char **temp = reallocarray(db_args, db_args_size + 1,
280 sizeof (char *)); /* one for NULL */
281 if (temp == NULL) {
282 fprintf(stderr,
283 gettext("%s: Cannot initialize. Not enough memory\n"),
284 argv[0]);
285 exit(1);
288 db_args = temp;
290 db_args[db_args_size-1] = db_name;
291 db_args[db_args_size] = NULL;
292 break;
293 case 's':
294 params.admin_server = optarg;
295 params.mask |= KADM5_CONFIG_ADMIN_SERVER;
296 break;
297 case 'm':
298 params.mkey_from_kbd = 1;
299 params.mask |= KADM5_CONFIG_MKEY_FROM_KBD;
300 break;
301 case 'e':
302 retval = krb5_string_to_keysalts(optarg,
303 ", \t",
304 ":.-",
306 &params.keysalts,
307 &params.num_keysalts);
308 if (retval) {
309 com_err(whoami, retval,
310 gettext("while parsing keysalts %s"), optarg);
311 exit(1);
313 params.mask |= KADM5_CONFIG_ENCTYPES;
314 break;
315 case 'O': /* Undocumented option for testing only */
316 svcname = KADM5_ADMIN_SERVICE_P;
317 break;
318 default:
319 usage(whoami);
322 if ((ccache_name && use_keytab) ||
323 (keytab_name && !use_keytab))
324 usage(whoami);
326 if (def_realm == NULL && krb5_get_default_realm(context, &def_realm)) {
327 if (freeprinc)
328 free(princstr);
329 fprintf(stderr,
330 gettext("%s: unable to get default realm\n"), whoami);
331 exit(1);
334 params.mask |= KADM5_CONFIG_REALM;
335 params.realm = def_realm;
337 if (svcname == NULL) {
338 if (kadm5_get_adm_host_srv_name(context,
339 def_realm, &svcname)) {
340 fprintf(stderr,
341 gettext("%s: unable to get host based "
342 "service name for realm %s\n"),
343 whoami, def_realm);
344 if (freeprinc)
345 free(princstr);
346 exit(1);
351 * Set cc to an open credentials cache, either specified by the -c
352 * argument or the default.
354 if (ccache_name == NULL) {
355 if ((retval = krb5_cc_default(context, &cc))) {
356 com_err(whoami, retval,
357 gettext("while opening default "
358 "credentials cache"));
359 exit(1);
361 } else {
362 if ((retval = krb5_cc_resolve(context, ccache_name, &cc))) {
363 com_err(whoami, retval,
364 gettext("while opening credentials cache %s"),
365 ccache_name);
366 exit(1);
371 * If no principal name is specified: If a ccache was specified
372 * and its primary principal name can be read, it is used, else if
373 * a keytab was specified, the principal name is host/hostname,
374 * otherwise append "/admin" to the primary name of the default
375 * ccache, $USER, or pw_name.
377 * Gee, 100+ lines to figure out the client principal name. This
378 * should be compressed...
381 if (princstr == NULL) {
382 if (ccache_name != NULL &&
383 !krb5_cc_get_principal(context, cc, &princ)) {
384 if ((retval = krb5_unparse_name(context, princ, &princstr))) {
385 com_err(whoami, retval,
386 gettext("while canonicalizing principal name"));
387 krb5_free_principal(context, princ);
388 exit(1);
390 krb5_free_principal(context, princ);
391 freeprinc++;
392 } else if (use_keytab != 0) {
393 if ((retval = krb5_sname_to_principal(context, NULL,
394 "host",
395 KRB5_NT_SRV_HST,
396 &princ))) {
397 com_err(whoami, retval,
398 gettext("creating host service principal"));
399 exit(1);
401 if ((retval = krb5_unparse_name(context, princ, &princstr))) {
402 com_err(whoami, retval,
403 gettext("while canonicalizing principal name"));
404 krb5_free_principal(context, princ);
405 exit(1);
407 krb5_free_principal(context, princ);
408 freeprinc++;
409 } else if (!krb5_cc_get_principal(context, cc, &princ)) {
410 char *realm = NULL;
411 if (krb5_unparse_name(context, princ, &canon)) {
412 fprintf(stderr,
413 gettext("%s: unable to canonicalize "
414 "principal\n"), whoami);
415 krb5_free_principal(context, princ);
416 exit(1);
418 /* strip out realm of principal if it's there */
419 realm = strchr(canon, '@');
420 while (realm) {
421 if (realm - canon && *(realm - 1) != '\\')
422 break;
423 else
424 realm = strchr(realm+1, '@');
426 if (realm)
427 *realm++ = '\0';
428 cp = strchr(canon, '/');
429 while (cp) {
430 if (cp - canon && *(cp - 1) != '\\')
431 break;
432 else
433 cp = strchr(cp+1, '/');
435 if (cp != NULL)
436 *cp = '\0';
437 princstr = (char*)malloc(strlen(canon) + 6 /* "/admin" */ +
438 (realm ? 1 + strlen(realm) : 0) + 1);
439 if (princstr == NULL) {
440 fprintf(stderr,
441 gettext("%s: out of memory\n"),
442 whoami);
443 exit(1);
445 strcpy(princstr, canon);
446 strcat(princstr, "/admin");
447 if (realm) {
448 strcat(princstr, "@");
449 strcat(princstr, realm);
451 free(canon);
452 krb5_free_principal(context, princ);
453 freeprinc++;
454 } else if ((luser = getenv("USER"))) {
455 princstr = (char *) malloc(strlen(luser) + 7 /* "/admin@" */
456 + strlen(def_realm) + 1);
457 if (princstr == NULL) {
458 fprintf(stderr,
459 gettext("%s: out of memory\n"),
460 whoami);
461 exit(1);
463 strcpy(princstr, luser);
464 strcat(princstr, "/admin");
465 strcat(princstr, "@");
466 strcat(princstr, def_realm);
467 freeprinc++;
468 } else if ((pw = getpwuid(getuid()))) {
469 princstr = (char *) malloc(strlen(pw->pw_name) + 7 /* "/admin@" */
470 + strlen(def_realm) + 1);
471 if (princstr == NULL) {
472 fprintf(stderr,
473 gettext("%s: out of memory\n"),
474 whoami);
475 exit(1);
477 strcpy(princstr, pw->pw_name);
478 strcat(princstr, "/admin@");
479 strcat(princstr, def_realm);
480 freeprinc++;
481 } else {
482 fprintf(stderr,
483 gettext("%s: unable to figure out "
484 "a principal name\n"),
485 whoami);
486 exit(1);
490 retval = krb5_klog_init(context, "admin_server", whoami, 0);
491 if (retval) {
492 com_err(whoami, retval, "while setting up logging");
493 exit(1);
497 * Initialize the kadm5 connection. If we were given a ccache,
498 * use it. Otherwise, use/prompt for the password.
501 /* Solaris Kerberos:
502 * Send warnings to stderr
504 if (ccache_name) {
505 fprintf(stderr, gettext("Authenticating as principal %s with existing credentials.\n"),
506 princstr);
507 retval = kadm5_init_with_creds(princstr, cc,
508 svcname,
509 &params,
510 KADM5_STRUCT_VERSION,
511 KADM5_API_VERSION_2,
512 db_args,
513 &handle);
514 } else if (use_keytab) {
515 if (keytab_name)
516 fprintf(stderr, gettext("Authenticating as principal %s with keytab %s.\n"),
517 princstr, keytab_name);
518 else
519 fprintf(stderr, gettext("Authenticating as principal %s with default keytab.\n"),
520 princstr);
521 retval = kadm5_init_with_skey(princstr, keytab_name,
522 svcname,
523 &params,
524 KADM5_STRUCT_VERSION,
525 KADM5_API_VERSION_2,
526 db_args,
527 &handle);
528 } else {
529 fprintf(stderr, gettext("Authenticating as principal %s with password.\n"),
530 princstr);
531 retval = kadm5_init_with_password(princstr, password,
532 svcname,
533 &params,
534 KADM5_STRUCT_VERSION,
535 KADM5_API_VERSION_2,
536 db_args,
537 &handle);
539 if (retval) {
540 if (retval == KADM5_RPC_ERROR_CANTENCODEARGS ||
541 retval == KADM5_RPC_ERROR_CANTDECODEARGS) {
542 com_err(whoami, KADM5_RPC_ERROR,
543 gettext("while initializing %s interface"), whoami);
545 /* privacy-enabled mech probably not installed/configed */
546 com_err(whoami, retval, gettext("."), whoami);
547 } else {
548 com_err(whoami, retval,
549 gettext("while initializing %s interface"), whoami);
550 if (retval == KADM5_BAD_CLIENT_PARAMS ||
551 retval == KADM5_BAD_SERVER_PARAMS)
552 usage(whoami);
554 exit(1);
556 if (freeprinc)
557 free(princstr);
559 if (db_name)
560 free(db_name), db_name=NULL;
562 if (db_args)
563 free(db_args), db_args=NULL;
565 if ((retval = krb5_cc_close(context, cc))) {
566 com_err(whoami, retval, gettext("while closing ccache %s"),
567 ccache_name);
568 exit(1);
571 /* register the WRFILE keytab type and set it as the default */
573 #define DEFAULT_KEYTAB "WRFILE:/etc/krb5/krb5.keytab"
574 /* XXX krb5_defkeyname is an internal library global and
575 should go away */
576 extern char *krb5_defkeyname;
577 krb5_defkeyname = DEFAULT_KEYTAB;
580 if ((retval = kadm5_init_iprop(handle)) != 0) {
581 com_err(whoami, retval, gettext("while mapping update log"));
582 exit(1);
585 /* Solaris kerberos: fix memory leak */
586 free(svcname);
588 return query;
591 int quit()
593 kadm5_ret_t retval;
595 if (locked) {
596 retval = kadm5_unlock(handle);
597 if (retval) {
598 com_err("quit", retval, gettext("while unlocking locked database"));
599 return 1;
601 locked = 0;
604 kadm5_destroy(handle);
605 if (ccache_name != NULL) {
606 fprintf(stderr,
607 gettext("\n\a\a\aAdministration credentials "
608 "NOT DESTROYED.\n"));
611 /* insert more random cleanup here */
612 krb5_klog_close(context);
613 krb5_free_context(context);
614 context = NULL;
615 return 0;
618 void kadmin_lock(argc, argv)
619 int argc;
620 char *argv[];
622 kadm5_ret_t retval;
624 if (locked)
625 return;
626 retval = kadm5_lock(handle);
627 if (retval) {
628 com_err("lock", retval, "");
629 return;
631 locked = 1;
634 void kadmin_unlock(argc, argv)
635 int argc;
636 char *argv[];
638 kadm5_ret_t retval;
640 if (!locked)
641 return;
642 retval = kadm5_unlock(handle);
643 if (retval) {
644 com_err("unlock", retval, "");
645 return;
647 locked = 0;
650 void kadmin_delprinc(argc, argv)
651 int argc;
652 char *argv[];
654 kadm5_ret_t retval;
655 krb5_principal princ;
656 char *canon;
657 char reply[32];
659 if (! (argc == 2 ||
660 (argc == 3 && !strcmp("-force", argv[1])))) {
661 fprintf(stderr, "%s: delete_principal [-force] %s\n",
662 gettext("usage"), gettext("principal"));
663 return;
665 retval = kadmin_parse_name(argv[argc - 1], &princ);
666 if (retval) {
667 com_err("delete_principal", retval,
668 gettext("while parsing principal name"));
669 return;
671 retval = krb5_unparse_name(context, princ, &canon);
672 if (retval) {
673 com_err("delete_principal", retval,
674 gettext("while canonicalizing principal"));
675 krb5_free_principal(context, princ);
676 return;
678 if (argc == 2) {
679 printf(gettext("Are you sure you want to delete "
680 "the principal \"%s\"? (yes/no): "), canon);
681 fgets(reply, sizeof (reply), stdin);
682 if (strncmp(gettext("yes\n"), reply, sizeof (reply)) &&
683 strncmp(gettext("y\n"), reply, sizeof (reply)) &&
684 strncmp(gettext("Y\n"), reply, sizeof (reply))) {
685 fprintf(stderr,
686 gettext("Principal \"%s\" not deleted\n"),
687 canon);
688 free(canon);
689 krb5_free_principal(context, princ);
690 return;
693 retval = kadm5_delete_principal(handle, princ);
694 krb5_free_principal(context, princ);
695 if (retval) {
696 com_err("delete_principal", retval,
697 gettext("while deleting principal \"%s\""), canon);
698 free(canon);
699 return;
701 printf(gettext("Principal \"%s\" deleted.\n"), canon);
702 printf(gettext("Make sure that you have removed this principal "
703 "from all ACLs before reusing.\n"));
704 free(canon);
705 return;
708 void kadmin_cpw(argc, argv)
709 int argc;
710 char *argv[];
712 kadm5_ret_t retval;
713 static char newpw[1024];
714 static char prompt1[1024], prompt2[1024];
715 char *canon;
716 char *pwarg = NULL;
717 int n_ks_tuple = 0, randkey = 0;
718 krb5_boolean keepold = FALSE;
719 krb5_key_salt_tuple *ks_tuple = NULL;
720 krb5_principal princ;
721 char **db_args = NULL;
722 int db_args_size = 0;
723 int local_kadmin = 0;
725 local_kadmin = (strcmp(whoami, KADMIN_LOCAL_NAME) == 0);
727 if (argc < 2) {
728 goto usage;
730 for (argv++, argc--; argc > 1; argc--, argv++) {
731 if (!strcmp("-x", *argv)) {
732 argc--;
733 if (argc < 1) {
734 fprintf(stderr, gettext("change_password: missing db argument\n"));
735 goto usage;
737 db_args_size++;
739 char **temp = reallocarray(db_args, db_args_size + 1,
740 sizeof (char *)); /* one for NULL */
741 if (temp == NULL) {
742 fprintf(stderr, gettext("change_password: Not enough memory\n"));
743 free(db_args), db_args = NULL;
744 exit(1);
747 db_args = temp;
749 db_args[db_args_size-1] = *++argv;
750 db_args[db_args_size] = NULL;
751 continue;
753 if (!strcmp("-pw", *argv)) {
754 argc--;
755 if (argc < 1) {
756 fprintf(stderr, "change_password: %s",
757 gettext("missing password arg\n"));
758 goto usage;
760 pwarg = *++argv;
761 continue;
763 if (!strcmp("-randkey", *argv)) {
764 randkey++;
765 continue;
767 if (!strcmp("-keepold", *argv)) {
768 keepold = TRUE;
769 continue;
771 if (!strcmp("-e", *argv)) {
772 argc--;
773 if (argc < 1) {
774 fprintf(stderr, "change_password: %s",
775 gettext("missing keysaltlist arg\n"));
776 goto usage;
778 retval = krb5_string_to_keysalts(*++argv, ", \t", ":.-", 0,
779 &ks_tuple, &n_ks_tuple);
780 if (retval) {
781 com_err("change_password", retval,
782 gettext("while parsing keysalts %s"), *argv);
783 return;
785 continue;
787 goto usage;
789 if (*argv == NULL) {
790 com_err("change_password", 0, "missing principal name");
791 goto usage;
793 retval = kadmin_parse_name(*argv, &princ);
794 if (retval) {
795 com_err("change_password", retval,
796 gettext("while parsing principal name"));
797 free(ks_tuple);
798 free(db_args);
799 goto usage;
801 retval = krb5_unparse_name(context, princ, &canon);
802 if (retval) {
803 com_err("change_password", retval,
804 gettext("while canonicalizing principal"));
805 krb5_free_principal(context, princ);
806 free(ks_tuple);
807 free(db_args);
808 return;
810 if (pwarg != NULL) {
811 if (keepold || ks_tuple != NULL) {
812 retval = kadm5_chpass_principal_3(handle, princ, keepold,
813 n_ks_tuple, ks_tuple, pwarg);
814 free(ks_tuple);
815 } else {
816 retval = kadm5_chpass_principal(handle, princ, pwarg);
818 krb5_free_principal(context, princ);
819 if (retval) {
820 com_err("change_password", retval,
821 gettext("while changing password for \"%s\"."),
822 canon);
823 free(canon);
824 free(db_args);
825 return;
827 printf(gettext("Password for \"%s\" changed.\n"), canon);
828 free(canon);
829 free(db_args);
830 return;
831 } else if (randkey) {
832 if (keepold || ks_tuple != NULL || local_kadmin) {
833 retval = kadm5_randkey_principal_3(handle, princ, keepold,
834 n_ks_tuple, ks_tuple,
835 NULL, NULL);
836 free(ks_tuple);
837 } else {
838 retval = kadm5_randkey_principal(handle, princ, NULL, NULL);
840 krb5_free_principal(context, princ);
841 if (retval) {
842 com_err("change_password", retval,
843 gettext("while randomizing key for \"%s\"."),
844 canon);
845 free(canon);
846 free(db_args);
847 return;
849 printf(gettext("Key for \"%s\" randomized.\n"), canon);
850 free(canon);
851 free(db_args);
852 return;
853 } else if (argc == 1) {
854 unsigned int i = sizeof (newpw) - 1;
856 snprintf(prompt1, sizeof (prompt1),
857 gettext("Enter password for principal \"%.900s\""),
858 *argv);
859 snprintf(prompt2, sizeof (prompt2),
860 gettext("Re-enter password for principal \"%.900s\""),
861 *argv);
862 retval = krb5_read_password(context, prompt1, prompt2,
863 newpw, &i);
864 if (retval) {
865 com_err("change_password", retval,
866 gettext("while reading password for \"%s\"."),
867 canon);
868 free(canon);
869 free(ks_tuple);
870 krb5_free_principal(context, princ);
871 free(db_args);
872 return;
874 if (keepold || ks_tuple != NULL) {
875 retval = kadm5_chpass_principal_3(handle, princ, keepold,
876 n_ks_tuple, ks_tuple,
877 newpw);
878 free(ks_tuple);
879 } else {
880 retval = kadm5_chpass_principal(handle, princ, newpw);
882 krb5_free_principal(context, princ);
883 memset(newpw, 0, sizeof (newpw));
884 if (retval) {
885 com_err("change_password", retval,
886 gettext("while changing password for \"%s\"."),
887 canon);
888 free(canon);
889 free(db_args);
890 return;
892 printf(gettext("Password for \"%s\" changed.\n"), canon);
893 free(canon);
894 free(db_args);
895 return;
896 } else {
897 free(canon);
898 krb5_free_principal(context, princ);
899 usage:
900 free(ks_tuple);
901 fprintf(stderr, "%s: change_password [-randkey] [-keepold] "
902 "[-e keysaltlist] [-pw password] %s\n",
903 gettext("usage"), gettext("principal"));
904 return;
908 static void
909 kadmin_free_tl_data(kadm5_principal_ent_t princ)
911 krb5_tl_data *tl_data = princ->tl_data;
912 int n_tl_data = princ->n_tl_data;
913 int i;
915 princ->n_tl_data = 0;
916 princ->tl_data = NULL;
918 for (i = 0; tl_data && (i < n_tl_data); i++) {
919 krb5_tl_data *next = tl_data->tl_data_next;
920 free(tl_data->tl_data_contents);
921 free(tl_data);
922 tl_data = next;
926 #define KRB5_TL_DB_ARGS 0x7fff
927 static int
928 kadmin_parse_princ_args(argc, argv, oprinc, mask, pass, randkey,
929 ks_tuple, n_ks_tuple, caller)
930 int argc;
931 char *argv[];
932 kadm5_principal_ent_t oprinc;
933 long *mask;
934 char **pass;
935 int *randkey;
936 krb5_key_salt_tuple **ks_tuple;
937 int *n_ks_tuple;
938 char *caller;
940 int i, j, attrib_set;
941 time_t date;
942 time_t now;
943 krb5_error_code retval;
944 krb5_tl_data *tl_data, *tail = NULL;
946 *mask = 0;
947 *pass = NULL;
948 *n_ks_tuple = 0;
949 *ks_tuple = NULL;
950 time(&now);
951 *randkey = 0;
952 for (i = 1; i < argc - 1; i++) {
953 attrib_set = 0;
954 if (strlen(argv[i]) == 2 &&
955 !strcmp("-x",argv[i])) {
956 if (++i > argc - 2)
957 return -1;
959 tl_data = malloc(sizeof(krb5_tl_data));
960 if (tl_data == NULL) {
961 fprintf(stderr, gettext("Not enough memory\n"));
962 return ENOMEM;
965 memset(tl_data, 0, sizeof(krb5_tl_data));
966 tl_data->tl_data_type = KRB5_TL_DB_ARGS;
967 tl_data->tl_data_length = strlen(argv[i])+1;
968 tl_data->tl_data_contents = (unsigned char*)strdup(argv[i]);
970 if (tail) {
971 tail->tl_data_next = tl_data;
972 } else {
973 oprinc->tl_data = tl_data;
975 tail = tl_data;
976 oprinc->n_tl_data++;
978 if (tl_data->tl_data_contents == NULL) {
979 fprintf(stderr, gettext("Not enough memory\n"));
980 return ENOMEM;
982 *mask |= KADM5_TL_DATA;
983 continue;
985 if (strlen(argv[i]) == 7 &&
986 !strcmp("-expire", argv[i])) {
987 if (++i > argc - 2)
988 return -1;
989 else {
990 date = get_date(argv[i]);
991 if (date == (time_t)-1) {
992 fprintf(stderr,
993 gettext("Invalid date "
994 "specification "
995 "\"%s\".\n"),
996 argv[i]);
997 return -1;
999 oprinc->princ_expire_time = date;
1000 *mask |= KADM5_PRINC_EXPIRE_TIME;
1001 continue;
1004 if (strlen(argv[i]) == 9 &&
1005 !strcmp("-pwexpire", argv[i])) {
1006 if (++i > argc - 2)
1007 return -1;
1008 else {
1009 date = get_date(argv[i]);
1010 if (date == (time_t)-1) {
1011 fprintf(stderr,
1012 gettext("Invalid date "
1013 "specification "
1014 "\"%s\".\n"),
1015 argv[i]);
1016 return -1;
1018 oprinc->pw_expiration = date;
1019 *mask |= KADM5_PW_EXPIRATION;
1020 continue;
1023 if (strlen(argv[i]) == 8 &&
1024 !strcmp("-maxlife", argv[i])) {
1025 if (++i > argc - 2)
1026 return -1;
1027 else {
1028 date = get_date(argv[i]);
1029 if (date == (time_t)-1) {
1030 fprintf(stderr,
1031 gettext("Invalid date "
1032 "specification "
1033 "\"%s\".\n"),
1034 argv[i]);
1035 return -1;
1037 oprinc->max_life = date - now;
1038 *mask |= KADM5_MAX_LIFE;
1039 continue;
1042 if (strlen(argv[i]) == 13 &&
1043 !strcmp("-maxrenewlife", argv[i])) {
1044 if (++i > argc - 2)
1045 return -1;
1046 else {
1047 date = get_date(argv[i]);
1048 if (date == (time_t)-1) {
1049 fprintf(stderr,
1050 gettext("Invalid date "
1051 "specification "
1052 "\"%s\".\n"),
1053 argv[i]);
1054 return -1;
1056 oprinc->max_renewable_life = date - now;
1057 *mask |= KADM5_MAX_RLIFE;
1058 continue;
1061 if (strlen(argv[i]) == 5 &&
1062 !strcmp("-kvno", argv[i])) {
1063 if (++i > argc - 2)
1064 return -1;
1065 else {
1066 oprinc->kvno = atoi(argv[i]);
1067 *mask |= KADM5_KVNO;
1068 continue;
1071 if (strlen(argv[i]) == 7 &&
1072 !strcmp("-policy", argv[i])) {
1073 if (++i > argc - 2)
1074 return -1;
1075 else {
1076 oprinc->policy = argv[i];
1077 *mask |= KADM5_POLICY;
1078 continue;
1081 if (strlen(argv[i]) == 12 &&
1082 !strcmp("-clearpolicy", argv[i])) {
1083 oprinc->policy = NULL;
1084 *mask |= KADM5_POLICY_CLR;
1085 continue;
1087 if (strlen(argv[i]) == 3 &&
1088 !strcmp("-pw", argv[i])) {
1089 if (++i > argc - 2)
1090 return -1;
1091 else {
1092 *pass = argv[i];
1093 continue;
1096 if (strlen(argv[i]) == 8 &&
1097 !strcmp("-randkey", argv[i])) {
1098 ++*randkey;
1099 continue;
1101 if (!strcmp("-e", argv[i])) {
1102 if (++i > argc - 2)
1103 return -1;
1104 else {
1105 retval = krb5_string_to_keysalts(argv[i], ", \t", ":.-", 0,
1106 ks_tuple, n_ks_tuple);
1107 if (retval) {
1108 com_err(caller, retval,
1109 gettext("while parsing keysalts %s"), argv[i]);
1110 return -1;
1113 continue;
1115 for (j = 0; j < sizeof (flags) / sizeof (struct pflag); j++) {
1116 if (strlen(argv[i]) == flags[j].flaglen + 1 &&
1117 !strcmp(flags[j].flagname,
1118 &argv[i][1] /* strip off leading + or - */)) {
1119 if ((flags[j].set && argv[i][0] == '-') ||
1120 (!flags[j].set && argv[i][0] == '+')) {
1121 oprinc->attributes |= flags[j].theflag;
1122 *mask |= KADM5_ATTRIBUTES;
1123 attrib_set++;
1124 break;
1125 } else if ((flags[j].set && argv[i][0] == '+') ||
1126 (!flags[j].set && argv[i][0] == '-')) {
1127 oprinc->attributes &= ~flags[j].theflag;
1128 *mask |= KADM5_ATTRIBUTES;
1129 attrib_set++;
1130 break;
1131 } else {
1132 return -1;
1136 if (!attrib_set)
1137 return -1; /* nothing was parsed */
1139 if (i != argc - 1) {
1140 return -1;
1142 retval = kadmin_parse_name(argv[i], &oprinc->principal);
1143 if (retval) {
1144 com_err(caller, retval, gettext("while parsing principal"));
1145 return -1;
1147 return 0;
1150 static void
1151 kadmin_addprinc_usage(func)
1152 char *func;
1154 fprintf(stderr, "%s: %s %s\n", gettext("usage"), func,
1155 gettext("[options] principal"));
1156 fprintf(stderr, gettext("\toptions are:\n"));
1157 fprintf(stderr, "\t\t[-expire expdate] [-pwexpire pwexpdate] "
1158 "[-maxlife maxtixlife]\n\t\t[-kvno kvno] [-policy policy] "
1159 "[-randkey] [-pw password]\n\t\t[-maxrenewlife maxrenewlife] "
1160 "[-e keysaltlist] [{+|-}attribute]\n");
1161 fprintf(stderr, gettext("\tattributes are:\n"));
1162 fprintf(stderr, "%s%s%s",
1163 "\t\tallow_postdated allow_forwardable allow_tgs_req "
1164 "allow_renewable\n",
1165 "\t\tallow_proxiable allow_dup_skey allow_tix "
1166 "requires_preauth\n",
1167 "\t\trequires_hwauth needchange allow_svr "
1168 "password_changing_service\n");
1171 static void
1172 kadmin_modprinc_usage(func)
1173 char *func;
1175 fprintf(stderr, "%s: %s %s\n", gettext("usage"), func,
1176 gettext("[options] principal"));
1177 fprintf(stderr, gettext("\toptions are:\n"));
1178 fprintf(stderr, "\t\t[-expire expdate] [-pwexpire pwexpdate] "
1179 "[-maxlife maxtixlife]\n\t\t[-kvno kvno] [-policy policy] "
1180 "[-clearpolicy]\n\t\t[-maxrenewlife maxrenewlife] "
1181 "[{+|-}attribute]\n");
1182 fprintf(stderr, gettext("\tattributes are:\n"));
1183 fprintf(stderr, "%s%s%s",
1184 "\t\tallow_postdated allow_forwardable allow_tgs_req "
1185 "allow_renewable\n",
1186 "\t\tallow_proxiable allow_dup_skey allow_tix "
1187 "requires_preauth\n",
1188 "\t\trequires_hwauth needchange allow_svr "
1189 "password_changing_service\n");
1192 void kadmin_addprinc(argc, argv)
1193 int argc;
1194 char *argv[];
1196 kadm5_principal_ent_rec princ, dprinc;
1197 kadm5_policy_ent_rec defpol;
1198 long mask;
1199 int randkey = 0, i;
1200 int n_ks_tuple;
1201 krb5_key_salt_tuple *ks_tuple;
1202 char *pass, *canon;
1203 krb5_error_code retval;
1204 static char newpw[1024], dummybuf[256];
1205 static char prompt1[1024], prompt2[1024];
1206 int local_kadmin = 0;
1208 local_kadmin = (strcmp(whoami, KADMIN_LOCAL_NAME) == 0);
1210 if (dummybuf[0] == 0) {
1211 for (i = 0; i < 256; i++)
1212 dummybuf[i] = (i+1) % 256;
1215 /* Zero all fields in request structure */
1216 memset(&princ, 0, sizeof(princ));
1217 memset(&dprinc, 0, sizeof(dprinc));
1219 princ.attributes = dprinc.attributes = 0;
1220 if (kadmin_parse_princ_args(argc, argv,
1221 &princ, &mask, &pass, &randkey,
1222 &ks_tuple, &n_ks_tuple,
1223 "add_principal")) {
1224 kadmin_addprinc_usage("add_principal");
1225 kadmin_free_tl_data(&princ); /* need to free ks_tuple also??? */
1226 return;
1229 retval = krb5_unparse_name(context, princ.principal, &canon);
1230 if (retval) {
1231 com_err("add_principal",
1232 retval, gettext("while canonicalizing principal"));
1233 krb5_free_principal(context, princ.principal);
1234 free(ks_tuple);
1235 kadmin_free_tl_data(&princ);
1236 return;
1240 * If -policy was not specified, and -clearpolicy was not
1241 * specified, and the policy "default" exists, assign it. If
1242 * -clearpolicy was specified, then KADM5_POLICY_CLR should be
1243 * unset, since it is never valid for kadm5_create_principal.
1245 if ((! (mask & KADM5_POLICY)) &&
1246 (! (mask & KADM5_POLICY_CLR))) {
1247 if (! kadm5_get_policy(handle, "default", &defpol)) {
1248 fprintf(stderr,
1249 gettext("NOTICE: no policy specified for %s; assigning \"default\"\n"),
1250 canon);
1251 princ.policy = "default";
1252 mask |= KADM5_POLICY;
1253 (void) kadm5_free_policy_ent(handle, &defpol);
1254 } else
1255 fprintf(stderr,
1256 gettext("WARNING: no policy specified for %s; defaulting to no policy\n"),
1257 canon);
1259 mask &= ~KADM5_POLICY_CLR;
1262 * Set 'notix' for randkey principals and also for principals which have
1263 * specified flag options on the cmdline. This is because we want to apply
1264 * generic flag settings from 'default_principal_flags' first (during
1265 * principal creation), followed by a kadm5_modify_principal() which
1266 * correctly applies the cli flag options. So, we do *not* want any tix
1267 * issued in the interim.
1269 if (randkey || (mask & KADM5_ATTRIBUTES))
1270 princ.attributes |= KRB5_KDB_DISALLOW_ALL_TIX;
1272 if (randkey) {
1273 mask |= KADM5_ATTRIBUTES;
1274 pass = dummybuf;
1275 } else if (pass == NULL) {
1276 unsigned int sz = sizeof (newpw) - 1;
1277 snprintf(prompt1, sizeof (prompt1),
1278 gettext("Enter password for principal \"%.900s\""),
1279 canon);
1280 snprintf(prompt2, sizeof (prompt1),
1281 gettext("Re-enter password for principal \"%.900s\""),
1282 canon);
1283 retval = krb5_read_password(context, prompt1, prompt2,
1284 newpw, &sz);
1285 if (retval) {
1286 com_err("add_principal", retval,
1287 gettext("while reading password for \"%s\"."), canon);
1288 free(canon);
1289 krb5_free_principal(context, princ.principal);
1290 kadmin_free_tl_data(&princ);
1291 return;
1293 pass = newpw;
1295 mask |= KADM5_PRINCIPAL;
1298 * If the client being used is local, always use the new
1299 * API so we get the full set of enctype support.
1301 if (ks_tuple != NULL || local_kadmin) {
1302 retval = kadm5_create_principal_3(handle, &princ, mask,
1303 n_ks_tuple, ks_tuple, pass);
1304 } else {
1305 retval = kadm5_create_principal(handle, &princ, mask, pass);
1307 if (retval) {
1308 com_err("add_principal", retval,
1309 gettext("while creating \"%s\"."), canon);
1310 krb5_free_principal(context, princ.principal);
1311 free(canon);
1312 free(ks_tuple);
1313 kadmin_free_tl_data(&princ);
1314 return;
1316 if (randkey) { /* more special stuff for -randkey */
1317 if (ks_tuple != NULL || local_kadmin) {
1318 retval = kadm5_randkey_principal_3(handle, princ.principal,
1319 FALSE,
1320 n_ks_tuple, ks_tuple,
1321 NULL, NULL);
1322 } else {
1323 retval = kadm5_randkey_principal(handle, princ.principal,
1324 NULL, NULL);
1326 if (retval) {
1327 com_err("add_principal", retval,
1328 gettext("while randomizing key for \"%s\"."), canon);
1329 krb5_free_principal(context, princ.principal);
1330 free(canon);
1331 free(ks_tuple);
1332 kadmin_free_tl_data(&princ);
1333 return;
1338 * We now retrieve the intersection set of the generic flag settings and
1339 * the ones specified on the cli & re-parse the princ args, just to make
1340 * sure we account for conflicts between 'default_principal_flags' and
1341 * the cmdline flag args. While we are here, also clear 'notix'.
1343 if (randkey || (mask & KADM5_ATTRIBUTES)) {
1344 retval = kadm5_get_principal(handle, princ.principal, &dprinc,
1345 KADM5_PRINCIPAL_NORMAL_MASK);
1346 if (retval == 0) {
1347 if (dprinc.attributes != 0)
1348 princ.attributes = dprinc.attributes;
1349 } else {
1350 com_err("add_principal", retval,
1351 gettext("while doing a get_principal on \"%s\"."), canon);
1352 printf(gettext("\nWarning: Principal \"%s\" could have incomplete "
1353 "flag settings, as a result of a failed get_principal.\n"
1354 "Check the 'default_principal_flags' setting in kdc.conf(4).\n"
1355 "If there is a mismatch, use modprinc in kadmin(1M) to rectify "
1356 "the same.\n\n"), canon);
1360 * Solaris Kerberos: We unset KRB5_KDB_DISALLOW_ALL_TIX before
1361 * kadmin_parse_princ_args is called, because -allow_tix may
1362 * have been an argument. We still have to unset here because
1363 * kadmin_parse_princ_args will not reset the attribute unless
1364 * it is was explicity defined.
1366 princ.attributes &= ~KRB5_KDB_DISALLOW_ALL_TIX;
1367 (void) kadmin_parse_princ_args(argc, argv, &princ, &mask, &pass,
1368 &randkey, &ks_tuple, &n_ks_tuple, "add_principal");
1369 mask = KADM5_ATTRIBUTES;
1370 retval = kadm5_modify_principal(handle, &princ, mask);
1371 if (retval) {
1372 com_err("add_principal", retval,
1373 gettext("while doing a modify_principal to restore flag "
1374 "settings for \"%s\"."), canon);
1375 krb5_free_principal(context, princ.principal);
1376 free(canon);
1377 free(ks_tuple);
1378 kadmin_free_tl_data(&princ);
1379 return;
1382 krb5_free_principal(context, princ.principal);
1383 printf(gettext("Principal \"%s\" created.\n"), canon);
1384 free(ks_tuple);
1385 free(canon);
1386 kadmin_free_tl_data(&princ);
1390 void kadmin_modprinc(argc, argv)
1391 int argc;
1392 char *argv[];
1394 kadm5_principal_ent_rec princ, oldprinc;
1395 krb5_principal kprinc;
1396 long mask;
1397 krb5_error_code retval;
1398 char *pass, *canon;
1399 int randkey = 0;
1400 int n_ks_tuple = 0;
1401 krb5_key_salt_tuple *ks_tuple;
1403 if (argc < 2) {
1404 kadmin_modprinc_usage("modify_principal");
1405 return;
1408 memset(&oldprinc, 0, sizeof(oldprinc));
1409 memset(&princ, 0, sizeof(princ));
1411 retval = kadmin_parse_name(argv[argc - 1], &kprinc);
1412 if (retval) {
1413 com_err("modify_principal", retval,
1414 gettext("while parsing principal"));
1415 return;
1417 retval = krb5_unparse_name(context, kprinc, &canon);
1418 if (retval) {
1419 com_err("modify_principal", retval,
1420 gettext("while canonicalizing principal"));
1421 krb5_free_principal(context, kprinc);
1422 return;
1424 retval = kadm5_get_principal(handle, kprinc, &oldprinc,
1425 KADM5_PRINCIPAL_NORMAL_MASK);
1426 krb5_free_principal(context, kprinc);
1427 if (retval) {
1428 com_err("modify_principal", retval,
1429 gettext("while getting \"%s\"."), canon);
1430 free(canon);
1431 return;
1433 princ.attributes = oldprinc.attributes;
1434 kadm5_free_principal_ent(handle, &oldprinc);
1435 retval = kadmin_parse_princ_args(argc, argv,
1436 &princ, &mask,
1437 &pass, &randkey,
1438 &ks_tuple, &n_ks_tuple,
1439 "modify_principal");
1440 if (ks_tuple != NULL) {
1441 free(ks_tuple);
1442 kadmin_modprinc_usage("modify_principal");
1443 free(canon);
1444 kadmin_free_tl_data(&princ);
1445 return;
1447 if (retval) {
1448 kadmin_modprinc_usage("modify_principal");
1449 free(canon);
1450 kadmin_free_tl_data(&princ);
1451 return;
1453 if (randkey) {
1454 fprintf(stderr, "modify_principal: -randkey %s ",
1455 gettext("not allowed\n"));
1456 krb5_free_principal(context, princ.principal);
1457 free(canon);
1458 kadmin_free_tl_data(&princ);
1459 return;
1461 if (pass) {
1462 fprintf(stderr,
1463 "modify_principal: -pw %s change_password\n",
1464 gettext("not allowed; use"));
1465 krb5_free_principal(context, princ.principal);
1466 free(canon);
1467 kadmin_free_tl_data(&princ);
1468 return;
1470 retval = kadm5_modify_principal(handle, &princ, mask);
1471 krb5_free_principal(context, princ.principal);
1472 if (retval) {
1473 com_err("modify_principal", retval,
1474 gettext("while modifying \"%s\"."), canon);
1475 free(canon);
1476 kadmin_free_tl_data(&princ);
1477 return;
1479 printf(gettext("Principal \"%s\" modified.\n"), canon);
1480 kadmin_free_tl_data(&princ);
1481 free(canon);
1484 void kadmin_getprinc(argc, argv)
1485 int argc;
1486 char *argv[];
1488 kadm5_principal_ent_rec dprinc;
1489 krb5_principal princ;
1490 krb5_error_code retval;
1491 char *canon, *modcanon;
1492 int i;
1494 if (! (argc == 2 ||
1495 (argc == 3 && !strcmp("-terse", argv[1])))) {
1496 fprintf(stderr, "%s: get_principal [-terse] %s\n",
1497 gettext("usage"), gettext("principal"));
1498 return;
1502 memset(&dprinc, 0, sizeof(dprinc));
1503 memset(&princ, 0, sizeof(princ));
1505 retval = kadmin_parse_name(argv[argc - 1], &princ);
1506 if (retval) {
1507 com_err("get_principal", retval,
1508 gettext("while parsing principal"));
1509 return;
1511 retval = krb5_unparse_name(context, princ, &canon);
1512 if (retval) {
1513 com_err("get_principal", retval,
1514 gettext("while canonicalizing principal"));
1515 krb5_free_principal(context, princ);
1516 return;
1518 retval = kadm5_get_principal(handle, princ, &dprinc,
1519 KADM5_PRINCIPAL_NORMAL_MASK | KADM5_KEY_DATA);
1520 krb5_free_principal(context, princ);
1521 if (retval) {
1522 com_err("get_principal", retval,
1523 gettext("while retrieving \"%s\"."), canon);
1524 free(canon);
1525 return;
1527 retval = krb5_unparse_name(context, dprinc.mod_name, &modcanon);
1528 if (retval) {
1529 com_err("get_principal", retval,
1530 gettext("while unparsing modname"));
1531 kadm5_free_principal_ent(handle, &dprinc);
1532 free(canon);
1533 return;
1535 if (argc == 2) {
1536 printf(gettext("Principal: %s\n"), canon);
1537 printf(gettext("Expiration date: %s\n"),
1538 dprinc.princ_expire_time ?
1539 strdate(dprinc.princ_expire_time) :
1540 gettext("[never]"));
1541 printf(gettext("Last password change: %s\n"),
1542 dprinc.last_pwd_change ?
1543 strdate(dprinc.last_pwd_change) :
1544 gettext("[never]"));
1545 printf(gettext("Password expiration date: %s\n"),
1546 dprinc.pw_expiration ?
1547 strdate(dprinc.pw_expiration) : gettext("[none]"));
1548 printf(gettext("Maximum ticket life: %s\n"),
1549 strdur(dprinc.max_life));
1550 printf(gettext("Maximum renewable life: %s\n"),
1551 strdur(dprinc.max_renewable_life));
1552 printf(gettext("Last modified: %s (%s)\n"),
1553 strdate(dprinc.mod_date), modcanon);
1554 printf(gettext("Last successful authentication: %s\n"),
1555 dprinc.last_success ? strdate(dprinc.last_success) :
1556 gettext("[never]"));
1557 printf(gettext("Last failed authentication: %s\n"),
1558 dprinc.last_failed ? strdate(dprinc.last_failed) :
1559 gettext("[never]"));
1560 printf(gettext("Failed password attempts: %d\n"),
1561 dprinc.fail_auth_count);
1562 printf(gettext("Number of keys: %d\n"), dprinc.n_key_data);
1563 for (i = 0; i < dprinc.n_key_data; i++) {
1564 krb5_key_data *key_data = &dprinc.key_data[i];
1565 char enctype[BUFSIZ], salttype[BUFSIZ];
1567 if (krb5_enctype_to_string(key_data->key_data_type[0],
1568 enctype, sizeof(enctype)))
1569 snprintf(enctype, sizeof (enctype), gettext("<Encryption type 0x%x>"),
1570 key_data->key_data_type[0]);
1571 printf("Key: vno %d, %s, ", key_data->key_data_kvno, enctype);
1572 if (key_data->key_data_ver > 1) {
1573 if (krb5_salttype_to_string(key_data->key_data_type[1],
1574 salttype, sizeof(salttype)))
1575 snprintf(salttype, sizeof(salttype), gettext("<Salt type 0x%x>"),
1576 key_data->key_data_type[1]);
1577 printf("%s\n", salttype);
1578 } else
1579 printf(gettext("no salt\n"));
1582 printf(gettext("Attributes:"));
1583 for (i = 0; i < sizeof (prflags) / sizeof (char *); i++) {
1584 if (dprinc.attributes & (krb5_flags) 1 << i)
1585 printf(" %s", prflags[i]);
1587 printf("\n");
1588 printf(gettext("Policy: %s\n"),
1589 dprinc.policy ? dprinc.policy : gettext("[none]"));
1590 } else {
1591 printf("\"%s\"\t%d\t%d\t%d\t%d\t\"%s\"\t%d\t%d\t%d\t%d\t\"%s\""
1592 "\t%d\t%d\t%d\t%d\t%d",
1593 canon, dprinc.princ_expire_time, dprinc.last_pwd_change,
1594 dprinc.pw_expiration, dprinc.max_life, modcanon,
1595 dprinc.mod_date, dprinc.attributes, dprinc.kvno,
1596 dprinc.mkvno, dprinc.policy ? dprinc.policy : gettext("[none]"),
1597 dprinc.max_renewable_life, dprinc.last_success,
1598 dprinc.last_failed, dprinc.fail_auth_count,
1599 dprinc.n_key_data);
1600 for (i = 0; i < dprinc.n_key_data; i++)
1601 printf("\t%d\t%d\t%d\t%d",
1602 dprinc.key_data[i].key_data_ver,
1603 dprinc.key_data[i].key_data_kvno,
1604 dprinc.key_data[i].key_data_type[0],
1605 dprinc.key_data[i].key_data_type[1]);
1606 printf("\n");
1608 free(modcanon);
1609 kadm5_free_principal_ent(handle, &dprinc);
1610 free(canon);
1613 void kadmin_getprincs(argc, argv)
1614 int argc;
1615 char *argv[];
1617 krb5_error_code retval;
1618 char *expr, **names;
1619 int i, count;
1621 FILE *output;
1622 int fd;
1623 struct sigaction nsig, osig;
1624 sigset_t nmask, omask;
1625 int waitb;
1627 expr = NULL;
1628 if (! (argc == 1 || (argc == 2 && (expr = argv[1])))) {
1629 fprintf(stderr, "%s: get_principals %s\n",
1630 gettext("usage"), gettext("[expression]"));
1631 return;
1633 retval = kadm5_get_principals(handle, expr, &names, &count);
1634 if (retval) {
1635 com_err("get_principals", retval,
1636 gettext("while retrieving list."));
1637 return;
1641 * Solaris: the following code is used for paging
1644 sigemptyset(&nmask);
1645 sigaddset(&nmask, SIGINT);
1646 sigprocmask(SIG_BLOCK, &nmask, &omask);
1648 nsig.sa_handler = SIG_IGN;
1649 sigemptyset(&nsig.sa_mask);
1650 nsig.sa_flags = 0;
1651 sigaction(SIGINT, &nsig, &osig);
1653 fd = ss_pager_create();
1654 output = fdopen(fd, "w");
1656 sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0);
1658 for (i = 0; i < count; i++)
1659 fprintf(output, "%s\n", names[i]);
1661 fclose(output);
1663 wait(&waitb);
1665 /* Solaris Kerberos:
1666 * Restore the original handler for SIGINT
1668 if (sigaction(SIGINT, &osig, NULL) == -1) {
1669 perror("sigaction");
1672 kadm5_free_name_list(handle, names, count);
1675 static int
1676 kadmin_parse_policy_args(argc, argv, policy, mask, caller)
1677 int argc;
1678 char *argv[];
1679 kadm5_policy_ent_t policy;
1680 long *mask;
1681 char *caller;
1683 int i;
1684 time_t now;
1685 time_t date;
1687 time(&now);
1688 *mask = 0;
1689 for (i = 1; i < argc - 1; i++) {
1690 if (strlen(argv[i]) == 8 &&
1691 !strcmp(argv[i], "-maxlife")) {
1692 if (++i > argc -2)
1693 return -1;
1694 else {
1695 date = get_date(argv[i]);
1696 if (date == (time_t)-1) {
1697 fprintf(stderr, gettext("Invalid date specification \"%s\".\n"),
1698 argv[i]);
1699 return -1;
1701 policy->pw_max_life = date - now;
1702 *mask |= KADM5_PW_MAX_LIFE;
1703 continue;
1705 } else if (strlen(argv[i]) == 8 &&
1706 !strcmp(argv[i], "-minlife")) {
1707 if (++i > argc - 2)
1708 return -1;
1709 else {
1710 date = get_date(argv[i]);
1711 if (date == (time_t)-1) {
1712 fprintf(stderr, gettext("Invalid date specification \"%s\".\n"),
1713 argv[i]);
1714 return -1;
1716 policy->pw_min_life = date - now;
1717 *mask |= KADM5_PW_MIN_LIFE;
1718 continue;
1720 } else if (strlen(argv[i]) == 10 &&
1721 !strcmp(argv[i], "-minlength")) {
1722 if (++i > argc - 2)
1723 return -1;
1724 else {
1725 policy->pw_min_length = atoi(argv[i]);
1726 *mask |= KADM5_PW_MIN_LENGTH;
1727 continue;
1729 } else if (strlen(argv[i]) == 11 &&
1730 !strcmp(argv[i], "-minclasses")) {
1731 if (++i > argc - 2)
1732 return -1;
1733 else {
1734 policy->pw_min_classes = atoi(argv[i]);
1735 *mask |= KADM5_PW_MIN_CLASSES;
1736 continue;
1738 } else if (strlen(argv[i]) == 8 &&
1739 !strcmp(argv[i], "-history")) {
1740 if (++i > argc - 2)
1741 return -1;
1742 else {
1743 policy->pw_history_num = atoi(argv[i]);
1744 *mask |= KADM5_PW_HISTORY_NUM;
1745 continue;
1747 } else
1748 return -1;
1750 if (i != argc -1) {
1751 fprintf(stderr, gettext("%s: parser lost count!\n"), caller);
1752 return -1;
1753 } else
1754 return 0;
1757 static void
1758 kadmin_addmodpol_usage(func)
1759 char *func;
1761 fprintf(stderr, "%s: %s %s\n", gettext("usage"), func,
1762 gettext("[options] policy"));
1763 fprintf(stderr, gettext("\toptions are:\n"));
1764 fprintf(stderr, "\t\t[-maxlife time] [-minlife time] "
1765 "[-minlength length]\n\t\t[-minclasses number] "
1766 "[-history number]\n");
1769 void kadmin_addpol(argc, argv)
1770 int argc;
1771 char *argv[];
1773 krb5_error_code retval;
1774 long mask;
1775 kadm5_policy_ent_rec policy;
1777 memset(&policy, 0, sizeof(policy));
1778 if (kadmin_parse_policy_args(argc, argv, &policy, &mask, "add_policy")) {
1779 kadmin_addmodpol_usage("add_policy");
1780 return;
1781 } else {
1782 policy.policy = argv[argc - 1];
1783 mask |= KADM5_POLICY;
1784 retval = kadm5_create_policy(handle, &policy, mask);
1785 if (retval) {
1786 com_err("add_policy", retval,
1787 gettext("while creating policy \"%s\"."),
1788 policy.policy);
1789 return;
1792 return;
1795 void kadmin_modpol(argc, argv)
1796 int argc;
1797 char *argv[];
1799 krb5_error_code retval;
1800 long mask;
1801 kadm5_policy_ent_rec policy;
1803 memset(&policy, 0, sizeof(policy));
1804 if (kadmin_parse_policy_args(argc, argv, &policy, &mask,
1805 "modify_policy")) {
1806 kadmin_addmodpol_usage("modify_policy");
1807 return;
1808 } else {
1809 policy.policy = argv[argc - 1];
1810 retval = kadm5_modify_policy(handle, &policy, mask);
1811 if (retval) {
1812 com_err("modify_policy", retval, gettext("while modifying policy \"%s\"."),
1813 policy.policy);
1814 return;
1817 return;
1820 void kadmin_delpol(argc, argv)
1821 int argc;
1822 char *argv[];
1824 krb5_error_code retval;
1825 char reply[32];
1827 if (! (argc == 2 ||
1828 (argc == 3 && !strcmp("-force", argv[1])))) {
1829 fprintf(stderr, "%s: delete_policy [-force] %s\n",
1830 gettext("usage"), gettext("policy"));
1831 return;
1833 if (argc == 2) {
1834 printf(gettext("Are you sure you want to delete the policy "
1835 "\"%s\"? (yes/no): "), argv[1]);
1836 fgets(reply, sizeof (reply), stdin);
1837 if (strncmp(gettext("yes\n"), reply, sizeof (reply)) &&
1838 strncmp(gettext("y\n"), reply, sizeof (reply)) &&
1839 strncmp(gettext("Y\n"), reply, sizeof (reply))
1841 fprintf(stderr,
1842 gettext("Policy \"%s\" not deleted.\n"),
1843 argv[1]);
1844 return;
1847 retval = kadm5_delete_policy(handle, argv[argc - 1]);
1848 if (retval) {
1849 com_err("delete_policy:", retval,
1850 gettext("while deleting policy \"%s\""),
1851 argv[argc - 1]);
1852 return;
1854 return;
1857 void kadmin_getpol(argc, argv)
1858 int argc;
1859 char *argv[];
1861 krb5_error_code retval;
1862 kadm5_policy_ent_rec policy;
1864 if (! (argc == 2 ||
1865 (argc == 3 && !strcmp("-terse", argv[1])))) {
1866 fprintf(stderr, "%s: get_policy [-terse] %s\n",
1867 gettext("usage"), gettext("policy"));
1868 return;
1870 retval = kadm5_get_policy(handle, argv[argc - 1], &policy);
1871 if (retval) {
1872 com_err("get_policy", retval,
1873 gettext("while retrieving policy \"%s\"."),
1874 argv[argc - 1]);
1875 return;
1877 if (argc == 2) {
1878 printf(gettext("Policy: %s\n"), policy.policy);
1879 printf(gettext("Maximum password life: %ld\n"),
1880 policy.pw_max_life);
1881 printf(gettext("Minimum password life: %ld\n"),
1882 policy.pw_min_life);
1883 printf(gettext("Minimum password length: %ld\n"),
1884 policy.pw_min_length);
1885 printf(gettext("Minimum number of password "
1886 "character classes: %ld\n"),
1887 policy.pw_min_classes);
1888 printf(gettext("Number of old keys kept: %ld\n"),
1889 policy.pw_history_num);
1890 printf(gettext("Reference count: %ld\n"), policy.policy_refcnt);
1891 } else {
1892 printf("\"%s\"\t%ld\t%ld\t%ld\t%ld\t%ld\t%ld\n",
1893 policy.policy, policy.pw_max_life, policy.pw_min_life,
1894 policy.pw_min_length, policy.pw_min_classes,
1895 policy.pw_history_num, policy.policy_refcnt);
1897 kadm5_free_policy_ent(handle, &policy);
1898 return;
1901 void kadmin_getpols(argc, argv)
1902 int argc;
1903 char *argv[];
1905 krb5_error_code retval;
1906 char *expr, **names;
1907 int i, count;
1909 /* Solaris Kerberos:
1910 * Use a pager for listing policies (similar to listing princs)
1912 FILE *output = NULL;
1913 int fd;
1914 struct sigaction nsig, osig;
1915 sigset_t nmask, omask;
1916 int waitb;
1918 expr = NULL;
1919 if (! (argc == 1 || (argc == 2 && (expr = argv[1])))) {
1920 fprintf(stderr, "%s: get_policies %s\n",
1921 gettext("usage"), gettext("[expression]\n"));
1922 return;
1924 retval = kadm5_get_policies(handle, expr, &names, &count);
1925 if (retval) {
1926 com_err("get_policies", retval,
1927 gettext("while retrieving list."));
1928 return;
1931 if (sigemptyset(&nmask) == -1) {
1932 perror("sigemptyset");
1933 kadm5_free_name_list(handle, names, count);
1934 return;
1937 if (sigaddset(&nmask, SIGINT) == -1) {
1938 perror("sigaddset");
1939 kadm5_free_name_list(handle, names, count);
1940 return;
1943 if (sigemptyset(&nsig.sa_mask) == -1) {
1944 perror("sigemptyset");
1945 kadm5_free_name_list(handle, names, count);
1946 return;
1949 if (sigprocmask(SIG_BLOCK, &nmask, &omask) == -1) {
1950 perror("sigprocmask");
1951 kadm5_free_name_list(handle, names, count);
1952 return;
1955 nsig.sa_handler = SIG_IGN;
1956 nsig.sa_flags = 0;
1957 if (sigaction(SIGINT, &nsig, &osig) == -1) {
1958 perror("sigaction");
1959 if (sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0) == -1) {
1960 perror("sigprocmask");
1962 kadm5_free_name_list(handle, names, count);
1963 return;
1966 fd = ss_pager_create();
1967 if (fd == -1) {
1968 fprintf(stderr, "%s: failed to create pager\n", whoami);
1969 if (sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0) == -1) {
1970 perror("sigprocmask");
1973 if (sigaction(SIGINT, &osig, NULL) == -1) {
1974 perror("sigaction");
1977 kadm5_free_name_list(handle, names, count);
1978 return;
1981 output = fdopen(fd, "w");
1982 if (output == NULL) {
1983 perror("fdopen");
1986 if (sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0) == -1) {
1987 perror("sigprocmask");
1990 if (output != NULL) {
1991 for (i = 0; i < count; i++)
1992 fprintf(output, "%s\n", names[i]);
1995 if (output != NULL && fclose(output) != 0) {
1996 perror("fclose");
1999 if (wait(&waitb) == -1) {
2000 perror("wait");
2003 if (sigaction(SIGINT, &osig, NULL) == -1) {
2004 perror("sigaction");
2006 kadm5_free_name_list(handle, names, count);