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