macos 10.6 warning fixes
[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, client;
1294     struct ktc_token auth_token;
1295     char realm[MAXKTCREALMLEN];
1296
1297     struct ktc_token token, *pToken;
1298     int i, acode, code = 0;
1299
1300     {
1301         char *ws = strrchr(as->a0name, '/');
1302         if (ws)
1303             ws++;               /* skip everything before the "/" */
1304         else
1305             ws = as->a0name;
1306         if (strlen(ws) > 0) {
1307             strncpy(whoami, ws, sizeof(whoami));
1308             if (strlen(whoami) + 1 >= sizeof(whoami))
1309                 strcpy(whoami, "kas:");
1310             else
1311                 strcat(whoami, ":");
1312         } else
1313             whoami[0] = 0;
1314         /* append sub-command name */
1315         strncat(whoami, as->name, sizeof(whoami) - strlen(whoami) - 1);
1316     }
1317
1318     if (as->parms[12].name == 0)
1319         return 0;
1320
1321     assert(as->parms[13].name && as->parms[14].name && as->parms[15].name
1322            && as->parms[16].name);
1323
1324     /* MyAfterProc() destroys the conn, but just to be sure */
1325     if (conn) {
1326         code = ubik_ClientDestroy(conn);
1327         conn = 0;
1328     }
1329
1330     if (!init || as->parms[12].items || as->parms[13].items
1331         || as->parms[14].items || as->parms[15].items
1332         || as->parms[16].items) {
1333         strcpy(instance, "");
1334         strcpy(newCell, "");
1335
1336         if (as->parms[12].items) {      /* -admin_username */
1337             code =
1338                 ka_ParseLoginName(as->parms[12].items->data, name, instance,
1339                                   newCell);
1340             if (code) {
1341                 afs_com_err(whoami, code, "parsing user's name '%s'",
1342                         as->parms[12].items->data);
1343                 return code;
1344             }
1345         } else {
1346 #ifdef AFS_NT40_ENV
1347             DWORD len = MAXKTCNAMELEN;
1348             if (!GetUserName((LPTSTR) name, &len)) {
1349                 printf("Can't get user name \n");
1350                 return KABADCMD;
1351             }
1352 #else
1353             /* No explicit name provided: use Unix uid. */
1354             struct passwd *pw = getpwuid(getuid());
1355             if (pw == NULL) {
1356                 printf("Can't figure out your name from your user id.\n");
1357                 return KABADCMD;
1358             }
1359             strncpy(name, pw->pw_name, sizeof(name));
1360 #endif
1361         }
1362
1363         if (as->parms[14].items) {      /* -cell */
1364             if (strlen(newCell) > 0) {
1365                 printf("Duplicate cell specification not allowed\n");
1366             } else {
1367                 strncpy(newCell, as->parms[14].items->data, sizeof(newCell));
1368             }
1369         }
1370         code = ka_ExpandCell(newCell, newCell, 0 /*local */ );
1371         if (code) {
1372             afs_com_err(whoami, code, "Can't expand cell name");
1373             return code;
1374         }
1375         strcpy(cell, newCell);
1376
1377         if (as->parms[15].items) {      /* -servers */
1378             struct cmd_item *ip;
1379             char *ap[MAXSERVERS + 2];
1380
1381             ap[0] = "";
1382             ap[1] = "-servers";
1383             for (ip = as->parms[15].items, i = 2; ip; ip = ip->next, i++)
1384                 ap[i] = ip->data;
1385             code = ubik_ParseClientList(i, ap, serverList);
1386             if (code) {
1387                 afs_com_err(whoami, code, "could not parse server list");
1388                 return code;
1389             }
1390             ka_ExplicitCell(cell, serverList);
1391         }
1392
1393         noauth = (as->parms[16].items ? 1 : 0); /* -noauth */
1394
1395         init = 1;
1396     }
1397
1398     token.ticketLen = 0;        /* in case there are no tokens */
1399     if (!noauth) {              /* Will prompt for a password */
1400         /* first see if there's already an admin ticket */
1401         code =
1402             ka_GetAdminToken(0, 0, cell, 0, KA_SIXHOURS, &token,
1403                              0 /* !new */ );
1404         if (code) {             /* if not then get key and try again */
1405             if (as->parms[13].items) {  /* if password specified */
1406                 strncpy(passwd, as->parms[13].items->data, sizeof(passwd));
1407                 memset(as->parms[13].items->data, 0,
1408                        strlen(as->parms[13].items->data));
1409             } else {
1410                 char msg[MAXKTCNAMELEN + 50];
1411                 if (as->parms[12].items)
1412                     sprintf(msg, "Administrator's (%s) Password: ", name);
1413                 else
1414                     sprintf(msg, "Password for %s: ", name);
1415                 code = read_pw_string(passwd, sizeof(passwd), msg, 0);
1416                 if (code)
1417                     code = KAREADPW;
1418                 else if (strlen(passwd) == 0)
1419                     code = KANULLPASSWORD;
1420                 if (code) {
1421                     afs_com_err(whoami, code, "reading password");
1422                     return code;
1423                 }
1424             }
1425             ka_StringToKey(passwd, cell, &key);
1426             code =
1427                 ka_GetAdminToken(name, instance, cell, &key, KA_SIXHOURS,
1428                                  &token, 0 /* !new */ );
1429             if (code == KABADREQUEST) {
1430                 des_string_to_key(passwd, ktc_to_cblockptr(&key));
1431                 code =
1432                     ka_GetAdminToken(name, instance, cell, &key, KA_SIXHOURS,
1433                                      &token, 0 /* !new */ );
1434             }
1435             if ((code == KABADREQUEST) && (strlen(passwd) > 8)) {
1436                 /* try with only the first 8 characters incase they set
1437                  * their password with an old style passwd program. */
1438                 passwd[8] = 0;
1439                 ka_StringToKey(passwd, cell, &key);
1440                 code =
1441                     ka_GetAdminToken(name, instance, cell, &key, KA_SIXHOURS,
1442                                      &token, 0 /* !new */ );
1443                 if (code == 0) {
1444                     fprintf(stderr,
1445                             "Warning: you have typed a password longer than 8 characters, but only the\n");
1446                     fprintf(stderr,
1447                             "first 8 characters were actually significant.  If you change your password\n");
1448                     fprintf(stderr,
1449                             "again this warning message will go away.\n");
1450                 }
1451             }
1452             if (code) {
1453                 char *reason;
1454                 switch (code) {
1455                 case KABADREQUEST:
1456                     reason = "password was incorrect";
1457                     break;
1458                 case KAUBIKCALL:
1459                     reason = "Authentication Server was unavailable";
1460                     break;
1461                 default:
1462                     reason = (char *)afs_error_message(code);
1463                 }
1464                 fprintf(stderr,
1465                         "%s: Auth. as %s to AuthServer failed: %s\nProceeding w/o authentication\n",
1466                         whoami, PrintedName(name, instance, cell), reason);
1467             }
1468             /* get an Authentication token while were at it. */
1469             if (ka_CellToRealm(cell, realm, 0) != 0)
1470                 realm[0] = '\0';
1471             strcpy(auth_server.name, KA_TGS_NAME);
1472             strcpy(auth_server.instance, realm);
1473             strcpy(auth_server.cell, cell);
1474             if (ktc_GetToken
1475                 (&auth_server, &auth_token, sizeof(struct ktc_token),
1476                  &client) != 0) {
1477                 acode =
1478                     ka_GetAuthToken(name, instance, cell, &key,
1479                                     MAXKTCTICKETLIFETIME, (afs_int32 *) 0
1480                                     /*Don't need pwd expiration info here */
1481                     );
1482                 if (acode && (acode != code))   /* codes are usually the same */
1483                     afs_com_err(whoami, code,
1484                             "getting Authentication token for %s",
1485                             PrintedName(name, instance, cell));
1486             }
1487             memset(&key, 0, sizeof(key));
1488         }
1489     }
1490
1491     pToken = ((token.ticketLen == 0) ? 0 : &token);
1492     code = ka_AuthServerConn(cell, KA_MAINTENANCE_SERVICE, pToken, &conn);
1493     if (code && pToken) {
1494         afs_com_err(whoami, code,
1495                 "connecting to AuthServer: now trying w/o authentication");
1496         code = ka_AuthServerConn(cell, KA_MAINTENANCE_SERVICE, 0, &conn);
1497         if (code)
1498             afs_com_err(whoami, code,
1499                     "making unauthenticated connection to AuthServer");
1500     }
1501     if (code) {
1502         afs_com_err(whoami, code,
1503                 "Couldn't establish connection to Authentication Server");
1504         return code;
1505     }
1506
1507     /* now default unspecified password by prompting from terminal */
1508     if (as->nParms >= 12)
1509         for (i = 0; i < 12; i++)
1510             if (as->parms[i].name && (as->parms[i].items == 0)) {
1511                 char *p = as->parms[i].name;    /* parameter name */
1512                 int l = strlen(p);      /* length of name */
1513                 /* does parameter end in "password"  */
1514                 if (strcmp(p + (l - 8), "password") == 0) {
1515                     char msg[32];
1516                     char password[BUFSIZ];
1517                     struct cmd_item *ip;
1518
1519                     strcpy(msg, p + 1);
1520                     strcat(msg, ": ");
1521                     code = read_pw_string(password, sizeof(password), msg, 1);
1522                     if (code)
1523                         code = KAREADPW;
1524                     else if (strlen(password) == 0)
1525                         code = KANULLPASSWORD;
1526                     if (code) {
1527                         afs_com_err(whoami, code, "prompting for %s", p + 1);
1528                         return code;
1529                     }
1530                     ip = (struct cmd_item *)malloc(sizeof(struct cmd_item));
1531                     ip->data = (char *)malloc(strlen(password) + 1);
1532                     ip->next = 0;
1533                     strcpy(ip->data, password);
1534                     as->parms[i].items = ip;
1535                 }
1536             }
1537     if (!conn) {                /* if all else fails... */
1538         code = NoAuth(0, 0);    /* get unauthenticated conn */
1539         if (code)
1540             return code;
1541     }
1542     return 0;
1543 }
1544
1545 /* These are some helpful command that deal with the cache managers tokens. */
1546
1547 static int
1548 ForgetTicket(struct cmd_syndesc *as, void *arock)
1549 {
1550     afs_int32 code;
1551
1552 #ifdef notdef
1553     struct ktc_principal server;
1554
1555     if (as->parms[0].items) {
1556         char *name = as->parms[0].items->data;
1557         code =
1558             ka_ParseLoginName(name, server.name, server.instance,
1559                               server.cell);
1560         if (code) {
1561             afs_com_err(whoami, code, "couldn't interpret name '%s'", name);
1562             return code;
1563         }
1564         if (server.cell[0] == 0) {
1565             if (code = DefaultCell())
1566                 return code;
1567             strcpy(server.cell, cell);
1568         } else {
1569             code = ka_ExpandCell(server.cell, server.cell, 0 /*local */ );
1570             if (code) {
1571                 afs_com_err(whoami, code, "Can't expand cell name");
1572                 return code;
1573             }
1574         }
1575         code = ktc_ForgetToken(&server);
1576         if (code) {
1577             afs_com_err(whoami, code, "couldn't remove tokens for %s",
1578                     PrintedPrincipal(&server));
1579             return code;
1580         }
1581     } else {
1582         if (!as->parms[1].items) {
1583             fprintf(stderr, "Must specify server name or -all\n");
1584             return KABADCMD;
1585         }
1586         code = ktc_ForgetAllTokens();
1587         if (code) {
1588             afs_com_err(whoami, code, "couldn't delete all tokens");
1589             return code;
1590         }
1591     }
1592 #endif
1593     code = ktc_ForgetAllTokens();
1594     if (code) {
1595         afs_com_err(whoami, code, "couldn't delete all tokens");
1596         return code;
1597     }
1598     return 0;
1599 }
1600
1601 static int
1602 ListTickets(struct cmd_syndesc *as, void *arock)
1603 {
1604     afs_int32 code = 0;
1605     int index, newIndex;
1606     struct ktc_principal server;
1607     int verbose = 0;
1608
1609     if (as->parms[1].items)
1610         verbose = 1;
1611     if (as->parms[0].items) {
1612         char *name = as->parms[0].items->data;
1613         code =
1614             ka_ParseLoginName(name, server.name, server.instance,
1615                               server.cell);
1616         if (code) {
1617             afs_com_err(whoami, code, "couldn't interpret name '%s'", name);
1618             return code;
1619         }
1620         if (server.cell[0] == 0) {
1621             if ((code = DefaultCell()))
1622                 return code;
1623             strcpy(server.cell, cell);
1624         } else {
1625             code = ka_ExpandCell(server.cell, server.cell, 0 /*local */ );
1626             if (code) {
1627                 afs_com_err(whoami, code, "Can't expand cell name");
1628                 return code;
1629             }
1630         }
1631         code = ListTicket(&server, verbose);
1632     } else
1633         for (index = 0;; index = newIndex) {
1634             code = ktc_ListTokens(index, &newIndex, &server);
1635             if (code) {
1636                 if (code == KTC_NOENT)
1637                     code = 0;   /* end of list */
1638                 break;
1639             }
1640             code = ListTicket(&server, verbose);
1641         }
1642     return code;
1643 }
1644
1645 static void
1646 add_std_args(register struct cmd_syndesc *ts)
1647 {
1648     cmd_Seek(ts, 12);
1649     /* 12 */ cmd_AddParm(ts, "-admin_username", CMD_SINGLE, CMD_OPTIONAL,
1650                          "admin principal to use for authentication");
1651     /* 13 */ cmd_AddParm(ts, "-password_for_admin", CMD_SINGLE, CMD_OPTIONAL,
1652                          "admin password");
1653     /* 14 */ cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
1654     /* 15 */ cmd_AddParm(ts, "-servers", CMD_LIST, CMD_OPTIONAL,
1655                          "explicit list of authentication servers");
1656     /* 16 */ cmd_AddParm(ts, "-noauth", CMD_FLAG, CMD_OPTIONAL,
1657                          "don't authenticate");
1658 }
1659
1660 afs_int32
1661 ka_AdminInteractive(int cmd_argc, char *cmd_argv[])
1662 {
1663     register int code;
1664     register struct cmd_syndesc *ts;
1665
1666     char line[BUFSIZ];
1667     afs_int32 argc;
1668     char *argv[32];
1669
1670     strncpy(myName, *cmd_argv, 509);
1671
1672     cmd_SetBeforeProc(MyBeforeProc, NULL);
1673     cmd_SetAfterProc(MyAfterProc, NULL);
1674
1675     ts = cmd_CreateSyntax("interactive", Interactive, NULL,
1676                           "enter interactive mode");
1677     add_std_args(ts);
1678
1679     ts = cmd_CreateSyntax("noauthentication", NoAuth, NULL,
1680                           "connect to AuthServer w/o using token");
1681
1682     ts = cmd_CreateSyntax("list", ListUsers, NULL, 
1683                           "list all users in database");
1684     cmd_AddParm(ts, "-long", CMD_FLAG, CMD_OPTIONAL,
1685                 "show detailed info about each user");
1686     cmd_AddParm(ts, "-showadmin", CMD_FLAG, CMD_OPTIONAL,
1687                 "show all cell administrators");
1688     cmd_AddParm(ts, "-showkey", CMD_FLAG, CMD_OPTIONAL,
1689                 "show the user's actual key rather than the checksum");
1690     add_std_args(ts);
1691     cmd_CreateAlias(ts, "ls");
1692
1693     ts = cmd_CreateSyntax("examine", ExamineUser, NULL,
1694                           "examine the entry for a user");
1695     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1696     cmd_AddParm(ts, "-showkey", CMD_FLAG, CMD_OPTIONAL,
1697                 "show the user's actual key rather than the checksum");
1698     add_std_args(ts);
1699
1700     ts = cmd_CreateSyntax("create", CreateUser, NULL,
1701                           "create an entry for a user");
1702     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1703     cmd_AddParm(ts, "-initial_password", CMD_SINGLE, CMD_OPTIONAL,
1704                 "initial password");
1705     add_std_args(ts);
1706
1707     ts = cmd_CreateSyntax("delete", DeleteUser, NULL, "delete a user");
1708     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1709     add_std_args(ts);
1710     cmd_CreateAlias(ts, "rm");
1711
1712     ts = cmd_CreateSyntax("setfields", SetFields, NULL,
1713                           "set various fields in a user's entry");
1714     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1715     cmd_AddParm(ts, "-flags", CMD_SINGLE, CMD_OPTIONAL,
1716                 "hex flag value or flag name expression");
1717     cmd_AddParm(ts, "-expiration", CMD_SINGLE, CMD_OPTIONAL,
1718                 "date of account expiration");
1719     cmd_AddParm(ts, "-lifetime", CMD_SINGLE, CMD_OPTIONAL,
1720                 "maximum ticket lifetime");
1721     cmd_AddParm(ts, "-pwexpires", CMD_SINGLE, CMD_OPTIONAL,
1722                 "number days password is valid ([0..254])");
1723     cmd_AddParm(ts, "-reuse", CMD_SINGLE, CMD_OPTIONAL,
1724                 "permit password reuse (yes/no)");
1725     cmd_AddParm(ts, "-attempts", CMD_SINGLE, CMD_OPTIONAL,
1726                 "maximum successive failed login tries ([0..254])");
1727     cmd_AddParm(ts, "-locktime", CMD_SINGLE, CMD_OPTIONAL,
1728                 "failure penalty [hh:mm or minutes]");
1729 #if ASSOCIATES
1730     cmd_AddParm(ts, "-associates", CMD_SINGLE, CMD_OPTIONAL,
1731                 "maximum associate instances");
1732 #endif
1733     add_std_args(ts);
1734     cmd_CreateAlias(ts, "sf");
1735
1736
1737     ts = cmd_CreateSyntax("unlock", Unlock, NULL,
1738                           "Enable authentication ID after max failed attempts exceeded");
1739     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "authentication ID");
1740     add_std_args(ts);
1741
1742
1743     ts = cmd_CreateSyntax("stringtokey", StringToKey, NULL,
1744                           "convert a string to a key");
1745     cmd_AddParm(ts, "-string", CMD_SINGLE, 0, "password string");
1746     cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
1747
1748     ts = cmd_CreateSyntax("setpassword", SetPassword, NULL,
1749                           "set a user's password");
1750     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1751     cmd_AddParm(ts, "-new_password", CMD_SINGLE, CMD_OPTIONAL,
1752                 "new password");
1753     cmd_Seek(ts, 3);
1754     cmd_AddParm(ts, "-kvno", CMD_SINGLE, CMD_OPTIONAL, "key version number");
1755     add_std_args(ts);
1756     cmd_CreateAlias(ts, "sp");
1757 #ifdef CMD_PARSER_AMBIG_FIX
1758     cmd_CreateAlias(ts, "setpasswd");
1759 #endif
1760
1761     /* set a user's key */
1762     ts = cmd_CreateSyntax("setkey", SetPassword, NULL, (char *)CMD_HIDDEN);
1763     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1764     cmd_Seek(ts, 2);
1765     cmd_AddParm(ts, "-new_key", CMD_SINGLE, 0, "eight byte new key");
1766     cmd_Seek(ts, 3);
1767     cmd_AddParm(ts, "-kvno", CMD_SINGLE, CMD_OPTIONAL, "key version number");
1768     add_std_args(ts);
1769
1770     /* get a user's password */
1771     ts = cmd_CreateSyntax("getpassword", GetPassword, NULL, (char *)CMD_HIDDEN);
1772     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1773     /* don't take standard args */
1774     /* add_std_args (ts); */
1775 #ifdef CMD_PARSER_AMBIG_FIX
1776     cmd_CreateAlias(ts, "getpasswd");
1777 #endif
1778
1779     /* get a random key */
1780     ts = cmd_CreateSyntax("getrandomkey", GetRandomKey, NULL,
1781                           (char *)CMD_HIDDEN);
1782     add_std_args(ts);
1783
1784     /* get a ticket for a specific server */
1785     ts = cmd_CreateSyntax("getticket", GetTicket, NULL, (char *)CMD_HIDDEN);
1786     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of server");
1787     cmd_AddParm(ts, "-lifetime", CMD_SINGLE, CMD_OPTIONAL, "ticket lifetime");
1788     add_std_args(ts);
1789
1790     ts = cmd_CreateSyntax("statistics", Statistics, NULL,
1791                           "show statistics for AuthServer");
1792     add_std_args(ts);
1793
1794     /* show debugging info from AuthServer */
1795     ts = cmd_CreateSyntax("debuginfo", DebugInfo, NULL, (char *)CMD_HIDDEN);
1796     cmd_AddParm(ts, "-hostname", CMD_SINGLE, CMD_OPTIONAL,
1797                 "authentication server host name");
1798     add_std_args(ts);
1799
1800     ts = cmd_CreateSyntax("forgetticket", ForgetTicket, NULL,
1801                           "delete user's tickets");
1802 #ifdef notdef
1803     cmd_AddParm(ts, "-name", CMD_SINGLE, (CMD_OPTIONAL | CMD_HIDE),
1804                 "name of server");
1805 #endif
1806     cmd_AddParm(ts, "-all", CMD_FLAG, CMD_OPTIONAL, "delete all tickets");
1807
1808     ts = cmd_CreateSyntax("listtickets", ListTickets, NULL,
1809                           "show all cache manager tickets");
1810     cmd_AddParm(ts, "-name", CMD_SINGLE, CMD_OPTIONAL, "name of server");
1811     cmd_AddParm(ts, "-long", CMD_FLAG, CMD_OPTIONAL,
1812                 "show session key and ticket");
1813
1814     ts = cmd_CreateSyntax("quit", Quit, NULL, "exit program");
1815
1816     finished = 1;
1817     conn = 0;                   /* no connection yet */
1818     zero_argc = cmd_argc;
1819     zero_argv = cmd_argv;
1820
1821     strcpy(whoami, "kas");
1822
1823     if ((code = cmd_Dispatch(cmd_argc, cmd_argv))) {
1824         return code;
1825     }
1826
1827     while (!finished) {
1828         char *s;
1829         int i;
1830
1831         printf("ka> ");
1832         s = fgets(line, sizeof(line), stdin);
1833         if (s == NULL)
1834             return 0;           /* EOF on input */
1835         for (i = strlen(line) - 1; i >= 0 && isspace(line[i]); i--)
1836             line[i] = 0;
1837         if (i < 0)
1838             continue;           /* blank line */
1839
1840         code =
1841             cmd_ParseLine(line, argv, &argc, sizeof(argv) / sizeof(argv[0]));
1842         if (code) {
1843             afs_com_err(whoami, code, "parsing line: '%s'", line);
1844             return code;
1845         }
1846         code = cmd_Dispatch(argc, argv);
1847         cmd_FreeArgv(argv);
1848     }
1849     return code;
1850 }