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