Initial IBM OpenAFS 1.0 tree
[openafs.git] / src / kauth / admin_tools.c
1 /* Copyright (C) 1990, 1989 Transarc Corporation - All rights reserved */
2 /*
3  * For copyright information, see IPL which you accepted in order to
4  * download this software.
5  *
6  */
7
8 /* These routines provide administrative tools for managing the AuthServer.
9    There is an interactive routine that can be used to examine the database and
10    make small changes as well as subroutines to permit specialized programs to
11    update the database, change the server passwords, etc. */
12
13 #include <afs/param.h>
14 #include <afs/stds.h>
15 #include <afs/debug.h>
16 #include <ctype.h>
17 #include <string.h>
18
19     /* These two needed for rxgen output to work */
20 #include <sys/types.h>
21 #include <rx/xdr.h>
22
23 #include <stdio.h>
24 #include <rx/rx.h>
25 #include <lock.h>
26 #include <ubik.h>
27 #ifndef AFS_NT40_ENV
28 #include <pwd.h>
29 #endif
30 #include <afs/auth.h>
31 #include <afs/cellconfig.h>
32 #include <afs/cmd.h>
33 #include <afs/com_err.h>
34 #include <afs/afsutil.h>
35
36 #include "kauth.h"
37 #include "kautils.h"
38 #include "kaport.h"
39
40
41 #define CMD_PARSER_AMBIG_FIX 1          /* allow ambiguous aliases */
42
43 extern char *ktime_GetDateUsage();
44
45 #define KA_SIXHOURS     (6*3600)
46
47 static struct ubik_client *conn;
48 static char cell[MAXKTCREALMLEN] = "";
49 static char whoami[32];
50 static char passwd[BUFSIZ];
51 static char myName[510];  /* almost like whoami save with path and without : */
52
53 static int finished;
54 static int zero_argc;
55 static char **zero_argv;
56 afs_uint32 ka_islocked();
57
58 afs_int32 DefaultCell (void)
59 {
60     afs_int32 code;
61
62     if (cell[0] != 0) return 0;
63     code = ka_ExpandCell (0, cell, 0/*local*/);
64     if (code) {
65         com_err (whoami, code, "Can't expand cell name");
66     }
67     return code;
68 }
69
70 /* These are the command operation procedures. */
71
72 int ListUsers (
73   struct cmd_syndesc *as,
74   char *arock)
75 {
76     struct kaident name;
77     afs_int32 index;
78     afs_int32 count;
79     afs_int32 next_index;
80     int  code, all=0, showa = 0;
81     int showkey = (as->parms[2].items != NULL);
82
83     if (as->parms[0].items) 
84         all = 1;
85     if (as->parms[1].items) {
86         all = 1;
87         showa = 1;
88     }
89     for (index = 0; 1; index = next_index) {
90         code = ubik_Call (KAM_ListEntry, conn, 0,
91                           index, &next_index, &count, &name);
92         if (code) {
93             com_err (whoami, code, "calling KAM_ListEntry");
94             break;
95         }
96         if (!next_index) break;
97         if (next_index < 0)
98             printf ("next_index (%d) is negative: ", next_index);
99         if (strlen(name.name) == 0) printf ("name is zero length: ");
100         if (all)
101             DumpUser(name.name, (char *)0, showa, showkey, name.instance);
102         else
103             ka_PrintUserID ("", name.name, name.instance, "\n");
104     }
105     return code;
106 }
107
108
109 int ExamineUser (
110   struct cmd_syndesc *as,
111   char *arock)
112 {
113     int showkey = (as->parms[1].items != NULL);
114     return DumpUser(as->parms[0].items->data, arock, 0, showkey, (char *)0);
115 }
116
117
118 int DumpUser (
119   char *user,
120   char *arock,
121   int showadmin,
122   int showkey,
123   char *inst)
124 {
125     char name[MAXKTCNAMELEN];
126     char instance[MAXKTCNAMELEN];
127     Date now = time(0);
128     int  code;
129     char bob[KA_TIMESTR_LEN];
130
131     struct kaentryinfo tentry;
132
133     code = ka_ParseLoginName (user, name, instance, 0);
134     if (code) {
135         com_err (whoami, code, "parsing user's name '%s'", user);
136         return KABADCMD;
137     }
138
139     if (!inst)
140         inst = instance;
141     code = ubik_Call (KAM_GetEntry, conn, 0, name, inst,
142                       KAMAJORVERSION, &tentry);
143     if (code) {
144         com_err (whoami, code,
145                  "getting information for %s.%s", name, inst);
146         return code;
147     }
148     if (tentry.minor_version != KAMINORVERSION)
149         printf ("Minor version number mismatch: got %d, expected %d\n",
150                 tentry.minor_version, KAMINORVERSION);
151     if (showadmin && !(tentry.flags & KAFADMIN))
152         return 0;
153     ka_PrintUserID ("\nUser data for ", name, inst, "");
154     {   char *prefix = " (";
155 #define NEWPREFIX "+"
156         if (tentry.flags & KAFADMIN) { printf ("%sADMIN", prefix); prefix = NEWPREFIX; }
157         if (tentry.flags & KAFNOTGS) { printf ("%sNOTGS", prefix); prefix = NEWPREFIX; }
158         if (tentry.flags & KAFNOCPW) { printf ("%sNOCPW", prefix); prefix = NEWPREFIX; }
159         if (tentry.flags & KAFNOSEAL) { printf ("%sNOSEAL", prefix); prefix = NEWPREFIX; }
160         if (tentry.flags & KAFNEWASSOC) { printf ("%sNEWASSOC", prefix); prefix = NEWPREFIX; }
161         if (tentry.flags & KAFASSOCROOT) { printf ("%sASSOCROOT", prefix); prefix = NEWPREFIX; }
162         if (tentry.flags & KAFASSOC) { printf ("%sASSOC", prefix); prefix = NEWPREFIX; }
163         if (tentry.user_expiration <= now) { printf ("%sexpired", prefix); prefix = NEWPREFIX; }
164         if (strcmp (prefix, NEWPREFIX) == 0) printf (")\n");
165         else printf ("\n");
166     }
167     if ((!ka_KeyIsZero((char *) &tentry.key, sizeof(tentry.key))) && 
168         (showkey)) {
169         printf ("  key (%d):", tentry.key_version);
170         ka_PrintBytes (&tentry.key, sizeof(tentry.key));
171     }
172     else {
173         if (tentry.keyCheckSum == 0) 
174             printf ("  key version is %d", tentry.key_version);
175         else
176             printf ("  key (%d) cksum is %u",
177                     tentry.key_version, tentry.keyCheckSum);
178     }
179     ka_timestr(tentry.change_password_time,bob,KA_TIMESTR_LEN);
180     printf (", last cpw: %s\n", bob);
181     if (!tentry.misc_auth_bytes) {
182        printf ("  password will never expire.\n");
183        printf ("  An unlimited number of unsuccessful authentications is permitted.\n");
184      }
185     else {
186       unsigned char misc_stuff[4];
187       afs_uint32 temp;
188
189       temp = tentry.misc_auth_bytes;
190 /*
191       temp = ntohl(tentry.misc_auth_bytes);
192 */
193       unpack_long(temp, misc_stuff);
194
195       if (!misc_stuff[0]) {
196         printf ("  password will never expire.\n");
197       }
198       else {
199         ka_timestr((tentry.change_password_time + misc_stuff[0]*24*60*60), bob, KA_TIMESTR_LEN);
200         printf ("  password will expire: %s\n", bob);
201       } 
202
203       if (!misc_stuff[2])
204          printf ("  An unlimited number of unsuccessful authentications is permitted.\n");
205       else {
206          printf ("  %d consecutive unsuccessful authentications are permitted.\n", misc_stuff[2]);
207
208          if (!misc_stuff[3])
209            printf ("  The lock time for this user is not limited.\n");
210          else 
211            printf ("  The lock time for this user is %4.1f minutes.\n", 
212                    (float) ((unsigned int) misc_stuff[3] << 9) / 60.0);
213
214          if (!(misc_stuff[1] & KA_ISLOCKED) || !ka_islocked(name, instance, &temp))
215            printf ("  User is not locked.\n");
216          else if (temp == (afs_uint32) (-1L))
217            printf ("  User is locked forever.\n");
218          else {
219            ka_timestr(temp,bob,KA_TIMESTR_LEN);
220            printf ("  User is locked until %s\n",bob);
221          }
222        }
223
224     }
225     {   char exp[KA_TIMESTR_LEN];
226         ka_timestr (tentry.user_expiration, exp, KA_TIMESTR_LEN);
227         if (tentry.user_expiration < now)
228             printf ("  DISABLED entry at %s.", exp);
229         else if (tentry.user_expiration == NEVERDATE)
230             printf ("  entry never expires.");
231         else printf ("  entry expires on %s.", exp);
232     }
233     printf ("  Max ticket lifetime %.2f hours.\n",
234             tentry.max_ticket_lifetime / 3600.0);
235     ka_timestr (tentry.modification_time,bob,KA_TIMESTR_LEN);
236     printf ("  last mod on %s by ", bob);
237     ka_PrintUserID ("", tentry.modification_user.name,
238                     tentry.modification_user.instance, "\n");
239     if ((tentry.reserved3 & 0xffff0000) == 0x12340000) {
240         int short reused = (short)tentry.reserved3;
241         if (!reused) {
242             printf("  permit password reuse\n");
243         } else {
244             printf("  don't permit password reuse\n");
245         }
246     }
247     return 0;
248 }
249
250 struct OKerrors {
251     int   code;
252     char *msg;
253 };
254
255 int handle_errors (
256   int              code,                /* error code to handle */
257   struct OKerrors  OKlist[],            /* list of errors & messages that should be ignored */
258   int             *persist)             /* set this if we should retry, clear otherwise */
259 {
260     int        i;  
261
262     for (i=0; OKlist[i].code; i++) {
263         if (OKlist[i].code == code) {
264             printf ("%s\n", OKlist[i].msg);
265             *persist = 0;               /* we're done */
266             return 0;
267         }
268     }
269
270     printf (" : [%s] %s", error_table_name(code), error_message(code));
271     switch (code) {
272       case UNOQUORUM:
273         printf (", wait one second\n");
274         IOMGR_Sleep (1);
275         return 0;
276       case KAEMPTY:
277       case RX_CALL_TIMEOUT:
278         printf (" (retrying)\n");
279         return 0;
280     }
281     printf ("\n");
282
283     *persist = 0;                       /* don't retry these errors */
284     return code;
285 }
286
287 int CreateUser (
288   struct cmd_syndesc *as,
289   char *arock)
290 {
291     int code;
292     char name[MAXKTCNAMELEN];
293     char instance[MAXKTCNAMELEN];
294     struct ktc_encryptionKey key;
295
296     int persist = 1;
297     struct OKerrors OKlist[2];
298     OKlist[0].code=0;
299
300     code = ka_ParseLoginName (as->parms[0].items->data, name, instance, 0);
301     if (code) {
302         com_err (whoami, code, "parsing user's name '%s'",
303                  as->parms[0].items->data);
304         return KABADCMD;
305     }
306     ka_StringToKey (as->parms[1].items->data, cell, &key);
307
308     do {
309         code = ubik_Call (KAM_CreateUser, conn, 0, name, instance, key);
310         if (!code) return 0;
311         ka_PrintUserID ("Creating user ", name, instance, " ");
312         code = handle_errors (code, OKlist, &persist);
313     } while (persist);
314     return code;
315 }
316
317 int DeleteUser (
318   struct cmd_syndesc *as,
319   char *arock)
320 {
321     int code;
322     char name[MAXKTCNAMELEN];
323     char instance[MAXKTCNAMELEN];
324
325     int persist = 1;
326     struct OKerrors OKlist[2];
327     OKlist[0].code=0;
328     code = ka_ParseLoginName (as->parms[0].items->data, name, instance, 0);
329     if (code) {
330         com_err (whoami, code, "parsing user's name '%s'",
331                  as->parms[0].items->data);
332         return KABADCMD;
333     }
334
335     do {
336         code = ubik_Call (KAM_DeleteUser, conn, 0, name, instance);
337         if (!code) return 0;
338         ka_PrintUserID ("Deleting user ", name, instance, " ");
339         code = handle_errors (code, OKlist, &persist);
340     } while (persist);
341     return code;
342 }
343
344 static int read_time_interval (
345   char *str,
346   afs_int32 *seconds)
347 {
348     char *s;
349     int   sec = 0;
350     char  buf[32];
351
352     str = strncpy (buf, str, sizeof(buf));
353     s = strchr (str, ':');
354     if (s == 0) sec = atoi (str);
355     else {
356         *s++ = '\0';                    /* separate hours and minutes */
357         sec = atoi(str)*3600 + atoi(s)*60;
358     }
359     *seconds = sec;
360     return 0;
361 }
362
363 int parse_flags (
364   char *name,
365   char *inst,
366   char *str,
367   afs_int32 *flags)
368 {
369     struct kaentryinfo tentry;
370     int code;
371     char bitspec[100];
372     afs_int32 f;
373     char bit[25];
374     char c;
375     int  addop;                         /* 1=add bit; 0=remove bit */
376     int  flag;
377     int  i;
378
379     str = lcstring (bitspec, str, sizeof(bitspec));
380     if (isdigit(*str)) {
381         if (strncmp(str, "0x", 2) == 0) /* 0x => hex */
382             sscanf (str, "0x%lx", &f);
383         else if (*str == '0')           /* assume octal */
384             sscanf (str, "%lo", &f);
385         else                            /* just assume hex */
386             sscanf (str, "%lx", &f);
387     }
388     else {
389         if (*str == '=') {
390             str++;
391             f = 0;
392             addop = 1;
393         }
394         else {
395             if (strchr ("+-", *str)) addop = (*str++ == '+');
396             else if (*str == '_') {addop = 0; str++;}
397             else addop = 1;
398             code = ubik_Call (KAM_GetEntry, conn, 0,
399                               name, inst, KAMAJORVERSION, &tentry);
400             if (code) {
401                 com_err (whoami, code,
402                          "could get current flag value for %s.%s", name, inst);
403                 return -1;
404             }
405             f = tentry.flags;
406         }
407         while (*str) {
408             i = 0;
409             while (1) {
410                 c = *str;
411                 if (isupper (c)) c = tolower(c);
412                 if (!islower(c)) break;
413                 bit[i++] = c;
414                 str++;
415             }
416             bit[i] = '\0';
417             if (strcmp (bit, "admin") == 0) flag = KAFADMIN;
418             else if (strcmp (bit, "noadmin") == 0) flag = KAFADMIN, addop = !addop;
419             else if (strcmp (bit, "notgs") == 0) flag = KAFNOTGS;
420             else if (strcmp (bit, "tgs") == 0) flag = KAFNOTGS, addop = !addop;
421             else if (strcmp (bit, "noseal") == 0) flag = KAFNOSEAL;
422             else if (strcmp (bit, "seal") == 0) flag = KAFNOSEAL, addop = !addop;
423             else if (strcmp (bit, "nocpw") == 0) flag = KAFNOCPW;
424             else if (strcmp (bit, "cpw") == 0) flag = KAFNOCPW, addop = !addop;
425             else if (strcmp (bit, "newassoc") == 0) flag = KAFNEWASSOC;
426             else if (strcmp (bit, "nonewassoc") == 0) flag = KAFNEWASSOC, addop = !addop;
427             else {
428                 printf ("Illegal bit name: %s; choices are: [no]admin, [no]tgs, [no]seal, [no]cpw\n", bit);
429                 return -1;
430             }
431
432             if (addop) f |= flag;
433             else f &= ~flag;
434
435             if (*str == 0) break;
436             if (*str == '+') addop = 1;                 /* get next op */
437             else if ((*str == '-') || (*str == '_')) addop = 0;
438             else {
439                 printf ("Illegal combination operator: %c\n", *str);
440                 return -1;
441             }
442             str++;
443         }
444     }
445     *flags = (f & KAF_SETTABLE_FLAGS) | KAFNORMAL;
446     return 0;
447 }
448 #define seriouserror(code) ((code <0) || ((code != UNOSERVERS) && (code != UNOQUORUM) && code != UNOTSYNC))
449
450 /* return MAXLONG if locked forever */
451 afs_uint32 ka_islocked (
452   char *name, 
453   char *instance,
454   afs_uint32 *when)
455 {
456   int count, code;
457   afs_uint32 tempwhen;
458
459   count = 0;
460   *when = 0;
461   do {
462     tempwhen = 0;
463     code = ubik_CallIter (KAM_LockStatus, conn, UPUBIKONLY, &count, 
464                           name, instance, &tempwhen, /*spares*/0,0,0,0);
465     if (code) {
466       if (seriouserror(code)) 
467         com_err (whoami, code, "");
468     }
469     else if (tempwhen) { /* user is locked */
470       if (!*when || tempwhen < *when) {
471           *when = tempwhen;
472           return (*when);
473       }
474     }
475     else /* ! tempwhen ==> user is not locked */
476       return 0;
477
478   } while (code != UNOSERVERS);
479   
480   return (*when);
481 }
482
483 int Unlock (
484   struct cmd_syndesc *as,
485   char *arock)
486 {
487   afs_int32 code, rcode=0;
488   afs_int32 count;
489   afs_int32 server;
490   char name[MAXKTCNAMELEN];
491   char instance[MAXKTCNAMELEN];
492
493     code = ka_ParseLoginName (as->parms[0].items->data, name, instance, 0);
494     if (code) {
495         com_err (whoami, code, "parsing user's name '%s'", as->parms[0].items->data);
496         return KABADCMD;
497     }
498   
499     count = 0;
500     do {
501       code = ubik_CallIter (KAM_Unlock, conn, 0, &count, name, instance, 
502                             /*spares*/0,0,0,0);
503       if (code && (code != UNOSERVERS)) {
504           server = 0;
505           if (conn && conn->conns[count-1] && conn->conns[count-1]->peer) {
506               server = conn->conns[count-1]->peer->host;
507           }
508           com_err (whoami, code,
509                    "so %s.%s may still be locked (on server %d.%d.%d.%d)", 
510                    name, instance, ((server>>24)&0xFF), ((server>>16)&0xFF),
511                    ((server>>8)&0xFF), (server&0xFF));
512
513          if (!rcode) {
514             rcode = code;
515          }
516       }
517     } while (code != UNOSERVERS);
518
519     return rcode;
520 }
521
522 int SetFields (
523   struct cmd_syndesc *as,
524   char *arock)
525 {
526     int code;
527     char name[MAXKTCNAMELEN];
528     char instance[MAXKTCNAMELEN];
529     afs_int32 flags = 0;
530     Date expiration = 0;
531     afs_int32 lifetime = 0;
532     afs_int32 maxAssociates = -1;
533     afs_int32 pwexpiry = 0;
534     afs_int32 was_spare = 0;
535     char misc_auth_bytes[4];
536     int i;
537
538     code = ka_ParseLoginName (as->parms[0].items->data, name, instance, 0);
539     if (code) {
540         com_err (whoami, code, "parsing user's name '%s'",
541                  as->parms[0].items->data);
542         return KABADCMD;
543     }
544
545     if (as->parms[1].items) {
546         code = parse_flags (name, instance, as->parms[1].items->data, &flags);
547         if (code) {
548             printf ("Illegal flag specification: %s, should be of the form <'='|'+'|'-'|'_'>bitname{<'+'|'-'>bitname}*\n", as->parms[1].items->data);
549             return KABADCMD;
550         }
551     }
552     if (as->parms[2].items) {
553         char  buf[32];
554         char *s = strncpy (buf, as->parms[2].items->data, sizeof(buf));
555         code = ktime_DateToInt32 (s, &expiration);
556         if (code) {
557             printf ("Illegal time format %s: %s\n",
558                     as->parms[2].items->data, ktime_GetDateUsage());
559             return KABADCMD;
560         }
561         if (expiration == 0) {
562             fprintf (stderr, "Expiration time must be after (about) 1970.\n");
563             return KABADCMD;
564         }
565         if (expiration < time(0)) {
566             fprintf (stderr, "Warning: expiration being set into the past, account will be disabled.\n");
567         }
568     }
569     /*
570      * TICKET lifetime...
571      */
572     if (as->parms[3].items) {
573         code = read_time_interval (as->parms[3].items->data, &lifetime);
574         if (code) return KABADCMD;
575     }
576
577     /*  no point in doing this any sooner than necessary */
578     for (i=0;i<4;misc_auth_bytes[i++] = 0);
579
580     if (as->parms[4].items) {
581         if (isint(as->parms[4].items->data))
582           pwexpiry = atoi (as->parms[4].items->data);
583         else {
584           fprintf(stderr,"Password lifetime specified must be a non-negative decimal integer.\n");
585           pwexpiry = -1;
586         }
587         if (pwexpiry <0 || pwexpiry >254) {
588             fprintf(stderr,"Password lifetime range must be [0..254] days.\n");
589             fprintf(stderr,"Zero represents an unlimited lifetime.\n");
590             return KABADCMD;
591         }
592         else {
593           misc_auth_bytes[0] = pwexpiry+1;
594         }
595     }
596
597     if (as->parms[5].items) {
598       char *reuse;
599       reuse = (as->parms[5].items->data);
600       
601       if (!strcmp(reuse, "yes")) {
602         misc_auth_bytes[1] = KA_REUSEPW;
603       }
604       else if (strcmp(reuse, "no")) {
605         fprintf(stderr,"must specify \"yes\" or \"no\": \"yes\" assumed\n");
606         misc_auth_bytes[1] = KA_REUSEPW;
607       }
608       else {
609         misc_auth_bytes[1] = KA_NOREUSEPW;
610       }
611     }
612
613     if (as->parms[6].items) {
614       int nfailures;
615
616       
617       if (isint(as->parms[6].items->data) && 
618         ((nfailures = atoi(as->parms[6].items->data)) < 255)) {
619         misc_auth_bytes[2] = nfailures+1;
620       }
621       else {
622         fprintf(stderr,"Failure limit must be in [0..254].\n");
623         fprintf(stderr,"Zero represents unlimited login attempts.\n");
624         return KABADCMD;
625       }
626     }
627
628     if (as->parms[7].items) {
629       int locktime, hrs, mins;
630       char *s;
631
632       hrs = 0;
633       s = as->parms[7].items->data;
634       if (index(s, ':'))
635         sscanf(s, "%d:%d", &hrs, &mins);
636       else
637         sscanf(s, "%d", &mins);
638
639       locktime = hrs*60 + mins;
640       if (hrs < 0 || hrs > 36 || mins < 0) { 
641         fprintf(stderr,"Lockout times must be either minutes or hh:mm.\n");
642         fprintf(stderr,"Lockout times must be less than 36 hours.\n");
643         return KABADCMD;
644       }
645       else if (locktime > 36*60 ) {
646         fprintf(stderr,"Lockout times must be either minutes or hh:mm.\n");
647         fprintf(stderr,"Lockout times must be less than 36 hours.\n");
648         fprintf(stderr,"Continuing with lock time of exactly 36 hours...\n");
649         locktime = 36*60;
650       }
651       locktime = (locktime * 60 + 511) >> 9; /* ceil(l*60/512) */
652       misc_auth_bytes[3] = locktime +1;  /* will be 1 if user said 0 */
653     }
654
655 #if ASSOCIATES
656     if (as->parms[8].items) {
657         maxAssociates = atoi (as->parms[6].items->data);
658         if (maxAssociates < 0) {
659             printf ("Illegal maximum number of associates\n");
660             return KABADCMD;
661         }
662     }
663 #endif
664     was_spare = pack_long(misc_auth_bytes);
665
666     if (was_spare || flags || expiration || lifetime || (maxAssociates >= 0))
667         code = ubik_Call
668             (KAM_SetFields, conn, 0,
669              name, instance, flags, expiration, lifetime, maxAssociates,
670              was_spare, /* spare */ 0);
671     else {
672         printf ("Must specify one of the optional parameters\n");
673         return KABADCMD;
674     }
675     if (code) com_err (whoami, code,
676                        "calling KAM_SetFields for %s.%s", name, instance);
677     return code;
678 }
679
680 int StringToKey (
681   struct cmd_syndesc *as,
682   char *arock)
683 {
684     afs_int32 code;
685     char realm[MAXKTCREALMLEN];
686     struct ktc_encryptionKey key;
687
688     if (as->parms[1].items) {
689         code = ka_ExpandCell (as->parms[1].items->data, realm, 0/*local*/);
690         if (code) {
691             com_err (whoami, code,
692                      "expanding %s as cell name, attempting to continue",
693                      as->parms[1].items->data);
694         }
695         ucstring (realm, realm, sizeof(realm));
696     }
697     else {
698         if (code = DefaultCell()) return code;
699         ucstring (realm, cell, sizeof(realm));
700     }
701     ka_StringToKey (as->parms[0].items->data, realm, &key);
702
703     printf ("Converting %s in realm '%s' yields key='",
704             as->parms[0].items->data, realm);
705     ka_PrintBytes (&key, sizeof(key));
706     printf ("'.\n");
707
708     return 0;
709 }
710
711 int SetPassword (
712   struct cmd_syndesc *as,
713   char *arock)
714 {
715     int code;
716     char name[MAXKTCNAMELEN];
717     char instance[MAXKTCNAMELEN];
718     char realm[MAXKTCREALMLEN];
719     struct ktc_encryptionKey key;
720     afs_int32 kvno = 0;
721
722     code = ka_ParseLoginName (as->parms[0].items->data, name, instance, realm);
723     if (code) {
724         com_err (whoami, code, "parsing user's name '%s'",
725                  as->parms[0].items->data);
726         return KABADCMD;
727     }
728     
729     if (strlen(realm) == 0) 
730       ucstring (realm, cell, sizeof(realm));
731
732     if (as->parms[1].items && as->parms[2].items) {
733         printf ("Can't specify both a password and a key\n");
734         return KABADCMD;
735       } 
736     else if (as->parms[1].items) {
737       (void) init_child(myName);
738       (void) give_to_child(passwd);  /* old password */
739       code = password_bad(as->parms[1].items->data);
740       (void) terminate_child();
741       if (code)
742         return KABADCMD;
743       ka_StringToKey (as->parms[1].items->data, realm, &key);
744     } 
745     else if (as->parms[2].items) {
746       if (ka_ReadBytes (as->parms[2].items->data, &key, sizeof(key)) != 8) {
747         printf ("Key must be 8 bytes: '%s' was too long\n",
748                          as->parms[2].items->data);
749         return KABADCMD;
750       }
751     } 
752     else {
753         printf ("Must specify new password or key\n");
754         return KABADCMD;
755     }
756
757
758     if (as->parms[3].items) 
759       sscanf (as->parms[3].items->data, "%d", &kvno);
760
761     code = ubik_Call (KAM_SetPassword, conn, 0, name, instance, kvno, key);
762     if (code) com_err (whoami, code,
763                        "so can't set password for %s.%s", name, instance);
764     return code;
765 }
766
767 #define PrintPrincipal(p,n,l) \
768     PrintName((p)->name, (p)->instance, (p)->cell, l, n)
769
770 static afs_int32 PrintName (
771   char *name,
772   char *inst,
773   char *acell,
774   int buflen,
775   char *buf)
776 {
777     int nlen, len;
778     int left;                           /* if ConvertBytes stops early */
779     afs_int32 code;
780
781     if (name == 0) name = "";
782     if (inst == 0) inst = "";
783     if (acell == 0) acell = "";
784     left = ka_ConvertBytes(buf, buflen, name, strlen(name));
785     if (left) {
786       bad_name:
787         code = KABADNAME;
788         com_err (whoami, code,
789                  "PrintName: principal name was '%s'.'%s'@'%s'",
790                  name, inst, acell);
791         return code;
792     }
793     nlen = strlen (buf);
794     len = strlen(inst);
795     if (len) {
796         if (nlen + len + 1 >= buflen) goto bad_name;
797         buf[nlen++] = '.';
798         left = ka_ConvertBytes(buf+nlen, buflen-nlen, inst, len);
799         if (left) goto bad_name;
800         nlen += len;
801     }
802
803     len = strlen(acell);
804     if (len) {
805         char *lcell = ka_LocalCell();
806         if (lcell == 0) lcell = "";
807         if (strcmp (acell, lcell) != 0) {
808             /* only append cell if not the local cell */
809             if (nlen + len + 1 >= buflen) goto bad_name;
810             buf[nlen++] = '@';
811             left = ka_ConvertBytes(buf+nlen, buflen-nlen, acell, len);
812             if (left) goto bad_name;
813             nlen += len;
814         }
815     }
816     return 0;
817 }
818
819 #define PrintedPrincipal(p) PrintedName ((p)->name, (p)->instance, (p)->cell)
820
821 /* PrintedName - returned a pointer to a static string in which the formated
822  * name has been stored. */
823
824 static char *PrintedName (
825   char *name,
826   char *inst,
827   char *cell)
828 {
829     static char printedName[128];
830     afs_int32 code;
831     code = PrintName (name, inst, cell, sizeof(printedName), printedName);
832     if (code) {
833         if (name == 0) name = "";
834         strncpy (printedName, name, sizeof(printedName));
835         printedName[sizeof(printedName)-8] = 0;
836         strcat (printedName, "<error>");
837     }
838     return printedName;
839 }
840
841 static afs_int32 ListTicket (
842   struct ktc_principal *server,
843   int verbose)
844 {
845     afs_int32 code;
846     struct ktc_token token;             /* the token we're printing */
847     struct ktc_principal client;
848     char  UserName[sizeof(struct ktc_principal)];
849     char  ServerName[sizeof(struct ktc_principal)];
850     afs_int32  now = time(0);
851     char bob[KA_TIMESTR_LEN];
852
853     /* get the ticket info itself */
854     code = ktc_GetToken (server, &token, sizeof(token), &client);
855     if (code) {
856         com_err (whoami, code, "failed to get token info for server %s",
857                  PrintedPrincipal (server));
858         return code;
859     }
860     code = PrintPrincipal (&client, UserName, sizeof(UserName));
861     if (code) return code;
862     /* spaces are printed as "\040" */
863     if (UserName[0] == 0)
864         printf("Tokens");
865     else if (strncmp(UserName, "AFS\\040ID\\040", 13) == 0) {
866         printf("User's (AFS ID %s) tokens", UserName+13);
867     }
868     else if (strncmp(UserName, "Unix\\040UID\\040", 15) == 0) {
869         printf("Tokens");
870     }
871     else
872         printf("User %s's tokens", UserName);
873     
874     code = PrintPrincipal (server, ServerName, sizeof(ServerName));
875     if (code) return code;
876     printf(" for %s ", ServerName);
877     
878     if (token.startTime > now) {
879         ka_timestr(token.startTime,bob,KA_TIMESTR_LEN);
880         printf("[>> POSTDATED 'till %s <<]",bob);
881     }
882
883    if (token.endTime <= now)
884         printf("[>> Expired <<]\n");
885     else {
886         ka_timestr(token.endTime,bob,KA_TIMESTR_LEN);
887         printf("[Expires %s]\n", bob);
888     }
889     if (verbose) {
890         printf ("SessionKey: ");
891         ka_PrintBytes (&token.sessionKey, sizeof(token.sessionKey));
892         printf ("\nTicket (kvno = %d, len = %d): ", token.kvno, 
893                 token.ticketLen);
894         ka_PrintBytes (token.ticket, token.ticketLen);
895         printf ("\n");
896     }
897     return 0;
898 }
899
900 static GetTicket (
901   struct cmd_syndesc *as,  
902   char *arock)
903 {
904     int code;
905     struct ktc_principal server;
906     struct ktc_token token;
907     afs_int32 life = KA_SIXHOURS;
908
909     if (as->parms[1].items) {
910         code = read_time_interval (as->parms[1].items->data, &life);
911         if (code) return KABADCMD;
912     }
913     code = ka_ParseLoginName (as->parms[0].items->data,
914                               server.name, server.instance, server.cell);
915     if (code) {
916         com_err (whoami, code, "parsing user's name '%s'",
917                  as->parms[0].items->data);
918         return KABADCMD;
919     }
920     if (server.cell[0] == 0) {
921         if (code = DefaultCell()) return code;
922         strcpy (server.cell, cell);
923     } else {
924         code = ka_ExpandCell (server.cell, server.cell, 0/*local*/);
925         if (code) {
926             com_err (whoami, code, "Can't expand cell name");
927             return code;
928         }
929     }
930
931     token.ticketLen = 0;                /* in case there are no tokens */
932     code = ka_GetServerToken (server.name, server.instance, server.cell,
933                               life, &token, /*new*/1, /*dosetpag*/0);
934     if (code) com_err (whoami, code,
935                        "getting ticket for %s", PrintedPrincipal (&server));
936     else {
937         code = ListTicket (&server, /*verbose*/1);
938     }
939     return code;
940 }
941
942 static GetPassword (
943   struct cmd_syndesc *as,
944   char *arock)
945 {
946     int code;
947     char name[MAXKTCNAMELEN];
948     struct ktc_encryptionKey key;
949     static struct ubik_client *lpbkConn = 0;
950
951      /* no instance allowed */
952     code = ka_ParseLoginName (as->parms[0].items->data, name, 0, 0);
953     if (code) {
954       abort:
955         com_err (whoami, code,
956                  "getting %s's password via loopback connection to GetPassword", name);
957         /* if we got a timeout, print a clarification, too */
958         if (code == -1) {
959             fprintf(stderr, "%s: please note that this command must be run locally on a database server machine.\n", whoami);
960         }
961         return code;
962     }
963     if (lpbkConn == 0) {
964         struct rx_connection    *conns[2];
965         struct rx_securityClass *sc;
966         int                      si;    /* security class index */
967
968         code = rx_Init(0);
969         if (code) goto abort;
970         sc = (struct rx_securityClass *) rxnull_NewClientSecurityObject();
971         si = RX_SCINDEX_NULL;
972         conns[0] = rx_NewConnection (htonl(INADDR_LOOPBACK), htons(AFSCONF_KAUTHPORT),
973                                      KA_MAINTENANCE_SERVICE, sc, si);
974         conns[1] = 0;
975         code = ubik_ClientInit(conns, &lpbkConn);
976         if (code) goto abort;
977     }
978     code = ubik_Call (KAM_GetPassword, lpbkConn, 0, name, &key);
979     /* Lets close down the ubik_Client connection now */
980     ubik_ClientDestroy(lpbkConn);
981     if (code) goto abort;
982     printf ("Key: ");
983     ka_PrintBytes (&key, sizeof(key));
984     printf ("\n");
985     return code;
986 }
987
988 int GetRandomKey (
989   struct cmd_syndesc *as,
990   char *arock)
991 {
992     int code;
993     struct ktc_encryptionKey key;
994
995     code = ubik_Call (KAM_GetRandomKey, conn, 0, &key);
996     if (code) com_err(whoami, code, "so can't get random key");
997     else {
998         int i;
999         printf ("Key: ");
1000         ka_PrintBytes (&key, sizeof(key));
1001         printf (" (");
1002         for (i=0; i<sizeof(key); i++) {
1003             printf ("%0.2x", ((char *)&key)[i] & 0xff);
1004             if (i==3) printf (" ");
1005             else if (i!=7) printf (".");
1006         }
1007         printf (")\n");
1008     }
1009     return code;
1010 }
1011
1012 int Statistics (
1013   struct cmd_syndesc *as,
1014   char *arock)
1015 {
1016     int code;
1017     kasstats statics;
1018     kadstats dynamics;
1019     afs_int32     admins;
1020     char bob[KA_TIMESTR_LEN];
1021
1022     code = ubik_Call (KAM_GetStats, conn, 0,
1023                       KAMAJORVERSION, &admins, &statics, &dynamics);
1024     if (code) {
1025         printf ("call to GetStats failed: %s\n", ka_ErrorString(code));
1026         return code;
1027     }
1028     if (statics.minor_version != KAMINORVERSION)
1029         printf ("Minor version number mismatch: got %d, expected %d\n",
1030                 statics.minor_version, KAMINORVERSION);
1031     printf ("%d allocs, %d frees, %d password changes\n",
1032             statics.allocs, statics.frees, statics.cpws);
1033     printf ("Hash table utilization = %f%%\n",
1034             (double)dynamics.hashTableUtilization / 100.0);
1035     ka_timestr(dynamics.start_time,bob,KA_TIMESTR_LEN);
1036     printf ("From host %lx started at %s:\n", dynamics.host, bob);
1037
1038 #define print_stat(name) if (dynamics.name.requests) printf ("  of %d requests for %s, %d were aborted.\n", dynamics.name.requests, # name, dynamics.name.aborts)
1039     print_stat (Authenticate);
1040     print_stat (ChangePassword);
1041     print_stat (GetTicket);
1042     print_stat (CreateUser);
1043     print_stat (SetPassword);
1044     print_stat (SetFields);
1045     print_stat (DeleteUser);
1046     print_stat (GetEntry);
1047     print_stat (ListEntry);
1048     print_stat (GetStats);
1049     print_stat (GetPassword);
1050     print_stat (GetRandomKey);
1051     print_stat (Debug);
1052     print_stat (UAuthenticate);
1053     print_stat (UGetTicket);
1054     
1055 #if (KAMAJORVERSION>5)
1056     print cpu stats
1057     printf ("%d string checks\n", dynamics.string_checks);
1058 #else
1059     printf ("Used %.3f seconds of CPU time.\n", dynamics.string_checks/1000.0);
1060 #endif
1061     printf ("%d admin accounts\n", admins);
1062     return 0;
1063 }
1064
1065 int DebugInfo (
1066   struct cmd_syndesc *as,
1067   char *arock)
1068 {
1069     int code;
1070     struct ka_debugInfo info;
1071     int i;
1072     Date start,now;
1073     int timeOffset;
1074     char bob[KA_TIMESTR_LEN];
1075
1076     start = time(0);
1077     if (as->parms[0].items) {
1078         struct ubik_client *iConn;
1079         code = ka_SingleServerConn (cell, as->parms[0].items->data, KA_MAINTENANCE_SERVICE, 0, &iConn);
1080         if (code) {
1081             struct afsconf_cell cellinfo;
1082
1083             com_err (whoami, code, "couldn't find host %s in cell %s",
1084                      as->parms[0].items->data, cell);
1085             code = ka_GetServers (cell, &cellinfo);
1086             if (code) com_err (whoami, code, "getting servers in cell %s", cell);
1087             else {
1088                 printf ("Servers in cell %s, are:\n", cell);
1089                 for (i=0; i<cellinfo.numServers; i++)
1090                     printf ("  %s\n", cellinfo.hostName[i]);
1091             }
1092             return code;
1093         }
1094         code = ubik_Call (KAM_Debug, iConn, 0, KAMAJORVERSION, 0, &info);
1095         ubik_ClientDestroy (iConn);
1096     }
1097     else code = ubik_Call (KAM_Debug, conn, 0, KAMAJORVERSION, 0, &info);
1098
1099     if (code) {
1100         com_err (whoami, code, "call to Debug failed");
1101         return code;
1102     }
1103     now = time(0);
1104
1105     if (info.minorVersion != KAMINORVERSION)
1106         printf ("Minor version number mismatch: got %d, expected %d\n",
1107                 info.minorVersion, KAMINORVERSION);
1108
1109     timeOffset = info.
1110 #if (KAMAJORVERSION>5)
1111         now
1112 #else
1113         reserved1
1114 #endif
1115         - now;
1116     if (timeOffset < 0) timeOffset = -timeOffset;
1117     if (timeOffset > 60) {
1118         printf ("WARNING: Large server client clock skew: %d seconds. Call itself took %d seconds.\n", timeOffset, now-start);
1119     }
1120     ka_timestr(info.startTime,bob,KA_TIMESTR_LEN);
1121     printf ("From host %lx started %sat %s:\n",
1122             info.host, (info.noAuth ? "w/o authorization " : ""),
1123             bob);
1124     ka_timestr (info.lastTrans,bob,KA_TIMESTR_LEN);
1125     printf ("Last trans was %s at %s\n", info.lastOperation, bob);
1126     ka_timestr (info.dbHeaderRead,bob,KA_TIMESTR_LEN);
1127     printf ("Header last read %s.\n", bob);
1128     printf ("db version=%d, keyVersion=%d, key cache version=%d\n",
1129             info.dbVersion, info.dbSpecialKeysVersion, info.kcVersion);
1130     printf ("db ptrs: free %d, eof %d, kvno %d.\n",
1131             info.dbFreePtr, info.dbEofPtr, info.dbKvnoPtr);
1132     ka_timestr (info.nextAutoCPW,bob,KA_TIMESTR_LEN);
1133     printf ("Next autoCPW at %s or in %d updates.\n",
1134             bob, info.updatesRemaining);
1135     if (info.cheader_lock || info.keycache_lock)
1136         printf ("locks: cheader %08lx, keycache %08lx\n",
1137                 info.cheader_lock, info.keycache_lock);
1138     printf ("Last authentication for %s, last admin user was %s\n",
1139             info.lastAuth, info.lastAdmin);
1140     printf ("Last TGS op was a %s ticket was for %s\n",
1141             info.lastTGSServer, info.lastTGS);
1142     printf ("Last UDP TGS was a %s ticket for %s.  UDP Authenticate for %s\n",
1143             info.lastUTGSServer, info.lastUTGS, info.lastUAuth);
1144     printf ("key cache size %d, used %d.\n",
1145             info.kcSize, info.kcUsed);
1146     if (info.kcUsed > KADEBUGKCINFOSIZE) {
1147         printf("insufficient room to return all key cache entries!\n");
1148         info.kcUsed = KADEBUGKCINFOSIZE;
1149     }
1150     for (i=0; i<info.kcUsed; i++)
1151         ka_timestr(info.kcInfo[i].used,bob,KA_TIMESTR_LEN);
1152         printf ("%32s %c %2x(%2x) used %s\n",
1153                 info.kcInfo[i].principal, (info.kcInfo[i].primary?'*':' '),
1154                 info.kcInfo[i].kvno, info.kcInfo[i].keycksum,
1155                 bob);
1156     return 0;
1157 }
1158
1159 int Interactive (
1160   struct cmd_syndesc *as,
1161   char *arock)
1162 {
1163     finished = 0;
1164     return 0;
1165 }
1166
1167 int Quit (
1168   struct cmd_syndesc *as,
1169   char *arock)
1170 {
1171     finished = 1;
1172     return 0;
1173 }
1174
1175 void MyAfterProc(
1176   struct cmd_syndesc *as)
1177 {
1178     if (!strcmp(as->name,"help")) return;
1179
1180     /* Determine if we need to destory the ubik connection.
1181      * Closing it avoids resends of packets. 
1182      */
1183     if (conn) {
1184         ubik_ClientDestroy(conn);
1185         conn = 0;
1186     }
1187
1188     return;
1189 }
1190
1191 int   init = 0, noauth;
1192 char  name[MAXKTCNAMELEN];
1193 char  instance[MAXKTCNAMELEN];
1194 char  newCell[MAXKTCREALMLEN];
1195 afs_int32 serverList[MAXSERVERS];
1196
1197 int NoAuth (
1198    struct cmd_syndesc *as,
1199    char *arock)
1200 {
1201    noauth = 1;
1202    return 0;
1203 }
1204
1205 static int MyBeforeProc(
1206   struct cmd_syndesc *as,
1207   char *arock)
1208 {
1209     extern struct passwd *getpwuid();
1210     struct passwd *pw;
1211     struct ktc_encryptionKey key;
1212     struct ktc_principal auth_server, auth_token, client;
1213     char realm[MAXKTCREALMLEN];
1214
1215     struct ktc_token token, *pToken;
1216     int i, acode, code = 0;
1217
1218     {   char *ws  = strrchr (as->a0name, '/');
1219         if (ws) ws++;                   /* skip everything before the "/" */
1220         else ws = as->a0name;
1221         if (strlen(ws) > 0) {
1222             strncpy (whoami, ws, sizeof(whoami));
1223             if (strlen (whoami)+1 >= sizeof(whoami)) strcpy (whoami, "kas:");
1224             else strcat (whoami, ":");
1225         } else whoami[0] = 0;
1226         /* append sub-command name */
1227         strncat (whoami, as->name, sizeof(whoami) - strlen(whoami) -1);
1228     }
1229
1230     if (as->parms[12].name == 0) return 0;
1231
1232     assert (as->parms[13].name && as->parms[14].name &&
1233             as->parms[15].name && as->parms[16].name);
1234
1235     /* MyAfterProc() destroys the conn, but just to be sure */
1236     if (conn) {
1237        code = ubik_ClientDestroy (conn);
1238        conn = 0;
1239     }
1240
1241     if (!init || as->parms[12].items || as->parms[13].items ||
1242                  as->parms[14].items || as->parms[15].items ||
1243                  as->parms[16].items) {
1244        strcpy (instance, "");
1245        strcpy (newCell,  "");
1246
1247        if (as->parms[12].items) {                     /* -admin_username */
1248           code = ka_ParseLoginName (as->parms[12].items->data, name, instance, newCell);
1249           if (code) {
1250              com_err (whoami, code, "parsing user's name '%s'", as->parms[12].items->data);
1251              return code;
1252           }
1253        } else {
1254 #ifdef AFS_NT40_ENV
1255           DWORD len = MAXKTCNAMELEN;
1256           if (!GetUserName((LPTSTR)name, &len)) {
1257              printf("Can't get user name \n");
1258              return KABADCMD;
1259           }
1260 #else
1261           /* No explicit name provided: use Unix uid. */
1262           pw = getpwuid(getuid());
1263           if (pw == 0) {
1264              printf ("Can't figure out your name from your user id.\n");
1265              return KABADCMD;
1266           }
1267           strncpy (name, pw->pw_name, sizeof(name));
1268 #endif
1269        }
1270
1271        if (as->parms[14].items) {                     /* -cell */
1272           if (strlen(newCell) > 0) {
1273              printf ("Duplicate cell specification not allowed\n");
1274           } else {
1275              strncpy (newCell, as->parms[14].items->data, sizeof(newCell));
1276           }
1277        }
1278        code = ka_ExpandCell (newCell, newCell, 0/*local*/);
1279        if (code) {
1280           com_err (whoami, code, "Can't expand cell name");
1281           return code;
1282        }
1283        strcpy (cell, newCell);
1284
1285        if (as->parms[15].items) {                   /* -servers */
1286           struct cmd_item *ip;
1287           char *ap[MAXSERVERS+2];
1288
1289           ap[0] = "";
1290           ap[1] = "-servers";
1291           for (ip = as->parms[15].items, i=2; ip; ip=ip->next, i++)
1292             ap[i] = ip->data;
1293           code = ubik_ParseClientList(i, ap, serverList);
1294           if (code) {
1295              com_err (whoami, code, "could not parse server list");
1296              return code;
1297           }
1298           ka_ExplicitCell (cell, serverList);
1299        }
1300
1301        noauth = (as->parms[16].items ? 1 : 0);       /* -noauth */
1302
1303        init = 1;
1304     }
1305
1306     token.ticketLen = 0;                /* in case there are no tokens */
1307     if (!noauth) {                      /* Will prompt for a password */
1308        /* first see if there's already an admin ticket */
1309        code = ka_GetAdminToken (0, 0, cell, 0, KA_SIXHOURS, &token, 0/* !new */);
1310        if (code) {                      /* if not then get key and try again */
1311           if (as->parms[13].items) { /* if password specified */
1312              strncpy (passwd, as->parms[13].items->data, sizeof(passwd));
1313              bzero (as->parms[13].items->data, strlen (as->parms[13].items->data));
1314           } else {
1315              char msg[MAXKTCNAMELEN+50];
1316              if (as->parms[12].items) sprintf (msg, "Administrator's (%s) Password: ", name);
1317              else sprintf (msg, "Password for %s: ", name);
1318              code = read_pw_string (passwd, sizeof(passwd), msg, 0);
1319              if (code) code = KAREADPW;
1320              else if (strlen(passwd) == 0) code = KANULLPASSWORD;
1321              if (code) {
1322                 com_err (whoami, code, "reading password");
1323                 return code;
1324              }
1325           }
1326           ka_StringToKey (passwd, cell, &key);
1327           code = ka_GetAdminToken (name, instance, cell, &key, KA_SIXHOURS,
1328                                    &token, 0/* !new */);
1329           if ((code == KABADREQUEST) && (strlen(passwd) > 8)) {
1330              /* try with only the first 8 characters incase they set
1331               * their password with an old style passwd program. */
1332              passwd[8] = 0;
1333              ka_StringToKey (passwd, cell, &key);
1334              code = ka_GetAdminToken (name, instance, cell, &key,
1335                                       KA_SIXHOURS, &token, 0/* !new */);
1336              if (code == 0) {
1337                 fprintf (stderr, "Warning: you have typed a password longer than 8 characters, but only the\n");
1338                 fprintf (stderr, "first 8 characters were actually significant.  If you change your password\n");
1339                 fprintf (stderr, "again this warning message will go away.\n");
1340              }
1341           }
1342           if (code) {
1343              char *reason;
1344              switch (code) {
1345                 case KABADREQUEST:
1346                    reason = "password was incorrect";
1347                    break;
1348                  case KAUBIKCALL:
1349                    reason = "Authentication Server was unavailable";
1350                    break;
1351                  default:
1352                    reason = (char *)error_message (code);
1353              }
1354              fprintf (stderr, "%s: Auth. as %s to AuthServer failed: %s\nProceeding w/o authentication\n",
1355                       whoami, PrintedName(name,instance,cell), reason);
1356           }
1357           /* get an Authentication token while were at it. */
1358           if (ka_CellToRealm(cell, realm, 0) != 0) realm[0] = '\0';
1359           strcpy(auth_server.name, KA_TGS_NAME);
1360           strcpy(auth_server.instance, realm);
1361           strcpy(auth_server.cell, cell);
1362           if (ktc_GetToken(&auth_server, &auth_token, sizeof(struct ktc_token), &client) != 0) {
1363              acode = ka_GetAuthToken (name, instance, cell, &key,
1364                                       MAXKTCTICKETLIFETIME,
1365                                       (afs_int32 *)0 /*Don't need pwd expiration info here*/);
1366              if (acode && (acode != code)) /* codes are usually the same */
1367                com_err (whoami, code,
1368                         "getting Authentication token for %s",
1369                         PrintedName (name, instance, cell));
1370           }
1371           bzero (&key, sizeof(key));
1372        }
1373     }
1374
1375     pToken = ((token.ticketLen == 0) ? 0 : &token);
1376     code = ka_AuthServerConn (cell, KA_MAINTENANCE_SERVICE, pToken, &conn);
1377     if (code && pToken) {
1378        com_err (whoami, code,
1379                 "connecting to AuthServer: now trying w/o authentication");
1380        code = ka_AuthServerConn (cell, KA_MAINTENANCE_SERVICE, 0, &conn);
1381        if (code) com_err (whoami, code, "making unauthenticated connection to AuthServer");
1382     }
1383     if (code) {
1384        com_err (whoami, code, "Couldn't establish connection to Authentication Server");
1385        return code;
1386     }
1387
1388     /* now default unspecified password by prompting from terminal */
1389     if (as->nParms >= 12) for (i=0; i<12; i++)
1390         if (as->parms[i].name && (as->parms[i].items == 0)) {
1391             char *p = as->parms[i].name; /* parameter name */
1392             int l = strlen (p);         /* length of name */
1393             /* does parameter end in "password"  */
1394             if (strcmp (p+(l-8), "password") == 0) {
1395                 char msg[32];
1396                 char password[BUFSIZ];
1397                 struct cmd_item *ip;
1398
1399                 strcpy (msg, p+1);
1400                 strcat (msg, ": ");
1401                 code = read_pw_string (password, sizeof(password), msg, 1);
1402                 if (code) code = KAREADPW;
1403                 else if (strlen(password) == 0) code = KANULLPASSWORD;
1404                 if (code) {
1405                     com_err (whoami, code, "prompting for %s", p+1);
1406                     return code;
1407                 }
1408                 ip = (struct cmd_item *)malloc (sizeof(struct cmd_item));
1409                 ip->data = (char *)malloc (strlen(password)+1);
1410                 ip->next = 0;
1411                 strcpy (ip->data, password);
1412                 as->parms[i].items = ip;
1413             }
1414         }
1415     if (!conn) {                        /* if all else fails... */
1416         code = NoAuth (0,0);            /* get unauthenticated conn */
1417         if (code) return code;
1418     }
1419     return 0;
1420 }
1421
1422 /* These are some helpful command that deal with the cache managers tokens. */
1423
1424 static ForgetTicket (
1425   struct cmd_syndesc *as,  
1426   char *arock)
1427 {
1428     afs_int32 code;
1429     struct ktc_principal server;
1430
1431 #ifdef notdef
1432     if (as->parms[0].items) {
1433         char *name = as->parms[0].items->data;
1434         code = ka_ParseLoginName
1435             (name, server.name, server.instance, server.cell);
1436         if (code) {
1437             com_err (whoami, code, "couldn't interpret name '%s'", name);
1438             return code;
1439         }
1440         if (server.cell[0] == 0) {
1441             if (code = DefaultCell()) return code;
1442             strcpy (server.cell, cell);
1443         } else {
1444             code = ka_ExpandCell (server.cell, server.cell, 0/*local*/);
1445             if (code) {
1446                 com_err (whoami, code, "Can't expand cell name");
1447                 return code;
1448             }
1449         }
1450         code = ktc_ForgetToken (&server);
1451         if (code) {
1452             com_err (whoami, code, "couldn't remove tokens for %s",
1453                      PrintedPrincipal (&server));
1454             return code;
1455         }
1456     }
1457     else {
1458         if (!as->parms[1].items) {
1459             fprintf (stderr, "Must specify server name or -all\n");
1460             return KABADCMD;
1461         }
1462         code = ktc_ForgetAllTokens();
1463         if (code) {
1464             com_err (whoami, code, "couldn't delete all tokens");
1465             return code;
1466         }
1467     }
1468 #endif
1469     code = ktc_ForgetAllTokens();
1470     if (code) {
1471        com_err (whoami, code, "couldn't delete all tokens");
1472        return code;
1473     }
1474     return 0;
1475 }
1476
1477 static ListTickets (
1478   struct cmd_syndesc *as,
1479   char *arock)
1480 {
1481     afs_int32 code=0;
1482     int   index, newIndex;
1483     struct ktc_principal server;
1484     int  verbose = 0;
1485
1486     if (as->parms[1].items) verbose = 1;
1487     if (as->parms[0].items) {
1488         char *name = as->parms[0].items->data;
1489         code = ka_ParseLoginName
1490             (name, server.name, server.instance, server.cell);
1491         if (code) {
1492             com_err (whoami, code, "couldn't interpret name '%s'", name);
1493             return code;
1494         }
1495         if (server.cell[0] == 0) {
1496             if (code = DefaultCell()) return code;
1497             strcpy (server.cell, cell);
1498         } else {
1499             code = ka_ExpandCell (server.cell, server.cell, 0/*local*/);
1500             if (code) {
1501                 com_err (whoami, code, "Can't expand cell name");
1502                 return code;
1503             }
1504         }
1505         code = ListTicket (&server, verbose);
1506     }
1507     else for (index = 0; ; index = newIndex) {
1508         code = ktc_ListTokens(index, &newIndex, &server);
1509         if (code) {
1510             if (code == KTC_NOENT) code = 0;   /* end of list */
1511             break;
1512         }
1513         code = ListTicket(&server, verbose);
1514     }
1515     return code;
1516 }
1517
1518 static void add_std_args (register struct cmd_syndesc *ts)
1519 {
1520     cmd_Seek(ts, 12);
1521     /* 12 */ cmd_AddParm (ts, "-admin_username", CMD_SINGLE, CMD_OPTIONAL,
1522                           "admin principal to use for authentication");
1523     /* 13 */ cmd_AddParm (ts, "-password_for_admin", CMD_SINGLE, CMD_OPTIONAL,
1524                           "admin password");
1525     /* 14 */ cmd_AddParm (ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
1526     /* 15 */ cmd_AddParm (ts, "-servers", CMD_LIST, CMD_OPTIONAL,
1527                           "explicit list of authentication servers");
1528     /* 16 */ cmd_AddParm (ts, "-noauth", CMD_FLAG, CMD_OPTIONAL,
1529                           "don't authenticate");
1530 }
1531
1532 afs_int32 ka_AdminInteractive (
1533   int   cmd_argc,
1534   char *cmd_argv[])
1535 {
1536     register int   code;
1537     register struct cmd_syndesc *ts;
1538
1539     char  line[BUFSIZ];
1540     afs_int32 argc;
1541     char *argv[32];
1542
1543     strncpy(myName, *cmd_argv, 509);
1544
1545     cmd_SetBeforeProc(MyBeforeProc,  (char *) 0);
1546     cmd_SetAfterProc(MyAfterProc, (char *) 0);
1547
1548     ts = cmd_CreateSyntax ("interactive", Interactive, 0, "enter interactive mode");
1549     add_std_args (ts);
1550
1551     ts = cmd_CreateSyntax ("noauthentication", NoAuth, 0, "connect to AuthServer w/o using token");
1552
1553     ts = cmd_CreateSyntax ("list", ListUsers, 0, "list all users in database");
1554     cmd_AddParm (ts, "-long", CMD_FLAG, CMD_OPTIONAL, "show detailed info about each user");
1555     cmd_AddParm (ts, "-showadmin", CMD_FLAG, CMD_OPTIONAL, "show all cell administrators");
1556     cmd_AddParm (ts, "-showkey", CMD_FLAG, CMD_OPTIONAL, "show the user's actual key rather than the checksum");
1557     add_std_args (ts);
1558     cmd_CreateAlias (ts, "ls");
1559
1560     ts = cmd_CreateSyntax ("examine", ExamineUser, 0, "examine the entry for a user");
1561     cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of user");
1562     cmd_AddParm (ts, "-showkey", CMD_FLAG, CMD_OPTIONAL, "show the user's actual key rather than the checksum");
1563     add_std_args (ts);
1564
1565     ts = cmd_CreateSyntax ("create", CreateUser, 0, "create an entry for a user");
1566     cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of user");
1567     cmd_AddParm (ts, "-initial_password", CMD_SINGLE, CMD_OPTIONAL, "initial password");
1568     add_std_args (ts);
1569
1570     ts = cmd_CreateSyntax ("delete", DeleteUser, 0, "delete a user");
1571     cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of user");
1572     add_std_args (ts);
1573     cmd_CreateAlias (ts, "rm");
1574
1575     ts = cmd_CreateSyntax ("setfields", SetFields, 0, "set various fields in a user's entry");
1576     cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of user");
1577     cmd_AddParm (ts, "-flags", CMD_SINGLE, CMD_OPTIONAL, "hex flag value or flag name expression");
1578     cmd_AddParm (ts, "-expiration", CMD_SINGLE, CMD_OPTIONAL, "date of account expiration");
1579     cmd_AddParm (ts, "-lifetime", CMD_SINGLE, CMD_OPTIONAL, "maximum ticket lifetime");
1580     cmd_AddParm (ts, "-pwexpires", CMD_SINGLE, CMD_OPTIONAL, "number days password is valid ([0..254])");
1581     cmd_AddParm (ts, "-reuse", CMD_SINGLE, CMD_OPTIONAL, "permit password reuse (yes/no)");
1582     cmd_AddParm (ts, "-attempts", CMD_SINGLE, CMD_OPTIONAL, "maximum successive failed login tries ([0..254])");
1583     cmd_AddParm (ts, "-locktime", CMD_SINGLE, CMD_OPTIONAL, "failure penalty [hh:mm or minutes]");
1584 #if ASSOCIATES
1585     cmd_AddParm (ts, "-associates", CMD_SINGLE, CMD_OPTIONAL, "maximum associate instances");
1586 #endif
1587     add_std_args (ts);
1588     cmd_CreateAlias (ts, "sf");
1589
1590
1591     ts = cmd_CreateSyntax ("unlock", Unlock, 0, "Enable authentication ID after max failed attempts exceeded");
1592     cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "authentication ID");
1593     add_std_args (ts);
1594
1595
1596     ts = cmd_CreateSyntax ("stringtokey", StringToKey, 0, "convert a string to a key");
1597     cmd_AddParm (ts, "-string", CMD_SINGLE, 0, "password string");
1598     cmd_AddParm (ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
1599
1600     ts = cmd_CreateSyntax ("setpassword", SetPassword, 0, "set a user's password");
1601     cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of user");
1602     cmd_AddParm (ts, "-new_password", CMD_SINGLE, CMD_OPTIONAL, "new password");
1603     cmd_Seek(ts, 3);
1604     cmd_AddParm (ts, "-kvno", CMD_SINGLE, CMD_OPTIONAL, "key version number");
1605     add_std_args (ts);
1606     cmd_CreateAlias (ts, "sp");
1607 #ifdef CMD_PARSER_AMBIG_FIX
1608     cmd_CreateAlias (ts, "setpasswd");
1609 #endif
1610
1611     /* set a user's key */
1612     ts = cmd_CreateSyntax ("setkey", SetPassword, 0, (char *) CMD_HIDDEN);
1613     cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of user");
1614     cmd_Seek(ts, 2);
1615     cmd_AddParm (ts, "-new_key", CMD_SINGLE, 0, "eight byte new key");
1616     cmd_Seek(ts, 3);
1617     cmd_AddParm (ts, "-kvno", CMD_SINGLE, CMD_OPTIONAL, "key version number");
1618     add_std_args (ts);
1619
1620     /* get a user's password */
1621     ts = cmd_CreateSyntax ("getpassword", GetPassword, 0, (char *) CMD_HIDDEN);
1622     cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of user");
1623     /* don't take standard args */
1624     /* add_std_args (ts); */
1625 #ifdef CMD_PARSER_AMBIG_FIX
1626     cmd_CreateAlias (ts, "getpasswd");
1627 #endif
1628
1629     /* get a random key */
1630     ts = cmd_CreateSyntax ("getrandomkey", GetRandomKey, 0, (char *) CMD_HIDDEN);
1631     add_std_args (ts);
1632
1633     /* get a ticket for a specific server */
1634     ts = cmd_CreateSyntax ("getticket", GetTicket, 0, (char *) CMD_HIDDEN);
1635     cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of server");
1636     cmd_AddParm (ts, "-lifetime", CMD_SINGLE, CMD_OPTIONAL, "ticket lifetime");
1637     add_std_args (ts);
1638
1639     ts = cmd_CreateSyntax ("statistics", Statistics, 0, "show statistics for AuthServer");
1640     add_std_args (ts);
1641
1642     /* show debugging info from AuthServer */
1643     ts = cmd_CreateSyntax ("debuginfo", DebugInfo, 0, (char *) CMD_HIDDEN);
1644     cmd_AddParm (ts, "-hostname", CMD_SINGLE, CMD_OPTIONAL, "authentication server host name");
1645     add_std_args (ts);
1646
1647     ts = cmd_CreateSyntax ("forgetticket", ForgetTicket, 0, "delete user's tickets");
1648 #ifdef notdef
1649     cmd_AddParm (ts, "-name", CMD_SINGLE, (CMD_OPTIONAL | CMD_HIDE), "name of server");
1650 #endif
1651     cmd_AddParm (ts, "-all", CMD_FLAG, CMD_OPTIONAL, "delete all tickets");
1652
1653     ts = cmd_CreateSyntax ("listtickets", ListTickets, 0, "show all cache manager tickets");
1654     cmd_AddParm (ts, "-name", CMD_SINGLE, CMD_OPTIONAL, "name of server");
1655     cmd_AddParm (ts, "-long", CMD_FLAG, CMD_OPTIONAL, "show session key and ticket");
1656
1657     ts = cmd_CreateSyntax ("quit", Quit, 0, "exit program");
1658
1659     finished = 1;
1660     conn = 0;                           /* no connection yet */
1661     zero_argc = cmd_argc;
1662     zero_argv = cmd_argv;
1663
1664     strcpy (whoami, "kas");
1665
1666     if (code = cmd_Dispatch(cmd_argc, cmd_argv)) {
1667         return code;
1668     }
1669
1670     while (!finished) {
1671         char *s;
1672         int i;
1673
1674         printf("ka> ");
1675         s = fgets (line, sizeof(line), stdin);
1676         if (s == NULL) return 0;        /* EOF on input */
1677         for (i=strlen(line)-1; i>=0 && isspace(line[i]); i--) line[i]=0;
1678         if (i < 0) continue;            /* blank line */
1679
1680         code = cmd_ParseLine (line, argv, &argc, sizeof(argv)/sizeof(argv[0]));
1681         if (code) {
1682             com_err (whoami, code, "parsing line: '%s'", line);
1683             return code;
1684         }
1685         code = cmd_Dispatch (argc, argv);
1686         cmd_FreeArgv (argv);
1687     }
1688     return code;
1689 }