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