linux-s390-kas-setpass-fix-20010515
[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 ((char *)&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 ((char *)&key, sizeof(key));
708     printf ("'.\n");
709
710     des_string_to_key (as->parms[0].items->data, &key);
711       
712     printf ("Converting %s with the DES string to key yields key='",
713             as->parms[0].items->data);
714     ka_PrintBytes (&key, sizeof(key));
715     printf ("'.\n");
716
717     return 0;
718 }
719
720 int SetPassword (
721   struct cmd_syndesc *as,
722   char *arock)
723 {
724     int code;
725     char name[MAXKTCNAMELEN];
726     char instance[MAXKTCNAMELEN];
727     char realm[MAXKTCREALMLEN];
728     struct ktc_encryptionKey key;
729     afs_int32 kvno = 0;
730
731     code = ka_ParseLoginName (as->parms[0].items->data, name, instance, realm);
732     if (code) {
733         com_err (whoami, code, "parsing user's name '%s'",
734                  as->parms[0].items->data);
735         return KABADCMD;
736     }
737     
738     if (strlen(realm) == 0) 
739       ucstring (realm, cell, sizeof(realm));
740
741     if (as->parms[1].items && as->parms[2].items) {
742         printf ("Can't specify both a password and a key\n");
743         return KABADCMD;
744       } 
745     else if (as->parms[1].items) {
746       (void) init_child(myName);
747       (void) give_to_child(passwd);  /* old password */
748       code = password_bad(as->parms[1].items->data);
749       (void) terminate_child();
750       if (code)
751         return KABADCMD;
752       ka_StringToKey (as->parms[1].items->data, realm, &key);
753     } 
754     else if (as->parms[2].items) {
755       if (ka_ReadBytes (as->parms[2].items->data, (char *)&key, sizeof(key))
756           != 8) {
757         printf ("Key must be 8 bytes: '%s' was too long\n",
758                 as->parms[2].items->data);
759         return KABADCMD;
760       }
761     } 
762     else {
763         printf ("Must specify new password or key\n");
764         return KABADCMD;
765     }
766
767
768     if (as->parms[3].items) 
769       sscanf (as->parms[3].items->data, "%d", &kvno);
770
771 #ifdef AFS_S390_LINUX20_ENV
772     code = ubik_Call (KAM_SetPassword, conn, 0, name, instance, kvno, 0, key);
773 #else
774     code = ubik_Call (KAM_SetPassword, conn, 0, name, instance, kvno, key);
775 #endif
776     if (code) com_err (whoami, code,
777                        "so can't set password for %s.%s", name, instance);
778     return code;
779 }
780
781 #define PrintPrincipal(p,n,l) \
782     PrintName((p)->name, (p)->instance, (p)->cell, l, n)
783
784 static afs_int32 PrintName (
785   char *name,
786   char *inst,
787   char *acell,
788   int buflen,
789   char *buf)
790 {
791     int nlen, len;
792     int left;                           /* if ConvertBytes stops early */
793     afs_int32 code;
794
795     if (name == 0) name = "";
796     if (inst == 0) inst = "";
797     if (acell == 0) acell = "";
798     left = ka_ConvertBytes(buf, buflen, name, strlen(name));
799     if (left) {
800       bad_name:
801         code = KABADNAME;
802         com_err (whoami, code,
803                  "PrintName: principal name was '%s'.'%s'@'%s'",
804                  name, inst, acell);
805         return code;
806     }
807     nlen = strlen (buf);
808     len = strlen(inst);
809     if (len) {
810         if (nlen + len + 1 >= buflen) goto bad_name;
811         buf[nlen++] = '.';
812         left = ka_ConvertBytes(buf+nlen, buflen-nlen, inst, len);
813         if (left) goto bad_name;
814         nlen += len;
815     }
816
817     len = strlen(acell);
818     if (len) {
819         char *lcell = ka_LocalCell();
820         if (lcell == 0) lcell = "";
821         if (strcmp (acell, lcell) != 0) {
822             /* only append cell if not the local cell */
823             if (nlen + len + 1 >= buflen) goto bad_name;
824             buf[nlen++] = '@';
825             left = ka_ConvertBytes(buf+nlen, buflen-nlen, acell, len);
826             if (left) goto bad_name;
827             nlen += len;
828         }
829     }
830     return 0;
831 }
832
833 #define PrintedPrincipal(p) PrintedName ((p)->name, (p)->instance, (p)->cell)
834
835 /* PrintedName - returned a pointer to a static string in which the formated
836  * name has been stored. */
837
838 static char *PrintedName (
839   char *name,
840   char *inst,
841   char *cell)
842 {
843     static char printedName[128];
844     afs_int32 code;
845     code = PrintName (name, inst, cell, sizeof(printedName), printedName);
846     if (code) {
847         if (name == 0) name = "";
848         strncpy (printedName, name, sizeof(printedName));
849         printedName[sizeof(printedName)-8] = 0;
850         strcat (printedName, "<error>");
851     }
852     return printedName;
853 }
854
855 static afs_int32 ListTicket (
856   struct ktc_principal *server,
857   int verbose)
858 {
859     afs_int32 code;
860     struct ktc_token token;             /* the token we're printing */
861     struct ktc_principal client;
862     char  UserName[sizeof(struct ktc_principal)];
863     char  ServerName[sizeof(struct ktc_principal)];
864     afs_int32  now = time(0);
865     char bob[KA_TIMESTR_LEN];
866
867     /* get the ticket info itself */
868     code = ktc_GetToken (server, &token, sizeof(token), &client);
869     if (code) {
870         com_err (whoami, code, "failed to get token info for server %s",
871                  PrintedPrincipal (server));
872         return code;
873     }
874     code = PrintPrincipal (&client, UserName, sizeof(UserName));
875     if (code) return code;
876     /* spaces are printed as "\040" */
877     if (UserName[0] == 0)
878         printf("Tokens");
879     else if (strncmp(UserName, "AFS\\040ID\\040", 13) == 0) {
880         printf("User's (AFS ID %s) tokens", UserName+13);
881     }
882     else if (strncmp(UserName, "Unix\\040UID\\040", 15) == 0) {
883         printf("Tokens");
884     }
885     else
886         printf("User %s's tokens", UserName);
887     
888     code = PrintPrincipal (server, ServerName, sizeof(ServerName));
889     if (code) return code;
890     printf(" for %s ", ServerName);
891     
892     if (token.startTime > now) {
893         ka_timestr(token.startTime,bob,KA_TIMESTR_LEN);
894         printf("[>> POSTDATED 'till %s <<]",bob);
895     }
896
897    if (token.endTime <= now)
898         printf("[>> Expired <<]\n");
899     else {
900         ka_timestr(token.endTime,bob,KA_TIMESTR_LEN);
901         printf("[Expires %s]\n", bob);
902     }
903     if (verbose) {
904         printf ("SessionKey: ");
905         ka_PrintBytes ((char *)&token.sessionKey, sizeof(token.sessionKey));
906         printf ("\nTicket (kvno = %d, len = %d): ", token.kvno, 
907                 token.ticketLen);
908         ka_PrintBytes ((char *)token.ticket, token.ticketLen);
909         printf ("\n");
910     }
911     return 0;
912 }
913
914 static GetTicket (
915   struct cmd_syndesc *as,  
916   char *arock)
917 {
918     int code;
919     struct ktc_principal server;
920     struct ktc_token token;
921     afs_int32 life = KA_SIXHOURS;
922
923     if (as->parms[1].items) {
924         code = read_time_interval (as->parms[1].items->data, &life);
925         if (code) return KABADCMD;
926     }
927     code = ka_ParseLoginName (as->parms[0].items->data,
928                               server.name, server.instance, server.cell);
929     if (code) {
930         com_err (whoami, code, "parsing user's name '%s'",
931                  as->parms[0].items->data);
932         return KABADCMD;
933     }
934     if (server.cell[0] == 0) {
935         if (code = DefaultCell()) return code;
936         strcpy (server.cell, cell);
937     } else {
938         code = ka_ExpandCell (server.cell, server.cell, 0/*local*/);
939         if (code) {
940             com_err (whoami, code, "Can't expand cell name");
941             return code;
942         }
943     }
944
945     token.ticketLen = 0;                /* in case there are no tokens */
946     code = ka_GetServerToken (server.name, server.instance, server.cell,
947                               life, &token, /*new*/1, /*dosetpag*/0);
948     if (code) com_err (whoami, code,
949                        "getting ticket for %s", PrintedPrincipal (&server));
950     else {
951         code = ListTicket (&server, /*verbose*/1);
952     }
953     return code;
954 }
955
956 static GetPassword (
957   struct cmd_syndesc *as,
958   char *arock)
959 {
960     int code;
961     char name[MAXKTCNAMELEN];
962     struct ktc_encryptionKey key;
963     static struct ubik_client *lpbkConn = 0;
964
965      /* no instance allowed */
966     code = ka_ParseLoginName (as->parms[0].items->data, name, 0, 0);
967     if (code) {
968       abort:
969         com_err (whoami, code,
970                  "getting %s's password via loopback connection to GetPassword", name);
971         /* if we got a timeout, print a clarification, too */
972         if (code == -1) {
973             fprintf(stderr, "%s: please note that this command must be run locally on a database server machine.\n", whoami);
974         }
975         return code;
976     }
977     if (lpbkConn == 0) {
978         struct rx_connection    *conns[2];
979         struct rx_securityClass *sc;
980         int                      si;    /* security class index */
981
982         code = rx_Init(0);
983         if (code) goto abort;
984         sc = (struct rx_securityClass *) rxnull_NewClientSecurityObject();
985         si = RX_SCINDEX_NULL;
986         conns[0] = rx_NewConnection (htonl(INADDR_LOOPBACK), htons(AFSCONF_KAUTHPORT),
987                                      KA_MAINTENANCE_SERVICE, sc, si);
988         conns[1] = 0;
989         code = ubik_ClientInit(conns, &lpbkConn);
990         if (code) goto abort;
991     }
992     code = ubik_Call (KAM_GetPassword, lpbkConn, 0, name, &key);
993     /* Lets close down the ubik_Client connection now */
994     ubik_ClientDestroy(lpbkConn);
995     if (code) goto abort;
996     printf ("Key: ");
997     ka_PrintBytes ((char *)&key, sizeof(key));
998     printf ("\n");
999     return code;
1000 }
1001
1002 int GetRandomKey (
1003   struct cmd_syndesc *as,
1004   char *arock)
1005 {
1006     int code;
1007     struct ktc_encryptionKey key;
1008
1009     code = ubik_Call (KAM_GetRandomKey, conn, 0, &key);
1010     if (code) com_err(whoami, code, "so can't get random key");
1011     else {
1012         int i;
1013         printf ("Key: ");
1014         ka_PrintBytes ((char *)&key, sizeof(key));
1015         printf (" (");
1016         for (i=0; i<sizeof(key); i++) {
1017             printf ("%0.2x", ((char *)&key)[i] & 0xff);
1018             if (i==3) printf (" ");
1019             else if (i!=7) printf (".");
1020         }
1021         printf (")\n");
1022     }
1023     return code;
1024 }
1025
1026 int Statistics (
1027   struct cmd_syndesc *as,
1028   char *arock)
1029 {
1030     int code;
1031     kasstats statics;
1032     kadstats dynamics;
1033     afs_int32     admins;
1034     char bob[KA_TIMESTR_LEN];
1035
1036     code = ubik_Call (KAM_GetStats, conn, 0,
1037                       KAMAJORVERSION, &admins, &statics, &dynamics);
1038     if (code) {
1039         printf ("call to GetStats failed: %s\n", ka_ErrorString(code));
1040         return code;
1041     }
1042     if (statics.minor_version != KAMINORVERSION)
1043         printf ("Minor version number mismatch: got %d, expected %d\n",
1044                 statics.minor_version, KAMINORVERSION);
1045     printf ("%d allocs, %d frees, %d password changes\n",
1046             statics.allocs, statics.frees, statics.cpws);
1047     printf ("Hash table utilization = %f%%\n",
1048             (double)dynamics.hashTableUtilization / 100.0);
1049     ka_timestr(dynamics.start_time,bob,KA_TIMESTR_LEN);
1050     printf ("From host %lx started at %s:\n", dynamics.host, bob);
1051
1052 #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)
1053     print_stat (Authenticate);
1054     print_stat (ChangePassword);
1055     print_stat (GetTicket);
1056     print_stat (CreateUser);
1057     print_stat (SetPassword);
1058     print_stat (SetFields);
1059     print_stat (DeleteUser);
1060     print_stat (GetEntry);
1061     print_stat (ListEntry);
1062     print_stat (GetStats);
1063     print_stat (GetPassword);
1064     print_stat (GetRandomKey);
1065     print_stat (Debug);
1066     print_stat (UAuthenticate);
1067     print_stat (UGetTicket);
1068     
1069 #if (KAMAJORVERSION>5)
1070     print cpu stats
1071     printf ("%d string checks\n", dynamics.string_checks);
1072 #else
1073     printf ("Used %.3f seconds of CPU time.\n", dynamics.string_checks/1000.0);
1074 #endif
1075     printf ("%d admin accounts\n", admins);
1076     return 0;
1077 }
1078
1079 int DebugInfo (
1080   struct cmd_syndesc *as,
1081   char *arock)
1082 {
1083     int code;
1084     struct ka_debugInfo info;
1085     int i;
1086     Date start,now;
1087     int timeOffset;
1088     char bob[KA_TIMESTR_LEN];
1089
1090     start = time(0);
1091     if (as->parms[0].items) {
1092         struct ubik_client *iConn;
1093         code = ka_SingleServerConn (cell, as->parms[0].items->data, KA_MAINTENANCE_SERVICE, 0, &iConn);
1094         if (code) {
1095             struct afsconf_cell cellinfo;
1096
1097             com_err (whoami, code, "couldn't find host %s in cell %s",
1098                      as->parms[0].items->data, cell);
1099             code = ka_GetServers (cell, &cellinfo);
1100             if (code) com_err (whoami, code, "getting servers in cell %s", cell);
1101             else {
1102                 printf ("Servers in cell %s, are:\n", cell);
1103                 for (i=0; i<cellinfo.numServers; i++)
1104                     printf ("  %s\n", cellinfo.hostName[i]);
1105             }
1106             return code;
1107         }
1108         code = ubik_Call (KAM_Debug, iConn, 0, KAMAJORVERSION, 0, &info);
1109         ubik_ClientDestroy (iConn);
1110     }
1111     else code = ubik_Call (KAM_Debug, conn, 0, KAMAJORVERSION, 0, &info);
1112
1113     if (code) {
1114         com_err (whoami, code, "call to Debug failed");
1115         return code;
1116     }
1117     now = time(0);
1118
1119     if (info.minorVersion != KAMINORVERSION)
1120         printf ("Minor version number mismatch: got %d, expected %d\n",
1121                 info.minorVersion, KAMINORVERSION);
1122
1123     timeOffset = info.
1124 #if (KAMAJORVERSION>5)
1125         now
1126 #else
1127         reserved1
1128 #endif
1129         - now;
1130     if (timeOffset < 0) timeOffset = -timeOffset;
1131     if (timeOffset > 60) {
1132         printf ("WARNING: Large server client clock skew: %d seconds. Call itself took %d seconds.\n", timeOffset, now-start);
1133     }
1134     ka_timestr(info.startTime,bob,KA_TIMESTR_LEN);
1135     printf ("From host %lx started %sat %s:\n",
1136             info.host, (info.noAuth ? "w/o authorization " : ""),
1137             bob);
1138     ka_timestr (info.lastTrans,bob,KA_TIMESTR_LEN);
1139     printf ("Last trans was %s at %s\n", info.lastOperation, bob);
1140     ka_timestr (info.dbHeaderRead,bob,KA_TIMESTR_LEN);
1141     printf ("Header last read %s.\n", bob);
1142     printf ("db version=%d, keyVersion=%d, key cache version=%d\n",
1143             info.dbVersion, info.dbSpecialKeysVersion, info.kcVersion);
1144     printf ("db ptrs: free %d, eof %d, kvno %d.\n",
1145             info.dbFreePtr, info.dbEofPtr, info.dbKvnoPtr);
1146     ka_timestr (info.nextAutoCPW,bob,KA_TIMESTR_LEN);
1147     printf ("Next autoCPW at %s or in %d updates.\n",
1148             bob, info.updatesRemaining);
1149     if (info.cheader_lock || info.keycache_lock)
1150         printf ("locks: cheader %08lx, keycache %08lx\n",
1151                 info.cheader_lock, info.keycache_lock);
1152     printf ("Last authentication for %s, last admin user was %s\n",
1153             info.lastAuth, info.lastAdmin);
1154     printf ("Last TGS op was a %s ticket was for %s\n",
1155             info.lastTGSServer, info.lastTGS);
1156     printf ("Last UDP TGS was a %s ticket for %s.  UDP Authenticate for %s\n",
1157             info.lastUTGSServer, info.lastUTGS, info.lastUAuth);
1158     printf ("key cache size %d, used %d.\n",
1159             info.kcSize, info.kcUsed);
1160     if (info.kcUsed > KADEBUGKCINFOSIZE) {
1161         printf("insufficient room to return all key cache entries!\n");
1162         info.kcUsed = KADEBUGKCINFOSIZE;
1163     }
1164     for (i=0; i<info.kcUsed; i++)
1165         ka_timestr(info.kcInfo[i].used,bob,KA_TIMESTR_LEN);
1166         printf ("%32s %c %2x(%2x) used %s\n",
1167                 info.kcInfo[i].principal, (info.kcInfo[i].primary?'*':' '),
1168                 info.kcInfo[i].kvno, info.kcInfo[i].keycksum,
1169                 bob);
1170     return 0;
1171 }
1172
1173 int Interactive (
1174   struct cmd_syndesc *as,
1175   char *arock)
1176 {
1177     finished = 0;
1178     return 0;
1179 }
1180
1181 int Quit (
1182   struct cmd_syndesc *as,
1183   char *arock)
1184 {
1185     finished = 1;
1186     return 0;
1187 }
1188
1189 int MyAfterProc(
1190   struct cmd_syndesc *as)
1191 {
1192     if (!strcmp(as->name,"help")) return;
1193
1194     /* Determine if we need to destory the ubik connection.
1195      * Closing it avoids resends of packets. 
1196      */
1197     if (conn) {
1198         ubik_ClientDestroy(conn);
1199         conn = 0;
1200     }
1201
1202     return 0;
1203 }
1204
1205 int   init = 0, noauth;
1206 char  name[MAXKTCNAMELEN];
1207 char  instance[MAXKTCNAMELEN];
1208 char  newCell[MAXKTCREALMLEN];
1209 afs_int32 serverList[MAXSERVERS];
1210
1211 int NoAuth (
1212    struct cmd_syndesc *as,
1213    char *arock)
1214 {
1215    noauth = 1;
1216    return 0;
1217 }
1218
1219 static int MyBeforeProc(
1220   struct cmd_syndesc *as,
1221   char *arock)
1222 {
1223     extern struct passwd *getpwuid();
1224     struct passwd *pw;
1225     struct ktc_encryptionKey key;
1226     struct ktc_principal auth_server, auth_token, client;
1227     char realm[MAXKTCREALMLEN];
1228
1229     struct ktc_token token, *pToken;
1230     int i, acode, code = 0;
1231
1232     {   char *ws  = strrchr (as->a0name, '/');
1233         if (ws) ws++;                   /* skip everything before the "/" */
1234         else ws = as->a0name;
1235         if (strlen(ws) > 0) {
1236             strncpy (whoami, ws, sizeof(whoami));
1237             if (strlen (whoami)+1 >= sizeof(whoami)) strcpy (whoami, "kas:");
1238             else strcat (whoami, ":");
1239         } else whoami[0] = 0;
1240         /* append sub-command name */
1241         strncat (whoami, as->name, sizeof(whoami) - strlen(whoami) -1);
1242     }
1243
1244     if (as->parms[12].name == 0) return 0;
1245
1246     assert (as->parms[13].name && as->parms[14].name &&
1247             as->parms[15].name && as->parms[16].name);
1248
1249     /* MyAfterProc() destroys the conn, but just to be sure */
1250     if (conn) {
1251        code = ubik_ClientDestroy (conn);
1252        conn = 0;
1253     }
1254
1255     if (!init || as->parms[12].items || as->parms[13].items ||
1256                  as->parms[14].items || as->parms[15].items ||
1257                  as->parms[16].items) {
1258        strcpy (instance, "");
1259        strcpy (newCell,  "");
1260
1261        if (as->parms[12].items) {                     /* -admin_username */
1262           code = ka_ParseLoginName (as->parms[12].items->data, name, instance, newCell);
1263           if (code) {
1264              com_err (whoami, code, "parsing user's name '%s'", as->parms[12].items->data);
1265              return code;
1266           }
1267        } else {
1268 #ifdef AFS_NT40_ENV
1269           DWORD len = MAXKTCNAMELEN;
1270           if (!GetUserName((LPTSTR)name, &len)) {
1271              printf("Can't get user name \n");
1272              return KABADCMD;
1273           }
1274 #else
1275           /* No explicit name provided: use Unix uid. */
1276           pw = getpwuid(getuid());
1277           if (pw == 0) {
1278              printf ("Can't figure out your name from your user id.\n");
1279              return KABADCMD;
1280           }
1281           strncpy (name, pw->pw_name, sizeof(name));
1282 #endif
1283        }
1284
1285        if (as->parms[14].items) {                     /* -cell */
1286           if (strlen(newCell) > 0) {
1287              printf ("Duplicate cell specification not allowed\n");
1288           } else {
1289              strncpy (newCell, as->parms[14].items->data, sizeof(newCell));
1290           }
1291        }
1292        code = ka_ExpandCell (newCell, newCell, 0/*local*/);
1293        if (code) {
1294           com_err (whoami, code, "Can't expand cell name");
1295           return code;
1296        }
1297        strcpy (cell, newCell);
1298
1299        if (as->parms[15].items) {                   /* -servers */
1300           struct cmd_item *ip;
1301           char *ap[MAXSERVERS+2];
1302
1303           ap[0] = "";
1304           ap[1] = "-servers";
1305           for (ip = as->parms[15].items, i=2; ip; ip=ip->next, i++)
1306             ap[i] = ip->data;
1307           code = ubik_ParseClientList(i, ap, serverList);
1308           if (code) {
1309              com_err (whoami, code, "could not parse server list");
1310              return code;
1311           }
1312           ka_ExplicitCell (cell, serverList);
1313        }
1314
1315        noauth = (as->parms[16].items ? 1 : 0);       /* -noauth */
1316
1317        init = 1;
1318     }
1319
1320     token.ticketLen = 0;                /* in case there are no tokens */
1321     if (!noauth) {                      /* Will prompt for a password */
1322        /* first see if there's already an admin ticket */
1323        code = ka_GetAdminToken (0, 0, cell, 0, KA_SIXHOURS, &token, 0/* !new */);
1324        if (code) {                      /* if not then get key and try again */
1325           if (as->parms[13].items) { /* if password specified */
1326              strncpy (passwd, as->parms[13].items->data, sizeof(passwd));
1327              bzero (as->parms[13].items->data, strlen (as->parms[13].items->data));
1328           } else {
1329              char msg[MAXKTCNAMELEN+50];
1330              if (as->parms[12].items) sprintf (msg, "Administrator's (%s) Password: ", name);
1331              else sprintf (msg, "Password for %s: ", name);
1332              code = read_pw_string (passwd, sizeof(passwd), msg, 0);
1333              if (code) code = KAREADPW;
1334              else if (strlen(passwd) == 0) code = KANULLPASSWORD;
1335              if (code) {
1336                 com_err (whoami, code, "reading password");
1337                 return code;
1338              }
1339           }
1340           ka_StringToKey (passwd, cell, &key);
1341           code = ka_GetAdminToken (name, instance, cell, &key, KA_SIXHOURS,
1342                                    &token, 0/* !new */);
1343           if (code == KABADREQUEST) {
1344               des_string_to_key (passwd, &key);
1345               code = ka_GetAdminToken (name, instance, cell, &key, KA_SIXHOURS,
1346                                        &token, 0/* !new */);
1347           }
1348           if ((code == KABADREQUEST) && (strlen(passwd) > 8)) {
1349              /* try with only the first 8 characters incase they set
1350               * their password with an old style passwd program. */
1351              passwd[8] = 0;
1352              ka_StringToKey (passwd, cell, &key);
1353              code = ka_GetAdminToken (name, instance, cell, &key,
1354                                       KA_SIXHOURS, &token, 0/* !new */);
1355              if (code == 0) {
1356                 fprintf (stderr, "Warning: you have typed a password longer than 8 characters, but only the\n");
1357                 fprintf (stderr, "first 8 characters were actually significant.  If you change your password\n");
1358                 fprintf (stderr, "again this warning message will go away.\n");
1359              }
1360           }
1361           if (code) {
1362              char *reason;
1363              switch (code) {
1364                 case KABADREQUEST:
1365                    reason = "password was incorrect";
1366                    break;
1367                  case KAUBIKCALL:
1368                    reason = "Authentication Server was unavailable";
1369                    break;
1370                  default:
1371                    reason = (char *)error_message (code);
1372              }
1373              fprintf (stderr, "%s: Auth. as %s to AuthServer failed: %s\nProceeding w/o authentication\n",
1374                       whoami, PrintedName(name,instance,cell), reason);
1375           }
1376           /* get an Authentication token while were at it. */
1377           if (ka_CellToRealm(cell, realm, 0) != 0) realm[0] = '\0';
1378           strcpy(auth_server.name, KA_TGS_NAME);
1379           strcpy(auth_server.instance, realm);
1380           strcpy(auth_server.cell, cell);
1381           if (ktc_GetToken(&auth_server, &auth_token, sizeof(struct ktc_token), &client) != 0) {
1382              acode = ka_GetAuthToken (name, instance, cell, &key,
1383                                       MAXKTCTICKETLIFETIME,
1384                                       (afs_int32 *)0 /*Don't need pwd expiration info here*/);
1385              if (acode && (acode != code)) /* codes are usually the same */
1386                com_err (whoami, code,
1387                         "getting Authentication token for %s",
1388                         PrintedName (name, instance, cell));
1389           }
1390           bzero (&key, sizeof(key));
1391        }
1392     }
1393
1394     pToken = ((token.ticketLen == 0) ? 0 : &token);
1395     code = ka_AuthServerConn (cell, KA_MAINTENANCE_SERVICE, pToken, &conn);
1396     if (code && pToken) {
1397        com_err (whoami, code,
1398                 "connecting to AuthServer: now trying w/o authentication");
1399        code = ka_AuthServerConn (cell, KA_MAINTENANCE_SERVICE, 0, &conn);
1400        if (code) com_err (whoami, code, "making unauthenticated connection to AuthServer");
1401     }
1402     if (code) {
1403        com_err (whoami, code, "Couldn't establish connection to Authentication Server");
1404        return code;
1405     }
1406
1407     /* now default unspecified password by prompting from terminal */
1408     if (as->nParms >= 12) for (i=0; i<12; i++)
1409         if (as->parms[i].name && (as->parms[i].items == 0)) {
1410             char *p = as->parms[i].name; /* parameter name */
1411             int l = strlen (p);         /* length of name */
1412             /* does parameter end in "password"  */
1413             if (strcmp (p+(l-8), "password") == 0) {
1414                 char msg[32];
1415                 char password[BUFSIZ];
1416                 struct cmd_item *ip;
1417
1418                 strcpy (msg, p+1);
1419                 strcat (msg, ": ");
1420                 code = read_pw_string (password, sizeof(password), msg, 1);
1421                 if (code) code = KAREADPW;
1422                 else if (strlen(password) == 0) code = KANULLPASSWORD;
1423                 if (code) {
1424                     com_err (whoami, code, "prompting for %s", p+1);
1425                     return code;
1426                 }
1427                 ip = (struct cmd_item *)malloc (sizeof(struct cmd_item));
1428                 ip->data = (char *)malloc (strlen(password)+1);
1429                 ip->next = 0;
1430                 strcpy (ip->data, password);
1431                 as->parms[i].items = ip;
1432             }
1433         }
1434     if (!conn) {                        /* if all else fails... */
1435         code = NoAuth (0,0);            /* get unauthenticated conn */
1436         if (code) return code;
1437     }
1438     return 0;
1439 }
1440
1441 /* These are some helpful command that deal with the cache managers tokens. */
1442
1443 static ForgetTicket (
1444   struct cmd_syndesc *as,  
1445   char *arock)
1446 {
1447     afs_int32 code;
1448     struct ktc_principal server;
1449
1450 #ifdef notdef
1451     if (as->parms[0].items) {
1452         char *name = as->parms[0].items->data;
1453         code = ka_ParseLoginName
1454             (name, server.name, server.instance, server.cell);
1455         if (code) {
1456             com_err (whoami, code, "couldn't interpret name '%s'", name);
1457             return code;
1458         }
1459         if (server.cell[0] == 0) {
1460             if (code = DefaultCell()) return code;
1461             strcpy (server.cell, cell);
1462         } else {
1463             code = ka_ExpandCell (server.cell, server.cell, 0/*local*/);
1464             if (code) {
1465                 com_err (whoami, code, "Can't expand cell name");
1466                 return code;
1467             }
1468         }
1469         code = ktc_ForgetToken (&server);
1470         if (code) {
1471             com_err (whoami, code, "couldn't remove tokens for %s",
1472                      PrintedPrincipal (&server));
1473             return code;
1474         }
1475     }
1476     else {
1477         if (!as->parms[1].items) {
1478             fprintf (stderr, "Must specify server name or -all\n");
1479             return KABADCMD;
1480         }
1481         code = ktc_ForgetAllTokens();
1482         if (code) {
1483             com_err (whoami, code, "couldn't delete all tokens");
1484             return code;
1485         }
1486     }
1487 #endif
1488     code = ktc_ForgetAllTokens();
1489     if (code) {
1490        com_err (whoami, code, "couldn't delete all tokens");
1491        return code;
1492     }
1493     return 0;
1494 }
1495
1496 static ListTickets (
1497   struct cmd_syndesc *as,
1498   char *arock)
1499 {
1500     afs_int32 code=0;
1501     int   index, newIndex;
1502     struct ktc_principal server;
1503     int  verbose = 0;
1504
1505     if (as->parms[1].items) verbose = 1;
1506     if (as->parms[0].items) {
1507         char *name = as->parms[0].items->data;
1508         code = ka_ParseLoginName
1509             (name, server.name, server.instance, server.cell);
1510         if (code) {
1511             com_err (whoami, code, "couldn't interpret name '%s'", name);
1512             return code;
1513         }
1514         if (server.cell[0] == 0) {
1515             if (code = DefaultCell()) return code;
1516             strcpy (server.cell, cell);
1517         } else {
1518             code = ka_ExpandCell (server.cell, server.cell, 0/*local*/);
1519             if (code) {
1520                 com_err (whoami, code, "Can't expand cell name");
1521                 return code;
1522             }
1523         }
1524         code = ListTicket (&server, verbose);
1525     }
1526     else for (index = 0; ; index = newIndex) {
1527         code = ktc_ListTokens(index, &newIndex, &server);
1528         if (code) {
1529             if (code == KTC_NOENT) code = 0;   /* end of list */
1530             break;
1531         }
1532         code = ListTicket(&server, verbose);
1533     }
1534     return code;
1535 }
1536
1537 static void add_std_args (register struct cmd_syndesc *ts)
1538 {
1539     cmd_Seek(ts, 12);
1540     /* 12 */ cmd_AddParm (ts, "-admin_username", CMD_SINGLE, CMD_OPTIONAL,
1541                           "admin principal to use for authentication");
1542     /* 13 */ cmd_AddParm (ts, "-password_for_admin", CMD_SINGLE, CMD_OPTIONAL,
1543                           "admin password");
1544     /* 14 */ cmd_AddParm (ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
1545     /* 15 */ cmd_AddParm (ts, "-servers", CMD_LIST, CMD_OPTIONAL,
1546                           "explicit list of authentication servers");
1547     /* 16 */ cmd_AddParm (ts, "-noauth", CMD_FLAG, CMD_OPTIONAL,
1548                           "don't authenticate");
1549 }
1550
1551 afs_int32 ka_AdminInteractive (
1552   int   cmd_argc,
1553   char *cmd_argv[])
1554 {
1555     register int   code;
1556     register struct cmd_syndesc *ts;
1557
1558     char  line[BUFSIZ];
1559     afs_int32 argc;
1560     char *argv[32];
1561
1562     strncpy(myName, *cmd_argv, 509);
1563
1564     cmd_SetBeforeProc(MyBeforeProc,  (char *) 0);
1565     cmd_SetAfterProc(MyAfterProc, (char *) 0);
1566
1567     ts = cmd_CreateSyntax ("interactive", Interactive, 0, "enter interactive mode");
1568     add_std_args (ts);
1569
1570     ts = cmd_CreateSyntax ("noauthentication", NoAuth, 0, "connect to AuthServer w/o using token");
1571
1572     ts = cmd_CreateSyntax ("list", ListUsers, 0, "list all users in database");
1573     cmd_AddParm (ts, "-long", CMD_FLAG, CMD_OPTIONAL, "show detailed info about each user");
1574     cmd_AddParm (ts, "-showadmin", CMD_FLAG, CMD_OPTIONAL, "show all cell administrators");
1575     cmd_AddParm (ts, "-showkey", CMD_FLAG, CMD_OPTIONAL, "show the user's actual key rather than the checksum");
1576     add_std_args (ts);
1577     cmd_CreateAlias (ts, "ls");
1578
1579     ts = cmd_CreateSyntax ("examine", ExamineUser, 0, "examine the entry for a user");
1580     cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of user");
1581     cmd_AddParm (ts, "-showkey", CMD_FLAG, CMD_OPTIONAL, "show the user's actual key rather than the checksum");
1582     add_std_args (ts);
1583
1584     ts = cmd_CreateSyntax ("create", CreateUser, 0, "create an entry for a user");
1585     cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of user");
1586     cmd_AddParm (ts, "-initial_password", CMD_SINGLE, CMD_OPTIONAL, "initial password");
1587     add_std_args (ts);
1588
1589     ts = cmd_CreateSyntax ("delete", DeleteUser, 0, "delete a user");
1590     cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of user");
1591     add_std_args (ts);
1592     cmd_CreateAlias (ts, "rm");
1593
1594     ts = cmd_CreateSyntax ("setfields", SetFields, 0, "set various fields in a user's entry");
1595     cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of user");
1596     cmd_AddParm (ts, "-flags", CMD_SINGLE, CMD_OPTIONAL, "hex flag value or flag name expression");
1597     cmd_AddParm (ts, "-expiration", CMD_SINGLE, CMD_OPTIONAL, "date of account expiration");
1598     cmd_AddParm (ts, "-lifetime", CMD_SINGLE, CMD_OPTIONAL, "maximum ticket lifetime");
1599     cmd_AddParm (ts, "-pwexpires", CMD_SINGLE, CMD_OPTIONAL, "number days password is valid ([0..254])");
1600     cmd_AddParm (ts, "-reuse", CMD_SINGLE, CMD_OPTIONAL, "permit password reuse (yes/no)");
1601     cmd_AddParm (ts, "-attempts", CMD_SINGLE, CMD_OPTIONAL, "maximum successive failed login tries ([0..254])");
1602     cmd_AddParm (ts, "-locktime", CMD_SINGLE, CMD_OPTIONAL, "failure penalty [hh:mm or minutes]");
1603 #if ASSOCIATES
1604     cmd_AddParm (ts, "-associates", CMD_SINGLE, CMD_OPTIONAL, "maximum associate instances");
1605 #endif
1606     add_std_args (ts);
1607     cmd_CreateAlias (ts, "sf");
1608
1609
1610     ts = cmd_CreateSyntax ("unlock", Unlock, 0, "Enable authentication ID after max failed attempts exceeded");
1611     cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "authentication ID");
1612     add_std_args (ts);
1613
1614
1615     ts = cmd_CreateSyntax ("stringtokey", StringToKey, 0, "convert a string to a key");
1616     cmd_AddParm (ts, "-string", CMD_SINGLE, 0, "password string");
1617     cmd_AddParm (ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
1618
1619     ts = cmd_CreateSyntax ("setpassword", SetPassword, 0, "set a user's password");
1620     cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of user");
1621     cmd_AddParm (ts, "-new_password", CMD_SINGLE, CMD_OPTIONAL, "new password");
1622     cmd_Seek(ts, 3);
1623     cmd_AddParm (ts, "-kvno", CMD_SINGLE, CMD_OPTIONAL, "key version number");
1624     add_std_args (ts);
1625     cmd_CreateAlias (ts, "sp");
1626 #ifdef CMD_PARSER_AMBIG_FIX
1627     cmd_CreateAlias (ts, "setpasswd");
1628 #endif
1629
1630     /* set a user's key */
1631     ts = cmd_CreateSyntax ("setkey", SetPassword, 0, (char *) CMD_HIDDEN);
1632     cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of user");
1633     cmd_Seek(ts, 2);
1634     cmd_AddParm (ts, "-new_key", CMD_SINGLE, 0, "eight byte new key");
1635     cmd_Seek(ts, 3);
1636     cmd_AddParm (ts, "-kvno", CMD_SINGLE, CMD_OPTIONAL, "key version number");
1637     add_std_args (ts);
1638
1639     /* get a user's password */
1640     ts = cmd_CreateSyntax ("getpassword", GetPassword, 0, (char *) CMD_HIDDEN);
1641     cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of user");
1642     /* don't take standard args */
1643     /* add_std_args (ts); */
1644 #ifdef CMD_PARSER_AMBIG_FIX
1645     cmd_CreateAlias (ts, "getpasswd");
1646 #endif
1647
1648     /* get a random key */
1649     ts = cmd_CreateSyntax ("getrandomkey", GetRandomKey, 0, (char *) CMD_HIDDEN);
1650     add_std_args (ts);
1651
1652     /* get a ticket for a specific server */
1653     ts = cmd_CreateSyntax ("getticket", GetTicket, 0, (char *) CMD_HIDDEN);
1654     cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of server");
1655     cmd_AddParm (ts, "-lifetime", CMD_SINGLE, CMD_OPTIONAL, "ticket lifetime");
1656     add_std_args (ts);
1657
1658     ts = cmd_CreateSyntax ("statistics", Statistics, 0, "show statistics for AuthServer");
1659     add_std_args (ts);
1660
1661     /* show debugging info from AuthServer */
1662     ts = cmd_CreateSyntax ("debuginfo", DebugInfo, 0, (char *) CMD_HIDDEN);
1663     cmd_AddParm (ts, "-hostname", CMD_SINGLE, CMD_OPTIONAL, "authentication server host name");
1664     add_std_args (ts);
1665
1666     ts = cmd_CreateSyntax ("forgetticket", ForgetTicket, 0, "delete user's tickets");
1667 #ifdef notdef
1668     cmd_AddParm (ts, "-name", CMD_SINGLE, (CMD_OPTIONAL | CMD_HIDE), "name of server");
1669 #endif
1670     cmd_AddParm (ts, "-all", CMD_FLAG, CMD_OPTIONAL, "delete all tickets");
1671
1672     ts = cmd_CreateSyntax ("listtickets", ListTickets, 0, "show all cache manager tickets");
1673     cmd_AddParm (ts, "-name", CMD_SINGLE, CMD_OPTIONAL, "name of server");
1674     cmd_AddParm (ts, "-long", CMD_FLAG, CMD_OPTIONAL, "show session key and ticket");
1675
1676     ts = cmd_CreateSyntax ("quit", Quit, 0, "exit program");
1677
1678     finished = 1;
1679     conn = 0;                           /* no connection yet */
1680     zero_argc = cmd_argc;
1681     zero_argv = cmd_argv;
1682
1683     strcpy (whoami, "kas");
1684
1685     if (code = cmd_Dispatch(cmd_argc, cmd_argv)) {
1686         return code;
1687     }
1688
1689     while (!finished) {
1690         char *s;
1691         int i;
1692
1693         printf("ka> ");
1694         s = fgets (line, sizeof(line), stdin);
1695         if (s == NULL) return 0;        /* EOF on input */
1696         for (i=strlen(line)-1; i>=0 && isspace(line[i]); i--) line[i]=0;
1697         if (i < 0) continue;            /* blank line */
1698
1699         code = cmd_ParseLine (line, argv, &argc, sizeof(argv)/sizeof(argv[0]));
1700         if (code) {
1701             com_err (whoami, code, "parsing line: '%s'", line);
1702             return code;
1703         }
1704         code = cmd_Dispatch (argc, argv);
1705         cmd_FreeArgv (argv);
1706     }
1707     return code;
1708 }