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