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;
strdur(duration)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
strdate(when)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
kadmin_parse_name(name,principal)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
extended_com_err_fn(const char * myprog,errcode_t code,const char * fmt,va_list args)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 }
kadmin_startup(argc,argv)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 *) ¶ms, 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 ¶ms.keysalts,
305 ¶ms.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 ¶ms,
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 ¶ms,
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 ¶ms,
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
quit()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
kadmin_lock(argc,argv)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
kadmin_unlock(argc,argv)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
kadmin_delprinc(argc,argv)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
kadmin_cpw(argc,argv)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
kadmin_free_tl_data(kadm5_principal_ent_t princ)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
kadmin_parse_princ_args(argc,argv,oprinc,mask,pass,randkey,ks_tuple,n_ks_tuple,caller)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
kadmin_addprinc_usage(func)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
kadmin_modprinc_usage(func)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
kadmin_addprinc(argc,argv)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(5).\n"
1364 "If there is a mismatch, use modprinc in kadmin(8) 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
kadmin_modprinc(argc,argv)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
kadmin_getprinc(argc,argv)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
kadmin_getprincs(argc,argv)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
kadmin_parse_policy_args(argc,argv,policy,mask,caller)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
kadmin_addmodpol_usage(func)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
kadmin_addpol(argc,argv)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
kadmin_modpol(argc,argv)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
kadmin_delpol(argc,argv)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
kadmin_getpol(argc,argv)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
kadmin_getpols(argc,argv)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