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