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