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