0a7c7d8a92198b92971494eb10b4bc1e02959a01
[openafs.git] / src / kauth / admin_tools.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /* These routines provide administrative tools for managing the AuthServer.
11    There is an interactive routine that can be used to examine the database and
12    make small changes as well as subroutines to permit specialized programs to
13    update the database, change the server passwords, etc. */
14
15 #include <afsconfig.h>
16 #include <afs/param.h>
17
18 RCSID
19     ("$Header$");
20
21 #include <afs/stds.h>
22 #include <afs/debug.h>
23 #include <ctype.h>
24 #include <string.h>
25
26     /* These two needed for rxgen output to work */
27 #include <sys/types.h>
28 #include <rx/xdr.h>
29
30 #include <stdio.h>
31 #include <rx/rx.h>
32 #include <lock.h>
33 #include <ubik.h>
34 #ifndef AFS_NT40_ENV
35 #include <pwd.h>
36 #endif
37 #include <afs/auth.h>
38 #include <afs/cellconfig.h>
39 #include <afs/cmd.h>
40 #include <afs/com_err.h>
41 #include <afs/afsutil.h>
42
43 #include "kauth.h"
44 #include "kautils.h"
45 #include "kaport.h"
46
47 #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();
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         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         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_Call(KAM_GetEntry, conn, 0, name, inst, KAMAJORVERSION, &tentry);
99     if (code) {
100         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, char *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_Call(KAM_ListEntry, conn, 0, index, &next_index, &count,
255                       &name);
256         if (code) {
257             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, char *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", error_table_name(code), 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, char *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         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_Call(KAM_CreateUser, conn, 0, name, instance, key);
342         if (!code)
343             return 0;
344         ka_PrintUserID("Creating user ", name, instance, " ");
345         code = handle_errors(code, OKlist, &persist);
346     } while (persist);
347     return code;
348 }
349
350 int
351 DeleteUser(struct cmd_syndesc *as, char *arock)
352 {
353     int code;
354     char name[MAXKTCNAMELEN];
355     char instance[MAXKTCNAMELEN];
356
357     int persist = 1;
358     struct OKerrors OKlist[2];
359     OKlist[0].code = 0;
360     code = ka_ParseLoginName(as->parms[0].items->data, name, instance, 0);
361     if (code) {
362         com_err(whoami, code, "parsing user's name '%s'",
363                 as->parms[0].items->data);
364         return KABADCMD;
365     }
366
367     do {
368         code = ubik_Call(KAM_DeleteUser, conn, 0, name, instance);
369         if (!code)
370             return 0;
371         ka_PrintUserID("Deleting user ", name, instance, " ");
372         code = handle_errors(code, OKlist, &persist);
373     } while (persist);
374     return code;
375 }
376
377 static int
378 read_time_interval(char *str, afs_int32 * seconds)
379 {
380     char *s;
381     int sec = 0;
382     char buf[32];
383
384     str = strncpy(buf, str, sizeof(buf));
385     s = strchr(str, ':');
386     if (s == 0)
387         sec = atoi(str);
388     else {
389         *s++ = '\0';            /* separate hours and minutes */
390         sec = atoi(str) * 3600 + atoi(s) * 60;
391     }
392     *seconds = sec;
393     return 0;
394 }
395
396 int
397 parse_flags(char *name, char *inst, char *str, afs_int32 * flags)
398 {
399     struct kaentryinfo tentry;
400     int code;
401     char bitspec[100];
402     afs_int32 f;
403     char bit[25];
404     char c;
405     int addop;                  /* 1=add bit; 0=remove bit */
406     int flag;
407     int i;
408
409     str = lcstring(bitspec, str, sizeof(bitspec));
410     if (isdigit(*str)) {
411         if (strncmp(str, "0x", 2) == 0) /* 0x => hex */
412             sscanf(str, "0x%lx", &f);
413         else if (*str == '0')   /* assume octal */
414             sscanf(str, "%lo", &f);
415         else                    /* just assume hex */
416             sscanf(str, "%lx", &f);
417     } else {
418         if (*str == '=') {
419             str++;
420             f = 0;
421             addop = 1;
422         } else {
423             if (strchr("+-", *str))
424                 addop = (*str++ == '+');
425             else if (*str == '_') {
426                 addop = 0;
427                 str++;
428             } else
429                 addop = 1;
430             code =
431                 ubik_Call(KAM_GetEntry, conn, 0, name, inst, KAMAJORVERSION,
432                           &tentry);
433             if (code) {
434                 com_err(whoami, code,
435                         "could get current flag value for %s.%s", name, inst);
436                 return -1;
437             }
438             f = tentry.flags;
439         }
440         while (*str) {
441             i = 0;
442             while (1) {
443                 c = *str;
444                 if (isupper(c))
445                     c = tolower(c);
446                 if (!islower(c))
447                     break;
448                 bit[i++] = c;
449                 str++;
450             }
451             bit[i] = '\0';
452             if (strcmp(bit, "admin") == 0)
453                 flag = KAFADMIN;
454             else if (strcmp(bit, "noadmin") == 0)
455                 flag = KAFADMIN, addop = !addop;
456             else if (strcmp(bit, "notgs") == 0)
457                 flag = KAFNOTGS;
458             else if (strcmp(bit, "tgs") == 0)
459                 flag = KAFNOTGS, addop = !addop;
460             else if (strcmp(bit, "noseal") == 0)
461                 flag = KAFNOSEAL;
462             else if (strcmp(bit, "seal") == 0)
463                 flag = KAFNOSEAL, addop = !addop;
464             else if (strcmp(bit, "nocpw") == 0)
465                 flag = KAFNOCPW;
466             else if (strcmp(bit, "cpw") == 0)
467                 flag = KAFNOCPW, addop = !addop;
468             else if (strcmp(bit, "newassoc") == 0)
469                 flag = KAFNEWASSOC;
470             else if (strcmp(bit, "nonewassoc") == 0)
471                 flag = KAFNEWASSOC, addop = !addop;
472             else {
473                 printf
474                     ("Illegal bit name: %s; choices are: [no]admin, [no]tgs, [no]seal, [no]cpw\n",
475                      bit);
476                 return -1;
477             }
478
479             if (addop)
480                 f |= flag;
481             else
482                 f &= ~flag;
483
484             if (*str == 0)
485                 break;
486             if (*str == '+')
487                 addop = 1;      /* get next op */
488             else if ((*str == '-') || (*str == '_'))
489                 addop = 0;
490             else {
491                 printf("Illegal combination operator: %c\n", *str);
492                 return -1;
493             }
494             str++;
495         }
496     }
497     *flags = (f & KAF_SETTABLE_FLAGS) | KAFNORMAL;
498     return 0;
499 }
500
501 #define seriouserror(code) ((code <0) || ((code != UNOSERVERS) && (code != UNOQUORUM) && code != UNOTSYNC))
502
503 /* return MAXLONG if locked forever */
504 afs_uint32
505 ka_islocked(char *name, char *instance, afs_uint32 * when)
506 {
507     int count, code;
508     afs_uint32 tempwhen;
509
510     count = 0;
511     *when = 0;
512     do {
513         tempwhen = 0;
514         code =
515             ubik_CallIter(KAM_LockStatus, conn, UPUBIKONLY, &count, name,
516                           instance, &tempwhen, /*spares */ 0, 0, 0,
517                           0, 0, 0, 0, 0, 0, 0, 0,
518                           0);
519         if (code) {
520             if (seriouserror(code))
521                 com_err(whoami, code, "");
522         } else if (tempwhen) {  /* user is locked */
523             if (!*when || tempwhen < *when) {
524                 *when = tempwhen;
525                 return (*when);
526             }
527         } else                  /* ! tempwhen ==> user is not locked */
528             return 0;
529
530     } while (code != UNOSERVERS);
531
532     return (*when);
533 }
534
535 int
536 Unlock(struct cmd_syndesc *as, char *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         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, name, instance,
554                              /*spares */ 0, 0, 0, 0);
555         if (code && (code != UNOSERVERS)) {
556             server = 0;
557             if (conn && conn->conns[count - 1]
558                 && conn->conns[count - 1]->peer) {
559                 server = conn->conns[count - 1]->peer->host;
560             }
561             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, char *arock)
578 {
579     int code;
580     char name[MAXKTCNAMELEN];
581     char instance[MAXKTCNAMELEN];
582     afs_int32 flags = 0;
583     Date expiration = 0;
584     afs_int32 lifetime = 0;
585     afs_int32 maxAssociates = -1;
586     afs_int32 pwexpiry = 0;
587     afs_int32 was_spare = 0;
588     char misc_auth_bytes[4];
589     int i;
590
591     code = ka_ParseLoginName(as->parms[0].items->data, name, instance, 0);
592     if (code) {
593         com_err(whoami, code, "parsing user's name '%s'",
594                 as->parms[0].items->data);
595         return KABADCMD;
596     }
597
598     if (as->parms[1].items) {
599         code = parse_flags(name, instance, as->parms[1].items->data, &flags);
600         if (code) {
601             printf
602                 ("Illegal flag specification: %s, should be of the form <'='|'+'|'-'|'_'>bitname{<'+'|'-'>bitname}*\n",
603                  as->parms[1].items->data);
604             return KABADCMD;
605         }
606     }
607     if (as->parms[2].items) {
608         char buf[32];
609         char *s = strncpy(buf, as->parms[2].items->data, sizeof(buf));
610         code = ktime_DateToInt32(s, &expiration);
611         if (code) {
612             printf("Illegal time format %s: %s\n", as->parms[2].items->data,
613                    ktime_GetDateUsage());
614             return KABADCMD;
615         }
616         if (expiration == 0) {
617             fprintf(stderr, "Expiration time must be after (about) 1970.\n");
618             return KABADCMD;
619         }
620         if (expiration < time(0)) {
621             fprintf(stderr,
622                     "Warning: expiration being set into the past, account will be disabled.\n");
623         }
624     }
625     /*
626      * TICKET lifetime...
627      */
628     if (as->parms[3].items) {
629         code = read_time_interval(as->parms[3].items->data, &lifetime);
630         if (code)
631             return KABADCMD;
632     }
633
634     /*  no point in doing this any sooner than necessary */
635     for (i = 0; i < 4; misc_auth_bytes[i++] = 0);
636
637     if (as->parms[4].items) {
638         if (util_isint(as->parms[4].items->data))
639             pwexpiry = atoi(as->parms[4].items->data);
640         else {
641             fprintf(stderr,
642                     "Password lifetime specified must be a non-negative decimal integer.\n");
643             pwexpiry = -1;
644         }
645         if (pwexpiry < 0 || pwexpiry > 254) {
646             fprintf(stderr,
647                     "Password lifetime range must be [0..254] days.\n");
648             fprintf(stderr, "Zero represents an unlimited lifetime.\n");
649             return KABADCMD;
650         } else {
651             misc_auth_bytes[0] = pwexpiry + 1;
652         }
653     }
654
655     if (as->parms[5].items) {
656         char *reuse;
657         reuse = (as->parms[5].items->data);
658
659         if (!strcmp(reuse, "yes")) {
660             misc_auth_bytes[1] = KA_REUSEPW;
661         } else if (strcmp(reuse, "no")) {
662             fprintf(stderr,
663                     "must specify \"yes\" or \"no\": \"yes\" assumed\n");
664             misc_auth_bytes[1] = KA_REUSEPW;
665         } else {
666             misc_auth_bytes[1] = KA_NOREUSEPW;
667         }
668     }
669
670     if (as->parms[6].items) {
671         int nfailures;
672
673
674         if (util_isint(as->parms[6].items->data)
675             && ((nfailures = atoi(as->parms[6].items->data)) < 255)) {
676             misc_auth_bytes[2] = nfailures + 1;
677         } else {
678             fprintf(stderr, "Failure limit must be in [0..254].\n");
679             fprintf(stderr, "Zero represents unlimited login attempts.\n");
680             return KABADCMD;
681         }
682     }
683
684     if (as->parms[7].items) {
685         int locktime, hrs, mins;
686         char *s;
687
688         hrs = 0;
689         s = as->parms[7].items->data;
690         if (strchr(s, ':'))
691             sscanf(s, "%d:%d", &hrs, &mins);
692         else
693             sscanf(s, "%d", &mins);
694
695         locktime = hrs * 60 + mins;
696         if (hrs < 0 || hrs > 36 || mins < 0) {
697             fprintf(stderr,
698                     "Lockout times must be either minutes or hh:mm.\n");
699             fprintf(stderr, "Lockout times must be less than 36 hours.\n");
700             return KABADCMD;
701         } else if (locktime > 36 * 60) {
702             fprintf(stderr,
703                     "Lockout times must be either minutes or hh:mm.\n");
704             fprintf(stderr, "Lockout times must be less than 36 hours.\n");
705             fprintf(stderr,
706                     "Continuing with lock time of exactly 36 hours...\n");
707             locktime = 36 * 60;
708         }
709         locktime = (locktime * 60 + 511) >> 9;  /* ceil(l*60/512) */
710         misc_auth_bytes[3] = locktime + 1;      /* will be 1 if user said 0 */
711     }
712 #if ASSOCIATES
713     if (as->parms[8].items) {
714         maxAssociates = atoi(as->parms[6].items->data);
715         if (maxAssociates < 0) {
716             printf("Illegal maximum number of associates\n");
717             return KABADCMD;
718         }
719     }
720 #endif
721     was_spare = pack_long(misc_auth_bytes);
722
723     if (was_spare || flags || expiration || lifetime || (maxAssociates >= 0))
724         code =
725             ubik_Call(KAM_SetFields, conn, 0, name, instance, flags,
726                       expiration, lifetime, maxAssociates, was_spare,
727                       /* spare */ 0);
728     else {
729         printf("Must specify one of the optional parameters\n");
730         return KABADCMD;
731     }
732     if (code)
733         com_err(whoami, code, "calling KAM_SetFields for %s.%s", name,
734                 instance);
735     return code;
736 }
737
738 int
739 StringToKey(struct cmd_syndesc *as, char *arock)
740 {
741     afs_int32 code;
742     char realm[MAXKTCREALMLEN];
743     struct ktc_encryptionKey key;
744
745     if (as->parms[1].items) {
746         code = ka_ExpandCell(as->parms[1].items->data, realm, 0 /*local */ );
747         if (code) {
748             com_err(whoami, code,
749                     "expanding %s as cell name, attempting to continue",
750                     as->parms[1].items->data);
751         }
752         ucstring(realm, realm, sizeof(realm));
753     } else {
754         if (code = DefaultCell())
755             return code;
756         ucstring(realm, cell, sizeof(realm));
757     }
758     ka_StringToKey(as->parms[0].items->data, realm, &key);
759
760     printf("Converting %s in realm '%s' yields key='",
761            as->parms[0].items->data, realm);
762     ka_PrintBytes((char *)&key, sizeof(key));
763     printf("'.\n");
764
765     des_string_to_key(as->parms[0].items->data, &key);
766
767     printf("Converting %s with the DES string to key yields key='",
768            as->parms[0].items->data);
769     ka_PrintBytes((char *)&key, sizeof(key));
770     printf("'.\n");
771
772     return 0;
773 }
774
775 int
776 SetPassword(struct cmd_syndesc *as, char *arock)
777 {
778     int code;
779     char name[MAXKTCNAMELEN];
780     char instance[MAXKTCNAMELEN];
781     char realm[MAXKTCREALMLEN];
782     struct ktc_encryptionKey key;
783     afs_int32 kvno = 0;
784
785     code = ka_ParseLoginName(as->parms[0].items->data, name, instance, realm);
786     if (code) {
787         com_err(whoami, code, "parsing user's name '%s'",
788                 as->parms[0].items->data);
789         return KABADCMD;
790     }
791
792     if (strlen(realm) == 0)
793         ucstring(realm, cell, sizeof(realm));
794
795     if (as->parms[1].items && as->parms[2].items) {
796         printf("Can't specify both a password and a key\n");
797         return KABADCMD;
798     } else if (as->parms[1].items) {
799         (void)init_child(myName);
800         (void)give_to_child(passwd);    /* old password */
801         code = password_bad(as->parms[1].items->data);
802         (void)terminate_child();
803         if (code)
804             return KABADCMD;
805         ka_StringToKey(as->parms[1].items->data, realm, &key);
806     } else if (as->parms[2].items) {
807         if (ka_ReadBytes(as->parms[2].items->data, (char *)&key, sizeof(key))
808             != 8) {
809             printf("Key must be 8 bytes: '%s' was too long\n",
810                    as->parms[2].items->data);
811             return KABADCMD;
812         }
813     } else {
814         printf("Must specify new password or key\n");
815         return KABADCMD;
816     }
817
818
819     if (as->parms[3].items)
820         sscanf(as->parms[3].items->data, "%d", &kvno);
821
822 #if defined(AFS_S390_LINUX20_ENV) && !defined(AFS_S390X_LINUX20_ENV)
823     code = ubik_Call(KAM_SetPassword, conn, 0, name, instance, kvno, 0, key);
824 #else
825     code = ubik_Call(KAM_SetPassword, conn, 0, name, instance, kvno, key);
826 #endif
827     if (code)
828         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         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         com_err(whoami, code, "failed to get token info for server %s",
924                 PrintedPrincipal(server));
925         return code;
926     }
927     code = PrintPrincipal(&client, UserName, sizeof(UserName));
928     if (code)
929         return code;
930     /* spaces are printed as "\040" */
931     if (UserName[0] == 0)
932         printf("Tokens");
933     else if (strncmp(UserName, "AFS\\040ID\\040", 13) == 0) {
934         printf("User's (AFS ID %s) tokens", UserName + 13);
935     } else if (strncmp(UserName, "Unix\\040UID\\040", 15) == 0) {
936         printf("Tokens");
937     } else
938         printf("User %s's tokens", UserName);
939
940     code = PrintPrincipal(server, ServerName, sizeof(ServerName));
941     if (code)
942         return code;
943     printf(" for %s ", ServerName);
944
945     if (token.startTime > now) {
946         ka_timestr(token.startTime, bob, KA_TIMESTR_LEN);
947         printf("[>> POSTDATED 'till %s <<]", bob);
948     }
949
950     if (token.endTime <= now)
951         printf("[>> Expired <<]\n");
952     else {
953         ka_timestr(token.endTime, bob, KA_TIMESTR_LEN);
954         printf("[Expires %s]\n", bob);
955     }
956     if (verbose) {
957         printf("SessionKey: ");
958         ka_PrintBytes((char *)&token.sessionKey, sizeof(token.sessionKey));
959         printf("\nTicket (kvno = %d, len = %d): ", token.kvno,
960                token.ticketLen);
961         ka_PrintBytes((char *)token.ticket, token.ticketLen);
962         printf("\n");
963     }
964     return 0;
965 }
966
967 static
968 GetTicket(struct cmd_syndesc *as, char *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         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             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         com_err(whoami, code, "getting ticket for %s",
1006                 PrintedPrincipal(&server));
1007     else {
1008         code = ListTicket(&server, /*verbose */ 1);
1009     }
1010     return code;
1011 }
1012
1013 static
1014 GetPassword(struct cmd_syndesc *as, char *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         com_err(whoami, code,
1026                 "getting %s's password via loopback connection to GetPassword",
1027                 name);
1028         /* if we got a timeout, print a clarification, too */
1029         if (code == -1) {
1030             fprintf(stderr,
1031                     "%s: please note that this command must be run locally on a database server machine.\n",
1032                     whoami);
1033         }
1034         return code;
1035     }
1036     if (lpbkConn == 0) {
1037         struct rx_connection *conns[2];
1038         struct rx_securityClass *sc;
1039         int si;                 /* security class index */
1040
1041         code = rx_Init(0);
1042         if (code)
1043             goto abort;
1044         sc = rxnull_NewClientSecurityObject();
1045         si = RX_SCINDEX_NULL;
1046         conns[0] =
1047             rx_NewConnection(htonl(INADDR_LOOPBACK), htons(AFSCONF_KAUTHPORT),
1048                              KA_MAINTENANCE_SERVICE, sc, si);
1049         conns[1] = 0;
1050         code = ubik_ClientInit(conns, &lpbkConn);
1051         if (code)
1052             goto abort;
1053     }
1054     code = ubik_Call(KAM_GetPassword, lpbkConn, 0, name, &key);
1055     /* Lets close down the ubik_Client connection now */
1056     ubik_ClientDestroy(lpbkConn);
1057     if (code)
1058         goto abort;
1059     printf("Key: ");
1060     ka_PrintBytes((char *)&key, sizeof(key));
1061     printf("\n");
1062     return code;
1063 }
1064
1065 int
1066 GetRandomKey(struct cmd_syndesc *as, char *arock)
1067 {
1068     int code;
1069     struct ktc_encryptionKey key;
1070
1071     code = ubik_Call(KAM_GetRandomKey, conn, 0, &key);
1072     if (code)
1073         com_err(whoami, code, "so can't get random key");
1074     else {
1075         int i;
1076         printf("Key: ");
1077         ka_PrintBytes((char *)&key, sizeof(key));
1078         printf(" (");
1079         for (i = 0; i < sizeof(key); i++) {
1080             printf("%0.2x", ((char *)&key)[i] & 0xff);
1081             if (i == 3)
1082                 printf(" ");
1083             else if (i != 7)
1084                 printf(".");
1085         }
1086         printf(")\n");
1087     }
1088     return code;
1089 }
1090
1091 int
1092 Statistics(struct cmd_syndesc *as, char *arock)
1093 {
1094     int code;
1095     kasstats statics;
1096     kadstats dynamics;
1097     afs_int32 admins;
1098     char bob[KA_TIMESTR_LEN];
1099
1100     code =
1101         ubik_Call(KAM_GetStats, conn, 0, KAMAJORVERSION, &admins, &statics,
1102                   &dynamics);
1103     if (code) {
1104         printf("call to GetStats failed: %s\n", ka_ErrorString(code));
1105         return code;
1106     }
1107     if (statics.minor_version != KAMINORVERSION)
1108         printf("Minor version number mismatch: got %d, expected %d\n",
1109                statics.minor_version, KAMINORVERSION);
1110     printf("%d allocs, %d frees, %d password changes\n", statics.allocs,
1111            statics.frees, statics.cpws);
1112     printf("Hash table utilization = %f%%\n",
1113            (double)dynamics.hashTableUtilization / 100.0);
1114     ka_timestr(dynamics.start_time, bob, KA_TIMESTR_LEN);
1115     printf("From host %lx started at %s:\n", dynamics.host, bob);
1116
1117 #define print_stat(name) if (dynamics.name.requests) printf ("  of %d requests for %s, %d were aborted.\n", dynamics.name.requests, # name, dynamics.name.aborts)
1118     print_stat(Authenticate);
1119     print_stat(ChangePassword);
1120     print_stat(GetTicket);
1121     print_stat(CreateUser);
1122     print_stat(SetPassword);
1123     print_stat(SetFields);
1124     print_stat(DeleteUser);
1125     print_stat(GetEntry);
1126     print_stat(ListEntry);
1127     print_stat(GetStats);
1128     print_stat(GetPassword);
1129     print_stat(GetRandomKey);
1130     print_stat(Debug);
1131     print_stat(UAuthenticate);
1132     print_stat(UGetTicket);
1133
1134 #if (KAMAJORVERSION>5)
1135     print cpu stats printf("%d string checks\n", dynamics.string_checks);
1136 #else
1137     printf("Used %.3f seconds of CPU time.\n",
1138            dynamics.string_checks / 1000.0);
1139 #endif
1140     printf("%d admin accounts\n", admins);
1141     return 0;
1142 }
1143
1144 int
1145 DebugInfo(struct cmd_syndesc *as, char *arock)
1146 {
1147     int code;
1148     struct ka_debugInfo info;
1149     int i;
1150     Date start, now;
1151     int timeOffset;
1152     char bob[KA_TIMESTR_LEN];
1153
1154     start = time(0);
1155     if (as->parms[0].items) {
1156         struct ubik_client *iConn;
1157         code =
1158             ka_SingleServerConn(cell, as->parms[0].items->data,
1159                                 KA_MAINTENANCE_SERVICE, 0, &iConn);
1160         if (code) {
1161             struct afsconf_cell cellinfo;
1162
1163             com_err(whoami, code, "couldn't find host %s in cell %s",
1164                     as->parms[0].items->data, cell);
1165             code = ka_GetServers(cell, &cellinfo);
1166             if (code)
1167                 com_err(whoami, code, "getting servers in cell %s", cell);
1168             else {
1169                 printf("Servers in cell %s, are:\n", cell);
1170                 for (i = 0; i < cellinfo.numServers; i++)
1171                     printf("  %s\n", cellinfo.hostName[i]);
1172             }
1173             return code;
1174         }
1175         code = ubik_Call(KAM_Debug, iConn, 0, KAMAJORVERSION, 0, &info);
1176         ubik_ClientDestroy(iConn);
1177     } else
1178         code = ubik_Call(KAM_Debug, conn, 0, KAMAJORVERSION, 0, &info);
1179
1180     if (code) {
1181         com_err(whoami, code, "call to Debug failed");
1182         return code;
1183     }
1184     now = time(0);
1185
1186     if (info.minorVersion != KAMINORVERSION)
1187         printf("Minor version number mismatch: got %d, expected %d\n",
1188                info.minorVersion, KAMINORVERSION);
1189
1190     timeOffset = info.
1191 #if (KAMAJORVERSION>5)
1192         now
1193 #else
1194         reserved1
1195 #endif
1196         - now;
1197     if (timeOffset < 0)
1198         timeOffset = -timeOffset;
1199     if (timeOffset > 60) {
1200         printf
1201             ("WARNING: Large server client clock skew: %d seconds. Call itself took %d seconds.\n",
1202              timeOffset, now - start);
1203     }
1204     ka_timestr(info.startTime, bob, KA_TIMESTR_LEN);
1205     printf("From host %lx started %sat %s:\n", info.host,
1206            (info.noAuth ? "w/o authorization " : ""), bob);
1207     ka_timestr(info.lastTrans, bob, KA_TIMESTR_LEN);
1208     printf("Last trans was %s at %s\n", info.lastOperation, bob);
1209     ka_timestr(info.dbHeaderRead, bob, KA_TIMESTR_LEN);
1210     printf("Header last read %s.\n", bob);
1211     printf("db version=%d, keyVersion=%d, key cache version=%d\n",
1212            info.dbVersion, info.dbSpecialKeysVersion, info.kcVersion);
1213     printf("db ptrs: free %d, eof %d, kvno %d.\n", info.dbFreePtr,
1214            info.dbEofPtr, info.dbKvnoPtr);
1215     ka_timestr(info.nextAutoCPW, bob, KA_TIMESTR_LEN);
1216     printf("Next autoCPW at %s or in %d updates.\n", bob,
1217            info.updatesRemaining);
1218     if (info.cheader_lock || info.keycache_lock)
1219         printf("locks: cheader %08lx, keycache %08lx\n", info.cheader_lock,
1220                info.keycache_lock);
1221     printf("Last authentication for %s, last admin user was %s\n",
1222            info.lastAuth, info.lastAdmin);
1223     printf("Last TGS op was a %s ticket was for %s\n", info.lastTGSServer,
1224            info.lastTGS);
1225     printf("Last UDP TGS was a %s ticket for %s.  UDP Authenticate for %s\n",
1226            info.lastUTGSServer, info.lastUTGS, info.lastUAuth);
1227     printf("key cache size %d, used %d.\n", info.kcSize, info.kcUsed);
1228     if (info.kcUsed > KADEBUGKCINFOSIZE) {
1229         printf("insufficient room to return all key cache entries!\n");
1230         info.kcUsed = KADEBUGKCINFOSIZE;
1231     }
1232     for (i = 0; i < info.kcUsed; i++)
1233         ka_timestr(info.kcInfo[i].used, bob, KA_TIMESTR_LEN);
1234     printf("%32s %c %2x(%2x) used %s\n", info.kcInfo[i].principal,
1235            (info.kcInfo[i].primary ? '*' : ' '), info.kcInfo[i].kvno,
1236            info.kcInfo[i].keycksum, bob);
1237     return 0;
1238 }
1239
1240 int
1241 Interactive(struct cmd_syndesc *as, char *arock)
1242 {
1243     finished = 0;
1244     return 0;
1245 }
1246
1247 int
1248 Quit(struct cmd_syndesc *as, char *arock)
1249 {
1250     finished = 1;
1251     return 0;
1252 }
1253
1254 int
1255 MyAfterProc(struct cmd_syndesc *as)
1256 {
1257     if (!strcmp(as->name, "help"))
1258         return 0;
1259
1260     /* Determine if we need to destory the ubik connection.
1261      * Closing it avoids resends of packets. 
1262      */
1263     if (conn) {
1264         ubik_ClientDestroy(conn);
1265         conn = 0;
1266     }
1267
1268     return 0;
1269 }
1270
1271 int init = 0, noauth;
1272 char name[MAXKTCNAMELEN];
1273 char instance[MAXKTCNAMELEN];
1274 char newCell[MAXKTCREALMLEN];
1275 afs_int32 serverList[MAXSERVERS];
1276
1277 int
1278 NoAuth(struct cmd_syndesc *as, char *arock)
1279 {
1280     noauth = 1;
1281     return 0;
1282 }
1283
1284 static int
1285 MyBeforeProc(struct cmd_syndesc *as, char *arock)
1286 {
1287     extern struct passwd *getpwuid();
1288     struct ktc_encryptionKey key;
1289     struct ktc_principal auth_server, auth_token, client;
1290     char realm[MAXKTCREALMLEN];
1291
1292     struct ktc_token token, *pToken;
1293     int i, acode, code = 0;
1294
1295     {
1296         char *ws = strrchr(as->a0name, '/');
1297         if (ws)
1298             ws++;               /* skip everything before the "/" */
1299         else
1300             ws = as->a0name;
1301         if (strlen(ws) > 0) {
1302             strncpy(whoami, ws, sizeof(whoami));
1303             if (strlen(whoami) + 1 >= sizeof(whoami))
1304                 strcpy(whoami, "kas:");
1305             else
1306                 strcat(whoami, ":");
1307         } else
1308             whoami[0] = 0;
1309         /* append sub-command name */
1310         strncat(whoami, as->name, sizeof(whoami) - strlen(whoami) - 1);
1311     }
1312
1313     if (as->parms[12].name == 0)
1314         return 0;
1315
1316     assert(as->parms[13].name && as->parms[14].name && as->parms[15].name
1317            && as->parms[16].name);
1318
1319     /* MyAfterProc() destroys the conn, but just to be sure */
1320     if (conn) {
1321         code = ubik_ClientDestroy(conn);
1322         conn = 0;
1323     }
1324
1325     if (!init || as->parms[12].items || as->parms[13].items
1326         || as->parms[14].items || as->parms[15].items
1327         || as->parms[16].items) {
1328         strcpy(instance, "");
1329         strcpy(newCell, "");
1330
1331         if (as->parms[12].items) {      /* -admin_username */
1332             code =
1333                 ka_ParseLoginName(as->parms[12].items->data, name, instance,
1334                                   newCell);
1335             if (code) {
1336                 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             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                 com_err(whoami, code, "could not parse server list");
1383                 return code;
1384             }
1385             ka_ExplicitCell(cell, serverList);
1386         }
1387
1388         noauth = (as->parms[16].items ? 1 : 0); /* -noauth */
1389
1390         init = 1;
1391     }
1392
1393     token.ticketLen = 0;        /* in case there are no tokens */
1394     if (!noauth) {              /* Will prompt for a password */
1395         /* first see if there's already an admin ticket */
1396         code =
1397             ka_GetAdminToken(0, 0, cell, 0, KA_SIXHOURS, &token,
1398                              0 /* !new */ );
1399         if (code) {             /* if not then get key and try again */
1400             if (as->parms[13].items) {  /* if password specified */
1401                 strncpy(passwd, as->parms[13].items->data, sizeof(passwd));
1402                 memset(as->parms[13].items->data, 0,
1403                        strlen(as->parms[13].items->data));
1404             } else {
1405                 char msg[MAXKTCNAMELEN + 50];
1406                 if (as->parms[12].items)
1407                     sprintf(msg, "Administrator's (%s) Password: ", name);
1408                 else
1409                     sprintf(msg, "Password for %s: ", name);
1410                 code = read_pw_string(passwd, sizeof(passwd), msg, 0);
1411                 if (code)
1412                     code = KAREADPW;
1413                 else if (strlen(passwd) == 0)
1414                     code = KANULLPASSWORD;
1415                 if (code) {
1416                     com_err(whoami, code, "reading password");
1417                     return code;
1418                 }
1419             }
1420             ka_StringToKey(passwd, cell, &key);
1421             code =
1422                 ka_GetAdminToken(name, instance, cell, &key, KA_SIXHOURS,
1423                                  &token, 0 /* !new */ );
1424             if (code == KABADREQUEST) {
1425                 des_string_to_key(passwd, &key);
1426                 code =
1427                     ka_GetAdminToken(name, instance, cell, &key, KA_SIXHOURS,
1428                                      &token, 0 /* !new */ );
1429             }
1430             if ((code == KABADREQUEST) && (strlen(passwd) > 8)) {
1431                 /* try with only the first 8 characters incase they set
1432                  * their password with an old style passwd program. */
1433                 passwd[8] = 0;
1434                 ka_StringToKey(passwd, cell, &key);
1435                 code =
1436                     ka_GetAdminToken(name, instance, cell, &key, KA_SIXHOURS,
1437                                      &token, 0 /* !new */ );
1438                 if (code == 0) {
1439                     fprintf(stderr,
1440                             "Warning: you have typed a password longer than 8 characters, but only the\n");
1441                     fprintf(stderr,
1442                             "first 8 characters were actually significant.  If you change your password\n");
1443                     fprintf(stderr,
1444                             "again this warning message will go away.\n");
1445                 }
1446             }
1447             if (code) {
1448                 char *reason;
1449                 switch (code) {
1450                 case KABADREQUEST:
1451                     reason = "password was incorrect";
1452                     break;
1453                 case KAUBIKCALL:
1454                     reason = "Authentication Server was unavailable";
1455                     break;
1456                 default:
1457                     reason = (char *)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                     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         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             com_err(whoami, code,
1494                     "making unauthenticated connection to AuthServer");
1495     }
1496     if (code) {
1497         com_err(whoami, code,
1498                 "Couldn't establish connection to Authentication Server");
1499         return code;
1500     }
1501
1502     /* now default unspecified password by prompting from terminal */
1503     if (as->nParms >= 12)
1504         for (i = 0; i < 12; i++)
1505             if (as->parms[i].name && (as->parms[i].items == 0)) {
1506                 char *p = as->parms[i].name;    /* parameter name */
1507                 int l = strlen(p);      /* length of name */
1508                 /* does parameter end in "password"  */
1509                 if (strcmp(p + (l - 8), "password") == 0) {
1510                     char msg[32];
1511                     char password[BUFSIZ];
1512                     struct cmd_item *ip;
1513
1514                     strcpy(msg, p + 1);
1515                     strcat(msg, ": ");
1516                     code = read_pw_string(password, sizeof(password), msg, 1);
1517                     if (code)
1518                         code = KAREADPW;
1519                     else if (strlen(password) == 0)
1520                         code = KANULLPASSWORD;
1521                     if (code) {
1522                         com_err(whoami, code, "prompting for %s", p + 1);
1523                         return code;
1524                     }
1525                     ip = (struct cmd_item *)malloc(sizeof(struct cmd_item));
1526                     ip->data = (char *)malloc(strlen(password) + 1);
1527                     ip->next = 0;
1528                     strcpy(ip->data, password);
1529                     as->parms[i].items = ip;
1530                 }
1531             }
1532     if (!conn) {                /* if all else fails... */
1533         code = NoAuth(0, 0);    /* get unauthenticated conn */
1534         if (code)
1535             return code;
1536     }
1537     return 0;
1538 }
1539
1540 /* These are some helpful command that deal with the cache managers tokens. */
1541
1542 static
1543 ForgetTicket(struct cmd_syndesc *as, char *arock)
1544 {
1545     afs_int32 code;
1546
1547 #ifdef notdef
1548     struct ktc_principal server;
1549
1550     if (as->parms[0].items) {
1551         char *name = as->parms[0].items->data;
1552         code =
1553             ka_ParseLoginName(name, server.name, server.instance,
1554                               server.cell);
1555         if (code) {
1556             com_err(whoami, code, "couldn't interpret name '%s'", name);
1557             return code;
1558         }
1559         if (server.cell[0] == 0) {
1560             if (code = DefaultCell())
1561                 return code;
1562             strcpy(server.cell, cell);
1563         } else {
1564             code = ka_ExpandCell(server.cell, server.cell, 0 /*local */ );
1565             if (code) {
1566                 com_err(whoami, code, "Can't expand cell name");
1567                 return code;
1568             }
1569         }
1570         code = ktc_ForgetToken(&server);
1571         if (code) {
1572             com_err(whoami, code, "couldn't remove tokens for %s",
1573                     PrintedPrincipal(&server));
1574             return code;
1575         }
1576     } else {
1577         if (!as->parms[1].items) {
1578             fprintf(stderr, "Must specify server name or -all\n");
1579             return KABADCMD;
1580         }
1581         code = ktc_ForgetAllTokens();
1582         if (code) {
1583             com_err(whoami, code, "couldn't delete all tokens");
1584             return code;
1585         }
1586     }
1587 #endif
1588     code = ktc_ForgetAllTokens();
1589     if (code) {
1590         com_err(whoami, code, "couldn't delete all tokens");
1591         return code;
1592     }
1593     return 0;
1594 }
1595
1596 static
1597 ListTickets(struct cmd_syndesc *as, char *arock)
1598 {
1599     afs_int32 code = 0;
1600     int index, newIndex;
1601     struct ktc_principal server;
1602     int verbose = 0;
1603
1604     if (as->parms[1].items)
1605         verbose = 1;
1606     if (as->parms[0].items) {
1607         char *name = as->parms[0].items->data;
1608         code =
1609             ka_ParseLoginName(name, server.name, server.instance,
1610                               server.cell);
1611         if (code) {
1612             com_err(whoami, code, "couldn't interpret name '%s'", name);
1613             return code;
1614         }
1615         if (server.cell[0] == 0) {
1616             if (code = DefaultCell())
1617                 return code;
1618             strcpy(server.cell, cell);
1619         } else {
1620             code = ka_ExpandCell(server.cell, server.cell, 0 /*local */ );
1621             if (code) {
1622                 com_err(whoami, code, "Can't expand cell name");
1623                 return code;
1624             }
1625         }
1626         code = ListTicket(&server, verbose);
1627     } else
1628         for (index = 0;; index = newIndex) {
1629             code = ktc_ListTokens(index, &newIndex, &server);
1630             if (code) {
1631                 if (code == KTC_NOENT)
1632                     code = 0;   /* end of list */
1633                 break;
1634             }
1635             code = ListTicket(&server, verbose);
1636         }
1637     return code;
1638 }
1639
1640 static void
1641 add_std_args(register struct cmd_syndesc *ts)
1642 {
1643     cmd_Seek(ts, 12);
1644     /* 12 */ cmd_AddParm(ts, "-admin_username", CMD_SINGLE, CMD_OPTIONAL,
1645                          "admin principal to use for authentication");
1646     /* 13 */ cmd_AddParm(ts, "-password_for_admin", CMD_SINGLE, CMD_OPTIONAL,
1647                          "admin password");
1648     /* 14 */ cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
1649     /* 15 */ cmd_AddParm(ts, "-servers", CMD_LIST, CMD_OPTIONAL,
1650                          "explicit list of authentication servers");
1651     /* 16 */ cmd_AddParm(ts, "-noauth", CMD_FLAG, CMD_OPTIONAL,
1652                          "don't authenticate");
1653 }
1654
1655 afs_int32
1656 ka_AdminInteractive(int cmd_argc, char *cmd_argv[])
1657 {
1658     register int code;
1659     register struct cmd_syndesc *ts;
1660
1661     char line[BUFSIZ];
1662     afs_int32 argc;
1663     char *argv[32];
1664
1665     strncpy(myName, *cmd_argv, 509);
1666
1667     cmd_SetBeforeProc(MyBeforeProc, NULL);
1668     cmd_SetAfterProc(MyAfterProc, NULL);
1669
1670     ts = cmd_CreateSyntax("interactive", Interactive, 0,
1671                           "enter interactive mode");
1672     add_std_args(ts);
1673
1674     ts = cmd_CreateSyntax("noauthentication", NoAuth, 0,
1675                           "connect to AuthServer w/o using token");
1676
1677     ts = cmd_CreateSyntax("list", ListUsers, 0, "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, 0,
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, 0,
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, 0, "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, 0,
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, 0,
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, 0,
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, 0,
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, 0, (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, 0, (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, 0,
1775                           (char *)CMD_HIDDEN);
1776     add_std_args(ts);
1777
1778     /* get a ticket for a specific server */
1779     ts = cmd_CreateSyntax("getticket", GetTicket, 0, (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, 0,
1785                           "show statistics for AuthServer");
1786     add_std_args(ts);
1787
1788     /* show debugging info from AuthServer */
1789     ts = cmd_CreateSyntax("debuginfo", DebugInfo, 0, (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, 0,
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, 0,
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, 0, "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             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 }