Initial import from FreeBSD RELENG_4:
[games.git] / crypto / kerberosIV / kadmin / kadmin.c
1 /* 
2   Copyright (C) 1989 by the Massachusetts Institute of Technology
3
4    Export of this software from the United States of America is assumed
5    to require a specific license from the United States Government.
6    It is the responsibility of any person or organization contemplating
7    export to obtain such a license before exporting.
8
9 WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
10 distribute this software and its documentation for any purpose and
11 without fee is hereby granted, provided that the above copyright
12 notice appear in all copies and that both that copyright notice and
13 this permission notice appear in supporting documentation, and that
14 the name of M.I.T. not be used in advertising or publicity pertaining
15 to distribution of the software without specific, written prior
16 permission.  M.I.T. makes no representations about the suitability of
17 this software for any purpose.  It is provided "as is" without express
18 or implied warranty.
19
20   */
21 /* $FreeBSD: src/crypto/kerberosIV/kadmin/kadmin.c,v 1.1.1.3.2.1 2003/02/14 22:37:37 nectar Exp $ */
22
23 /*
24  * Kerberos database administrator's tool.  
25  * 
26  * The default behavior of kadmin is if the -m option is given 
27  * on the commandline, multiple requests are allowed to be given
28  * with one entry of the admin password (until the tickets expire).
29  */
30
31 #include "kadm_locl.h"
32 #include "getarg.h"
33 #include "parse_time.h"
34
35 RCSID("$Id: kadmin.c,v 1.62 1999/11/02 17:02:14 bg Exp $");
36
37 static int change_password(int argc, char **argv);
38 static int change_key(int argc, char **argv);
39 static int change_admin_password(int argc, char **argv);
40 static int add_new_key(int argc, char **argv);
41 static int del_entry(int argc, char **argv);
42 static int get_entry(int argc, char **argv);
43 static int mod_entry(int argc, char **argv);
44 static int help(int argc, char **argv);
45 static int clean_up_cmd(int argc, char **argv);
46 static int quit_cmd(int argc, char **argv);
47 static int set_timeout_cmd(int argc, char **argv);
48
49 static int set_timeout(const char *);
50
51 static SL_cmd cmds[] = {
52   {"change_password", change_password, "Change a user's password"},
53   {"cpw"},
54   {"passwd"},
55   {"change_key", change_key, "Change a user's password as a DES binary key"},
56   {"ckey"},
57   {"change_admin_password", change_admin_password,
58    "Change your admin password"},
59   {"cap"},
60   {"add_new_key", add_new_key, "Add new user to kerberos database"},
61   {"ank"},
62   {"del_entry", del_entry, "Delete entry from database"},
63   {"del"},
64   {"delete"},
65   {"get_entry", get_entry, "Get entry from kerberos database"},
66   {"mod_entry", mod_entry, "Modify entry in kerberos database"},
67   {"destroy_tickets", clean_up_cmd, "Destroy admin tickets"},
68   {"set_timeout", set_timeout_cmd, "Set ticket timeout"},
69   {"timeout" },
70   {"exit", quit_cmd, "Exit program"},
71   {"quit"},
72   {"help", help, "Help"},
73   {"?"},
74   {NULL}
75 };
76
77 #define BAD_PW 1
78 #define GOOD_PW 0
79 #define FUDGE_VALUE 15          /* for ticket expiration time */
80 #define PE_NO 0
81 #define PE_YES 1
82 #define PE_UNSURE 2
83
84 /* for get_password, whether it should do the swapping...necessary for
85    using vals structure, unnecessary for change_pw requests */
86 #define DONTSWAP 0
87 #define SWAP 1
88
89 static krb_principal pr;
90 static char default_realm[REALM_SZ]; /* default kerberos realm */
91 static char krbrlm[REALM_SZ];   /* current realm being administered */
92
93 #ifdef NOENCRYPTION
94 #define read_long_pw_string placebo_read_pw_string
95 #else
96 #define read_long_pw_string des_read_pw_string
97 #endif
98
99 static void
100 get_maxlife(Kadm_vals *vals)
101 {
102     char buff[BUFSIZ];
103     time_t life;
104     int l;
105
106     do {
107         printf("Maximum ticket lifetime?  (%d)  [%s]  ",
108              vals->max_life, krb_life_to_atime(vals->max_life));
109         fflush(stdout);
110         if (fgets(buff, sizeof(buff), stdin) == NULL || *buff == '\n') {
111             clearerr(stdin);
112             return;
113         }
114         life = krb_atime_to_life(buff);
115     } while (life <= 0);
116
117     l = strlen(buff);
118     if (buff[l-2] == 'm')
119         life = krb_time_to_life(0L, life*60);
120     if (buff[l-2] == 'h')
121         life = krb_time_to_life(0L, life*60*60);
122
123     vals->max_life = life;
124     SET_FIELD(KADM_MAXLIFE,vals->fields);
125 }
126
127 static void
128 get_attr(Kadm_vals *vals)
129 {
130     char buff[BUFSIZ], *out;
131     int attr;
132
133     do {
134         printf("Attributes?  [0x%.2x]  ", vals->attributes);
135         fflush(stdout);
136         if (fgets(buff, sizeof(buff), stdin) == NULL || *buff == '\n') {
137             clearerr(stdin);
138             return;
139         }
140         attr = strtol(buff, &out, 0);
141         if (attr == 0 && out == buff)
142           attr = -1;
143     } while (attr < 0 || attr > 0xffff);
144
145     vals->attributes = attr;
146     SET_FIELD(KADM_ATTR,vals->fields);
147 }
148
149 static time_t
150 parse_expdate(const char *str)
151 {
152     struct tm edate;
153
154     memset(&edate, 0, sizeof(edate));
155     if (sscanf(str, "%d-%d-%d",
156                &edate.tm_year, &edate.tm_mon, &edate.tm_mday) == 3) {
157         edate.tm_mon--;     /* January is 0, not 1 */
158         edate.tm_hour = 23; /* nearly midnight at the end of the */
159         edate.tm_min = 59;  /* specified day */
160     }
161     if(krb_check_tm (edate))
162         return -1;
163     edate.tm_year -= 1900;
164     return tm2time (edate, 1);
165 }
166
167 static void
168 get_expdate(Kadm_vals *vals)
169 {
170     char buff[BUFSIZ];
171     time_t t;
172
173     do {
174         strftime(buff, sizeof(buff), "%Y-%m-%d", k_localtime(&vals->exp_date));
175         printf("Expiration date (enter yyyy-mm-dd) ?  [%s]  ", buff);
176         fflush(stdout);
177         if (fgets(buff, sizeof(buff), stdin) == NULL || *buff == '\n') {
178             clearerr(stdin);
179             return;
180         }
181         t = parse_expdate(buff);
182     }while(t < 0);
183     vals->exp_date = t;
184     SET_FIELD(KADM_EXPDATE,vals->fields);
185 }
186
187 static int
188 princ_exists(char *name, char *instance, char *realm)
189 {
190     int status;
191
192     int old = krb_use_admin_server(1);
193     status = krb_get_pw_in_tkt(name, instance, realm,
194                                KRB_TICKET_GRANTING_TICKET,
195                                realm, 1, "");
196     krb_use_admin_server(old);
197
198     if ((status == KSUCCESS) || (status == INTK_BADPW))
199         return(PE_YES);
200     else if (status == KDC_PR_UNKNOWN)
201         return(PE_NO);
202     else
203         return(PE_UNSURE);
204 }
205
206 static void
207 passwd_to_lowhigh(u_int32_t *low, u_int32_t *high, char *password, int byteswap)
208 {
209     des_cblock newkey;
210
211     if (strlen(password) == 0) {
212         printf("Using random password.\n");
213 #ifdef NOENCRYPTION
214         memset(newkey, 0, sizeof(newkey));
215 #else
216         des_random_key(newkey);
217 #endif
218     } else {
219 #ifdef NOENCRYPTION
220       memset(newkey, 0, sizeof(newkey));
221 #else
222       des_string_to_key(password, &newkey);
223 #endif
224     }
225
226     memcpy(low, newkey, 4);
227     memcpy(high, ((char *)newkey) + 4, 4);
228
229     memset(newkey, 0, sizeof(newkey));
230
231 #ifdef NOENCRYPTION
232     *low = 1;
233 #endif
234
235     if (byteswap != DONTSWAP) {
236         *low = htonl(*low);
237         *high = htonl(*high);
238     }
239 }
240
241 static int
242 get_password(u_int32_t *low, u_int32_t *high, char *prompt, int byteswap)
243 {
244     char new_passwd[MAX_KPW_LEN];       /* new password */
245
246     if (read_long_pw_string(new_passwd, sizeof(new_passwd)-1, prompt, 1))
247         return(BAD_PW);
248     passwd_to_lowhigh (low, high, new_passwd, byteswap);
249     memset (new_passwd, 0, sizeof(new_passwd));
250     return(GOOD_PW);
251 }
252
253 static int
254 get_admin_password(void)
255 {
256     int status;
257     char admin_passwd[MAX_KPW_LEN];     /* Admin's password */
258     int ticket_life = 1;        /* minimum ticket lifetime */
259     CREDENTIALS c;
260
261     alarm(0);
262     /* If admin tickets exist and are valid, just exit. */
263     memset(&c, 0, sizeof(c));
264     if (krb_get_cred(PWSERV_NAME, KADM_SINST, krbrlm, &c) == KSUCCESS)
265         /* 
266          * If time is less than lifetime - FUDGE_VALUE after issue date,
267          * tickets will probably last long enough for the next 
268          * transaction.
269          */
270         if (time(0) < (c.issue_date + (5 * 60 * c.lifetime) - FUDGE_VALUE))
271             return(KADM_SUCCESS);
272     ticket_life = DEFAULT_TKT_LIFE;
273     
274     if (princ_exists(pr.name, pr.instance, pr.realm) != PE_NO) {
275         char prompt[256];
276         snprintf(prompt, sizeof(prompt), "%s's Password: ", 
277                  krb_unparse_name(&pr));
278         if (read_long_pw_string(admin_passwd,
279                                 sizeof(admin_passwd)-1,
280                                 prompt, 0)) {
281             warnx ("Error reading admin password.");
282             goto bad;
283         }
284         status = krb_get_pw_in_tkt(pr.name, pr.instance, pr.realm,
285                                    PWSERV_NAME, KADM_SINST,
286                                    ticket_life, admin_passwd);
287         memset(admin_passwd, 0, sizeof(admin_passwd));
288         
289         /* Initialize non shared random sequence from session key. */
290         memset(&c, 0, sizeof(c));
291         krb_get_cred(PWSERV_NAME, KADM_SINST, krbrlm, &c);
292     }
293     else
294         status = KDC_PR_UNKNOWN;
295
296     switch(status) {
297     case GT_PW_OK:
298         return(GOOD_PW);
299     case KDC_PR_UNKNOWN:
300         printf("Principal %s does not exist.\n", krb_unparse_name(&pr));
301         goto bad;
302     case GT_PW_BADPW:
303         printf("Incorrect admin password.\n");
304         goto bad;
305     default:
306         com_err("kadmin", status+krb_err_base,
307                 "while getting password tickets");
308         goto bad;
309     }
310     
311  bad:
312     memset(admin_passwd, 0, sizeof(admin_passwd));
313     dest_tkt();
314     return(BAD_PW);
315 }
316
317 static char *principal;
318 static char *username;
319 static char *realm;
320 static char *timeout;
321 static int tflag; /* use existing tickets */
322 static int mflag; /* compatibility */
323 static int version_flag;
324 static int help_flag;
325
326 static time_t destroy_timeout = 5 * 60;
327
328 struct getargs args[] = {
329     { NULL,     'p',    arg_string, &principal, 
330       "principal to authenticate as"},
331     { NULL,     'u',    arg_string, &username, 
332       "username, other than default" },
333     { NULL,     'r',    arg_string, &realm, "local realm" },
334     { NULL,     'm',    arg_flag, &mflag, "disable ticket timeout" },
335     { NULL,     'T',    arg_string, &timeout, "default ticket timeout" },
336     { NULL,     't',    arg_flag, &tflag, "use existing tickets" },
337     { "version",0,      arg_flag, &version_flag },
338     { "help",   'h',    arg_flag, &help_flag },
339 };
340
341 static int num_args = sizeof(args) / sizeof(args[0]);
342
343 static int
344 clean_up()
345 {
346     if(!tflag)
347         return dest_tkt() == KSUCCESS;
348     return 0; 
349 }
350
351 static int
352 clean_up_cmd (int argc, char **argv)
353 {
354     clean_up();
355     return 0;
356 }
357
358 static int
359 quit_cmd (int argc, char **argv)
360 {
361     return 1;
362 }
363
364 static void 
365 usage(int code)
366 {
367     arg_printusage(args, num_args, NULL, "[command]");
368     exit(code);
369 }
370
371 static int
372 do_init(int argc, char **argv)
373 {
374     int optind = 0;
375     int ret;
376
377     set_progname (argv[0]);
378     
379     if(getarg(args, num_args, argc, argv, &optind) < 0)
380         usage(1);
381     if(help_flag)
382         usage(0);
383     if(version_flag) {
384         print_version(NULL);
385         exit(0);
386     }
387
388     memset(&pr, 0, sizeof(pr));
389     ret = krb_get_default_principal(pr.name, pr.instance, default_realm);
390     if(ret < 0)
391         errx(1, "Can't figure out default principal");
392     if(pr.instance[0] == '\0')
393         strlcpy(pr.instance, "admin", sizeof(pr.instance));
394     if(principal) {
395         if(username)
396             warnx("Ignoring username when principal is given");
397         ret = krb_parse_name(principal, &pr);
398         if(ret)
399             errx(1, "%s: %s", principal, krb_get_err_text(ret));
400         if(pr.realm[0] != '\0')
401             strlcpy(default_realm, pr.realm, sizeof(default_realm));
402     } else if(username) {
403         strlcpy(pr.name, username, sizeof(pr.name));
404         strlcpy(pr.instance, "admin", sizeof(pr.instance));
405     } 
406     
407     if(realm)
408         strlcpy(default_realm, realm, sizeof(default_realm));
409     
410     strlcpy(krbrlm, default_realm, sizeof(krbrlm));
411
412     if(pr.realm[0] == '\0')
413         strlcpy(pr.realm, krbrlm, sizeof(pr.realm));
414
415     if (kadm_init_link(PWSERV_NAME, KRB_MASTER, krbrlm) != KADM_SUCCESS)
416         *krbrlm = '\0';
417     
418     if(timeout) {
419         if(set_timeout(timeout) == -1)
420             warnx("bad timespecification `%s'", timeout);
421     } else if(mflag)
422         destroy_timeout = 0;
423
424     if (tflag)
425         destroy_timeout = 0; /* disable timeout */
426     else{
427         char tktstring[128];
428         snprintf(tktstring, sizeof(tktstring), "%s_adm_%d",
429                  TKT_ROOT, (int)getpid());
430         krb_set_tkt_string(tktstring);
431     }
432     return optind;
433 }
434
435 static void
436 sigalrm(int sig)
437 {
438     if(clean_up())
439         printf("\nTickets destroyed.\n");
440 }
441
442 int
443 main(int argc, char **argv)
444 {
445     int optind = do_init(argc, argv);
446     if(argc > optind)
447         sl_command(cmds, argc - optind, argv + optind);
448     else {
449         void *data = NULL;
450         signal(SIGALRM, sigalrm);
451         while(sl_command_loop(cmds, "kadmin: ", &data) == 0)
452             alarm(destroy_timeout);
453     }
454     clean_up();
455     exit(0);
456 }
457
458 static int
459 setvals(Kadm_vals *vals, char *string)
460 {
461     char realm[REALM_SZ];
462     int status = KADM_SUCCESS;
463
464     memset(vals, 0, sizeof(*vals));
465     memset(realm, 0, sizeof(realm));
466
467     SET_FIELD(KADM_NAME,vals->fields);
468     SET_FIELD(KADM_INST,vals->fields);
469     if ((status = kname_parse(vals->name, vals->instance, realm, string))) {
470         printf("kerberos error: %s\n", krb_get_err_text(status));
471         return status;
472     }
473     if (!realm[0])
474         strlcpy(realm, default_realm, sizeof(realm));
475     if (strcmp(realm, krbrlm)) {
476         strlcpy(krbrlm, realm, sizeof(krbrlm));
477         if ((status = kadm_init_link(PWSERV_NAME, KRB_MASTER, krbrlm)) 
478             != KADM_SUCCESS)
479             printf("kadm error for realm %s: %s\n", 
480                    krbrlm, error_message(status));
481     }
482     if (status) 
483         return 1;
484     else
485         return KADM_SUCCESS;
486 }    
487
488 static int 
489 set_timeout(const char *timespec)
490 {
491     int t = parse_time(timespec, "s");
492     if(t == -1)
493         return -1;
494     destroy_timeout = t;
495     return 0;
496 }
497
498 static int
499 set_timeout_cmd(int argc, char **argv)
500 {
501     char ts[128];
502     if (argc > 2) {
503         printf("Usage: set_timeout [timeout]\n");
504         return 0;
505     }
506     if(argc == 2) {
507         if(set_timeout(argv[1]) == -1){
508             printf("Bad time specification `%s'\n", argv[1]);
509             return 0;
510         }
511     }
512     if(destroy_timeout == 0)
513         printf("Timeout disabled.\n");
514     else{
515         unparse_time(destroy_timeout, ts, sizeof(ts));
516         printf("Timeout after %s.\n", ts);
517     }
518     return 0;
519 }
520
521 static int 
522 change_password(int argc, char **argv)
523 {
524     Kadm_vals old, new;
525     int status;
526     char pw_prompt[BUFSIZ];
527
528     char pw[32];
529     int generate_password = 0;
530     int i;
531     int optind = 0;
532     char *user = NULL;
533
534     struct getargs cpw_args[] = {
535         { "random", 'r', arg_flag, NULL, "generate random password" },
536     };
537     i = 0;
538     cpw_args[i++].value = &generate_password;
539
540     if(getarg(cpw_args, sizeof(cpw_args) / sizeof(cpw_args[0]), 
541               argc, argv, &optind)){
542         arg_printusage(cpw_args, 
543                        sizeof(cpw_args) / sizeof(cpw_args[0]), 
544                        "cpw",
545                        "principal");
546         return 0;
547     }
548
549     argc -= optind;
550     argv += optind;
551
552     if (argc != 1) {
553         printf("Usage: change_password [options] principal\n");
554         return 0;
555     }
556
557     user = argv[0];
558
559     if (setvals(&old, user) != KADM_SUCCESS)
560         return 0;
561
562     new = old;
563
564     SET_FIELD(KADM_DESKEY,new.fields);
565
566     if (princ_exists(old.name, old.instance, krbrlm) != PE_NO) {
567         /* get the admin's password */
568         if (get_admin_password() != GOOD_PW)
569             return 0;
570
571
572         if (generate_password) {
573             random_password(pw, sizeof(pw), &new.key_low, &new.key_high);
574         } else {
575             /* get the new password */
576             snprintf(pw_prompt, sizeof(pw_prompt), 
577                      "New password for %s:", user);
578         
579             if (get_password(&new.key_low, &new.key_high,
580                              pw_prompt, SWAP) != GOOD_PW) {
581                 printf("Error reading password; password unchanged\n");
582                 return 0;
583             }
584         }
585
586         status = kadm_mod(&old, &new);
587         if (status == KADM_SUCCESS) {
588             printf("Password changed for %s.\n", user);
589             if (generate_password)
590                 printf("Password is: %s\n", pw);
591         } else {
592             printf("kadmin: %s\nwhile changing password for %s",
593                    error_message(status), user);
594         }
595
596         memset(pw, 0, sizeof(pw));
597         memset(&new, 0, sizeof(new));
598     } else 
599         printf("kadmin: Principal %s does not exist.\n",
600                krb_unparse_name_long (old.name, old.instance, krbrlm));
601     return 0;
602 }
603
604 static int
605 getkey(unsigned char *k)
606 {
607     int i, c;
608     for (i = 0; i < 8; i++)
609         {
610             c = getchar();
611             if (c == EOF)
612                 return 0;
613             else if (c == '\\')
614                 {
615                     int oct = -1;
616                     scanf("%03o", &oct);
617                     if (oct < 0 || oct > 255)
618                         return 0;
619                     k[i] = oct;
620                 }
621             else if (!isalpha(c))
622                 return 0;
623             else
624                 k[i] = c;
625         }
626     c = getchar();
627     if (c != '\n')
628         return 0;
629     return 1;                   /* Success */
630 }
631
632 static void
633 printkey(unsigned char *tkey)
634 {
635     int j;
636     for(j = 0; j < 8; j++)
637         if(tkey[j] != '\\' && isalpha(tkey[j]) != 0)
638             printf("%c", tkey[j]);
639         else
640             printf("\\%03o",(unsigned char)tkey[j]);
641     printf("\n");
642 }
643
644 static int 
645 change_key(int argc, char **argv)
646 {
647     Kadm_vals old, new;
648     unsigned char newkey[8];
649     int status;
650
651     if (argc != 2) {
652         printf("Usage: change_key principal-name\n");
653         return 0;
654     }
655
656     if (setvals(&old, argv[1]) != KADM_SUCCESS)
657         return 0;
658
659     new = old;
660
661     SET_FIELD(KADM_DESKEY,new.fields);
662
663     if (princ_exists(old.name, old.instance, krbrlm) != PE_NO) {
664         /* get the admin's password */
665         if (get_admin_password() != GOOD_PW)
666             return 0;
667
668         /* get the new password */
669         printf("New DES key for %s: ", argv[1]);
670         
671         if (getkey(newkey)) {
672             memcpy(&new.key_low, newkey, 4);
673             memcpy(&new.key_high, ((char *)newkey) + 4, 4);
674             printf("Entered key for %s: ", argv[1]);
675             printkey(newkey);
676             memset(newkey, 0, sizeof(newkey));
677
678             status = kadm_mod(&old, &new);
679             if (status == KADM_SUCCESS) {
680                 printf("Key changed for %s.\n", argv[1]);
681             } else {
682                 printf("kadmin: %s\nwhile changing key for %s",
683                        error_message(status), argv[1]);
684             }
685         } else
686             printf("Error reading key; key unchanged\n");
687         memset(&new, 0, sizeof(new));
688     }
689     else 
690         printf("kadmin: Principal %s does not exist.\n",
691                krb_unparse_name_long (old.name, old.instance, krbrlm));
692     return 0;
693 }
694
695 static int 
696 change_admin_password(int argc, char **argv)
697 {
698     des_cblock newkey;
699     int status;
700     char pword[MAX_KPW_LEN];
701     char *pw_msg;
702
703     alarm(0);
704     if (argc != 1) {
705         printf("Usage: change_admin_password\n");
706         return 0;
707     }
708     if (get_pw_new_pwd(pword, sizeof(pword), &pr, 1) == 0) {
709          des_string_to_key(pword, &newkey);
710          status = kadm_change_pw_plain(newkey, pword, &pw_msg);
711          if(status == KADM_INSECURE_PW)
712               printf("Insecure password: %s\n", pw_msg);
713          else if (status == KADM_SUCCESS)
714               printf("Admin password changed\n");
715          else
716               printf("kadm error: %s\n",error_message(status));
717          memset(newkey, 0, sizeof(newkey));
718          memset(pword, 0, sizeof(pword));
719     }
720     return 0;
721 }
722
723 void random_password(char*, size_t, u_int32_t*, u_int32_t*);
724
725 static int 
726 add_new_key(int argc, char **argv)
727 {
728     int i;
729     char pw_prompt[BUFSIZ];
730     int status;
731     int generate_password = 0;
732     char *password = NULL;
733
734     char *expiration_string = NULL;
735     time_t default_expiration = 0;
736     int expiration_set = 0;
737
738     char *life_string = NULL;
739     time_t default_life = 0;
740     int life_set = 0;
741
742     int attributes = -1;
743     int default_attributes = 0;
744     int attributes_set = 0;
745
746     int optind = 0;
747
748     /* XXX remember to update value assignments below */
749     struct getargs add_args[] = {
750         { "random", 'r', arg_flag, NULL, "generate random password" },
751         { "password", 'p', arg_string, NULL },
752         { "life", 'l', arg_string, NULL, "max ticket life" },
753         { "expiration", 'e', arg_string, NULL, "principal expiration" },
754         { "attributes", 'a', arg_integer, NULL }
755     };
756     i = 0;
757     add_args[i++].value = &generate_password;
758     add_args[i++].value = &password;
759     add_args[i++].value = &life_string;
760     add_args[i++].value = &expiration_string;
761     add_args[i++].value = &attributes;
762
763
764     if(getarg(add_args, sizeof(add_args) / sizeof(add_args[0]), 
765               argc, argv, &optind)){
766         arg_printusage(add_args, 
767                        sizeof(add_args) / sizeof(add_args[0]), 
768                        "add",
769                        "principal ...");
770         return 0;
771     }
772
773     if(expiration_string) {
774         default_expiration = parse_expdate(expiration_string);
775         if(default_expiration < 0)
776             warnx("Unknown expiration date `%s'", expiration_string);
777         else
778             expiration_set = 1;
779     }
780     if(life_string) {
781         time_t t = parse_time(life_string, "hour");
782         if(t == -1) 
783             warnx("Unknown lifetime `%s'", life_string);
784         else {
785             default_life = krb_time_to_life(0, t);
786             life_set = 1;
787         }
788     }
789     if(attributes != -1) {
790         default_attributes = attributes;
791         attributes_set = 1;
792     }
793
794
795     {
796         char default_name[ANAME_SZ + INST_SZ + 1];
797         char old_default[INST_SZ + 1] = "";
798         Kadm_vals new, default_vals;
799         char pw[32];
800         u_char fields[4];
801
802         for(i = optind; i < argc; i++) {
803             if (setvals(&new, argv[i]) != KADM_SUCCESS)
804                 return 0;
805             SET_FIELD(KADM_EXPDATE, new.fields);
806             SET_FIELD(KADM_ATTR, new.fields);
807             SET_FIELD(KADM_MAXLIFE, new.fields);
808             SET_FIELD(KADM_DESKEY, new.fields);
809
810             if (princ_exists(new.name, new.instance, krbrlm) == PE_YES) {
811                 printf("kadmin: Principal %s already exists.\n", argv[i]);
812                 continue;
813             }
814             /* get the admin's password */
815             if (get_admin_password() != GOOD_PW)
816                 return 0;
817         
818             snprintf (default_name, sizeof(default_name), 
819                       "default.%s", new.instance);
820             if(strcmp(old_default, default_name) != 0) {
821                 memset(fields, 0, sizeof(fields));
822                 SET_FIELD(KADM_NAME, fields);
823                 SET_FIELD(KADM_INST, fields);
824                 SET_FIELD(KADM_EXPDATE, fields);
825                 SET_FIELD(KADM_ATTR, fields);
826                 SET_FIELD(KADM_MAXLIFE, fields);
827                 if (setvals(&default_vals, default_name) != KADM_SUCCESS)
828                     return 0;
829         
830                 if (kadm_get(&default_vals, fields) != KADM_SUCCESS) {
831                     /* no such entry, try just `default' */
832                     if (setvals(&default_vals, "default") != KADM_SUCCESS)
833                         continue;
834                     if ((status = kadm_get(&default_vals, fields)) != KADM_SUCCESS) {
835                         warnx ("kadm error: %s", error_message(status));
836                         break; /* no point in continuing */
837                     }
838                 }
839
840                 if (default_vals.max_life == 255) /* Defaults not set! */ {
841                     /* This is the default maximum lifetime for new principals. */
842                     if (strcmp(new.instance, "admin") == 0)
843                         default_vals.max_life = 1 + (CLOCK_SKEW/(5*60)); /* 5+5 minutes */
844                     else if (strcmp(new.instance, "root") == 0)
845                         default_vals.max_life = 96;    /* 8 hours */
846                     else if (krb_life_to_time(0, 162) >= 24*60*60)
847                         default_vals.max_life = 162;     /* ca 100 hours */
848                     else
849                         default_vals.max_life = 255;     /* ca 21 hours (maximum) */
850                 
851                     /* Also fix expiration date. */
852                     {
853                         time_t now;
854                         struct tm tm;
855
856                         now = time(0);
857                         tm = *gmtime(&now);
858                         if (strcmp(new.name, "rcmd") == 0 ||
859                             strcmp(new.name, "ftp")  == 0 ||
860                             strcmp(new.name, "pop")  == 0)
861                             tm.tm_year += 5;
862                         else
863                             tm.tm_year += 2;
864                         default_vals.exp_date = mktime(&tm);
865                     }           
866                     default_vals.attributes = default_vals.attributes;
867                 }
868                 if(!life_set)
869                     default_life = default_vals.max_life;
870                 if(!expiration_set)
871                     default_expiration = default_vals.exp_date;
872                 if(!attributes_set)
873                     default_attributes = default_vals.attributes;
874             }
875
876             new.max_life = default_life;
877             new.exp_date = default_expiration;
878             new.attributes = default_attributes;
879             if(!life_set)
880                 get_maxlife(&new);
881             if(!attributes_set)
882                 get_attr(&new);
883             if(!expiration_set)
884                 get_expdate(&new);
885
886             if(generate_password) {
887                 random_password(pw, sizeof(pw), &new.key_low, &new.key_high);
888             } else if (password == NULL) {
889                 /* get the new password */
890                 snprintf(pw_prompt, sizeof(pw_prompt), "Password for %s:", 
891                          argv[i]);
892         
893                 if (get_password(&new.key_low, &new.key_high,
894                                  pw_prompt, SWAP) != GOOD_PW) {
895                     printf("Error reading password: %s not added\n", argv[i]);
896                     memset(&new, 0, sizeof(new));
897                     return 0;
898                 }
899             } else {
900                 passwd_to_lowhigh (&new.key_low, &new.key_high, password, SWAP);
901                 memset (password, 0, strlen(password));
902             }
903
904             status = kadm_add(&new);
905             if (status == KADM_SUCCESS) {
906                 printf("%s added to database", argv[i]);
907                 if (generate_password)
908                     printf (" with password `%s'", pw);
909                 printf (".\n");
910             } else 
911                 printf("kadm error: %s\n",error_message(status));
912                 
913             memset(pw, 0, sizeof(pw));
914             memset(&new, 0, sizeof(new));
915         }
916     }
917     
918     return 0;
919 }
920
921 static int 
922 del_entry(int argc, char **argv)
923 {
924     int status;
925     Kadm_vals vals;
926     int i;
927
928     if (argc < 2) {
929         printf("Usage: delete principal...\n");
930         return 0;
931     }
932
933     for(i = 1; i < argc; i++) {
934         if (setvals(&vals, argv[i]) != KADM_SUCCESS)
935             return 0;
936         
937         if (princ_exists(vals.name, vals.instance, krbrlm) != PE_NO) {
938             /* get the admin's password */
939             if (get_admin_password() != GOOD_PW)
940                 return 0;
941             
942             if ((status = kadm_del(&vals)) == KADM_SUCCESS)
943                 printf("%s removed from database.\n", argv[i]);
944             else 
945                 printf("kadm error: %s\n",error_message(status));
946         }
947         else
948             printf("kadmin: Principal %s does not exist.\n",
949                    krb_unparse_name_long (vals.name, vals.instance, krbrlm));
950     }
951     return 0;
952 }
953
954 static int 
955 get_entry(int argc, char **argv)
956 {
957     int status;
958     u_char fields[4];
959     Kadm_vals vals;
960
961     if (argc != 2) {
962         printf("Usage: get_entry username\n");
963         return 0;
964     }
965
966     memset(fields, 0, sizeof(fields));
967
968     SET_FIELD(KADM_NAME,fields);
969     SET_FIELD(KADM_INST,fields);
970     SET_FIELD(KADM_EXPDATE,fields);
971     SET_FIELD(KADM_ATTR,fields);
972     SET_FIELD(KADM_MAXLIFE,fields);
973 #if 0
974     SET_FIELD(KADM_DESKEY,fields); 
975 #endif
976 #ifdef EXTENDED_KADM
977     SET_FIELD(KADM_MODDATE, fields);
978     SET_FIELD(KADM_MODNAME, fields);
979     SET_FIELD(KADM_MODINST, fields);
980     SET_FIELD(KADM_KVNO, fields);
981 #endif
982
983     if (setvals(&vals, argv[1]) != KADM_SUCCESS)
984         return 0;
985
986
987     if (princ_exists(vals.name, vals.instance, krbrlm) != PE_NO) {
988         /* get the admin's password */
989         if (get_admin_password() != GOOD_PW)
990             return 0;
991         
992         if ((status = kadm_get(&vals, fields)) == KADM_SUCCESS)
993             prin_vals(&vals);
994         else
995             printf("kadm error: %s\n",error_message(status));
996     }
997     else
998         printf("kadmin: Principal %s does not exist.\n",
999                krb_unparse_name_long (vals.name, vals.instance, krbrlm));
1000     return 0;
1001 }
1002
1003 static int 
1004 mod_entry(int argc, char **argv)
1005 {
1006     int status;
1007     u_char fields[4];
1008     Kadm_vals ovals, nvals;
1009     int i;
1010
1011     char *expiration_string = NULL;
1012     time_t default_expiration = 0;
1013     int expiration_set = 0;
1014
1015     char *life_string = NULL;
1016     time_t default_life = 0;
1017     int life_set = 0;
1018
1019     int attributes = -1;
1020     int default_attributes = 0;
1021     int attributes_set = 0;
1022
1023     int optind = 0;
1024
1025     /* XXX remember to update value assignments below */
1026     struct getargs mod_args[] = {
1027         { "life", 'l', arg_string, NULL, "max ticket life" },
1028         { "expiration", 'e', arg_string, NULL, "principal expiration" },
1029         { "attributes", 'a', arg_integer, NULL }
1030     };
1031     i = 0;
1032     mod_args[i++].value = &life_string;
1033     mod_args[i++].value = &expiration_string;
1034     mod_args[i++].value = &attributes;
1035
1036
1037     if(getarg(mod_args, sizeof(mod_args) / sizeof(mod_args[0]), 
1038               argc, argv, &optind)){
1039         arg_printusage(mod_args, 
1040                        sizeof(mod_args) / sizeof(mod_args[0]), 
1041                        "mod",
1042                        "principal ...");
1043         return 0;
1044     }
1045
1046     if(expiration_string) {
1047         default_expiration = parse_expdate(expiration_string);
1048         if(default_expiration < 0)
1049             warnx("Unknown expiration date `%s'", expiration_string);
1050         else
1051             expiration_set = 1;
1052     }
1053     if(life_string) {
1054         time_t t = parse_time(life_string, "hour");
1055         if(t == -1) 
1056             warnx("Unknown lifetime `%s'", life_string);
1057         else {
1058             default_life = krb_time_to_life(0, t);
1059             life_set = 1;
1060         }
1061     }
1062     if(attributes != -1) {
1063         default_attributes = attributes;
1064         attributes_set = 1;
1065     }
1066
1067
1068     for(i = optind; i < argc; i++) {
1069
1070         memset(fields, 0, sizeof(fields));
1071
1072         SET_FIELD(KADM_NAME,fields);
1073         SET_FIELD(KADM_INST,fields);
1074         SET_FIELD(KADM_EXPDATE,fields);
1075         SET_FIELD(KADM_ATTR,fields);
1076         SET_FIELD(KADM_MAXLIFE,fields);
1077
1078         if (setvals(&ovals, argv[i]) != KADM_SUCCESS)
1079             return 0;
1080
1081         nvals = ovals;
1082
1083         if (princ_exists(ovals.name, ovals.instance, krbrlm) == PE_NO) {
1084             printf("kadmin: Principal %s does not exist.\n",
1085                    krb_unparse_name_long (ovals.name, ovals.instance, krbrlm));
1086             return 0;
1087         }
1088
1089         /* get the admin's password */
1090         if (get_admin_password() != GOOD_PW)
1091             return 0;
1092         
1093         if ((status = kadm_get(&ovals, fields)) != KADM_SUCCESS) {
1094             printf("[ unable to retrieve current settings: %s ]\n",
1095                    error_message(status));
1096             nvals.max_life = DEFAULT_TKT_LIFE;
1097             nvals.exp_date = 0;
1098             nvals.attributes = 0;
1099         } else {
1100             nvals.max_life = ovals.max_life;
1101             nvals.exp_date = ovals.exp_date;
1102             nvals.attributes = ovals.attributes;
1103     }
1104
1105         if(life_set) {
1106             nvals.max_life = default_life;
1107             SET_FIELD(KADM_MAXLIFE, nvals.fields);
1108         } else
1109             get_maxlife(&nvals);
1110         if(attributes_set) {
1111             nvals.attributes = default_attributes;
1112             SET_FIELD(KADM_ATTR, nvals.fields);
1113         } else
1114             get_attr(&nvals);
1115         if(expiration_set) {
1116             nvals.exp_date = default_expiration;
1117             SET_FIELD(KADM_EXPDATE, nvals.fields);
1118         } else
1119             get_expdate(&nvals);
1120     
1121         if (IS_FIELD(KADM_MAXLIFE, nvals.fields) ||
1122             IS_FIELD(KADM_ATTR, nvals.fields) ||
1123             IS_FIELD(KADM_EXPDATE, nvals.fields)) {
1124             if ((status = kadm_mod(&ovals, &nvals)) != KADM_SUCCESS) {
1125                 printf("kadm error: %s\n",error_message(status));
1126                 goto out;
1127             }
1128             if ((status = kadm_get(&ovals, fields)) != KADM_SUCCESS) {
1129                 printf("kadm error: %s\n",error_message(status));
1130                 goto out;
1131             }
1132         }
1133         prin_vals(&ovals);
1134     }
1135     
1136 out:
1137     return 0;
1138 }
1139
1140 static int
1141 help(int argc, char **argv)
1142 {
1143     sl_help (cmds, argc, argv);
1144     return 0;
1145 }