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