f518eb2d8b9cc70c24b9fba4cba600d55e7c4306
[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 #include <afs/stds.h>
18
19 #include <roken.h>
20 #include <afs/opr.h>
21 #include <afs/opr_assert.h>
22
23 #include <ctype.h>
24
25 #include <hcrypto/des.h>
26 #include <hcrypto/ui.h>
27
28 #include <rx/xdr.h>
29 #include <rx/rx.h>
30 #include <rx/rxkad.h>
31 #include <rx/rxkad_convert.h>
32 #include <lock.h>
33 #define UBIK_LEGACY_CALLITER 1
34 #include <ubik.h>
35 #include <afs/auth.h>
36 #include <afs/cellconfig.h>
37 #include <afs/cmd.h>
38 #include <afs/com_err.h>
39 #include <afs/afsutil.h>
40
41 #include "kauth.h"
42 #include "kauth_internal.h"
43 #include "kautils.h"
44 #include "kaport.h"
45 #include "kkids.h"
46
47 #define CMD_PARSER_AMBIG_FIX 1  /* allow ambiguous aliases */
48
49 #define KA_SIXHOURS     (6*3600)
50
51 static struct ubik_client *conn;
52 static char cell[MAXKTCREALMLEN] = "";
53 static char whoami[32];
54 static char passwd[BUFSIZ];
55 static char myName[510];        /* almost like whoami save with path and without : */
56
57 static int finished;
58 static int zero_argc;
59 static char **zero_argv;
60 afs_uint32 ka_islocked(char *, char *, afs_uint32 *);
61
62 afs_int32
63 DefaultCell(void)
64 {
65     afs_int32 code;
66
67     if (cell[0] != 0)
68         return 0;
69     code = ka_ExpandCell(0, cell, 0 /*local */ );
70     if (code) {
71         afs_com_err(whoami, code, "Can't expand cell name");
72     }
73     return code;
74 }
75
76 /* These are the command operation procedures. */
77
78 int
79 DumpUser(char *user, char *arock, int showadmin, int showkey, char *inst)
80 {
81     char name[MAXKTCNAMELEN];
82     char instance[MAXKTCNAMELEN];
83     Date now = time(0);
84     int code;
85     char bob[KA_TIMESTR_LEN];
86
87     struct kaentryinfo tentry;
88
89     code = ka_ParseLoginName(user, name, instance, 0);
90     if (code) {
91         afs_com_err(whoami, code, "parsing user's name '%s'", user);
92         return KABADCMD;
93     }
94
95     if (!inst)
96         inst = instance;
97     code =
98         ubik_KAM_GetEntry(conn, 0, name, inst, KAMAJORVERSION, &tentry);
99     if (code) {
100         afs_com_err(whoami, code, "getting information for %s.%s", name, inst);
101         return code;
102     }
103     if (tentry.minor_version != KAMINORVERSION)
104         printf("Minor version number mismatch: got %d, expected %d\n",
105                tentry.minor_version, KAMINORVERSION);
106     if (showadmin && !(tentry.flags & KAFADMIN))
107         return 0;
108     ka_PrintUserID("\nUser data for ", name, inst, "");
109     {
110         char *prefix = " (";
111 #define NEWPREFIX "+"
112         if (tentry.flags & KAFADMIN) {
113             printf("%sADMIN", prefix);
114             prefix = NEWPREFIX;
115         }
116         if (tentry.flags & KAFNOTGS) {
117             printf("%sNOTGS", prefix);
118             prefix = NEWPREFIX;
119         }
120         if (tentry.flags & KAFNOCPW) {
121             printf("%sNOCPW", prefix);
122             prefix = NEWPREFIX;
123         }
124         if (tentry.flags & KAFNOSEAL) {
125             printf("%sNOSEAL", prefix);
126             prefix = NEWPREFIX;
127         }
128         if (tentry.flags & KAFNEWASSOC) {
129             printf("%sNEWASSOC", prefix);
130             prefix = NEWPREFIX;
131         }
132         if (tentry.flags & KAFASSOCROOT) {
133             printf("%sASSOCROOT", prefix);
134             prefix = NEWPREFIX;
135         }
136         if (tentry.flags & KAFASSOC) {
137             printf("%sASSOC", prefix);
138             prefix = NEWPREFIX;
139         }
140         if (tentry.user_expiration <= now) {
141             printf("%sexpired", prefix);
142             prefix = NEWPREFIX;
143         }
144         if (strcmp(prefix, NEWPREFIX) == 0)
145             printf(")\n");
146         else
147             printf("\n");
148     }
149     if ((!ka_KeyIsZero((char *)&tentry.key, sizeof(tentry.key))) && (showkey)) {
150         printf("  key (%d):", tentry.key_version);
151         ka_PrintBytes((char *)&tentry.key, sizeof(tentry.key));
152     } else {
153         if (tentry.keyCheckSum == 0)
154             printf("  key version is %d", tentry.key_version);
155         else
156             printf("  key (%d) cksum is %u", tentry.key_version,
157                    tentry.keyCheckSum);
158     }
159     ka_timestr(tentry.change_password_time, bob, KA_TIMESTR_LEN);
160     printf(", last cpw: %s\n", bob);
161     if (!tentry.misc_auth_bytes) {
162         printf("  password will never expire.\n");
163         printf
164             ("  An unlimited number of unsuccessful authentications is permitted.\n");
165     } else {
166         unsigned char misc_stuff[4];
167         afs_uint32 temp;
168
169         temp = tentry.misc_auth_bytes;
170 /*
171       temp = ntohl(tentry.misc_auth_bytes);
172 */
173         unpack_long(temp, misc_stuff);
174
175         if (!misc_stuff[0]) {
176             printf("  password will never expire.\n");
177         } else {
178             ka_timestr((tentry.change_password_time +
179                         misc_stuff[0] * 24 * 60 * 60), bob, KA_TIMESTR_LEN);
180             printf("  password will expire: %s\n", bob);
181         }
182
183         if (!misc_stuff[2])
184             printf
185                 ("  An unlimited number of unsuccessful authentications is permitted.\n");
186         else {
187             printf
188                 ("  %d consecutive unsuccessful authentications are permitted.\n",
189                  misc_stuff[2]);
190
191             if (!misc_stuff[3])
192                 printf("  The lock time for this user is not limited.\n");
193             else
194                 printf("  The lock time for this user is %4.1f minutes.\n",
195                        (float)((unsigned int)misc_stuff[3] << 9) / 60.0);
196
197             if (!(misc_stuff[1] & KA_ISLOCKED)
198                 || !ka_islocked(name, instance, &temp))
199                 printf("  User is not locked.\n");
200             else if (temp == (afs_uint32) (-1L))
201                 printf("  User is locked forever.\n");
202             else {
203                 ka_timestr(temp, bob, KA_TIMESTR_LEN);
204                 printf("  User is locked until %s\n", bob);
205             }
206         }
207
208     }
209     {
210         char exp[KA_TIMESTR_LEN];
211         ka_timestr(tentry.user_expiration, exp, KA_TIMESTR_LEN);
212         if (tentry.user_expiration < now)
213             printf("  DISABLED entry at %s.", exp);
214         else if (tentry.user_expiration == NEVERDATE)
215             printf("  entry never expires.");
216         else
217             printf("  entry expires on %s.", exp);
218     }
219     printf("  Max ticket lifetime %.2f hours.\n",
220            tentry.max_ticket_lifetime / 3600.0);
221     ka_timestr(tentry.modification_time, bob, KA_TIMESTR_LEN);
222     printf("  last mod on %s by ", bob);
223     ka_PrintUserID("", tentry.modification_user.name,
224                    tentry.modification_user.instance, "\n");
225     if ((tentry.reserved3 & 0xffff0000) == 0x12340000) {
226         int short reused = (short)tentry.reserved3;
227         if (!reused) {
228             printf("  permit password reuse\n");
229         } else {
230             printf("  don't permit password reuse\n");
231         }
232     }
233     return 0;
234 }
235
236 int
237 ListUsers(struct cmd_syndesc *as, void *arock)
238 {
239     struct kaident name;
240     afs_int32 index;
241     afs_int32 count;
242     afs_int32 next_index;
243     int code, all = 0, showa = 0;
244     int showkey = (as->parms[2].items != NULL);
245
246     if (as->parms[0].items)
247         all = 1;
248     if (as->parms[1].items) {
249         all = 1;
250         showa = 1;
251     }
252     for (index = 0; 1; index = next_index) {
253         code =
254             ubik_KAM_ListEntry(conn, 0, index, &next_index, &count,
255                       &name);
256         if (code) {
257             afs_com_err(whoami, code, "calling KAM_ListEntry");
258             break;
259         }
260         if (!next_index)
261             break;
262         if (next_index < 0)
263             printf("next_index (%d) is negative: ", next_index);
264         if (strlen(name.name) == 0)
265             printf("name is zero length: ");
266         if (all)
267             DumpUser(name.name, NULL, showa, showkey, name.instance);
268         else
269             ka_PrintUserID("", name.name, name.instance, "\n");
270     }
271     return code;
272 }
273
274
275 int
276 ExamineUser(struct cmd_syndesc *as, void *arock)
277 {
278     int showkey = (as->parms[1].items != NULL);
279     return DumpUser(as->parms[0].items->data, arock, 0, showkey, NULL);
280 }
281
282
283 struct OKerrors {
284     int code;
285     char *msg;
286 };
287
288 int
289 handle_errors(int code,         /* error code to handle */
290               struct OKerrors OKlist[], /* list of errors & messages that should be ignored */
291               int *persist)
292 {                               /* set this if we should retry, clear otherwise */
293     int i;
294
295     for (i = 0; OKlist[i].code; i++) {
296         if (OKlist[i].code == code) {
297             printf("%s\n", OKlist[i].msg);
298             *persist = 0;       /* we're done */
299             return 0;
300         }
301     }
302
303     printf(" : [%s] %s", afs_error_table_name(code), afs_error_message(code));
304     switch (code) {
305     case UNOQUORUM:
306         printf(", wait one second\n");
307         IOMGR_Sleep(1);
308         return 0;
309     case KAEMPTY:
310     case RX_CALL_TIMEOUT:
311         printf(" (retrying)\n");
312         return 0;
313     }
314     printf("\n");
315
316     *persist = 0;               /* don't retry these errors */
317     return code;
318 }
319
320 int
321 CreateUser(struct cmd_syndesc *as, void *arock)
322 {
323     int code;
324     char name[MAXKTCNAMELEN];
325     char instance[MAXKTCNAMELEN];
326     struct ktc_encryptionKey key;
327
328     int persist = 1;
329     struct OKerrors OKlist[2];
330     OKlist[0].code = 0;
331
332     code = ka_ParseLoginName(as->parms[0].items->data, name, instance, 0);
333     if (code) {
334         afs_com_err(whoami, code, "parsing user's name '%s'",
335                 as->parms[0].items->data);
336         return KABADCMD;
337     }
338     ka_StringToKey(as->parms[1].items->data, cell, &key);
339
340     do {
341         code = ubik_KAM_CreateUser(conn, 0, name, instance,
342                                    *ktc_to_EncryptionKey(&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_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", (long unsigned int *) &f);
414         else if (*str == '0')   /* assume octal */
415             sscanf(str, "%lo", (long unsigned int *) &f);
416         else                    /* just assume hex */
417             sscanf(str, "%lx", (long unsigned int *) &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_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, NULL);
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                 && rx_PeerOf(conn->conns[count - 1])) {
559                 server = rx_HostOf(rx_PeerOf(conn->conns[count - 1]));
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     char *end;
583     afs_int32 flags = 0;
584     Date expiration = 0;
585     afs_int32 lifetime = 0;
586     afs_int32 maxAssociates = -1;
587     afs_int32 pwexpiry = 0;
588     afs_int32 was_spare = 0;
589     char misc_auth_bytes[4];
590     int i;
591
592     code = ka_ParseLoginName(as->parms[0].items->data, name, instance, 0);
593     if (code) {
594         afs_com_err(whoami, code, "parsing user's name '%s'",
595                 as->parms[0].items->data);
596         return KABADCMD;
597     }
598
599     if (as->parms[1].items) {
600         code = parse_flags(name, instance, as->parms[1].items->data, &flags);
601         if (code) {
602             printf
603                 ("Illegal flag specification: %s, should be of the form <'='|'+'|'-'|'_'>bitname{<'+'|'-'>bitname}*\n",
604                  as->parms[1].items->data);
605             return KABADCMD;
606         }
607     }
608     if (as->parms[2].items) {
609         char buf[32];
610         char *s = strncpy(buf, as->parms[2].items->data, sizeof(buf));
611         code = ktime_DateToInt32(s, &expiration);
612         if (code) {
613             printf("Illegal time format %s: %s\n", as->parms[2].items->data,
614                    ktime_GetDateUsage());
615             return KABADCMD;
616         }
617         if (expiration == 0) {
618             fprintf(stderr, "Expiration time must be after (about) 1970.\n");
619             return KABADCMD;
620         }
621         if (expiration < time(0)) {
622             fprintf(stderr,
623                     "Warning: expiration being set into the past, account will be disabled.\n");
624         }
625     }
626     /*
627      * TICKET lifetime...
628      */
629     if (as->parms[3].items) {
630         code = read_time_interval(as->parms[3].items->data, &lifetime);
631         if (code)
632             return KABADCMD;
633     }
634
635     /*  no point in doing this any sooner than necessary */
636     for (i = 0; i < 4; misc_auth_bytes[i++] = 0);
637
638     if (as->parms[4].items) {
639         pwexpiry = strtol(as->parms[4].items->data, &end, 10);
640         if (*end != '\0') {
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         }
651
652         misc_auth_bytes[0] = pwexpiry + 1;
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         nfailures = strtol(as->parms[6].items->data, &end, 10);
674
675         if (*end != '\0' || nfailures < 0 || nfailures > 254) {
676             fprintf(stderr, "Failure limit must be in [0..254].\n");
677             fprintf(stderr, "Zero represents unlimited login attempts.\n");
678             return KABADCMD;
679         }
680         misc_auth_bytes[2] = nfailures + 1;
681     }
682
683     if (as->parms[7].items) {
684         int locktime, hrs, mins;
685         char *s;
686
687         hrs = 0;
688         s = as->parms[7].items->data;
689         if (strchr(s, ':'))
690             sscanf(s, "%d:%d", &hrs, &mins);
691         else
692             sscanf(s, "%d", &mins);
693
694         locktime = hrs * 60 + mins;
695         if (hrs < 0 || hrs > 36 || mins < 0) {
696             fprintf(stderr,
697                     "Lockout times must be either minutes or hh:mm.\n");
698             fprintf(stderr, "Lockout times must be less than 36 hours.\n");
699             return KABADCMD;
700         } else if (locktime > 36 * 60) {
701             fprintf(stderr,
702                     "Lockout times must be either minutes or hh:mm.\n");
703             fprintf(stderr, "Lockout times must be less than 36 hours.\n");
704             fprintf(stderr,
705                     "Continuing with lock time of exactly 36 hours...\n");
706             locktime = 36 * 60;
707         }
708         locktime = (locktime * 60 + 511) >> 9;  /* ceil(l*60/512) */
709         misc_auth_bytes[3] = locktime + 1;      /* will be 1 if user said 0 */
710     }
711 #if ASSOCIATES
712     if (as->parms[8].items) {
713         maxAssociates = atoi(as->parms[6].items->data);
714         if (maxAssociates < 0) {
715             printf("Illegal maximum number of associates\n");
716             return KABADCMD;
717         }
718     }
719 #endif
720     was_spare = pack_long(misc_auth_bytes);
721
722     if (was_spare || flags || expiration || lifetime || (maxAssociates >= 0))
723         code =
724             ubik_KAM_SetFields(conn, 0, name, instance, flags,
725                       expiration, lifetime, maxAssociates, was_spare,
726                       /* spare */ 0);
727     else {
728         printf("Must specify one of the optional parameters\n");
729         return KABADCMD;
730     }
731     if (code)
732         afs_com_err(whoami, code, "calling KAM_SetFields for %s.%s", name,
733                 instance);
734     return code;
735 }
736
737 int
738 StringToKey(struct cmd_syndesc *as, void *arock)
739 {
740     afs_int32 code;
741     char realm[MAXKTCREALMLEN];
742     struct ktc_encryptionKey key;
743
744     if (as->parms[1].items) {
745         code = ka_ExpandCell(as->parms[1].items->data, realm, 0 /*local */ );
746         if (code) {
747             afs_com_err(whoami, code,
748                     "expanding %s as cell name, attempting to continue",
749                     as->parms[1].items->data);
750         }
751         ucstring(realm, realm, sizeof(realm));
752     } else {
753         if ((code = DefaultCell()))
754             return code;
755         ucstring(realm, cell, sizeof(realm));
756     }
757     ka_StringToKey(as->parms[0].items->data, realm, &key);
758
759     printf("Converting %s in realm '%s' yields key='",
760            as->parms[0].items->data, realm);
761     ka_PrintBytes((char *)&key, sizeof(key));
762     printf("'.\n");
763
764     DES_string_to_key(as->parms[0].items->data, ktc_to_cblockptr(&key));
765
766     printf("Converting %s with the DES string to key yields key='",
767            as->parms[0].items->data);
768     ka_PrintBytes((char *)&key, sizeof(key));
769     printf("'.\n");
770
771     return 0;
772 }
773
774 int
775 SetPassword(struct cmd_syndesc *as, void *arock)
776 {
777     int code;
778     char name[MAXKTCNAMELEN];
779     char instance[MAXKTCNAMELEN];
780     char realm[MAXKTCREALMLEN];
781     struct ktc_encryptionKey key;
782     afs_int32 kvno = 0;
783
784     code = ka_ParseLoginName(as->parms[0].items->data, name, instance, realm);
785     if (code) {
786         afs_com_err(whoami, code, "parsing user's name '%s'",
787                 as->parms[0].items->data);
788         return KABADCMD;
789     }
790
791     if (strlen(realm) == 0)
792         ucstring(realm, cell, sizeof(realm));
793
794     if (as->parms[1].items && as->parms[2].items) {
795         printf("Can't specify both a password and a key\n");
796         return KABADCMD;
797     } else if (as->parms[1].items) {
798         (void)init_child(myName);
799         (void)give_to_child(passwd);    /* old password */
800         code = password_bad(as->parms[1].items->data);
801         (void)terminate_child();
802         if (code)
803             return KABADCMD;
804         ka_StringToKey(as->parms[1].items->data, realm, &key);
805     } else if (as->parms[2].items) {
806         if (ka_ReadBytes(as->parms[2].items->data, (char *)&key, sizeof(key))
807             != 8) {
808             printf("Key must be 8 bytes: '%s' was too long\n",
809                    as->parms[2].items->data);
810             return KABADCMD;
811         }
812     } else {
813         printf("Must specify new password or key\n");
814         return KABADCMD;
815     }
816
817
818     if (as->parms[3].items)
819         sscanf(as->parms[3].items->data, "%d", &kvno);
820
821     code = ubik_KAM_SetPassword(conn, 0, name, instance, kvno,
822                                 *ktc_to_EncryptionKey(&key));
823     if (code)
824         afs_com_err(whoami, code, "so can't set password for %s.%s", name,
825                 instance);
826     return code;
827 }
828
829 #define PrintPrincipal(p,n,l) \
830     PrintName((p)->name, (p)->instance, (p)->cell, l, n)
831
832 static afs_int32
833 PrintName(char *name, char *inst, char *acell, int buflen, char *buf)
834 {
835     int nlen, len;
836     int left;                   /* if ConvertBytes stops early */
837     afs_int32 code;
838
839     if (name == 0)
840         name = "";
841     if (inst == 0)
842         inst = "";
843     if (acell == 0)
844         acell = "";
845     left = ka_ConvertBytes(buf, buflen, name, strlen(name));
846     if (left) {
847       bad_name:
848         code = KABADNAME;
849         afs_com_err(whoami, code, "PrintName: principal name was '%s'.'%s'@'%s'",
850                 name, inst, acell);
851         return code;
852     }
853     nlen = strlen(buf);
854     len = strlen(inst);
855     if (len) {
856         if (nlen + len + 1 >= buflen)
857             goto bad_name;
858         buf[nlen++] = '.';
859         left = ka_ConvertBytes(buf + nlen, buflen - nlen, inst, len);
860         if (left)
861             goto bad_name;
862         nlen += len;
863     }
864
865     len = strlen(acell);
866     if (len) {
867         char *lcell = ka_LocalCell();
868         if (lcell == 0)
869             lcell = "";
870         if (strcmp(acell, lcell) != 0) {
871             /* only append cell if not the local cell */
872             if (nlen + len + 1 >= buflen)
873                 goto bad_name;
874             buf[nlen++] = '@';
875             left = ka_ConvertBytes(buf + nlen, buflen - nlen, acell, len);
876             if (left)
877                 goto bad_name;
878             nlen += len;
879         }
880     }
881     return 0;
882 }
883
884 #define PrintedPrincipal(p) PrintedName ((p)->name, (p)->instance, (p)->cell)
885
886 /* PrintedName - returned a pointer to a static string in which the formated
887  * name has been stored. */
888
889 static char *
890 PrintedName(char *name, char *inst, char *cell)
891 {
892     static char printedName[128];
893     afs_int32 code;
894     code = PrintName(name, inst, cell, sizeof(printedName), printedName);
895     if (code) {
896         if (name == 0)
897             name = "";
898         strncpy(printedName, name, sizeof(printedName));
899         printedName[sizeof(printedName) - 8] = 0;
900         strcat(printedName, "<error>");
901     }
902     return printedName;
903 }
904
905 static afs_int32
906 ListTicket(struct ktc_principal *server, int verbose)
907 {
908     afs_int32 code;
909     struct ktc_token token;     /* the token we're printing */
910     struct ktc_principal client;
911     char UserName[sizeof(struct ktc_principal)];
912     char ServerName[sizeof(struct ktc_principal)];
913     afs_int32 now = time(0);
914     char bob[KA_TIMESTR_LEN];
915
916     /* get the ticket info itself */
917     code = ktc_GetToken(server, &token, sizeof(token), &client);
918     if (code) {
919         afs_com_err(whoami, code, "failed to get token info for server %s",
920                 PrintedPrincipal(server));
921         return code;
922     }
923     code = PrintPrincipal(&client, UserName, sizeof(UserName));
924     if (code)
925         return code;
926     /* spaces are printed as "\040" */
927     if (UserName[0] == 0)
928         printf("Tokens");
929     else if (strncmp(UserName, "AFS\\040ID\\040", 13) == 0) {
930         printf("User's (AFS ID %s) tokens", UserName + 13);
931     } else if (strncmp(UserName, "Unix\\040UID\\040", 15) == 0) {
932         printf("Tokens");
933     } else
934         printf("User %s's tokens", UserName);
935
936     code = PrintPrincipal(server, ServerName, sizeof(ServerName));
937     if (code)
938         return code;
939     printf(" for %s ", ServerName);
940
941     if (token.startTime > now) {
942         ka_timestr(token.startTime, bob, KA_TIMESTR_LEN);
943         printf("[>> POSTDATED 'till %s <<]", bob);
944     }
945
946     if (token.endTime <= now)
947         printf("[>> Expired <<]\n");
948     else {
949         ka_timestr(token.endTime, bob, KA_TIMESTR_LEN);
950         printf("[Expires %s]\n", bob);
951     }
952     if (verbose) {
953         printf("SessionKey: ");
954         ka_PrintBytes((char *)&token.sessionKey, sizeof(token.sessionKey));
955         printf("\nTicket (kvno = %d, len = %d): ", token.kvno,
956                token.ticketLen);
957         ka_PrintBytes((char *)token.ticket, token.ticketLen);
958         printf("\n");
959     }
960     return 0;
961 }
962
963 static int
964 GetTicket(struct cmd_syndesc *as, void *arock)
965 {
966     int code;
967     struct ktc_principal server;
968     struct ktc_token token;
969     afs_int32 life = KA_SIXHOURS;
970
971     if (as->parms[1].items) {
972         code = read_time_interval(as->parms[1].items->data, &life);
973         if (code)
974             return KABADCMD;
975     }
976     code =
977         ka_ParseLoginName(as->parms[0].items->data, server.name,
978                           server.instance, server.cell);
979     if (code) {
980         afs_com_err(whoami, code, "parsing user's name '%s'",
981                 as->parms[0].items->data);
982         return KABADCMD;
983     }
984     if (server.cell[0] == 0) {
985         if ((code = DefaultCell()))
986             return code;
987         strcpy(server.cell, cell);
988     } else {
989         code = ka_ExpandCell(server.cell, server.cell, 0 /*local */ );
990         if (code) {
991             afs_com_err(whoami, code, "Can't expand cell name");
992             return code;
993         }
994     }
995
996     token.ticketLen = 0;        /* in case there are no tokens */
997     code =
998         ka_GetServerToken(server.name, server.instance, server.cell, life,
999                           &token, /*new */ 1, /*dosetpag */ 0);
1000     if (code)
1001         afs_com_err(whoami, code, "getting ticket for %s",
1002                 PrintedPrincipal(&server));
1003     else {
1004         code = ListTicket(&server, /*verbose */ 1);
1005     }
1006     return code;
1007 }
1008
1009 static int
1010 GetPassword(struct cmd_syndesc *as, void *arock)
1011 {
1012     int code;
1013     char name[MAXKTCNAMELEN];
1014     struct ktc_encryptionKey key;
1015     static struct ubik_client *lpbkConn = 0;
1016
1017     /* no instance allowed */
1018     code = ka_ParseLoginName(as->parms[0].items->data, name, 0, 0);
1019     if (code) {
1020       abort:
1021         afs_com_err(whoami, code,
1022                 "getting %s's password via loopback connection to GetPassword",
1023                 name);
1024         /* if we got a timeout, print a clarification, too */
1025         if (code == -1) {
1026             fprintf(stderr,
1027                     "%s: please note that this command must be run locally on a database server machine.\n",
1028                     whoami);
1029         }
1030         return code;
1031     }
1032     if (lpbkConn == 0) {
1033         struct rx_connection *conns[2];
1034         struct rx_securityClass *sc;
1035         int si;                 /* security class index */
1036
1037         code = rx_Init(0);
1038         if (code)
1039             goto abort;
1040         sc = rxnull_NewClientSecurityObject();
1041         si = RX_SCINDEX_NULL;
1042         conns[0] =
1043             rx_NewConnection(htonl(INADDR_LOOPBACK), htons(AFSCONF_KAUTHPORT),
1044                              KA_MAINTENANCE_SERVICE, sc, si);
1045         conns[1] = 0;
1046         code = ubik_ClientInit(conns, &lpbkConn);
1047         if (code)
1048             goto abort;
1049     }
1050     code = ubik_KAM_GetPassword(lpbkConn, 0, name,
1051                                 ktc_to_EncryptionKey(&key));
1052     /* Lets close down the ubik_Client connection now */
1053     ubik_ClientDestroy(lpbkConn);
1054     if (code)
1055         goto abort;
1056     printf("Key: ");
1057     ka_PrintBytes((char *)&key, sizeof(key));
1058     printf("\n");
1059     return code;
1060 }
1061
1062 int
1063 GetRandomKey(struct cmd_syndesc *as, void *arock)
1064 {
1065     int code;
1066     struct ktc_encryptionKey key;
1067
1068     code = ubik_KAM_GetRandomKey(conn, 0, ktc_to_EncryptionKey(&key));
1069     if (code)
1070         afs_com_err(whoami, code, "so can't get random key");
1071     else {
1072         int i;
1073         printf("Key: ");
1074         ka_PrintBytes((char *)&key, sizeof(key));
1075         printf(" (");
1076         for (i = 0; i < sizeof(key); i++) {
1077             printf("%.2x", ((char *)&key)[i] & 0xff);
1078             if (i == 3)
1079                 printf(" ");
1080             else if (i != 7)
1081                 printf(".");
1082         }
1083         printf(")\n");
1084     }
1085     return code;
1086 }
1087
1088 int
1089 Statistics(struct cmd_syndesc *as, void *arock)
1090 {
1091     int code;
1092     kasstats statics;
1093     kadstats dynamics;
1094     afs_int32 admins;
1095     char bob[KA_TIMESTR_LEN];
1096
1097     code =
1098         ubik_KAM_GetStats(conn, 0, KAMAJORVERSION, &admins, &statics,
1099                   &dynamics);
1100     if (code) {
1101         printf("call to GetStats failed: %s\n", ka_ErrorString(code));
1102         return code;
1103     }
1104     if (statics.minor_version != KAMINORVERSION)
1105         printf("Minor version number mismatch: got %d, expected %d\n",
1106                statics.minor_version, KAMINORVERSION);
1107     printf("%d allocs, %d frees, %d password changes\n", statics.allocs,
1108            statics.frees, statics.cpws);
1109     printf("Hash table utilization = %f%%\n",
1110            (double)dynamics.hashTableUtilization / 100.0);
1111     ka_timestr(dynamics.start_time, bob, KA_TIMESTR_LEN);
1112     printf("From host %lx started at %s:\n",
1113            afs_printable_uint32_lu(dynamics.host), bob);
1114
1115 #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)
1116     print_stat(Authenticate);
1117     print_stat(ChangePassword);
1118     print_stat(GetTicket);
1119     print_stat(CreateUser);
1120     print_stat(SetPassword);
1121     print_stat(SetFields);
1122     print_stat(DeleteUser);
1123     print_stat(GetEntry);
1124     print_stat(ListEntry);
1125     print_stat(GetStats);
1126     print_stat(GetPassword);
1127     print_stat(GetRandomKey);
1128     print_stat(Debug);
1129     print_stat(UAuthenticate);
1130     print_stat(UGetTicket);
1131
1132 #if (KAMAJORVERSION>5)
1133     print cpu stats printf("%d string checks\n", dynamics.string_checks);
1134 #else
1135     printf("Used %.3f seconds of CPU time.\n",
1136            dynamics.string_checks / 1000.0);
1137 #endif
1138     printf("%d admin accounts\n", admins);
1139     return 0;
1140 }
1141
1142 int
1143 DebugInfo(struct cmd_syndesc *as, void *arock)
1144 {
1145     int code;
1146     struct ka_debugInfo info;
1147     int i;
1148     Date start, now;
1149     int timeOffset;
1150     char bob[KA_TIMESTR_LEN];
1151
1152     start = time(0);
1153     if (as->parms[0].items) {
1154         struct ubik_client *iConn;
1155         code =
1156             ka_SingleServerConn(cell, as->parms[0].items->data,
1157                                 KA_MAINTENANCE_SERVICE, 0, &iConn);
1158         if (code) {
1159             struct afsconf_cell cellinfo;
1160
1161             afs_com_err(whoami, code, "couldn't find host %s in cell %s",
1162                     as->parms[0].items->data, cell);
1163             code = ka_GetServers(cell, &cellinfo);
1164             if (code)
1165                 afs_com_err(whoami, code, "getting servers in cell %s", cell);
1166             else {
1167                 printf("Servers in cell %s, are:\n", cell);
1168                 for (i = 0; i < cellinfo.numServers; i++)
1169                     printf("  %s\n", cellinfo.hostName[i]);
1170             }
1171             return code;
1172         }
1173         code = ubik_KAM_Debug(iConn, 0, KAMAJORVERSION, 0, &info);
1174         ubik_ClientDestroy(iConn);
1175     } else
1176         code = ubik_KAM_Debug(conn, 0, KAMAJORVERSION, 0, &info);
1177
1178     if (code) {
1179         afs_com_err(whoami, code, "call to Debug failed");
1180         return code;
1181     }
1182     now = time(0);
1183
1184     if (info.minorVersion != KAMINORVERSION)
1185         printf("Minor version number mismatch: got %d, expected %d\n",
1186                info.minorVersion, KAMINORVERSION);
1187
1188     timeOffset = info.
1189 #if (KAMAJORVERSION>5)
1190         now
1191 #else
1192         reserved1
1193 #endif
1194         - now;
1195     if (timeOffset < 0)
1196         timeOffset = -timeOffset;
1197     if (timeOffset > 60) {
1198         printf
1199             ("WARNING: Large server client clock skew: %d seconds. Call itself took %d seconds.\n",
1200              timeOffset, now - start);
1201     }
1202     ka_timestr(info.startTime, bob, KA_TIMESTR_LEN);
1203     printf("From host %lx started %sat %s:\n",
1204            afs_printable_uint32_lu(info.host),
1205            (info.noAuth ? "w/o authorization " : ""), bob);
1206     ka_timestr(info.lastTrans, bob, KA_TIMESTR_LEN);
1207     printf("Last trans was %s at %s\n", info.lastOperation, bob);
1208     ka_timestr(info.dbHeaderRead, bob, KA_TIMESTR_LEN);
1209     printf("Header last read %s.\n", bob);
1210     printf("db version=%d, keyVersion=%d, key cache version=%d\n",
1211            info.dbVersion, info.dbSpecialKeysVersion, info.kcVersion);
1212     printf("db ptrs: free %d, eof %d, kvno %d.\n", info.dbFreePtr,
1213            info.dbEofPtr, info.dbKvnoPtr);
1214     ka_timestr(info.nextAutoCPW, bob, KA_TIMESTR_LEN);
1215     printf("Next autoCPW at %s or in %d updates.\n", bob,
1216            info.updatesRemaining);
1217     if (info.cheader_lock || info.keycache_lock)
1218         printf("locks: cheader %08lx, keycache %08lx\n",
1219                 afs_printable_uint32_lu(info.cheader_lock),
1220                 afs_printable_uint32_lu(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_uint32 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     struct ktc_encryptionKey key;
1288     struct ktc_principal auth_server, client;
1289     struct ktc_token auth_token;
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 = UI_UTIL_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, ktc_to_cblockptr(&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 = UI_UTIL_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 = malloc(sizeof(struct cmd_item));
1526                     ip->data = strdup(password);
1527                     ip->next = 0;
1528                     as->parms[i].items = ip;
1529                 }
1530             }
1531     if (!conn) {                /* if all else fails... */
1532         code = NoAuth(0, 0);    /* get unauthenticated conn */
1533         if (code)
1534             return code;
1535     }
1536     return 0;
1537 }
1538
1539 /* These are some helpful command that deal with the cache managers tokens. */
1540
1541 static int
1542 ForgetTicket(struct cmd_syndesc *as, void *arock)
1543 {
1544     afs_int32 code;
1545
1546 #ifdef notdef
1547     struct ktc_principal server;
1548
1549     if (as->parms[0].items) {
1550         char *name = as->parms[0].items->data;
1551         code =
1552             ka_ParseLoginName(name, server.name, server.instance,
1553                               server.cell);
1554         if (code) {
1555             afs_com_err(whoami, code, "couldn't interpret name '%s'", name);
1556             return code;
1557         }
1558         if (server.cell[0] == 0) {
1559             if (code = DefaultCell())
1560                 return code;
1561             strcpy(server.cell, cell);
1562         } else {
1563             code = ka_ExpandCell(server.cell, server.cell, 0 /*local */ );
1564             if (code) {
1565                 afs_com_err(whoami, code, "Can't expand cell name");
1566                 return code;
1567             }
1568         }
1569         code = ktc_ForgetToken(&server);
1570         if (code) {
1571             afs_com_err(whoami, code, "couldn't remove tokens for %s",
1572                     PrintedPrincipal(&server));
1573             return code;
1574         }
1575     } else {
1576         if (!as->parms[1].items) {
1577             fprintf(stderr, "Must specify server name or -all\n");
1578             return KABADCMD;
1579         }
1580         code = ktc_ForgetAllTokens();
1581         if (code) {
1582             afs_com_err(whoami, code, "couldn't delete all tokens");
1583             return code;
1584         }
1585     }
1586 #endif
1587     code = ktc_ForgetAllTokens();
1588     if (code) {
1589         afs_com_err(whoami, code, "couldn't delete all tokens");
1590         return code;
1591     }
1592     return 0;
1593 }
1594
1595 static int
1596 ListTickets(struct cmd_syndesc *as, void *arock)
1597 {
1598     afs_int32 code = 0;
1599     int index, newIndex;
1600     struct ktc_principal server;
1601     int verbose = 0;
1602
1603     if (as->parms[1].items)
1604         verbose = 1;
1605     if (as->parms[0].items) {
1606         char *name = as->parms[0].items->data;
1607         code =
1608             ka_ParseLoginName(name, server.name, server.instance,
1609                               server.cell);
1610         if (code) {
1611             afs_com_err(whoami, code, "couldn't interpret name '%s'", name);
1612             return code;
1613         }
1614         if (server.cell[0] == 0) {
1615             if ((code = DefaultCell()))
1616                 return code;
1617             strcpy(server.cell, cell);
1618         } else {
1619             code = ka_ExpandCell(server.cell, server.cell, 0 /*local */ );
1620             if (code) {
1621                 afs_com_err(whoami, code, "Can't expand cell name");
1622                 return code;
1623             }
1624         }
1625         code = ListTicket(&server, verbose);
1626     } else
1627         for (index = 0;; index = newIndex) {
1628             code = ktc_ListTokens(index, &newIndex, &server);
1629             if (code) {
1630                 if (code == KTC_NOENT)
1631                     code = 0;   /* end of list */
1632                 break;
1633             }
1634             code = ListTicket(&server, verbose);
1635         }
1636     return code;
1637 }
1638
1639 static void
1640 add_std_args(struct cmd_syndesc *ts)
1641 {
1642     cmd_Seek(ts, 12);
1643     /* 12 */ cmd_AddParm(ts, "-admin_username", CMD_SINGLE, CMD_OPTIONAL,
1644                          "admin principal to use for authentication");
1645     /* 13 */ cmd_AddParm(ts, "-password_for_admin", CMD_SINGLE, CMD_OPTIONAL,
1646                          "admin password");
1647     /* 14 */ cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
1648     /* 15 */ cmd_AddParm(ts, "-servers", CMD_LIST, CMD_OPTIONAL,
1649                          "explicit list of authentication servers");
1650     /* 16 */ cmd_AddParm(ts, "-noauth", CMD_FLAG, CMD_OPTIONAL,
1651                          "don't authenticate");
1652 }
1653
1654 afs_int32
1655 ka_AdminInteractive(int cmd_argc, char *cmd_argv[])
1656 {
1657     int code;
1658     struct cmd_syndesc *ts;
1659
1660     char line[BUFSIZ];
1661     afs_int32 argc;
1662     char *argv[32];
1663
1664     strncpy(myName, *cmd_argv, 509);
1665
1666     cmd_SetBeforeProc(MyBeforeProc, NULL);
1667     cmd_SetAfterProc(MyAfterProc, NULL);
1668
1669     ts = cmd_CreateSyntax("interactive", Interactive, NULL,
1670                           "enter interactive mode");
1671     add_std_args(ts);
1672
1673     ts = cmd_CreateSyntax("noauthentication", NoAuth, NULL,
1674                           "connect to AuthServer w/o using token");
1675
1676     ts = cmd_CreateSyntax("list", ListUsers, NULL,
1677                           "list all users in database");
1678     cmd_AddParm(ts, "-long", CMD_FLAG, CMD_OPTIONAL,
1679                 "show detailed info about each user");
1680     cmd_AddParm(ts, "-showadmin", CMD_FLAG, CMD_OPTIONAL,
1681                 "show all cell administrators");
1682     cmd_AddParm(ts, "-showkey", CMD_FLAG, CMD_OPTIONAL,
1683                 "show the user's actual key rather than the checksum");
1684     add_std_args(ts);
1685     cmd_CreateAlias(ts, "ls");
1686
1687     ts = cmd_CreateSyntax("examine", ExamineUser, NULL,
1688                           "examine the entry for a user");
1689     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1690     cmd_AddParm(ts, "-showkey", CMD_FLAG, CMD_OPTIONAL,
1691                 "show the user's actual key rather than the checksum");
1692     add_std_args(ts);
1693
1694     ts = cmd_CreateSyntax("create", CreateUser, NULL,
1695                           "create an entry for a user");
1696     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1697     cmd_AddParm(ts, "-initial_password", CMD_SINGLE, CMD_OPTIONAL,
1698                 "initial password");
1699     add_std_args(ts);
1700
1701     ts = cmd_CreateSyntax("delete", DeleteUser, NULL, "delete a user");
1702     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1703     add_std_args(ts);
1704     cmd_CreateAlias(ts, "rm");
1705
1706     ts = cmd_CreateSyntax("setfields", SetFields, NULL,
1707                           "set various fields in a user's entry");
1708     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1709     cmd_AddParm(ts, "-flags", CMD_SINGLE, CMD_OPTIONAL,
1710                 "hex flag value or flag name expression");
1711     cmd_AddParm(ts, "-expiration", CMD_SINGLE, CMD_OPTIONAL,
1712                 "date of account expiration");
1713     cmd_AddParm(ts, "-lifetime", CMD_SINGLE, CMD_OPTIONAL,
1714                 "maximum ticket lifetime");
1715     cmd_AddParm(ts, "-pwexpires", CMD_SINGLE, CMD_OPTIONAL,
1716                 "number days password is valid ([0..254])");
1717     cmd_AddParm(ts, "-reuse", CMD_SINGLE, CMD_OPTIONAL,
1718                 "permit password reuse (yes/no)");
1719     cmd_AddParm(ts, "-attempts", CMD_SINGLE, CMD_OPTIONAL,
1720                 "maximum successive failed login tries ([0..254])");
1721     cmd_AddParm(ts, "-locktime", CMD_SINGLE, CMD_OPTIONAL,
1722                 "failure penalty [hh:mm or minutes]");
1723 #if ASSOCIATES
1724     cmd_AddParm(ts, "-associates", CMD_SINGLE, CMD_OPTIONAL,
1725                 "maximum associate instances");
1726 #endif
1727     add_std_args(ts);
1728     cmd_CreateAlias(ts, "sf");
1729
1730
1731     ts = cmd_CreateSyntax("unlock", Unlock, NULL,
1732                           "Enable authentication ID after max failed attempts exceeded");
1733     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "authentication ID");
1734     add_std_args(ts);
1735
1736
1737     ts = cmd_CreateSyntax("stringtokey", StringToKey, NULL,
1738                           "convert a string to a key");
1739     cmd_AddParm(ts, "-string", CMD_SINGLE, 0, "password string");
1740     cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
1741
1742     ts = cmd_CreateSyntax("setpassword", SetPassword, NULL,
1743                           "set a user's password");
1744     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1745     cmd_AddParm(ts, "-new_password", CMD_SINGLE, CMD_OPTIONAL,
1746                 "new password");
1747     cmd_Seek(ts, 3);
1748     cmd_AddParm(ts, "-kvno", CMD_SINGLE, CMD_OPTIONAL, "key version number");
1749     add_std_args(ts);
1750     cmd_CreateAlias(ts, "sp");
1751 #ifdef CMD_PARSER_AMBIG_FIX
1752     cmd_CreateAlias(ts, "setpasswd");
1753 #endif
1754
1755     /* set a user's key */
1756     ts = cmd_CreateSyntax("setkey", SetPassword, NULL, (char *)CMD_HIDDEN);
1757     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1758     cmd_Seek(ts, 2);
1759     cmd_AddParm(ts, "-new_key", CMD_SINGLE, 0, "eight byte new key");
1760     cmd_Seek(ts, 3);
1761     cmd_AddParm(ts, "-kvno", CMD_SINGLE, CMD_OPTIONAL, "key version number");
1762     add_std_args(ts);
1763
1764     /* get a user's password */
1765     ts = cmd_CreateSyntax("getpassword", GetPassword, NULL, (char *)CMD_HIDDEN);
1766     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1767     /* don't take standard args */
1768     /* add_std_args (ts); */
1769 #ifdef CMD_PARSER_AMBIG_FIX
1770     cmd_CreateAlias(ts, "getpasswd");
1771 #endif
1772
1773     /* get a random key */
1774     ts = cmd_CreateSyntax("getrandomkey", GetRandomKey, NULL,
1775                           (char *)CMD_HIDDEN);
1776     add_std_args(ts);
1777
1778     /* get a ticket for a specific server */
1779     ts = cmd_CreateSyntax("getticket", GetTicket, NULL, (char *)CMD_HIDDEN);
1780     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of server");
1781     cmd_AddParm(ts, "-lifetime", CMD_SINGLE, CMD_OPTIONAL, "ticket lifetime");
1782     add_std_args(ts);
1783
1784     ts = cmd_CreateSyntax("statistics", Statistics, NULL,
1785                           "show statistics for AuthServer");
1786     add_std_args(ts);
1787
1788     /* show debugging info from AuthServer */
1789     ts = cmd_CreateSyntax("debuginfo", DebugInfo, NULL, (char *)CMD_HIDDEN);
1790     cmd_AddParm(ts, "-hostname", CMD_SINGLE, CMD_OPTIONAL,
1791                 "authentication server host name");
1792     add_std_args(ts);
1793
1794     ts = cmd_CreateSyntax("forgetticket", ForgetTicket, NULL,
1795                           "delete user's tickets");
1796 #ifdef notdef
1797     cmd_AddParm(ts, "-name", CMD_SINGLE, (CMD_OPTIONAL | CMD_HIDE),
1798                 "name of server");
1799 #endif
1800     cmd_AddParm(ts, "-all", CMD_FLAG, CMD_OPTIONAL, "delete all tickets");
1801
1802     ts = cmd_CreateSyntax("listtickets", ListTickets, NULL,
1803                           "show all cache manager tickets");
1804     cmd_AddParm(ts, "-name", CMD_SINGLE, CMD_OPTIONAL, "name of server");
1805     cmd_AddParm(ts, "-long", CMD_FLAG, CMD_OPTIONAL,
1806                 "show session key and ticket");
1807
1808     ts = cmd_CreateSyntax("quit", Quit, NULL, "exit program");
1809
1810     finished = 1;
1811     conn = 0;                   /* no connection yet */
1812     zero_argc = cmd_argc;
1813     zero_argv = cmd_argv;
1814
1815     strcpy(whoami, "kas");
1816
1817     if ((code = cmd_Dispatch(cmd_argc, cmd_argv))) {
1818         return code;
1819     }
1820
1821     while (!finished) {
1822         char *s;
1823         int i;
1824
1825         printf("ka> ");
1826         s = fgets(line, sizeof(line), stdin);
1827         if (s == NULL)
1828             return 0;           /* EOF on input */
1829         for (i = strlen(line) - 1; i >= 0 && isspace(line[i]); i--)
1830             line[i] = 0;
1831         if (i < 0)
1832             continue;           /* blank line */
1833
1834         code =
1835             cmd_ParseLine(line, argv, &argc, sizeof(argv) / sizeof(argv[0]));
1836         if (code) {
1837             afs_com_err(whoami, code, "parsing line: '%s'", line);
1838             return code;
1839         }
1840         code = cmd_Dispatch(argc, argv);
1841         cmd_FreeArgv(argv);
1842     }
1843     return code;
1844 }