ubik-iter-proto-20041208
[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, (long) name,
516                           (long) instance, (long) &tempwhen, 0, 0, 0,
517                           0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
518         if (code) {
519             if (seriouserror(code))
520                 com_err(whoami, code, "");
521         } else if (tempwhen) {  /* user is locked */
522             if (!*when || tempwhen < *when) {
523                 *when = tempwhen;
524                 return (*when);
525             }
526         } else                  /* ! tempwhen ==> user is not locked */
527             return 0;
528
529     } while (code != UNOSERVERS);
530
531     return (*when);
532 }
533
534 int
535 Unlock(struct cmd_syndesc *as, char *arock)
536 {
537     afs_int32 code, rcode = 0;
538     afs_int32 count;
539     afs_int32 server;
540     char name[MAXKTCNAMELEN];
541     char instance[MAXKTCNAMELEN];
542
543     code = ka_ParseLoginName(as->parms[0].items->data, name, instance, 0);
544     if (code) {
545         com_err(whoami, code, "parsing user's name '%s'",
546                 as->parms[0].items->data);
547         return KABADCMD;
548     }
549
550     count = 0;
551     do {
552         code = ubik_CallIter(KAM_Unlock, conn, 0, &count, (long) name, (long) instance,
553                              0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
554         if (code && (code != UNOSERVERS)) {
555             server = 0;
556             if (conn && conn->conns[count - 1]
557                 && conn->conns[count - 1]->peer) {
558                 server = conn->conns[count - 1]->peer->host;
559             }
560             com_err(whoami, code,
561                     "so %s.%s may still be locked (on server %d.%d.%d.%d)",
562                     name, instance, ((server >> 24) & 0xFF),
563                     ((server >> 16) & 0xFF), ((server >> 8) & 0xFF),
564                     (server & 0xFF));
565
566             if (!rcode) {
567                 rcode = code;
568             }
569         }
570     } while (code != UNOSERVERS);
571
572     return rcode;
573 }
574
575 int
576 SetFields(struct cmd_syndesc *as, char *arock)
577 {
578     int code;
579     char name[MAXKTCNAMELEN];
580     char instance[MAXKTCNAMELEN];
581     afs_int32 flags = 0;
582     Date expiration = 0;
583     afs_int32 lifetime = 0;
584     afs_int32 maxAssociates = -1;
585     afs_int32 pwexpiry = 0;
586     afs_int32 was_spare = 0;
587     char misc_auth_bytes[4];
588     int i;
589
590     code = ka_ParseLoginName(as->parms[0].items->data, name, instance, 0);
591     if (code) {
592         com_err(whoami, code, "parsing user's name '%s'",
593                 as->parms[0].items->data);
594         return KABADCMD;
595     }
596
597     if (as->parms[1].items) {
598         code = parse_flags(name, instance, as->parms[1].items->data, &flags);
599         if (code) {
600             printf
601                 ("Illegal flag specification: %s, should be of the form <'='|'+'|'-'|'_'>bitname{<'+'|'-'>bitname}*\n",
602                  as->parms[1].items->data);
603             return KABADCMD;
604         }
605     }
606     if (as->parms[2].items) {
607         char buf[32];
608         char *s = strncpy(buf, as->parms[2].items->data, sizeof(buf));
609         code = ktime_DateToInt32(s, &expiration);
610         if (code) {
611             printf("Illegal time format %s: %s\n", as->parms[2].items->data,
612                    ktime_GetDateUsage());
613             return KABADCMD;
614         }
615         if (expiration == 0) {
616             fprintf(stderr, "Expiration time must be after (about) 1970.\n");
617             return KABADCMD;
618         }
619         if (expiration < time(0)) {
620             fprintf(stderr,
621                     "Warning: expiration being set into the past, account will be disabled.\n");
622         }
623     }
624     /*
625      * TICKET lifetime...
626      */
627     if (as->parms[3].items) {
628         code = read_time_interval(as->parms[3].items->data, &lifetime);
629         if (code)
630             return KABADCMD;
631     }
632
633     /*  no point in doing this any sooner than necessary */
634     for (i = 0; i < 4; misc_auth_bytes[i++] = 0);
635
636     if (as->parms[4].items) {
637         if (util_isint(as->parms[4].items->data))
638             pwexpiry = atoi(as->parms[4].items->data);
639         else {
640             fprintf(stderr,
641                     "Password lifetime specified must be a non-negative decimal integer.\n");
642             pwexpiry = -1;
643         }
644         if (pwexpiry < 0 || pwexpiry > 254) {
645             fprintf(stderr,
646                     "Password lifetime range must be [0..254] days.\n");
647             fprintf(stderr, "Zero represents an unlimited lifetime.\n");
648             return KABADCMD;
649         } else {
650             misc_auth_bytes[0] = pwexpiry + 1;
651         }
652     }
653
654     if (as->parms[5].items) {
655         char *reuse;
656         reuse = (as->parms[5].items->data);
657
658         if (!strcmp(reuse, "yes")) {
659             misc_auth_bytes[1] = KA_REUSEPW;
660         } else if (strcmp(reuse, "no")) {
661             fprintf(stderr,
662                     "must specify \"yes\" or \"no\": \"yes\" assumed\n");
663             misc_auth_bytes[1] = KA_REUSEPW;
664         } else {
665             misc_auth_bytes[1] = KA_NOREUSEPW;
666         }
667     }
668
669     if (as->parms[6].items) {
670         int nfailures;
671
672
673         if (util_isint(as->parms[6].items->data)
674             && ((nfailures = atoi(as->parms[6].items->data)) < 255)) {
675             misc_auth_bytes[2] = nfailures + 1;
676         } else {
677             fprintf(stderr, "Failure limit must be in [0..254].\n");
678             fprintf(stderr, "Zero represents unlimited login attempts.\n");
679             return KABADCMD;
680         }
681     }
682
683     if (as->parms[7].items) {
684         int locktime, hrs, mins;
685         char *s;
686
687         hrs = 0;
688         s = as->parms[7].items->data;
689         if (strchr(s, ':'))
690             sscanf(s, "%d:%d", &hrs, &mins);
691         else
692             sscanf(s, "%d", &mins);
693
694         locktime = hrs * 60 + mins;
695         if (hrs < 0 || hrs > 36 || mins < 0) {
696             fprintf(stderr,
697                     "Lockout times must be either minutes or hh:mm.\n");
698             fprintf(stderr, "Lockout times must be less than 36 hours.\n");
699             return KABADCMD;
700         } else if (locktime > 36 * 60) {
701             fprintf(stderr,
702                     "Lockout times must be either minutes or hh:mm.\n");
703             fprintf(stderr, "Lockout times must be less than 36 hours.\n");
704             fprintf(stderr,
705                     "Continuing with lock time of exactly 36 hours...\n");
706             locktime = 36 * 60;
707         }
708         locktime = (locktime * 60 + 511) >> 9;  /* ceil(l*60/512) */
709         misc_auth_bytes[3] = locktime + 1;      /* will be 1 if user said 0 */
710     }
711 #if ASSOCIATES
712     if (as->parms[8].items) {
713         maxAssociates = atoi(as->parms[6].items->data);
714         if (maxAssociates < 0) {
715             printf("Illegal maximum number of associates\n");
716             return KABADCMD;
717         }
718     }
719 #endif
720     was_spare = pack_long(misc_auth_bytes);
721
722     if (was_spare || flags || expiration || lifetime || (maxAssociates >= 0))
723         code =
724             ubik_Call(KAM_SetFields, conn, 0, name, instance, flags,
725                       expiration, lifetime, maxAssociates, was_spare,
726                       /* spare */ 0);
727     else {
728         printf("Must specify one of the optional parameters\n");
729         return KABADCMD;
730     }
731     if (code)
732         com_err(whoami, code, "calling KAM_SetFields for %s.%s", name,
733                 instance);
734     return code;
735 }
736
737 int
738 StringToKey(struct cmd_syndesc *as, char *arock)
739 {
740     afs_int32 code;
741     char realm[MAXKTCREALMLEN];
742     struct ktc_encryptionKey key;
743
744     if (as->parms[1].items) {
745         code = ka_ExpandCell(as->parms[1].items->data, realm, 0 /*local */ );
746         if (code) {
747             com_err(whoami, code,
748                     "expanding %s as cell name, attempting to continue",
749                     as->parms[1].items->data);
750         }
751         ucstring(realm, realm, sizeof(realm));
752     } else {
753         if (code = DefaultCell())
754             return code;
755         ucstring(realm, cell, sizeof(realm));
756     }
757     ka_StringToKey(as->parms[0].items->data, realm, &key);
758
759     printf("Converting %s in realm '%s' yields key='",
760            as->parms[0].items->data, realm);
761     ka_PrintBytes((char *)&key, sizeof(key));
762     printf("'.\n");
763
764     des_string_to_key(as->parms[0].items->data, &key);
765
766     printf("Converting %s with the DES string to key yields key='",
767            as->parms[0].items->data);
768     ka_PrintBytes((char *)&key, sizeof(key));
769     printf("'.\n");
770
771     return 0;
772 }
773
774 int
775 SetPassword(struct cmd_syndesc *as, char *arock)
776 {
777     int code;
778     char name[MAXKTCNAMELEN];
779     char instance[MAXKTCNAMELEN];
780     char realm[MAXKTCREALMLEN];
781     struct ktc_encryptionKey key;
782     afs_int32 kvno = 0;
783
784     code = ka_ParseLoginName(as->parms[0].items->data, name, instance, realm);
785     if (code) {
786         com_err(whoami, code, "parsing user's name '%s'",
787                 as->parms[0].items->data);
788         return KABADCMD;
789     }
790
791     if (strlen(realm) == 0)
792         ucstring(realm, cell, sizeof(realm));
793
794     if (as->parms[1].items && as->parms[2].items) {
795         printf("Can't specify both a password and a key\n");
796         return KABADCMD;
797     } else if (as->parms[1].items) {
798         (void)init_child(myName);
799         (void)give_to_child(passwd);    /* old password */
800         code = password_bad(as->parms[1].items->data);
801         (void)terminate_child();
802         if (code)
803             return KABADCMD;
804         ka_StringToKey(as->parms[1].items->data, realm, &key);
805     } else if (as->parms[2].items) {
806         if (ka_ReadBytes(as->parms[2].items->data, (char *)&key, sizeof(key))
807             != 8) {
808             printf("Key must be 8 bytes: '%s' was too long\n",
809                    as->parms[2].items->data);
810             return KABADCMD;
811         }
812     } else {
813         printf("Must specify new password or key\n");
814         return KABADCMD;
815     }
816
817
818     if (as->parms[3].items)
819         sscanf(as->parms[3].items->data, "%d", &kvno);
820
821 #if defined(AFS_S390_LINUX20_ENV) && !defined(AFS_S390X_LINUX20_ENV)
822     code = ubik_Call(KAM_SetPassword, conn, 0, name, instance, kvno, 0, key);
823 #else
824     code = ubik_Call(KAM_SetPassword, conn, 0, name, instance, kvno, key);
825 #endif
826     if (code)
827         com_err(whoami, code, "so can't set password for %s.%s", name,
828                 instance);
829     return code;
830 }
831
832 #define PrintPrincipal(p,n,l) \
833     PrintName((p)->name, (p)->instance, (p)->cell, l, n)
834
835 static afs_int32
836 PrintName(char *name, char *inst, char *acell, int buflen, char *buf)
837 {
838     int nlen, len;
839     int left;                   /* if ConvertBytes stops early */
840     afs_int32 code;
841
842     if (name == 0)
843         name = "";
844     if (inst == 0)
845         inst = "";
846     if (acell == 0)
847         acell = "";
848     left = ka_ConvertBytes(buf, buflen, name, strlen(name));
849     if (left) {
850       bad_name:
851         code = KABADNAME;
852         com_err(whoami, code, "PrintName: principal name was '%s'.'%s'@'%s'",
853                 name, inst, acell);
854         return code;
855     }
856     nlen = strlen(buf);
857     len = strlen(inst);
858     if (len) {
859         if (nlen + len + 1 >= buflen)
860             goto bad_name;
861         buf[nlen++] = '.';
862         left = ka_ConvertBytes(buf + nlen, buflen - nlen, inst, len);
863         if (left)
864             goto bad_name;
865         nlen += len;
866     }
867
868     len = strlen(acell);
869     if (len) {
870         char *lcell = ka_LocalCell();
871         if (lcell == 0)
872             lcell = "";
873         if (strcmp(acell, lcell) != 0) {
874             /* only append cell if not the local cell */
875             if (nlen + len + 1 >= buflen)
876                 goto bad_name;
877             buf[nlen++] = '@';
878             left = ka_ConvertBytes(buf + nlen, buflen - nlen, acell, len);
879             if (left)
880                 goto bad_name;
881             nlen += len;
882         }
883     }
884     return 0;
885 }
886
887 #define PrintedPrincipal(p) PrintedName ((p)->name, (p)->instance, (p)->cell)
888
889 /* PrintedName - returned a pointer to a static string in which the formated
890  * name has been stored. */
891
892 static char *
893 PrintedName(char *name, char *inst, char *cell)
894 {
895     static char printedName[128];
896     afs_int32 code;
897     code = PrintName(name, inst, cell, sizeof(printedName), printedName);
898     if (code) {
899         if (name == 0)
900             name = "";
901         strncpy(printedName, name, sizeof(printedName));
902         printedName[sizeof(printedName) - 8] = 0;
903         strcat(printedName, "<error>");
904     }
905     return printedName;
906 }
907
908 static afs_int32
909 ListTicket(struct ktc_principal *server, int verbose)
910 {
911     afs_int32 code;
912     struct ktc_token token;     /* the token we're printing */
913     struct ktc_principal client;
914     char UserName[sizeof(struct ktc_principal)];
915     char ServerName[sizeof(struct ktc_principal)];
916     afs_int32 now = time(0);
917     char bob[KA_TIMESTR_LEN];
918
919     /* get the ticket info itself */
920     code = ktc_GetToken(server, &token, sizeof(token), &client);
921     if (code) {
922         com_err(whoami, code, "failed to get token info for server %s",
923                 PrintedPrincipal(server));
924         return code;
925     }
926     code = PrintPrincipal(&client, UserName, sizeof(UserName));
927     if (code)
928         return code;
929     /* spaces are printed as "\040" */
930     if (UserName[0] == 0)
931         printf("Tokens");
932     else if (strncmp(UserName, "AFS\\040ID\\040", 13) == 0) {
933         printf("User's (AFS ID %s) tokens", UserName + 13);
934     } else if (strncmp(UserName, "Unix\\040UID\\040", 15) == 0) {
935         printf("Tokens");
936     } else
937         printf("User %s's tokens", UserName);
938
939     code = PrintPrincipal(server, ServerName, sizeof(ServerName));
940     if (code)
941         return code;
942     printf(" for %s ", ServerName);
943
944     if (token.startTime > now) {
945         ka_timestr(token.startTime, bob, KA_TIMESTR_LEN);
946         printf("[>> POSTDATED 'till %s <<]", bob);
947     }
948
949     if (token.endTime <= now)
950         printf("[>> Expired <<]\n");
951     else {
952         ka_timestr(token.endTime, bob, KA_TIMESTR_LEN);
953         printf("[Expires %s]\n", bob);
954     }
955     if (verbose) {
956         printf("SessionKey: ");
957         ka_PrintBytes((char *)&token.sessionKey, sizeof(token.sessionKey));
958         printf("\nTicket (kvno = %d, len = %d): ", token.kvno,
959                token.ticketLen);
960         ka_PrintBytes((char *)token.ticket, token.ticketLen);
961         printf("\n");
962     }
963     return 0;
964 }
965
966 static
967 GetTicket(struct cmd_syndesc *as, char *arock)
968 {
969     int code;
970     struct ktc_principal server;
971     struct ktc_token token;
972     afs_int32 life = KA_SIXHOURS;
973
974     if (as->parms[1].items) {
975         code = read_time_interval(as->parms[1].items->data, &life);
976         if (code)
977             return KABADCMD;
978     }
979     code =
980         ka_ParseLoginName(as->parms[0].items->data, server.name,
981                           server.instance, server.cell);
982     if (code) {
983         com_err(whoami, code, "parsing user's name '%s'",
984                 as->parms[0].items->data);
985         return KABADCMD;
986     }
987     if (server.cell[0] == 0) {
988         if (code = DefaultCell())
989             return code;
990         strcpy(server.cell, cell);
991     } else {
992         code = ka_ExpandCell(server.cell, server.cell, 0 /*local */ );
993         if (code) {
994             com_err(whoami, code, "Can't expand cell name");
995             return code;
996         }
997     }
998
999     token.ticketLen = 0;        /* in case there are no tokens */
1000     code =
1001         ka_GetServerToken(server.name, server.instance, server.cell, life,
1002                           &token, /*new */ 1, /*dosetpag */ 0);
1003     if (code)
1004         com_err(whoami, code, "getting ticket for %s",
1005                 PrintedPrincipal(&server));
1006     else {
1007         code = ListTicket(&server, /*verbose */ 1);
1008     }
1009     return code;
1010 }
1011
1012 static
1013 GetPassword(struct cmd_syndesc *as, char *arock)
1014 {
1015     int code;
1016     char name[MAXKTCNAMELEN];
1017     struct ktc_encryptionKey key;
1018     static struct ubik_client *lpbkConn = 0;
1019
1020     /* no instance allowed */
1021     code = ka_ParseLoginName(as->parms[0].items->data, name, 0, 0);
1022     if (code) {
1023       abort:
1024         com_err(whoami, code,
1025                 "getting %s's password via loopback connection to GetPassword",
1026                 name);
1027         /* if we got a timeout, print a clarification, too */
1028         if (code == -1) {
1029             fprintf(stderr,
1030                     "%s: please note that this command must be run locally on a database server machine.\n",
1031                     whoami);
1032         }
1033         return code;
1034     }
1035     if (lpbkConn == 0) {
1036         struct rx_connection *conns[2];
1037         struct rx_securityClass *sc;
1038         int si;                 /* security class index */
1039
1040         code = rx_Init(0);
1041         if (code)
1042             goto abort;
1043         sc = rxnull_NewClientSecurityObject();
1044         si = RX_SCINDEX_NULL;
1045         conns[0] =
1046             rx_NewConnection(htonl(INADDR_LOOPBACK), htons(AFSCONF_KAUTHPORT),
1047                              KA_MAINTENANCE_SERVICE, sc, si);
1048         conns[1] = 0;
1049         code = ubik_ClientInit(conns, &lpbkConn);
1050         if (code)
1051             goto abort;
1052     }
1053     code = ubik_Call(KAM_GetPassword, lpbkConn, 0, name, &key);
1054     /* Lets close down the ubik_Client connection now */
1055     ubik_ClientDestroy(lpbkConn);
1056     if (code)
1057         goto abort;
1058     printf("Key: ");
1059     ka_PrintBytes((char *)&key, sizeof(key));
1060     printf("\n");
1061     return code;
1062 }
1063
1064 int
1065 GetRandomKey(struct cmd_syndesc *as, char *arock)
1066 {
1067     int code;
1068     struct ktc_encryptionKey key;
1069
1070     code = ubik_Call(KAM_GetRandomKey, conn, 0, &key);
1071     if (code)
1072         com_err(whoami, code, "so can't get random key");
1073     else {
1074         int i;
1075         printf("Key: ");
1076         ka_PrintBytes((char *)&key, sizeof(key));
1077         printf(" (");
1078         for (i = 0; i < sizeof(key); i++) {
1079             printf("%0.2x", ((char *)&key)[i] & 0xff);
1080             if (i == 3)
1081                 printf(" ");
1082             else if (i != 7)
1083                 printf(".");
1084         }
1085         printf(")\n");
1086     }
1087     return code;
1088 }
1089
1090 int
1091 Statistics(struct cmd_syndesc *as, char *arock)
1092 {
1093     int code;
1094     kasstats statics;
1095     kadstats dynamics;
1096     afs_int32 admins;
1097     char bob[KA_TIMESTR_LEN];
1098
1099     code =
1100         ubik_Call(KAM_GetStats, conn, 0, KAMAJORVERSION, &admins, &statics,
1101                   &dynamics);
1102     if (code) {
1103         printf("call to GetStats failed: %s\n", ka_ErrorString(code));
1104         return code;
1105     }
1106     if (statics.minor_version != KAMINORVERSION)
1107         printf("Minor version number mismatch: got %d, expected %d\n",
1108                statics.minor_version, KAMINORVERSION);
1109     printf("%d allocs, %d frees, %d password changes\n", statics.allocs,
1110            statics.frees, statics.cpws);
1111     printf("Hash table utilization = %f%%\n",
1112            (double)dynamics.hashTableUtilization / 100.0);
1113     ka_timestr(dynamics.start_time, bob, KA_TIMESTR_LEN);
1114     printf("From host %lx started at %s:\n", dynamics.host, bob);
1115
1116 #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)
1117     print_stat(Authenticate);
1118     print_stat(ChangePassword);
1119     print_stat(GetTicket);
1120     print_stat(CreateUser);
1121     print_stat(SetPassword);
1122     print_stat(SetFields);
1123     print_stat(DeleteUser);
1124     print_stat(GetEntry);
1125     print_stat(ListEntry);
1126     print_stat(GetStats);
1127     print_stat(GetPassword);
1128     print_stat(GetRandomKey);
1129     print_stat(Debug);
1130     print_stat(UAuthenticate);
1131     print_stat(UGetTicket);
1132
1133 #if (KAMAJORVERSION>5)
1134     print cpu stats printf("%d string checks\n", dynamics.string_checks);
1135 #else
1136     printf("Used %.3f seconds of CPU time.\n",
1137            dynamics.string_checks / 1000.0);
1138 #endif
1139     printf("%d admin accounts\n", admins);
1140     return 0;
1141 }
1142
1143 int
1144 DebugInfo(struct cmd_syndesc *as, char *arock)
1145 {
1146     int code;
1147     struct ka_debugInfo info;
1148     int i;
1149     Date start, now;
1150     int timeOffset;
1151     char bob[KA_TIMESTR_LEN];
1152
1153     start = time(0);
1154     if (as->parms[0].items) {
1155         struct ubik_client *iConn;
1156         code =
1157             ka_SingleServerConn(cell, as->parms[0].items->data,
1158                                 KA_MAINTENANCE_SERVICE, 0, &iConn);
1159         if (code) {
1160             struct afsconf_cell cellinfo;
1161
1162             com_err(whoami, code, "couldn't find host %s in cell %s",
1163                     as->parms[0].items->data, cell);
1164             code = ka_GetServers(cell, &cellinfo);
1165             if (code)
1166                 com_err(whoami, code, "getting servers in cell %s", cell);
1167             else {
1168                 printf("Servers in cell %s, are:\n", cell);
1169                 for (i = 0; i < cellinfo.numServers; i++)
1170                     printf("  %s\n", cellinfo.hostName[i]);
1171             }
1172             return code;
1173         }
1174         code = ubik_Call(KAM_Debug, iConn, 0, KAMAJORVERSION, 0, &info);
1175         ubik_ClientDestroy(iConn);
1176     } else
1177         code = ubik_Call(KAM_Debug, conn, 0, KAMAJORVERSION, 0, &info);
1178
1179     if (code) {
1180         com_err(whoami, code, "call to Debug failed");
1181         return code;
1182     }
1183     now = time(0);
1184
1185     if (info.minorVersion != KAMINORVERSION)
1186         printf("Minor version number mismatch: got %d, expected %d\n",
1187                info.minorVersion, KAMINORVERSION);
1188
1189     timeOffset = info.
1190 #if (KAMAJORVERSION>5)
1191         now
1192 #else
1193         reserved1
1194 #endif
1195         - now;
1196     if (timeOffset < 0)
1197         timeOffset = -timeOffset;
1198     if (timeOffset > 60) {
1199         printf
1200             ("WARNING: Large server client clock skew: %d seconds. Call itself took %d seconds.\n",
1201              timeOffset, now - start);
1202     }
1203     ka_timestr(info.startTime, bob, KA_TIMESTR_LEN);
1204     printf("From host %lx started %sat %s:\n", info.host,
1205            (info.noAuth ? "w/o authorization " : ""), bob);
1206     ka_timestr(info.lastTrans, bob, KA_TIMESTR_LEN);
1207     printf("Last trans was %s at %s\n", info.lastOperation, bob);
1208     ka_timestr(info.dbHeaderRead, bob, KA_TIMESTR_LEN);
1209     printf("Header last read %s.\n", bob);
1210     printf("db version=%d, keyVersion=%d, key cache version=%d\n",
1211            info.dbVersion, info.dbSpecialKeysVersion, info.kcVersion);
1212     printf("db ptrs: free %d, eof %d, kvno %d.\n", info.dbFreePtr,
1213            info.dbEofPtr, info.dbKvnoPtr);
1214     ka_timestr(info.nextAutoCPW, bob, KA_TIMESTR_LEN);
1215     printf("Next autoCPW at %s or in %d updates.\n", bob,
1216            info.updatesRemaining);
1217     if (info.cheader_lock || info.keycache_lock)
1218         printf("locks: cheader %08lx, keycache %08lx\n", info.cheader_lock,
1219                info.keycache_lock);
1220     printf("Last authentication for %s, last admin user was %s\n",
1221            info.lastAuth, info.lastAdmin);
1222     printf("Last TGS op was a %s ticket was for %s\n", info.lastTGSServer,
1223            info.lastTGS);
1224     printf("Last UDP TGS was a %s ticket for %s.  UDP Authenticate for %s\n",
1225            info.lastUTGSServer, info.lastUTGS, info.lastUAuth);
1226     printf("key cache size %d, used %d.\n", info.kcSize, info.kcUsed);
1227     if (info.kcUsed > KADEBUGKCINFOSIZE) {
1228         printf("insufficient room to return all key cache entries!\n");
1229         info.kcUsed = KADEBUGKCINFOSIZE;
1230     }
1231     for (i = 0; i < info.kcUsed; i++)
1232         ka_timestr(info.kcInfo[i].used, bob, KA_TIMESTR_LEN);
1233     printf("%32s %c %2x(%2x) used %s\n", info.kcInfo[i].principal,
1234            (info.kcInfo[i].primary ? '*' : ' '), info.kcInfo[i].kvno,
1235            info.kcInfo[i].keycksum, bob);
1236     return 0;
1237 }
1238
1239 int
1240 Interactive(struct cmd_syndesc *as, char *arock)
1241 {
1242     finished = 0;
1243     return 0;
1244 }
1245
1246 int
1247 Quit(struct cmd_syndesc *as, char *arock)
1248 {
1249     finished = 1;
1250     return 0;
1251 }
1252
1253 int
1254 MyAfterProc(struct cmd_syndesc *as)
1255 {
1256     if (!strcmp(as->name, "help"))
1257         return 0;
1258
1259     /* Determine if we need to destory the ubik connection.
1260      * Closing it avoids resends of packets. 
1261      */
1262     if (conn) {
1263         ubik_ClientDestroy(conn);
1264         conn = 0;
1265     }
1266
1267     return 0;
1268 }
1269
1270 int init = 0, noauth;
1271 char name[MAXKTCNAMELEN];
1272 char instance[MAXKTCNAMELEN];
1273 char newCell[MAXKTCREALMLEN];
1274 afs_int32 serverList[MAXSERVERS];
1275
1276 int
1277 NoAuth(struct cmd_syndesc *as, char *arock)
1278 {
1279     noauth = 1;
1280     return 0;
1281 }
1282
1283 static int
1284 MyBeforeProc(struct cmd_syndesc *as, char *arock)
1285 {
1286     extern struct passwd *getpwuid();
1287     struct ktc_encryptionKey key;
1288     struct ktc_principal auth_server, auth_token, client;
1289     char realm[MAXKTCREALMLEN];
1290
1291     struct ktc_token token, *pToken;
1292     int i, acode, code = 0;
1293
1294     {
1295         char *ws = strrchr(as->a0name, '/');
1296         if (ws)
1297             ws++;               /* skip everything before the "/" */
1298         else
1299             ws = as->a0name;
1300         if (strlen(ws) > 0) {
1301             strncpy(whoami, ws, sizeof(whoami));
1302             if (strlen(whoami) + 1 >= sizeof(whoami))
1303                 strcpy(whoami, "kas:");
1304             else
1305                 strcat(whoami, ":");
1306         } else
1307             whoami[0] = 0;
1308         /* append sub-command name */
1309         strncat(whoami, as->name, sizeof(whoami) - strlen(whoami) - 1);
1310     }
1311
1312     if (as->parms[12].name == 0)
1313         return 0;
1314
1315     assert(as->parms[13].name && as->parms[14].name && as->parms[15].name
1316            && as->parms[16].name);
1317
1318     /* MyAfterProc() destroys the conn, but just to be sure */
1319     if (conn) {
1320         code = ubik_ClientDestroy(conn);
1321         conn = 0;
1322     }
1323
1324     if (!init || as->parms[12].items || as->parms[13].items
1325         || as->parms[14].items || as->parms[15].items
1326         || as->parms[16].items) {
1327         strcpy(instance, "");
1328         strcpy(newCell, "");
1329
1330         if (as->parms[12].items) {      /* -admin_username */
1331             code =
1332                 ka_ParseLoginName(as->parms[12].items->data, name, instance,
1333                                   newCell);
1334             if (code) {
1335                 com_err(whoami, code, "parsing user's name '%s'",
1336                         as->parms[12].items->data);
1337                 return code;
1338             }
1339         } else {
1340 #ifdef AFS_NT40_ENV
1341             DWORD len = MAXKTCNAMELEN;
1342             if (!GetUserName((LPTSTR) name, &len)) {
1343                 printf("Can't get user name \n");
1344                 return KABADCMD;
1345             }
1346 #else
1347             /* No explicit name provided: use Unix uid. */
1348             struct passwd *pw = getpwuid(getuid());
1349             if (pw == NULL) {
1350                 printf("Can't figure out your name from your user id.\n");
1351                 return KABADCMD;
1352             }
1353             strncpy(name, pw->pw_name, sizeof(name));
1354 #endif
1355         }
1356
1357         if (as->parms[14].items) {      /* -cell */
1358             if (strlen(newCell) > 0) {
1359                 printf("Duplicate cell specification not allowed\n");
1360             } else {
1361                 strncpy(newCell, as->parms[14].items->data, sizeof(newCell));
1362             }
1363         }
1364         code = ka_ExpandCell(newCell, newCell, 0 /*local */ );
1365         if (code) {
1366             com_err(whoami, code, "Can't expand cell name");
1367             return code;
1368         }
1369         strcpy(cell, newCell);
1370
1371         if (as->parms[15].items) {      /* -servers */
1372             struct cmd_item *ip;
1373             char *ap[MAXSERVERS + 2];
1374
1375             ap[0] = "";
1376             ap[1] = "-servers";
1377             for (ip = as->parms[15].items, i = 2; ip; ip = ip->next, i++)
1378                 ap[i] = ip->data;
1379             code = ubik_ParseClientList(i, ap, serverList);
1380             if (code) {
1381                 com_err(whoami, code, "could not parse server list");
1382                 return code;
1383             }
1384             ka_ExplicitCell(cell, serverList);
1385         }
1386
1387         noauth = (as->parms[16].items ? 1 : 0); /* -noauth */
1388
1389         init = 1;
1390     }
1391
1392     token.ticketLen = 0;        /* in case there are no tokens */
1393     if (!noauth) {              /* Will prompt for a password */
1394         /* first see if there's already an admin ticket */
1395         code =
1396             ka_GetAdminToken(0, 0, cell, 0, KA_SIXHOURS, &token,
1397                              0 /* !new */ );
1398         if (code) {             /* if not then get key and try again */
1399             if (as->parms[13].items) {  /* if password specified */
1400                 strncpy(passwd, as->parms[13].items->data, sizeof(passwd));
1401                 memset(as->parms[13].items->data, 0,
1402                        strlen(as->parms[13].items->data));
1403             } else {
1404                 char msg[MAXKTCNAMELEN + 50];
1405                 if (as->parms[12].items)
1406                     sprintf(msg, "Administrator's (%s) Password: ", name);
1407                 else
1408                     sprintf(msg, "Password for %s: ", name);
1409                 code = read_pw_string(passwd, sizeof(passwd), msg, 0);
1410                 if (code)
1411                     code = KAREADPW;
1412                 else if (strlen(passwd) == 0)
1413                     code = KANULLPASSWORD;
1414                 if (code) {
1415                     com_err(whoami, code, "reading password");
1416                     return code;
1417                 }
1418             }
1419             ka_StringToKey(passwd, cell, &key);
1420             code =
1421                 ka_GetAdminToken(name, instance, cell, &key, KA_SIXHOURS,
1422                                  &token, 0 /* !new */ );
1423             if (code == KABADREQUEST) {
1424                 des_string_to_key(passwd, &key);
1425                 code =
1426                     ka_GetAdminToken(name, instance, cell, &key, KA_SIXHOURS,
1427                                      &token, 0 /* !new */ );
1428             }
1429             if ((code == KABADREQUEST) && (strlen(passwd) > 8)) {
1430                 /* try with only the first 8 characters incase they set
1431                  * their password with an old style passwd program. */
1432                 passwd[8] = 0;
1433                 ka_StringToKey(passwd, cell, &key);
1434                 code =
1435                     ka_GetAdminToken(name, instance, cell, &key, KA_SIXHOURS,
1436                                      &token, 0 /* !new */ );
1437                 if (code == 0) {
1438                     fprintf(stderr,
1439                             "Warning: you have typed a password longer than 8 characters, but only the\n");
1440                     fprintf(stderr,
1441                             "first 8 characters were actually significant.  If you change your password\n");
1442                     fprintf(stderr,
1443                             "again this warning message will go away.\n");
1444                 }
1445             }
1446             if (code) {
1447                 char *reason;
1448                 switch (code) {
1449                 case KABADREQUEST:
1450                     reason = "password was incorrect";
1451                     break;
1452                 case KAUBIKCALL:
1453                     reason = "Authentication Server was unavailable";
1454                     break;
1455                 default:
1456                     reason = (char *)error_message(code);
1457                 }
1458                 fprintf(stderr,
1459                         "%s: Auth. as %s to AuthServer failed: %s\nProceeding w/o authentication\n",
1460                         whoami, PrintedName(name, instance, cell), reason);
1461             }
1462             /* get an Authentication token while were at it. */
1463             if (ka_CellToRealm(cell, realm, 0) != 0)
1464                 realm[0] = '\0';
1465             strcpy(auth_server.name, KA_TGS_NAME);
1466             strcpy(auth_server.instance, realm);
1467             strcpy(auth_server.cell, cell);
1468             if (ktc_GetToken
1469                 (&auth_server, &auth_token, sizeof(struct ktc_token),
1470                  &client) != 0) {
1471                 acode =
1472                     ka_GetAuthToken(name, instance, cell, &key,
1473                                     MAXKTCTICKETLIFETIME, (afs_int32 *) 0
1474                                     /*Don't need pwd expiration info here */
1475                     );
1476                 if (acode && (acode != code))   /* codes are usually the same */
1477                     com_err(whoami, code,
1478                             "getting Authentication token for %s",
1479                             PrintedName(name, instance, cell));
1480             }
1481             memset(&key, 0, sizeof(key));
1482         }
1483     }
1484
1485     pToken = ((token.ticketLen == 0) ? 0 : &token);
1486     code = ka_AuthServerConn(cell, KA_MAINTENANCE_SERVICE, pToken, &conn);
1487     if (code && pToken) {
1488         com_err(whoami, code,
1489                 "connecting to AuthServer: now trying w/o authentication");
1490         code = ka_AuthServerConn(cell, KA_MAINTENANCE_SERVICE, 0, &conn);
1491         if (code)
1492             com_err(whoami, code,
1493                     "making unauthenticated connection to AuthServer");
1494     }
1495     if (code) {
1496         com_err(whoami, code,
1497                 "Couldn't establish connection to Authentication Server");
1498         return code;
1499     }
1500
1501     /* now default unspecified password by prompting from terminal */
1502     if (as->nParms >= 12)
1503         for (i = 0; i < 12; i++)
1504             if (as->parms[i].name && (as->parms[i].items == 0)) {
1505                 char *p = as->parms[i].name;    /* parameter name */
1506                 int l = strlen(p);      /* length of name */
1507                 /* does parameter end in "password"  */
1508                 if (strcmp(p + (l - 8), "password") == 0) {
1509                     char msg[32];
1510                     char password[BUFSIZ];
1511                     struct cmd_item *ip;
1512
1513                     strcpy(msg, p + 1);
1514                     strcat(msg, ": ");
1515                     code = read_pw_string(password, sizeof(password), msg, 1);
1516                     if (code)
1517                         code = KAREADPW;
1518                     else if (strlen(password) == 0)
1519                         code = KANULLPASSWORD;
1520                     if (code) {
1521                         com_err(whoami, code, "prompting for %s", p + 1);
1522                         return code;
1523                     }
1524                     ip = (struct cmd_item *)malloc(sizeof(struct cmd_item));
1525                     ip->data = (char *)malloc(strlen(password) + 1);
1526                     ip->next = 0;
1527                     strcpy(ip->data, password);
1528                     as->parms[i].items = ip;
1529                 }
1530             }
1531     if (!conn) {                /* if all else fails... */
1532         code = NoAuth(0, 0);    /* get unauthenticated conn */
1533         if (code)
1534             return code;
1535     }
1536     return 0;
1537 }
1538
1539 /* These are some helpful command that deal with the cache managers tokens. */
1540
1541 static
1542 ForgetTicket(struct cmd_syndesc *as, char *arock)
1543 {
1544     afs_int32 code;
1545
1546 #ifdef notdef
1547     struct ktc_principal server;
1548
1549     if (as->parms[0].items) {
1550         char *name = as->parms[0].items->data;
1551         code =
1552             ka_ParseLoginName(name, server.name, server.instance,
1553                               server.cell);
1554         if (code) {
1555             com_err(whoami, code, "couldn't interpret name '%s'", name);
1556             return code;
1557         }
1558         if (server.cell[0] == 0) {
1559             if (code = DefaultCell())
1560                 return code;
1561             strcpy(server.cell, cell);
1562         } else {
1563             code = ka_ExpandCell(server.cell, server.cell, 0 /*local */ );
1564             if (code) {
1565                 com_err(whoami, code, "Can't expand cell name");
1566                 return code;
1567             }
1568         }
1569         code = ktc_ForgetToken(&server);
1570         if (code) {
1571             com_err(whoami, code, "couldn't remove tokens for %s",
1572                     PrintedPrincipal(&server));
1573             return code;
1574         }
1575     } else {
1576         if (!as->parms[1].items) {
1577             fprintf(stderr, "Must specify server name or -all\n");
1578             return KABADCMD;
1579         }
1580         code = ktc_ForgetAllTokens();
1581         if (code) {
1582             com_err(whoami, code, "couldn't delete all tokens");
1583             return code;
1584         }
1585     }
1586 #endif
1587     code = ktc_ForgetAllTokens();
1588     if (code) {
1589         com_err(whoami, code, "couldn't delete all tokens");
1590         return code;
1591     }
1592     return 0;
1593 }
1594
1595 static
1596 ListTickets(struct cmd_syndesc *as, char *arock)
1597 {
1598     afs_int32 code = 0;
1599     int index, newIndex;
1600     struct ktc_principal server;
1601     int verbose = 0;
1602
1603     if (as->parms[1].items)
1604         verbose = 1;
1605     if (as->parms[0].items) {
1606         char *name = as->parms[0].items->data;
1607         code =
1608             ka_ParseLoginName(name, server.name, server.instance,
1609                               server.cell);
1610         if (code) {
1611             com_err(whoami, code, "couldn't interpret name '%s'", name);
1612             return code;
1613         }
1614         if (server.cell[0] == 0) {
1615             if (code = DefaultCell())
1616                 return code;
1617             strcpy(server.cell, cell);
1618         } else {
1619             code = ka_ExpandCell(server.cell, server.cell, 0 /*local */ );
1620             if (code) {
1621                 com_err(whoami, code, "Can't expand cell name");
1622                 return code;
1623             }
1624         }
1625         code = ListTicket(&server, verbose);
1626     } else
1627         for (index = 0;; index = newIndex) {
1628             code = ktc_ListTokens(index, &newIndex, &server);
1629             if (code) {
1630                 if (code == KTC_NOENT)
1631                     code = 0;   /* end of list */
1632                 break;
1633             }
1634             code = ListTicket(&server, verbose);
1635         }
1636     return code;
1637 }
1638
1639 static void
1640 add_std_args(register struct cmd_syndesc *ts)
1641 {
1642     cmd_Seek(ts, 12);
1643     /* 12 */ cmd_AddParm(ts, "-admin_username", CMD_SINGLE, CMD_OPTIONAL,
1644                          "admin principal to use for authentication");
1645     /* 13 */ cmd_AddParm(ts, "-password_for_admin", CMD_SINGLE, CMD_OPTIONAL,
1646                          "admin password");
1647     /* 14 */ cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
1648     /* 15 */ cmd_AddParm(ts, "-servers", CMD_LIST, CMD_OPTIONAL,
1649                          "explicit list of authentication servers");
1650     /* 16 */ cmd_AddParm(ts, "-noauth", CMD_FLAG, CMD_OPTIONAL,
1651                          "don't authenticate");
1652 }
1653
1654 afs_int32
1655 ka_AdminInteractive(int cmd_argc, char *cmd_argv[])
1656 {
1657     register int code;
1658     register struct cmd_syndesc *ts;
1659
1660     char line[BUFSIZ];
1661     afs_int32 argc;
1662     char *argv[32];
1663
1664     strncpy(myName, *cmd_argv, 509);
1665
1666     cmd_SetBeforeProc(MyBeforeProc, NULL);
1667     cmd_SetAfterProc(MyAfterProc, NULL);
1668
1669     ts = cmd_CreateSyntax("interactive", Interactive, 0,
1670                           "enter interactive mode");
1671     add_std_args(ts);
1672
1673     ts = cmd_CreateSyntax("noauthentication", NoAuth, 0,
1674                           "connect to AuthServer w/o using token");
1675
1676     ts = cmd_CreateSyntax("list", ListUsers, 0, "list all users in database");
1677     cmd_AddParm(ts, "-long", CMD_FLAG, CMD_OPTIONAL,
1678                 "show detailed info about each user");
1679     cmd_AddParm(ts, "-showadmin", CMD_FLAG, CMD_OPTIONAL,
1680                 "show all cell administrators");
1681     cmd_AddParm(ts, "-showkey", CMD_FLAG, CMD_OPTIONAL,
1682                 "show the user's actual key rather than the checksum");
1683     add_std_args(ts);
1684     cmd_CreateAlias(ts, "ls");
1685
1686     ts = cmd_CreateSyntax("examine", ExamineUser, 0,
1687                           "examine the entry for a user");
1688     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1689     cmd_AddParm(ts, "-showkey", CMD_FLAG, CMD_OPTIONAL,
1690                 "show the user's actual key rather than the checksum");
1691     add_std_args(ts);
1692
1693     ts = cmd_CreateSyntax("create", CreateUser, 0,
1694                           "create an entry for a user");
1695     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1696     cmd_AddParm(ts, "-initial_password", CMD_SINGLE, CMD_OPTIONAL,
1697                 "initial password");
1698     add_std_args(ts);
1699
1700     ts = cmd_CreateSyntax("delete", DeleteUser, 0, "delete a user");
1701     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1702     add_std_args(ts);
1703     cmd_CreateAlias(ts, "rm");
1704
1705     ts = cmd_CreateSyntax("setfields", SetFields, 0,
1706                           "set various fields in a user's entry");
1707     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1708     cmd_AddParm(ts, "-flags", CMD_SINGLE, CMD_OPTIONAL,
1709                 "hex flag value or flag name expression");
1710     cmd_AddParm(ts, "-expiration", CMD_SINGLE, CMD_OPTIONAL,
1711                 "date of account expiration");
1712     cmd_AddParm(ts, "-lifetime", CMD_SINGLE, CMD_OPTIONAL,
1713                 "maximum ticket lifetime");
1714     cmd_AddParm(ts, "-pwexpires", CMD_SINGLE, CMD_OPTIONAL,
1715                 "number days password is valid ([0..254])");
1716     cmd_AddParm(ts, "-reuse", CMD_SINGLE, CMD_OPTIONAL,
1717                 "permit password reuse (yes/no)");
1718     cmd_AddParm(ts, "-attempts", CMD_SINGLE, CMD_OPTIONAL,
1719                 "maximum successive failed login tries ([0..254])");
1720     cmd_AddParm(ts, "-locktime", CMD_SINGLE, CMD_OPTIONAL,
1721                 "failure penalty [hh:mm or minutes]");
1722 #if ASSOCIATES
1723     cmd_AddParm(ts, "-associates", CMD_SINGLE, CMD_OPTIONAL,
1724                 "maximum associate instances");
1725 #endif
1726     add_std_args(ts);
1727     cmd_CreateAlias(ts, "sf");
1728
1729
1730     ts = cmd_CreateSyntax("unlock", Unlock, 0,
1731                           "Enable authentication ID after max failed attempts exceeded");
1732     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "authentication ID");
1733     add_std_args(ts);
1734
1735
1736     ts = cmd_CreateSyntax("stringtokey", StringToKey, 0,
1737                           "convert a string to a key");
1738     cmd_AddParm(ts, "-string", CMD_SINGLE, 0, "password string");
1739     cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
1740
1741     ts = cmd_CreateSyntax("setpassword", SetPassword, 0,
1742                           "set a user's password");
1743     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1744     cmd_AddParm(ts, "-new_password", CMD_SINGLE, CMD_OPTIONAL,
1745                 "new password");
1746     cmd_Seek(ts, 3);
1747     cmd_AddParm(ts, "-kvno", CMD_SINGLE, CMD_OPTIONAL, "key version number");
1748     add_std_args(ts);
1749     cmd_CreateAlias(ts, "sp");
1750 #ifdef CMD_PARSER_AMBIG_FIX
1751     cmd_CreateAlias(ts, "setpasswd");
1752 #endif
1753
1754     /* set a user's key */
1755     ts = cmd_CreateSyntax("setkey", SetPassword, 0, (char *)CMD_HIDDEN);
1756     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1757     cmd_Seek(ts, 2);
1758     cmd_AddParm(ts, "-new_key", CMD_SINGLE, 0, "eight byte new key");
1759     cmd_Seek(ts, 3);
1760     cmd_AddParm(ts, "-kvno", CMD_SINGLE, CMD_OPTIONAL, "key version number");
1761     add_std_args(ts);
1762
1763     /* get a user's password */
1764     ts = cmd_CreateSyntax("getpassword", GetPassword, 0, (char *)CMD_HIDDEN);
1765     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1766     /* don't take standard args */
1767     /* add_std_args (ts); */
1768 #ifdef CMD_PARSER_AMBIG_FIX
1769     cmd_CreateAlias(ts, "getpasswd");
1770 #endif
1771
1772     /* get a random key */
1773     ts = cmd_CreateSyntax("getrandomkey", GetRandomKey, 0,
1774                           (char *)CMD_HIDDEN);
1775     add_std_args(ts);
1776
1777     /* get a ticket for a specific server */
1778     ts = cmd_CreateSyntax("getticket", GetTicket, 0, (char *)CMD_HIDDEN);
1779     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of server");
1780     cmd_AddParm(ts, "-lifetime", CMD_SINGLE, CMD_OPTIONAL, "ticket lifetime");
1781     add_std_args(ts);
1782
1783     ts = cmd_CreateSyntax("statistics", Statistics, 0,
1784                           "show statistics for AuthServer");
1785     add_std_args(ts);
1786
1787     /* show debugging info from AuthServer */
1788     ts = cmd_CreateSyntax("debuginfo", DebugInfo, 0, (char *)CMD_HIDDEN);
1789     cmd_AddParm(ts, "-hostname", CMD_SINGLE, CMD_OPTIONAL,
1790                 "authentication server host name");
1791     add_std_args(ts);
1792
1793     ts = cmd_CreateSyntax("forgetticket", ForgetTicket, 0,
1794                           "delete user's tickets");
1795 #ifdef notdef
1796     cmd_AddParm(ts, "-name", CMD_SINGLE, (CMD_OPTIONAL | CMD_HIDE),
1797                 "name of server");
1798 #endif
1799     cmd_AddParm(ts, "-all", CMD_FLAG, CMD_OPTIONAL, "delete all tickets");
1800
1801     ts = cmd_CreateSyntax("listtickets", ListTickets, 0,
1802                           "show all cache manager tickets");
1803     cmd_AddParm(ts, "-name", CMD_SINGLE, CMD_OPTIONAL, "name of server");
1804     cmd_AddParm(ts, "-long", CMD_FLAG, CMD_OPTIONAL,
1805                 "show session key and ticket");
1806
1807     ts = cmd_CreateSyntax("quit", Quit, 0, "exit program");
1808
1809     finished = 1;
1810     conn = 0;                   /* no connection yet */
1811     zero_argc = cmd_argc;
1812     zero_argv = cmd_argv;
1813
1814     strcpy(whoami, "kas");
1815
1816     if (code = cmd_Dispatch(cmd_argc, cmd_argv)) {
1817         return code;
1818     }
1819
1820     while (!finished) {
1821         char *s;
1822         int i;
1823
1824         printf("ka> ");
1825         s = fgets(line, sizeof(line), stdin);
1826         if (s == NULL)
1827             return 0;           /* EOF on input */
1828         for (i = strlen(line) - 1; i >= 0 && isspace(line[i]); i--)
1829             line[i] = 0;
1830         if (i < 0)
1831             continue;           /* blank line */
1832
1833         code =
1834             cmd_ParseLine(line, argv, &argc, sizeof(argv) / sizeof(argv[0]));
1835         if (code) {
1836             com_err(whoami, code, "parsing line: '%s'", line);
1837             return code;
1838         }
1839         code = cmd_Dispatch(argc, argv);
1840         cmd_FreeArgv(argv);
1841     }
1842     return code;
1843 }