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