xref: /illumos-gate/usr/src/cmd/krb5/kadmin/cli/kadmin.c (revision 7153155797a2d348ef707cf0655ea4f87b029013)
1 /*
2  * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
3  */
4 
5 /*
6  * Copyright 1994 by the Massachusetts Institute of Technology.
7  * All Rights Reserved.
8  *
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.
13  *
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.
27  *
28  * kadmin.c: base functions for a kadmin command line interface using
29  * the OVSecure library
30  */
31 
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>
45 
46 /*
47  * Solaris:  the following are needed for paging
48  */
49 #include <signal.h>
50 #include <sys/wait.h>
51 
52 /* command name when called "locally" (i.e. non-networked client ) */
53 #define KADMIN_LOCAL_NAME "kadmin.local"
54 
55 /* functions defined in remote/local specific files */
56 extern void usage(const char *);
57 
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 '-') */
65 };
66 
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 }
81 };
82 
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 */
100 };
101 
102 char *getenv();
103 int exit_status = 0;
104 char *def_realm = NULL;
105 char *whoami = NULL;
106 
107 void *handle = NULL;
108 krb5_context context;
109 char *ccache_name = NULL;
110 
111 int locked = 0;
112 static char *strdur(duration)
113     time_t duration;
114 {
115     static char out[50];
116     int neg, days, hours, minutes, seconds;
117 
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;
134 }
135 
136 static char *strdate(when)
137     krb5_timestamp when;
138 {
139     struct tm *tm;
140     static char out[40];
141 
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;
146 }
147 
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;
154 {
155     char *cp, *fullname;
156     krb5_error_code retval;
157 
158     if (name == NULL)
159 	return (EINVAL);
160 
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, '@');
172     }
173     if (cp == NULL) {
174 	strcat(fullname, "@");
175 	strcat(fullname, def_realm);
176     }
177     retval = krb5_parse_name(context, fullname, principal);
178     free(fullname);
179     return retval;
180 }
181 
182 static void extended_com_err_fn (const char *myprog, errcode_t code,
183 				 const char *fmt, va_list args)
184 {
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);
192     }
193     vfprintf (stderr, fmt, args);
194     fprintf (stderr, "\n");
195 }
196 char *kadmin_startup(argc, argv)
197     int argc;
198     char *argv[];
199 {
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;
214 
215     memset((char *) &params, 0, sizeof(params));
216 
217     if (strcmp (whoami, "kadmin.local") == 0)
218 	set_com_err_hook(extended_com_err_fn);
219 
220     retval = kadm5_init_krb5_context(&context);
221     if (retval) {
222 	com_err(whoami, retval, gettext("while initializing krb5 library"));
223 	exit(1);
224     }
225 
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++;
230 	    {
231 		char **temp = realloc(db_args, sizeof(char*) * (db_args_size+1));
232 		if (temp == NULL) {
233 		    fprintf(stderr, gettext("%s: Cannot initialize. Not enough memory\n"),
234 			    argv[0]);
235 		    exit(1);
236 		}
237 
238 		db_args = temp;
239 	    }
240 	    db_args[db_args_size-1] = optarg;
241 	    db_args[db_args_size]   = NULL;
242 	    break;
243 
244 	case 'r':
245 	    def_realm = optarg;
246 	    break;
247 	case 'p':
248 	    princstr = optarg;
249 	    break;
250 	case 'c':
251 	    ccache_name = optarg;
252 	    break;
253 	case 'k':
254 	    use_keytab++;
255 	    break;
256 	case 't':
257 	    keytab_name = optarg;
258 	    break;
259 	case 'w':
260 	    password = optarg;
261 	    break;
262 	case 'q':
263 	    query = optarg;
264 	    break;
265 	case 'd':
266 	    /* now db_name is not a seperate argument. It has to be passed as part of the db_args */
267 	    if (!db_name) {
268 		db_name = malloc(strlen(optarg) + sizeof("dbname="));
269 	    } else {
270 		db_name = realloc(db_name, strlen(optarg) + sizeof("dbname="));
271 	    }
272 
273 	    strcpy(db_name, "dbname=");
274 	    strcat(db_name, optarg);
275 
276 	    db_args_size++;
277 	    {
278 		char **temp = realloc(db_args, sizeof(char*) * (db_args_size+1)); /* one for NULL */
279 		if (temp == NULL) {
280 		    fprintf(stderr,
281 			    gettext("%s: Cannot initialize. Not enough memory\n"),
282 			    argv[0]);
283 		    exit(1);
284 		}
285 
286 		db_args = temp;
287 	    }
288 	    db_args[db_args_size-1] = db_name;
289 	    db_args[db_args_size]   = NULL;
290 	    break;
291 	case 's':
292 	    params.admin_server = optarg;
293 	    params.mask |= KADM5_CONFIG_ADMIN_SERVER;
294 	    break;
295 	case 'm':
296 	    params.mkey_from_kbd = 1;
297 	    params.mask |= KADM5_CONFIG_MKEY_FROM_KBD;
298 	    break;
299 	case 'e':
300 	    retval = krb5_string_to_keysalts(optarg,
301 					     ", \t",
302 					     ":.-",
303 					     0,
304 					     &params.keysalts,
305 					     &params.num_keysalts);
306 	    if (retval) {
307 		 com_err(whoami, retval,
308 			gettext("while parsing keysalts %s"), optarg);
309 		 exit(1);
310 	    }
311 	    params.mask |= KADM5_CONFIG_ENCTYPES;
312 	    break;
313 	case 'O':	/* Undocumented option for testing only */
314 		svcname = KADM5_ADMIN_SERVICE_P;
315 	    break;
316 	default:
317 	    usage(whoami);
318 	}
319     }
320     if ((ccache_name && use_keytab) ||
321 	(keytab_name && !use_keytab))
322 	 usage(whoami);
323 
324     if (def_realm == NULL && krb5_get_default_realm(context, &def_realm)) {
325 	if (freeprinc)
326 	    free(princstr);
327 	fprintf(stderr,
328 		gettext("%s: unable to get default realm\n"), whoami);
329 	exit(1);
330     }
331 
332     params.mask |= KADM5_CONFIG_REALM;
333     params.realm = def_realm;
334 
335     if (svcname == NULL) {
336 	if (kadm5_get_adm_host_srv_name(context,
337 			       def_realm, &svcname)) {
338 		fprintf(stderr,
339 			gettext("%s: unable to get host based "
340 				"service name for realm %s\n"),
341 			whoami, def_realm);
342 		if (freeprinc)
343 			free(princstr);
344 		exit(1);
345 	}
346     }
347 
348     /*
349      * Set cc to an open credentials cache, either specified by the -c
350      * argument or the default.
351      */
352     if (ccache_name == NULL) {
353 	 if ((retval = krb5_cc_default(context, &cc))) {
354 	      com_err(whoami, retval,
355 				gettext("while opening default "
356 					"credentials cache"));
357 	      exit(1);
358 	 }
359     } else {
360 	 if ((retval = krb5_cc_resolve(context, ccache_name, &cc))) {
361 	      com_err(whoami, retval,
362 			gettext("while opening credentials cache %s"),
363 			ccache_name);
364 	      exit(1);
365 	 }
366     }
367 
368     /*
369      * If no principal name is specified: If a ccache was specified
370      * and its primary principal name can be read, it is used, else if
371      * a keytab was specified, the principal name is host/hostname,
372      * otherwise append "/admin" to the primary name of the default
373      * ccache, $USER, or pw_name.
374      *
375      * Gee, 100+ lines to figure out the client principal name.  This
376      * should be compressed...
377      */
378 
379     if (princstr == NULL) {
380 	if (ccache_name != NULL &&
381 	    !krb5_cc_get_principal(context, cc, &princ)) {
382 	     if ((retval = krb5_unparse_name(context, princ, &princstr))) {
383 		  com_err(whoami, retval,
384 			gettext("while canonicalizing principal name"));
385 		  krb5_free_principal(context, princ);
386 		  exit(1);
387 	     }
388 	     krb5_free_principal(context, princ);
389 	     freeprinc++;
390 	} else if (use_keytab != 0) {
391 	    if ((retval = krb5_sname_to_principal(context, NULL,
392 						  "host",
393 						  KRB5_NT_SRV_HST,
394 						  &princ))) {
395 		com_err(whoami, retval,
396 			gettext("creating host service principal"));
397 		exit(1);
398 	    }
399 	    if ((retval = krb5_unparse_name(context, princ, &princstr))) {
400 		com_err(whoami, retval,
401 			gettext("while canonicalizing principal name"));
402 		krb5_free_principal(context, princ);
403 		exit(1);
404 	    }
405 	    krb5_free_principal(context, princ);
406 	    freeprinc++;
407 	} else if (!krb5_cc_get_principal(context, cc, &princ)) {
408 	    char *realm = NULL;
409 	    if (krb5_unparse_name(context, princ, &canon)) {
410 		fprintf(stderr,
411 			gettext("%s: unable to canonicalize "
412 				"principal\n"), whoami);
413 		krb5_free_principal(context, princ);
414 		exit(1);
415 	    }
416 	    /* strip out realm of principal if it's there */
417 	    realm = strchr(canon, '@');
418 	    while (realm) {
419 		if (realm - canon && *(realm - 1) != '\\')
420 		    break;
421 		else
422 		    realm = strchr(realm+1, '@');
423 	    }
424 	    if (realm)
425 		*realm++ = '\0';
426 	    cp = strchr(canon, '/');
427 	    while (cp) {
428 		if (cp - canon && *(cp - 1) != '\\')
429 		    break;
430 		else
431 		    cp = strchr(cp+1, '/');
432 	    }
433 	    if (cp != NULL)
434 		*cp = '\0';
435 	    princstr = (char*)malloc(strlen(canon) + 6 /* "/admin" */ +
436 				     (realm ? 1 + strlen(realm) : 0) + 1);
437 	    if (princstr == NULL) {
438 		fprintf(stderr,
439 			gettext("%s: out of memory\n"),
440 			whoami);
441 		exit(1);
442 	    }
443 	    strcpy(princstr, canon);
444 	    strcat(princstr, "/admin");
445 	    if (realm) {
446 		strcat(princstr, "@");
447 		strcat(princstr, realm);
448 	    }
449 	    free(canon);
450 	    krb5_free_principal(context, princ);
451 	    freeprinc++;
452 	} else if ((luser = getenv("USER"))) {
453 	    princstr = (char *) malloc(strlen(luser) + 7 /* "/admin@" */
454 				       + strlen(def_realm) + 1);
455 	    if (princstr == NULL) {
456 		fprintf(stderr,
457 			gettext("%s: out of memory\n"),
458 			whoami);
459 		exit(1);
460 	    }
461 	    strcpy(princstr, luser);
462 	    strcat(princstr, "/admin");
463 	    strcat(princstr, "@");
464 	    strcat(princstr, def_realm);
465 	    freeprinc++;
466 	} else if ((pw = getpwuid(getuid()))) {
467 	    princstr = (char *) malloc(strlen(pw->pw_name) + 7 /* "/admin@" */
468 				       + strlen(def_realm) + 1);
469 	    if (princstr == NULL) {
470 		fprintf(stderr,
471 			gettext("%s: out of memory\n"),
472 			whoami);
473 		exit(1);
474 	    }
475 	    strcpy(princstr, pw->pw_name);
476 	    strcat(princstr, "/admin@");
477 	    strcat(princstr, def_realm);
478 	    freeprinc++;
479 	} else {
480 	    fprintf(stderr,
481 			gettext("%s: unable to figure out "
482 				"a principal name\n"),
483 		    whoami);
484 	    exit(1);
485 	}
486     }
487 
488     retval = krb5_klog_init(context, "admin_server", whoami, 0);
489     if (retval) {
490 	com_err(whoami, retval, "while setting up logging");
491 	exit(1);
492     }
493 
494     /*
495      * Initialize the kadm5 connection.  If we were given a ccache,
496      * use it.  Otherwise, use/prompt for the password.
497      */
498 
499     /* Solaris Kerberos:
500      * Send warnings to stderr
501      */
502     if (ccache_name) {
503 	fprintf(stderr, gettext("Authenticating as principal %s with existing credentials.\n"),
504 	       princstr);
505 	retval = kadm5_init_with_creds(princstr, cc,
506 				       svcname,
507 				       &params,
508 				       KADM5_STRUCT_VERSION,
509 				       KADM5_API_VERSION_2,
510 				       db_args,
511 				       &handle);
512     } else if (use_keytab) {
513 	if (keytab_name)
514 	    fprintf(stderr, gettext("Authenticating as principal %s with keytab %s.\n"),
515 		   princstr, keytab_name);
516 	else
517 	    fprintf(stderr, gettext("Authenticating as principal %s with default keytab.\n"),
518 		   princstr);
519 	retval = kadm5_init_with_skey(princstr, keytab_name,
520 				      svcname,
521 				      &params,
522 				      KADM5_STRUCT_VERSION,
523 				      KADM5_API_VERSION_2,
524 				      db_args,
525 				      &handle);
526     } else {
527 	 fprintf(stderr, gettext("Authenticating as principal %s with password.\n"),
528 	       princstr);
529 	retval = kadm5_init_with_password(princstr, password,
530 					  svcname,
531 					  &params,
532 					  KADM5_STRUCT_VERSION,
533 					  KADM5_API_VERSION_2,
534 					  db_args,
535 					  &handle);
536     }
537     if (retval) {
538 	    if (retval == KADM5_RPC_ERROR_CANTENCODEARGS ||
539 		retval == KADM5_RPC_ERROR_CANTDECODEARGS) {
540 		    com_err(whoami, KADM5_RPC_ERROR,
541 			gettext("while initializing %s interface"), whoami);
542 
543 		    /* privacy-enabled mech probably not installed/configed */
544 		    com_err(whoami, retval, gettext("."), whoami);
545 	    } else {
546 		    com_err(whoami, retval,
547 			gettext("while initializing %s interface"), whoami);
548 	if (retval == KADM5_BAD_CLIENT_PARAMS ||
549 	    retval == KADM5_BAD_SERVER_PARAMS)
550 		usage(whoami);
551 	}
552 	exit(1);
553     }
554     if (freeprinc)
555 	free(princstr);
556 
557     if (db_name)
558 	free(db_name), db_name=NULL;
559 
560     if (db_args)
561 	free(db_args), db_args=NULL;
562 
563     if ((retval = krb5_cc_close(context, cc))) {
564 	 com_err(whoami, retval, gettext("while closing ccache %s"),
565 		 ccache_name);
566 	 exit(1);
567     }
568 
569     /* register the WRFILE keytab type and set it as the default */
570     {
571 #define DEFAULT_KEYTAB "WRFILE:/etc/krb5/krb5.keytab"
572 	/* XXX krb5_defkeyname is an internal library global and
573 	   should go away */
574 	extern char *krb5_defkeyname;
575 	krb5_defkeyname = DEFAULT_KEYTAB;
576     }
577 
578     if ((retval = kadm5_init_iprop(handle)) != 0) {
579 	com_err(whoami, retval, gettext("while mapping update log"));
580 	exit(1);
581     }
582 
583     /* Solaris kerberos: fix memory leak */
584     if (svcname)
585 	free(svcname);
586 
587     return query;
588 }
589 
590 int quit()
591 {
592     kadm5_ret_t retval;
593 
594     if (locked) {
595 	retval = kadm5_unlock(handle);
596 	if (retval) {
597 	    com_err("quit", retval, gettext("while unlocking locked database"));
598 	    return 1;
599 	}
600 	locked = 0;
601     }
602 
603      kadm5_destroy(handle);
604      if (ccache_name != NULL) {
605 	  fprintf(stderr,
606 			gettext("\n\a\a\aAdministration credentials "
607 				"NOT DESTROYED.\n"));
608      }
609 
610      /* insert more random cleanup here */
611      krb5_klog_close(context);
612      krb5_free_context(context);
613      context = NULL;
614      return 0;
615 }
616 
617 void kadmin_lock(argc, argv)
618     int argc;
619     char *argv[];
620 {
621     kadm5_ret_t retval;
622 
623     if (locked)
624 	return;
625     retval = kadm5_lock(handle);
626     if (retval) {
627 	com_err("lock", retval, "");
628 	return;
629     }
630     locked = 1;
631 }
632 
633 void kadmin_unlock(argc, argv)
634     int argc;
635     char *argv[];
636 {
637     kadm5_ret_t retval;
638 
639     if (!locked)
640 	return;
641     retval = kadm5_unlock(handle);
642     if (retval) {
643 	com_err("unlock", retval, "");
644 	return;
645     }
646     locked = 0;
647 }
648 
649 void kadmin_delprinc(argc, argv)
650     int argc;
651     char *argv[];
652 {
653     kadm5_ret_t retval;
654     krb5_principal princ;
655     char *canon;
656     char reply[32];
657 
658     if (! (argc == 2 ||
659 	   (argc == 3 && !strcmp("-force", argv[1])))) {
660 	fprintf(stderr, "%s: delete_principal [-force] %s\n",
661 			gettext("usage"), gettext("principal"));
662 	return;
663     }
664     retval = kadmin_parse_name(argv[argc - 1], &princ);
665     if (retval) {
666 	com_err("delete_principal", retval,
667 			gettext("while parsing principal name"));
668 	return;
669     }
670     retval = krb5_unparse_name(context, princ, &canon);
671     if (retval) {
672 	com_err("delete_principal", retval,
673 			gettext("while canonicalizing principal"));
674 	krb5_free_principal(context, princ);
675 	return;
676     }
677     if (argc == 2) {
678 	printf(gettext("Are you sure you want to delete "
679 			    "the principal \"%s\"? (yes/no): "), canon);
680 	fgets(reply, sizeof (reply), stdin);
681 		if (strncmp(gettext("yes\n"), reply, sizeof (reply)) &&
682 			strncmp(gettext("y\n"), reply, sizeof (reply)) &&
683 			strncmp(gettext("Y\n"), reply, sizeof (reply))) {
684 			fprintf(stderr,
685 				gettext("Principal \"%s\" not deleted\n"),
686 				canon);
687 	    free(canon);
688 	    krb5_free_principal(context, princ);
689 	    return;
690 	}
691     }
692     retval = kadm5_delete_principal(handle, princ);
693     krb5_free_principal(context, princ);
694     if (retval) {
695 	com_err("delete_principal", retval,
696 			gettext("while deleting principal \"%s\""), canon);
697 	free(canon);
698 	return;
699     }
700     printf(gettext("Principal \"%s\" deleted.\n"), canon);
701 	printf(gettext("Make sure that you have removed this principal "
702 			"from all ACLs before reusing.\n"));
703     free(canon);
704     return;
705 }
706 
707 void kadmin_cpw(argc, argv)
708     int argc;
709     char *argv[];
710 {
711     kadm5_ret_t retval;
712     static char newpw[1024];
713     static char prompt1[1024], prompt2[1024];
714     char *canon;
715     char *pwarg = NULL;
716     int n_ks_tuple = 0, randkey = 0;
717     krb5_boolean keepold = FALSE;
718     krb5_key_salt_tuple *ks_tuple = NULL;
719     krb5_principal princ;
720     char **db_args = NULL;
721     int db_args_size = 0;
722     int local_kadmin = 0;
723 
724     local_kadmin = (strcmp(whoami, KADMIN_LOCAL_NAME) == 0);
725 
726     if (argc < 2) {
727 	goto usage;
728     }
729     for (argv++, argc--; argc > 1; argc--, argv++) {
730 	if (!strcmp("-x", *argv)) {
731 	    argc--;
732 	    if (argc < 1) {
733 		fprintf(stderr, gettext("change_password: missing db argument\n"));
734 		goto usage;
735 	    }
736 	    db_args_size++;
737 	    {
738 		char **temp = realloc(db_args, sizeof(char*) * (db_args_size+1)); /* one for NULL */
739 		if (temp == NULL) {
740 		    fprintf(stderr, gettext("change_password: Not enough memory\n"));
741 		    free(db_args), db_args = NULL;
742 		    exit(1);
743 		}
744 
745 		db_args = temp;
746 	    }
747 	    db_args[db_args_size-1] = *++argv;
748 	    db_args[db_args_size]   = NULL;
749 	    continue;
750 	}
751 	if (!strcmp("-pw", *argv)) {
752 	    argc--;
753 	    if (argc < 1) {
754 		fprintf(stderr, "change_password: %s",
755 			gettext("missing password arg\n"));
756 		goto usage;
757 	    }
758 	    pwarg = *++argv;
759 	    continue;
760 	}
761 	if (!strcmp("-randkey", *argv)) {
762 	    randkey++;
763 	    continue;
764 	}
765 	if (!strcmp("-keepold", *argv)) {
766 	    keepold = TRUE;
767 	    continue;
768 	}
769 	if (!strcmp("-e", *argv)) {
770 	    argc--;
771 	    if (argc < 1) {
772 		fprintf(stderr, "change_password: %s",
773 			gettext("missing keysaltlist arg\n"));
774 		goto usage;
775 	    }
776 	    retval = krb5_string_to_keysalts(*++argv, ", \t", ":.-", 0,
777 					     &ks_tuple, &n_ks_tuple);
778 	    if (retval) {
779 		com_err("change_password", retval,
780 			gettext("while parsing keysalts %s"), *argv);
781 		return;
782 	    }
783 	    continue;
784 	}
785 	goto usage;
786     }
787     if (*argv == NULL) {
788 	com_err("change_password", 0, "missing principal name");
789 	goto usage;
790     }
791     retval = kadmin_parse_name(*argv, &princ);
792     if (retval) {
793 	com_err("change_password", retval,
794 		gettext("while parsing principal name"));
795 	if (ks_tuple != NULL)
796 	    free(ks_tuple);
797 	if (db_args) free(db_args);
798 	goto usage;
799     }
800     retval = krb5_unparse_name(context, princ, &canon);
801     if (retval) {
802 		com_err("change_password", retval,
803 			gettext("while canonicalizing principal"));
804 	krb5_free_principal(context, princ);
805 	if (ks_tuple != NULL)
806 	    free(ks_tuple);
807 	if (db_args) free(db_args);
808 	return;
809     }
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 	    if (ks_tuple != NULL)
815 		free(ks_tuple);
816 	} else {
817 	    retval = kadm5_chpass_principal(handle, princ, pwarg);
818 	}
819 	krb5_free_principal(context, princ);
820 	if (retval) {
821 	    com_err("change_password", retval,
822 				gettext("while changing password for \"%s\"."),
823 				canon);
824 	    free(canon);
825 	    if (db_args) free(db_args);
826 	    return;
827 	}
828 		printf(gettext("Password for \"%s\" changed.\n"), canon);
829 	free(canon);
830 	if (db_args) free(db_args);
831 	return;
832     } else if (randkey) {
833 	if (keepold || ks_tuple != NULL || local_kadmin) {
834 	    retval = kadm5_randkey_principal_3(handle, princ, keepold,
835 					       n_ks_tuple, ks_tuple,
836 					       NULL, NULL);
837 	    if (ks_tuple != NULL)
838 		free(ks_tuple);
839 	} else {
840 	    retval = kadm5_randkey_principal(handle, princ, NULL, NULL);
841 	}
842 	krb5_free_principal(context, princ);
843 	if (retval) {
844 	    com_err("change_password", retval,
845 				gettext("while randomizing key for \"%s\"."),
846 				canon);
847 	    free(canon);
848 	    if (db_args) free(db_args);
849 	    return;
850 	}
851 	printf(gettext("Key for \"%s\" randomized.\n"), canon);
852 	free(canon);
853 	if (db_args) free(db_args);
854 	return;
855     } else if (argc == 1) {
856 	unsigned int i = sizeof (newpw) - 1;
857 
858 		snprintf(prompt1, sizeof (prompt1),
859 			gettext("Enter password for principal \"%.900s\""),
860 			*argv);
861 		snprintf(prompt2, sizeof (prompt2),
862 			gettext("Re-enter password for principal \"%.900s\""),
863 			*argv);
864 	retval = krb5_read_password(context, prompt1, prompt2,
865 				    newpw, &i);
866 	if (retval) {
867 	    com_err("change_password", retval,
868 				gettext("while reading password for \"%s\"."),
869 				canon);
870 	    free(canon);
871 	    if (ks_tuple != NULL)
872 		free(ks_tuple);
873 	    krb5_free_principal(context, princ);
874 	    if (db_args) free(db_args);
875 	    return;
876 	}
877 	if (keepold || ks_tuple != NULL) {
878 	    retval = kadm5_chpass_principal_3(handle, princ, keepold,
879 					      n_ks_tuple, ks_tuple,
880 					      newpw);
881 	    if (ks_tuple != NULL)
882 		free(ks_tuple);
883 	} else {
884 	    retval = kadm5_chpass_principal(handle, princ, newpw);
885 	}
886 	krb5_free_principal(context, princ);
887 	memset(newpw, 0, sizeof (newpw));
888 	if (retval) {
889 	    com_err("change_password", retval,
890 				gettext("while changing password for \"%s\"."),
891 				canon);
892 	    free(canon);
893 	    if (db_args) free(db_args);
894 	    return;
895 	}
896 		printf(gettext("Password for \"%s\" changed.\n"), canon);
897 	free(canon);
898 	if (db_args) free(db_args);
899 	return;
900     } else {
901 	free(canon);
902 	krb5_free_principal(context, princ);
903     usage:
904 	if (ks_tuple != NULL)
905 	    free(ks_tuple);
906 		fprintf(stderr, "%s: change_password [-randkey] [-keepold] "
907 			"[-e keysaltlist] [-pw password] %s\n",
908 			gettext("usage"), gettext("principal"));
909 	return;
910     }
911 }
912 
913 static void
914 kadmin_free_tl_data(kadm5_principal_ent_t princ)
915 {
916     krb5_tl_data *tl_data = princ->tl_data;
917     int n_tl_data         = princ->n_tl_data;
918     int i;
919 
920     princ->n_tl_data = 0;
921     princ->tl_data   = NULL;
922 
923     for (i = 0; tl_data && (i < n_tl_data); i++) {
924 	krb5_tl_data *next = tl_data->tl_data_next;
925 	if (tl_data->tl_data_contents)
926 	    free(tl_data->tl_data_contents);
927 	free(tl_data);
928 	tl_data = next;
929     }
930 }
931 
932 #define KRB5_TL_DB_ARGS 0x7fff
933 static int
934 kadmin_parse_princ_args(argc, argv, oprinc, mask, pass, randkey,
935 			ks_tuple, n_ks_tuple, caller)
936     int argc;
937     char *argv[];
938     kadm5_principal_ent_t oprinc;
939     long *mask;
940     char **pass;
941     int *randkey;
942     krb5_key_salt_tuple **ks_tuple;
943     int *n_ks_tuple;
944     char *caller;
945 {
946     int i, j, attrib_set;
947     time_t date;
948     time_t now;
949     krb5_error_code retval;
950     krb5_tl_data *tl_data, *tail = NULL;
951 
952     *mask = 0;
953     *pass = NULL;
954     *n_ks_tuple = 0;
955     *ks_tuple = NULL;
956     time(&now);
957     *randkey = 0;
958     for (i = 1; i < argc - 1; i++) {
959 	attrib_set = 0;
960 	if (strlen(argv[i]) == 2 &&
961 	    !strcmp("-x",argv[i])) {
962 	    if (++i > argc - 2)
963 		return -1;
964 
965 	    tl_data = malloc(sizeof(krb5_tl_data));
966 	    if (tl_data == NULL) {
967 		fprintf(stderr, gettext("Not enough memory\n"));
968 		return ENOMEM;
969 	    }
970 
971 	    memset(tl_data, 0, sizeof(krb5_tl_data));
972 	    tl_data->tl_data_type = KRB5_TL_DB_ARGS;
973 	    tl_data->tl_data_length  = strlen(argv[i])+1;
974 	    tl_data->tl_data_contents = (unsigned char*)strdup(argv[i]);
975 
976 	    if (tail) {
977 		tail->tl_data_next = tl_data;
978 	    } else {
979 		oprinc->tl_data = tl_data;
980 	    }
981 	    tail = tl_data;
982 	    oprinc->n_tl_data++;
983 
984 	    if (tl_data->tl_data_contents == NULL) {
985 		fprintf(stderr, gettext("Not enough memory\n"));
986 		return ENOMEM;
987 	    }
988 	    *mask |= KADM5_TL_DATA;
989 	    continue;
990 	}
991 	if (strlen(argv[i]) == 7 &&
992 	    !strcmp("-expire", argv[i])) {
993 	    if (++i > argc - 2)
994 		return -1;
995 	    else {
996 		date = get_date(argv[i]);
997  		if (date == (time_t)-1) {
998 		     fprintf(stderr,
999 						gettext("Invalid date "
1000 							"specification "
1001 							"\"%s\".\n"),
1002 			     argv[i]);
1003 		     return -1;
1004  		}
1005 		oprinc->princ_expire_time = date;
1006 		*mask |= KADM5_PRINC_EXPIRE_TIME;
1007 		continue;
1008 	    }
1009 	}
1010 	if (strlen(argv[i]) == 9 &&
1011 	    !strcmp("-pwexpire", argv[i])) {
1012 	    if (++i > argc - 2)
1013 		return -1;
1014 	    else {
1015 		date = get_date(argv[i]);
1016  		if (date == (time_t)-1) {
1017 		     fprintf(stderr,
1018 						gettext("Invalid date "
1019 							"specification "
1020 							"\"%s\".\n"),
1021 			     argv[i]);
1022 		     return -1;
1023  		}
1024 		oprinc->pw_expiration = date;
1025 		*mask |= KADM5_PW_EXPIRATION;
1026 		continue;
1027 	    }
1028 	}
1029 	if (strlen(argv[i]) == 8 &&
1030 	    !strcmp("-maxlife", argv[i])) {
1031 	    if (++i > argc - 2)
1032 		return -1;
1033 	    else {
1034 		date = get_date(argv[i]);
1035  		if (date == (time_t)-1) {
1036 					fprintf(stderr,
1037 						gettext("Invalid date "
1038 							"specification "
1039 							"\"%s\".\n"),
1040 			     argv[i]);
1041 		     return -1;
1042  		}
1043 		oprinc->max_life = date - now;
1044 		*mask |= KADM5_MAX_LIFE;
1045 		continue;
1046 	    }
1047 	}
1048 	if (strlen(argv[i]) == 13 &&
1049 	    !strcmp("-maxrenewlife", argv[i])) {
1050 	    if (++i > argc - 2)
1051 		return -1;
1052 	    else {
1053 		date = get_date(argv[i]);
1054  		if (date == (time_t)-1) {
1055 					fprintf(stderr,
1056 						gettext("Invalid date "
1057 							"specification "
1058 							"\"%s\".\n"),
1059 			     argv[i]);
1060 		     return -1;
1061  		}
1062 		oprinc->max_renewable_life = date - now;
1063 		*mask |= KADM5_MAX_RLIFE;
1064 		continue;
1065 	    }
1066 	}
1067 	if (strlen(argv[i]) == 5 &&
1068 	    !strcmp("-kvno", argv[i])) {
1069 	    if (++i > argc - 2)
1070 		return -1;
1071 	    else {
1072 		oprinc->kvno = atoi(argv[i]);
1073 		*mask |= KADM5_KVNO;
1074 		continue;
1075 	    }
1076 	}
1077 	if (strlen(argv[i]) == 7 &&
1078 	    !strcmp("-policy", argv[i])) {
1079 	    if (++i > argc - 2)
1080 		return -1;
1081 	    else {
1082 		oprinc->policy = argv[i];
1083 		*mask |= KADM5_POLICY;
1084 		continue;
1085 	    }
1086 	}
1087 	if (strlen(argv[i]) == 12 &&
1088 	    !strcmp("-clearpolicy", argv[i])) {
1089 	    oprinc->policy = NULL;
1090 	    *mask |= KADM5_POLICY_CLR;
1091 	    continue;
1092 	}
1093 	if (strlen(argv[i]) == 3 &&
1094 	    !strcmp("-pw", argv[i])) {
1095 	    if (++i > argc - 2)
1096 		return -1;
1097 	    else {
1098 		*pass = argv[i];
1099 		continue;
1100 	    }
1101 	}
1102 	if (strlen(argv[i]) == 8 &&
1103 	    !strcmp("-randkey", argv[i])) {
1104 	    ++*randkey;
1105 	    continue;
1106 	}
1107 	if (!strcmp("-e", argv[i])) {
1108 	    if (++i > argc - 2)
1109 		return -1;
1110 	    else {
1111 		retval = krb5_string_to_keysalts(argv[i], ", \t", ":.-", 0,
1112 						 ks_tuple, n_ks_tuple);
1113 		if (retval) {
1114 		    com_err(caller, retval,
1115 			    gettext("while parsing keysalts %s"), argv[i]);
1116 		    return -1;
1117 		}
1118 	    }
1119 	    continue;
1120 	}
1121 	for (j = 0; j < sizeof (flags) / sizeof (struct pflag); j++) {
1122 	    if (strlen(argv[i]) == flags[j].flaglen + 1 &&
1123 		!strcmp(flags[j].flagname,
1124 			&argv[i][1] /* strip off leading + or - */)) {
1125 		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 if ((flags[j].set && argv[i][0] == '+') ||
1132 			   (!flags[j].set && argv[i][0] == '-')) {
1133 		    oprinc->attributes &= ~flags[j].theflag;
1134 		    *mask |= KADM5_ATTRIBUTES;
1135 		    attrib_set++;
1136 		    break;
1137 		} else {
1138 		    return -1;
1139 		}
1140 	    }
1141 	}
1142 	if (!attrib_set)
1143 	    return -1;		/* nothing was parsed */
1144     }
1145     if (i != argc - 1) {
1146 	return -1;
1147     }
1148     retval = kadmin_parse_name(argv[i], &oprinc->principal);
1149     if (retval) {
1150 	com_err(caller, retval, gettext("while parsing principal"));
1151 	return -1;
1152     }
1153     return 0;
1154 }
1155 
1156 static void
1157 kadmin_addprinc_usage(func)
1158     char *func;
1159 {
1160 	fprintf(stderr, "%s: %s %s\n", gettext("usage"), func,
1161 		gettext("[options] principal"));
1162 	fprintf(stderr, gettext("\toptions are:\n"));
1163 	fprintf(stderr, "\t\t[-expire expdate] [-pwexpire pwexpdate] "
1164 		"[-maxlife maxtixlife]\n\t\t[-kvno kvno] [-policy policy] "
1165 		"[-randkey] [-pw password]\n\t\t[-maxrenewlife maxrenewlife] "
1166 		"[-e keysaltlist] [{+|-}attribute]\n");
1167 	fprintf(stderr, gettext("\tattributes are:\n"));
1168      fprintf(stderr, "%s%s%s",
1169 		"\t\tallow_postdated allow_forwardable allow_tgs_req "
1170 		"allow_renewable\n",
1171 		"\t\tallow_proxiable allow_dup_skey allow_tix "
1172 		"requires_preauth\n",
1173 		"\t\trequires_hwauth needchange allow_svr "
1174 		"password_changing_service\n");
1175 }
1176 
1177 static void
1178 kadmin_modprinc_usage(func)
1179     char *func;
1180 {
1181 	fprintf(stderr, "%s: %s %s\n", gettext("usage"), func,
1182 		gettext("[options] principal"));
1183 	fprintf(stderr, gettext("\toptions are:\n"));
1184 	fprintf(stderr, "\t\t[-expire expdate] [-pwexpire pwexpdate] "
1185 		"[-maxlife maxtixlife]\n\t\t[-kvno kvno] [-policy policy] "
1186 		"[-clearpolicy]\n\t\t[-maxrenewlife maxrenewlife] "
1187 		"[{+|-}attribute]\n");
1188 	fprintf(stderr, gettext("\tattributes are:\n"));
1189      fprintf(stderr, "%s%s%s",
1190 		"\t\tallow_postdated allow_forwardable allow_tgs_req "
1191 		"allow_renewable\n",
1192 		"\t\tallow_proxiable allow_dup_skey allow_tix "
1193 		"requires_preauth\n",
1194 		"\t\trequires_hwauth needchange allow_svr "
1195 		"password_changing_service\n");
1196 }
1197 
1198 void kadmin_addprinc(argc, argv)
1199     int argc;
1200     char *argv[];
1201 {
1202     kadm5_principal_ent_rec princ, dprinc;
1203     kadm5_policy_ent_rec defpol;
1204     long mask;
1205     int randkey = 0, i;
1206     int n_ks_tuple;
1207     krb5_key_salt_tuple *ks_tuple;
1208     char *pass, *canon;
1209     krb5_error_code retval;
1210     static char newpw[1024], dummybuf[256];
1211     static char prompt1[1024], prompt2[1024];
1212     int local_kadmin = 0;
1213 
1214     local_kadmin = (strcmp(whoami, KADMIN_LOCAL_NAME) == 0);
1215 
1216     if (dummybuf[0] == 0) {
1217 	for (i = 0; i < 256; i++)
1218 	    dummybuf[i] = (i+1) % 256;
1219     }
1220 
1221     /* Zero all fields in request structure */
1222     memset(&princ, 0, sizeof(princ));
1223     memset(&dprinc, 0, sizeof(dprinc));
1224 
1225     princ.attributes = dprinc.attributes = 0;
1226     if (kadmin_parse_princ_args(argc, argv,
1227 				&princ, &mask, &pass, &randkey,
1228 				&ks_tuple, &n_ks_tuple,
1229 				"add_principal")) {
1230 	kadmin_addprinc_usage("add_principal");
1231 	kadmin_free_tl_data(&princ); /* need to free ks_tuple also??? */
1232 	return;
1233     }
1234 
1235     retval = krb5_unparse_name(context, princ.principal, &canon);
1236     if (retval) {
1237 	com_err("add_principal",
1238 		retval, gettext("while canonicalizing principal"));
1239 	krb5_free_principal(context, princ.principal);
1240 	if (ks_tuple != NULL)
1241 	    free(ks_tuple);
1242 	kadmin_free_tl_data(&princ);
1243 	return;
1244     }
1245 
1246     /*
1247      * If -policy was not specified, and -clearpolicy was not
1248      * specified, and the policy "default" exists, assign it.  If
1249      * -clearpolicy was specified, then KADM5_POLICY_CLR should be
1250      * unset, since it is never valid for kadm5_create_principal.
1251      */
1252     if ((! (mask & KADM5_POLICY)) &&
1253 	(! (mask & KADM5_POLICY_CLR))) {
1254 	if (! kadm5_get_policy(handle, "default", &defpol)) {
1255 	    fprintf(stderr,
1256 		    gettext("NOTICE: no policy specified for %s; assigning \"default\"\n"),
1257 		    canon);
1258 	    princ.policy = "default";
1259 	    mask |= KADM5_POLICY;
1260 	    (void) kadm5_free_policy_ent(handle, &defpol);
1261 	} else
1262 	    fprintf(stderr,
1263 		    gettext("WARNING: no policy specified for %s; defaulting to no policy\n"),
1264 		    canon);
1265     }
1266     mask &= ~KADM5_POLICY_CLR;
1267 
1268     /*
1269      * Set 'notix' for randkey principals and also for principals which have
1270      * specified flag options on the cmdline. This is because we want to apply
1271      * generic flag settings from 'default_principal_flags' first (during
1272      * principal creation), followed by a kadm5_modify_principal() which
1273      * correctly applies the cli flag options. So, we do *not* want any tix
1274      * issued in the interim.
1275      */
1276     if (randkey || (mask & KADM5_ATTRIBUTES))
1277 	princ.attributes |= KRB5_KDB_DISALLOW_ALL_TIX;
1278 
1279     if (randkey) {
1280 	mask |= KADM5_ATTRIBUTES;
1281 	pass = dummybuf;
1282     } else if (pass == NULL) {
1283 	unsigned int sz = sizeof (newpw) - 1;
1284 	snprintf(prompt1, sizeof (prompt1),
1285 		gettext("Enter password for principal \"%.900s\""),
1286 		canon);
1287 	snprintf(prompt2, sizeof (prompt1),
1288 		gettext("Re-enter password for principal \"%.900s\""),
1289 		canon);
1290 	retval = krb5_read_password(context, prompt1, prompt2,
1291 				    newpw, &sz);
1292 	if (retval) {
1293 	    com_err("add_principal", retval,
1294 		gettext("while reading password for \"%s\"."), canon);
1295 	    free(canon);
1296 	    krb5_free_principal(context, princ.principal);
1297 	    kadmin_free_tl_data(&princ);
1298 	    return;
1299 	}
1300 	pass = newpw;
1301     }
1302     mask |= KADM5_PRINCIPAL;
1303 
1304     /*
1305      * If the client being used is local, always use the new
1306      * API so we get the full set of enctype support.
1307      */
1308     if (ks_tuple != NULL || local_kadmin) {
1309 	retval = kadm5_create_principal_3(handle, &princ, mask,
1310 					  n_ks_tuple, ks_tuple, pass);
1311     } else {
1312 	retval = kadm5_create_principal(handle, &princ, mask, pass);
1313     }
1314     if (retval) {
1315 	com_err("add_principal", retval,
1316 		gettext("while creating \"%s\"."), canon);
1317 	krb5_free_principal(context, princ.principal);
1318 	free(canon);
1319 	if (ks_tuple != NULL)
1320 	    free(ks_tuple);
1321 	kadmin_free_tl_data(&princ);
1322 	return;
1323     }
1324     if (randkey) {		/* more special stuff for -randkey */
1325 	if (ks_tuple != NULL || local_kadmin) {
1326 	    retval = kadm5_randkey_principal_3(handle, princ.principal,
1327 					       FALSE,
1328 					       n_ks_tuple, ks_tuple,
1329 					       NULL, NULL);
1330 	} else {
1331 	    retval = kadm5_randkey_principal(handle, princ.principal,
1332 					     NULL, NULL);
1333 	}
1334 	if (retval) {
1335 	    com_err("add_principal", retval,
1336 		gettext("while randomizing key for \"%s\"."), canon);
1337 	    krb5_free_principal(context, princ.principal);
1338 	    free(canon);
1339 	    if (ks_tuple != NULL)
1340 		free(ks_tuple);
1341 	    kadmin_free_tl_data(&princ);
1342 	    return;
1343 	}
1344     }
1345 
1346     /*
1347      * We now retrieve the intersection set of the generic flag settings and
1348      * the ones specified on the cli & re-parse the princ args, just to make
1349      * sure we account for conflicts between 'default_principal_flags' and
1350      * the cmdline flag args. While we are here, also clear 'notix'.
1351      */
1352     if (randkey || (mask & KADM5_ATTRIBUTES)) {
1353 	retval = kadm5_get_principal(handle, princ.principal, &dprinc,
1354 			KADM5_PRINCIPAL_NORMAL_MASK);
1355         if (retval == 0) {
1356 	    if (dprinc.attributes != 0)
1357 		princ.attributes = dprinc.attributes;
1358 	} else {
1359 	    com_err("add_principal", retval,
1360 		gettext("while doing a get_principal on \"%s\"."), canon);
1361 	    printf(gettext("\nWarning: Principal \"%s\" could have incomplete "
1362 		"flag settings, as a result of a failed get_principal.\n"
1363 		"Check the 'default_principal_flags' setting in kdc.conf(4).\n"
1364 		"If there is a mismatch, use modprinc in kadmin(1M) to rectify "
1365 		"the same.\n\n"), canon);
1366 	}
1367 
1368 	/*
1369 	 * Solaris Kerberos: We unset KRB5_KDB_DISALLOW_ALL_TIX before
1370 	 * kadmin_parse_princ_args is called, because -allow_tix may
1371 	 * have been an argument.  We still have to unset here because
1372 	 * kadmin_parse_princ_args will not reset the attribute unless
1373 	 * it is was explicity defined.
1374 	 */
1375 	princ.attributes &= ~KRB5_KDB_DISALLOW_ALL_TIX;
1376 	(void) kadmin_parse_princ_args(argc, argv, &princ, &mask, &pass,
1377 			&randkey, &ks_tuple, &n_ks_tuple, "add_principal");
1378 	mask = KADM5_ATTRIBUTES;
1379 	retval = kadm5_modify_principal(handle, &princ, mask);
1380 	if (retval) {
1381 	    com_err("add_principal", retval,
1382 		gettext("while doing a modify_principal to restore flag "
1383 			"settings for \"%s\"."), canon);
1384 	    krb5_free_principal(context, princ.principal);
1385 	    free(canon);
1386 	    if (ks_tuple != NULL)
1387 		free(ks_tuple);
1388 	    kadmin_free_tl_data(&princ);
1389 	    return;
1390 	}
1391     }
1392     krb5_free_principal(context, princ.principal);
1393 	printf(gettext("Principal \"%s\" created.\n"), canon);
1394     if (ks_tuple != NULL)
1395 	free(ks_tuple);
1396     free(canon);
1397     kadmin_free_tl_data(&princ);
1398 
1399 }
1400 
1401 void kadmin_modprinc(argc, argv)
1402     int argc;
1403     char *argv[];
1404 {
1405     kadm5_principal_ent_rec princ, oldprinc;
1406     krb5_principal kprinc;
1407     long mask;
1408     krb5_error_code retval;
1409     char *pass, *canon;
1410     int randkey = 0;
1411     int n_ks_tuple = 0;
1412     krb5_key_salt_tuple *ks_tuple;
1413 
1414     if (argc < 2) {
1415 	kadmin_modprinc_usage("modify_principal");
1416 	return;
1417     }
1418 
1419     memset(&oldprinc, 0, sizeof(oldprinc));
1420     memset(&princ, 0, sizeof(princ));
1421 
1422     retval = kadmin_parse_name(argv[argc - 1], &kprinc);
1423     if (retval) {
1424 	com_err("modify_principal", retval,
1425 			gettext("while parsing principal"));
1426 	return;
1427     }
1428     retval = krb5_unparse_name(context, kprinc, &canon);
1429     if (retval) {
1430 	com_err("modify_principal", retval,
1431 			gettext("while canonicalizing principal"));
1432 	krb5_free_principal(context, kprinc);
1433 	return;
1434     }
1435     retval = kadm5_get_principal(handle, kprinc, &oldprinc,
1436 				 KADM5_PRINCIPAL_NORMAL_MASK);
1437     krb5_free_principal(context, kprinc);
1438     if (retval) {
1439 	com_err("modify_principal", retval,
1440 			gettext("while getting \"%s\"."), canon);
1441 	free(canon);
1442 	return;
1443     }
1444     princ.attributes = oldprinc.attributes;
1445     kadm5_free_principal_ent(handle, &oldprinc);
1446     retval = kadmin_parse_princ_args(argc, argv,
1447 				     &princ, &mask,
1448 				     &pass, &randkey,
1449 				     &ks_tuple, &n_ks_tuple,
1450 				     "modify_principal");
1451     if (ks_tuple != NULL) {
1452 	free(ks_tuple);
1453 	kadmin_modprinc_usage("modify_principal");
1454 	free(canon);
1455 	kadmin_free_tl_data(&princ);
1456 	return;
1457     }
1458     if (retval) {
1459 	kadmin_modprinc_usage("modify_principal");
1460 	free(canon);
1461 	kadmin_free_tl_data(&princ);
1462 	return;
1463     }
1464     if (randkey) {
1465 		fprintf(stderr, "modify_principal: -randkey %s ",
1466 			gettext("not allowed\n"));
1467 	krb5_free_principal(context, princ.principal);
1468 	free(canon);
1469 	kadmin_free_tl_data(&princ);
1470 	return;
1471     }
1472     if (pass) {
1473 	fprintf(stderr,
1474 		"modify_principal: -pw %s change_password\n",
1475 		gettext("not allowed; use"));
1476 	krb5_free_principal(context, princ.principal);
1477 	free(canon);
1478 	kadmin_free_tl_data(&princ);
1479 	return;
1480     }
1481     retval = kadm5_modify_principal(handle, &princ, mask);
1482     krb5_free_principal(context, princ.principal);
1483     if (retval) {
1484 	com_err("modify_principal", retval,
1485 			gettext("while modifying \"%s\"."), canon);
1486 	free(canon);
1487 	kadmin_free_tl_data(&princ);
1488 	return;
1489     }
1490 	printf(gettext("Principal \"%s\" modified.\n"), canon);
1491     kadmin_free_tl_data(&princ);
1492     free(canon);
1493 }
1494 
1495 void kadmin_getprinc(argc, argv)
1496     int argc;
1497     char *argv[];
1498 {
1499     kadm5_principal_ent_rec dprinc;
1500     krb5_principal princ;
1501     krb5_error_code retval;
1502     char *canon, *modcanon;
1503     int i;
1504 
1505     if (! (argc == 2 ||
1506 	   (argc == 3 && !strcmp("-terse", argv[1])))) {
1507 		fprintf(stderr, "%s: get_principal [-terse] %s\n",
1508 			gettext("usage"), gettext("principal"));
1509 	return;
1510     }
1511 
1512 
1513     memset(&dprinc, 0, sizeof(dprinc));
1514     memset(&princ, 0, sizeof(princ));
1515 
1516     retval = kadmin_parse_name(argv[argc - 1], &princ);
1517     if (retval) {
1518 	com_err("get_principal", retval,
1519 			gettext("while parsing principal"));
1520 	return;
1521     }
1522     retval = krb5_unparse_name(context, princ, &canon);
1523     if (retval) {
1524 	com_err("get_principal", retval,
1525 			gettext("while canonicalizing principal"));
1526 	krb5_free_principal(context, princ);
1527 	return;
1528     }
1529     retval = kadm5_get_principal(handle, princ, &dprinc,
1530 				 KADM5_PRINCIPAL_NORMAL_MASK | KADM5_KEY_DATA);
1531     krb5_free_principal(context, princ);
1532     if (retval) {
1533 	com_err("get_principal", retval,
1534 			gettext("while retrieving \"%s\"."), canon);
1535 	free(canon);
1536 	return;
1537     }
1538     retval = krb5_unparse_name(context, dprinc.mod_name, &modcanon);
1539     if (retval) {
1540 	com_err("get_principal", retval,
1541 			gettext("while unparsing modname"));
1542 	kadm5_free_principal_ent(handle, &dprinc);
1543 	free(canon);
1544 	return;
1545     }
1546     if (argc == 2) {
1547 		printf(gettext("Principal: %s\n"), canon);
1548 		printf(gettext("Expiration date: %s\n"),
1549 		    dprinc.princ_expire_time ?
1550 		    strdate(dprinc.princ_expire_time) :
1551 		    gettext("[never]"));
1552 		printf(gettext("Last password change: %s\n"),
1553 		    dprinc.last_pwd_change ?
1554 		    strdate(dprinc.last_pwd_change) :
1555 		    gettext("[never]"));
1556 		printf(gettext("Password expiration date: %s\n"),
1557 	       dprinc.pw_expiration ?
1558 		    strdate(dprinc.pw_expiration) : gettext("[none]"));
1559 		printf(gettext("Maximum ticket life: %s\n"),
1560 		    strdur(dprinc.max_life));
1561 		printf(gettext("Maximum renewable life: %s\n"),
1562 		    strdur(dprinc.max_renewable_life));
1563 		printf(gettext("Last modified: %s (%s)\n"),
1564 		    strdate(dprinc.mod_date), modcanon);
1565 		printf(gettext("Last successful authentication: %s\n"),
1566 	       dprinc.last_success ? strdate(dprinc.last_success) :
1567 		    gettext("[never]"));
1568 		printf(gettext("Last failed authentication: %s\n"),
1569 	       dprinc.last_failed ? strdate(dprinc.last_failed) :
1570 		    gettext("[never]"));
1571 		printf(gettext("Failed password attempts: %d\n"),
1572 	       dprinc.fail_auth_count);
1573 		printf(gettext("Number of keys: %d\n"), dprinc.n_key_data);
1574 	for (i = 0; i < dprinc.n_key_data; i++) {
1575 	    krb5_key_data *key_data = &dprinc.key_data[i];
1576 	    char enctype[BUFSIZ], salttype[BUFSIZ];
1577 
1578 	    if (krb5_enctype_to_string(key_data->key_data_type[0],
1579 				       enctype, sizeof(enctype)))
1580 		snprintf(enctype, sizeof (enctype), gettext("<Encryption type 0x%x>"),
1581 			key_data->key_data_type[0]);
1582 	    printf("Key: vno %d, %s, ", key_data->key_data_kvno, enctype);
1583 	    if (key_data->key_data_ver > 1) {
1584 		if (krb5_salttype_to_string(key_data->key_data_type[1],
1585 					    salttype, sizeof(salttype)))
1586 		    snprintf(salttype, sizeof(salttype), gettext("<Salt type 0x%x>"),
1587 			    key_data->key_data_type[1]);
1588 		printf("%s\n", salttype);
1589 	    } else
1590 		printf(gettext("no salt\n"));
1591 	}
1592 
1593 	printf(gettext("Attributes:"));
1594 	for (i = 0; i < sizeof (prflags) / sizeof (char *); i++) {
1595 	    if (dprinc.attributes & (krb5_flags) 1 << i)
1596 		printf(" %s", prflags[i]);
1597 	}
1598 	printf("\n");
1599 		printf(gettext("Policy: %s\n"),
1600 		    dprinc.policy ? dprinc.policy : gettext("[none]"));
1601     } else {
1602 	printf("\"%s\"\t%d\t%d\t%d\t%d\t\"%s\"\t%d\t%d\t%d\t%d\t\"%s\""
1603 	       "\t%d\t%d\t%d\t%d\t%d",
1604 	       canon, dprinc.princ_expire_time, dprinc.last_pwd_change,
1605 	       dprinc.pw_expiration, dprinc.max_life, modcanon,
1606 	       dprinc.mod_date, dprinc.attributes, dprinc.kvno,
1607 	       dprinc.mkvno, dprinc.policy ? dprinc.policy : gettext("[none]"),
1608 	       dprinc.max_renewable_life, dprinc.last_success,
1609 	       dprinc.last_failed, dprinc.fail_auth_count,
1610 	       dprinc.n_key_data);
1611 	for (i = 0; i < dprinc.n_key_data; i++)
1612 	    printf("\t%d\t%d\t%d\t%d",
1613 		   dprinc.key_data[i].key_data_ver,
1614 		   dprinc.key_data[i].key_data_kvno,
1615 		   dprinc.key_data[i].key_data_type[0],
1616 		   dprinc.key_data[i].key_data_type[1]);
1617 	printf("\n");
1618     }
1619     free(modcanon);
1620     kadm5_free_principal_ent(handle, &dprinc);
1621     free(canon);
1622 }
1623 
1624 void kadmin_getprincs(argc, argv)
1625     int argc;
1626     char *argv[];
1627 {
1628     krb5_error_code retval;
1629     char *expr, **names;
1630     int i, count;
1631 
1632 	FILE *output;
1633 	int fd;
1634 	struct sigaction nsig, osig;
1635 	sigset_t nmask, omask;
1636 	int waitb;
1637 
1638     expr = NULL;
1639     if (! (argc == 1 || (argc == 2 && (expr = argv[1])))) {
1640 		fprintf(stderr, "%s: get_principals %s\n",
1641 			gettext("usage"), gettext("[expression]"));
1642 	return;
1643     }
1644     retval = kadm5_get_principals(handle, expr, &names, &count);
1645     if (retval) {
1646 	com_err("get_principals", retval,
1647 			gettext("while retrieving list."));
1648 	return;
1649     }
1650 
1651 	/*
1652 	 * Solaris:  the following code is used for paging
1653 	 */
1654 
1655 	sigemptyset(&nmask);
1656 	sigaddset(&nmask, SIGINT);
1657 	sigprocmask(SIG_BLOCK, &nmask, &omask);
1658 
1659 	nsig.sa_handler = SIG_IGN;
1660 	sigemptyset(&nsig.sa_mask);
1661 	nsig.sa_flags = 0;
1662 	sigaction(SIGINT, &nsig, &osig);
1663 
1664 	fd = ss_pager_create();
1665 	output = fdopen(fd, "w");
1666 
1667 	sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0);
1668 
1669     for (i = 0; i < count; i++)
1670 	 fprintf(output, "%s\n", names[i]);
1671 
1672 	fclose(output);
1673 
1674 	wait(&waitb);
1675 
1676 	/* Solaris Kerberos:
1677 	 * Restore the original handler for SIGINT
1678 	 */
1679 	if (sigaction(SIGINT, &osig, (struct sigaction *)0) == -1) {
1680 		perror("sigaction");
1681 	}
1682 
1683     kadm5_free_name_list(handle, names, count);
1684 }
1685 
1686 static int
1687 kadmin_parse_policy_args(argc, argv, policy, mask, caller)
1688     int argc;
1689     char *argv[];
1690     kadm5_policy_ent_t policy;
1691     long *mask;
1692     char *caller;
1693 {
1694     int i;
1695     time_t now;
1696     time_t date;
1697 
1698     time(&now);
1699     *mask = 0;
1700     for (i = 1; i < argc - 1; i++) {
1701 	if (strlen(argv[i]) == 8 &&
1702 	    !strcmp(argv[i], "-maxlife")) {
1703 	    if (++i > argc -2)
1704 		return -1;
1705 	    else {
1706 		date = get_date(argv[i]);
1707 		if (date == (time_t)-1) {
1708 		    fprintf(stderr, gettext("Invalid date specification \"%s\".\n"),
1709 			    argv[i]);
1710 		    return -1;
1711 		}
1712 		policy->pw_max_life = date - now;
1713 		*mask |= KADM5_PW_MAX_LIFE;
1714 		continue;
1715 	    }
1716 	} else if (strlen(argv[i]) == 8 &&
1717 		   !strcmp(argv[i], "-minlife")) {
1718 	    if (++i > argc - 2)
1719 		return -1;
1720 	    else {
1721 		date = get_date(argv[i]);
1722 		if (date == (time_t)-1) {
1723 		    fprintf(stderr, gettext("Invalid date specification \"%s\".\n"),
1724 			    argv[i]);
1725 		    return -1;
1726 		}
1727 		policy->pw_min_life = date - now;
1728 		*mask |= KADM5_PW_MIN_LIFE;
1729 		continue;
1730 	    }
1731 	} else if (strlen(argv[i]) == 10 &&
1732 		   !strcmp(argv[i], "-minlength")) {
1733 	    if (++i > argc - 2)
1734 		return -1;
1735 	    else {
1736 		policy->pw_min_length = atoi(argv[i]);
1737 		*mask |= KADM5_PW_MIN_LENGTH;
1738 		continue;
1739 	    }
1740 	} else if (strlen(argv[i]) == 11 &&
1741 		   !strcmp(argv[i], "-minclasses")) {
1742 	    if (++i > argc - 2)
1743 		return -1;
1744 	    else {
1745 		policy->pw_min_classes = atoi(argv[i]);
1746 		*mask |= KADM5_PW_MIN_CLASSES;
1747 		continue;
1748 	    }
1749 	} else if (strlen(argv[i]) == 8 &&
1750 		   !strcmp(argv[i], "-history")) {
1751 	    if (++i > argc - 2)
1752 		return -1;
1753 	    else {
1754 		policy->pw_history_num = atoi(argv[i]);
1755 		*mask |= KADM5_PW_HISTORY_NUM;
1756 		continue;
1757 	    }
1758 	} else
1759 	    return -1;
1760     }
1761     if (i != argc -1) {
1762 	fprintf(stderr, gettext("%s: parser lost count!\n"), caller);
1763 	return -1;
1764     } else
1765 	return 0;
1766 }
1767 
1768 static void
1769 kadmin_addmodpol_usage(func)
1770     char *func;
1771 {
1772 	fprintf(stderr, "%s: %s %s\n", gettext("usage"), func,
1773 		gettext("[options] policy"));
1774 	fprintf(stderr, gettext("\toptions are:\n"));
1775 	fprintf(stderr, "\t\t[-maxlife time] [-minlife time] "
1776 		"[-minlength length]\n\t\t[-minclasses number] "
1777 		"[-history number]\n");
1778 }
1779 
1780 void kadmin_addpol(argc, argv)
1781     int argc;
1782     char *argv[];
1783 {
1784     krb5_error_code retval;
1785     long mask;
1786     kadm5_policy_ent_rec policy;
1787 
1788     memset(&policy, 0, sizeof(policy));
1789     if (kadmin_parse_policy_args(argc, argv, &policy, &mask, "add_policy")) {
1790 	kadmin_addmodpol_usage("add_policy");
1791 	return;
1792     } else {
1793 	policy.policy = argv[argc - 1];
1794 	mask |= KADM5_POLICY;
1795 	retval = kadm5_create_policy(handle, &policy, mask);
1796 	if (retval) {
1797 			com_err("add_policy", retval,
1798 				gettext("while creating policy \"%s\"."),
1799 		    policy.policy);
1800 	    return;
1801 	}
1802     }
1803     return;
1804 }
1805 
1806 void kadmin_modpol(argc, argv)
1807     int argc;
1808     char *argv[];
1809 {
1810     krb5_error_code retval;
1811     long mask;
1812     kadm5_policy_ent_rec policy;
1813 
1814     memset(&policy, 0, sizeof(policy));
1815     if (kadmin_parse_policy_args(argc, argv, &policy, &mask,
1816 				 "modify_policy")) {
1817 	kadmin_addmodpol_usage("modify_policy");
1818 	return;
1819     } else {
1820 	policy.policy = argv[argc - 1];
1821 	retval = kadm5_modify_policy(handle, &policy, mask);
1822 	if (retval) {
1823 	    com_err("modify_policy", retval, gettext("while modifying policy \"%s\"."),
1824 		    policy.policy);
1825 	    return;
1826 	}
1827     }
1828     return;
1829 }
1830 
1831 void kadmin_delpol(argc, argv)
1832     int argc;
1833     char *argv[];
1834 {
1835     krb5_error_code retval;
1836     char reply[32];
1837 
1838     if (! (argc == 2 ||
1839 	   (argc == 3 && !strcmp("-force", argv[1])))) {
1840 	fprintf(stderr, "%s: delete_policy [-force] %s\n",
1841 			gettext("usage"), gettext("policy"));
1842 	return;
1843     }
1844     if (argc == 2) {
1845 		printf(gettext("Are you sure you want to delete the policy "
1846 			    "\"%s\"? (yes/no): "), argv[1]);
1847 	fgets(reply, sizeof (reply), stdin);
1848 		if (strncmp(gettext("yes\n"), reply, sizeof (reply)) &&
1849 			strncmp(gettext("y\n"), reply, sizeof (reply)) &&
1850 			strncmp(gettext("Y\n"), reply, sizeof (reply))
1851 			) {
1852 			fprintf(stderr,
1853 				gettext("Policy \"%s\" not deleted.\n"),
1854 				argv[1]);
1855 	    return;
1856 	}
1857     }
1858     retval = kadm5_delete_policy(handle, argv[argc - 1]);
1859     if (retval) {
1860 		com_err("delete_policy:", retval,
1861 			gettext("while deleting policy \"%s\""),
1862 		argv[argc - 1]);
1863 	return;
1864     }
1865     return;
1866 }
1867 
1868 void kadmin_getpol(argc, argv)
1869     int argc;
1870     char *argv[];
1871 {
1872     krb5_error_code retval;
1873     kadm5_policy_ent_rec policy;
1874 
1875     if (! (argc == 2 ||
1876 	   (argc == 3 && !strcmp("-terse", argv[1])))) {
1877 		fprintf(stderr, "%s: get_policy [-terse] %s\n",
1878 			gettext("usage"), gettext("policy"));
1879 	return;
1880     }
1881     retval = kadm5_get_policy(handle, argv[argc - 1], &policy);
1882     if (retval) {
1883 		com_err("get_policy", retval,
1884 			gettext("while retrieving policy \"%s\"."),
1885 		argv[argc - 1]);
1886 	return;
1887     }
1888     if (argc == 2) {
1889 		printf(gettext("Policy: %s\n"), policy.policy);
1890 		printf(gettext("Maximum password life: %ld\n"),
1891 		    policy.pw_max_life);
1892 		printf(gettext("Minimum password life: %ld\n"),
1893 		    policy.pw_min_life);
1894 		printf(gettext("Minimum password length: %ld\n"),
1895 		    policy.pw_min_length);
1896 		printf(gettext("Minimum number of password "
1897 			    "character classes: %ld\n"),
1898 	       policy.pw_min_classes);
1899 		printf(gettext("Number of old keys kept: %ld\n"),
1900 		    policy.pw_history_num);
1901 		printf(gettext("Reference count: %ld\n"), policy.policy_refcnt);
1902     } else {
1903 	printf("\"%s\"\t%ld\t%ld\t%ld\t%ld\t%ld\t%ld\n",
1904 	       policy.policy, policy.pw_max_life, policy.pw_min_life,
1905 	       policy.pw_min_length, policy.pw_min_classes,
1906 	       policy.pw_history_num, policy.policy_refcnt);
1907     }
1908     kadm5_free_policy_ent(handle, &policy);
1909     return;
1910 }
1911 
1912 void kadmin_getpols(argc, argv)
1913     int argc;
1914     char *argv[];
1915 {
1916     krb5_error_code retval;
1917     char *expr, **names;
1918     int i, count;
1919 
1920     /* Solaris Kerberos:
1921      * Use a pager for listing policies (similar to listing princs)
1922      */
1923     FILE *output = NULL;
1924     int fd;
1925     struct sigaction nsig, osig;
1926     sigset_t nmask, omask;
1927     int waitb;
1928 
1929     expr = NULL;
1930     if (! (argc == 1 || (argc == 2 && (expr = argv[1])))) {
1931 	fprintf(stderr, "%s: get_policies %s\n",
1932 			gettext("usage"), gettext("[expression]\n"));
1933 	return;
1934     }
1935     retval = kadm5_get_policies(handle, expr, &names, &count);
1936     if (retval) {
1937 	com_err("get_policies", retval,
1938 			gettext("while retrieving list."));
1939 	return;
1940     }
1941 
1942     if (sigemptyset(&nmask) == -1) {
1943         perror("sigemptyset");
1944         kadm5_free_name_list(handle, names, count);
1945         return;
1946     }
1947 
1948     if (sigaddset(&nmask, SIGINT) == -1) {
1949         perror("sigaddset");
1950         kadm5_free_name_list(handle, names, count);
1951         return;
1952     }
1953 
1954     if (sigemptyset(&nsig.sa_mask) == -1) {
1955         perror("sigemptyset");
1956         kadm5_free_name_list(handle, names, count);
1957         return;
1958     }
1959 
1960     if (sigprocmask(SIG_BLOCK, &nmask, &omask) == -1) {
1961         perror("sigprocmask");
1962         kadm5_free_name_list(handle, names, count);
1963         return;
1964     }
1965 
1966     nsig.sa_handler = SIG_IGN;
1967     nsig.sa_flags = 0;
1968     if (sigaction(SIGINT, &nsig, &osig) == -1) {
1969         perror("sigaction");
1970         if (sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0) == -1) {
1971             perror("sigprocmask");
1972         }
1973         kadm5_free_name_list(handle, names, count);
1974         return;
1975     }
1976 
1977     fd = ss_pager_create();
1978     if (fd == -1) {
1979         fprintf(stderr, "%s: failed to create pager\n", whoami);
1980         if (sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0) == -1) {
1981             perror("sigprocmask");
1982         }
1983 
1984         if (sigaction(SIGINT, &osig, (struct sigaction *)0) == -1) {
1985             perror("sigaction");
1986         }
1987 
1988         kadm5_free_name_list(handle, names, count);
1989         return;
1990     }
1991 
1992     output = fdopen(fd, "w");
1993     if (output == NULL) {
1994         perror("fdopen");
1995     }
1996 
1997     if (sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0) == -1) {
1998         perror("sigprocmask");
1999     }
2000 
2001     if (output != NULL) {
2002         for (i = 0; i < count; i++)
2003         fprintf(output, "%s\n", names[i]);
2004     }
2005 
2006     if (output != NULL && fclose(output) != 0) {
2007         perror("fclose");
2008     }
2009 
2010     if (wait(&waitb) == -1) {
2011         perror("wait");
2012     }
2013 
2014     if (sigaction(SIGINT, &osig, (struct sigaction *)0) == -1) {
2015         perror("sigaction");
2016     }
2017     kadm5_free_name_list(handle, names, count);
2018 }
2019