reindent-20030715
[openafs.git] / src / kauth / admin_tools.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /* These routines provide administrative tools for managing the AuthServer.
11    There is an interactive routine that can be used to examine the database and
12    make small changes as well as subroutines to permit specialized programs to
13    update the database, change the server passwords, etc. */
14
15 #include <afsconfig.h>
16 #include <afs/param.h>
17
18 RCSID
19     ("$Header$");
20
21 #include <afs/stds.h>
22 #include <afs/debug.h>
23 #include <ctype.h>
24 #include <string.h>
25
26     /* These two needed for rxgen output to work */
27 #include <sys/types.h>
28 #include <rx/xdr.h>
29
30 #include <stdio.h>
31 #include <rx/rx.h>
32 #include <lock.h>
33 #include <ubik.h>
34 #ifndef AFS_NT40_ENV
35 #include <pwd.h>
36 #endif
37 #include <afs/auth.h>
38 #include <afs/cellconfig.h>
39 #include <afs/cmd.h>
40 #include <afs/com_err.h>
41 #include <afs/afsutil.h>
42
43 #include "kauth.h"
44 #include "kautils.h"
45 #include "kaport.h"
46
47
48 #define CMD_PARSER_AMBIG_FIX 1  /* allow ambiguous aliases */
49
50 extern char *ktime_GetDateUsage();
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();
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         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 ListUsers(struct cmd_syndesc *as, char *arock)
83 {
84     struct kaident name;
85     afs_int32 index;
86     afs_int32 count;
87     afs_int32 next_index;
88     int code, all = 0, showa = 0;
89     int showkey = (as->parms[2].items != NULL);
90
91     if (as->parms[0].items)
92         all = 1;
93     if (as->parms[1].items) {
94         all = 1;
95         showa = 1;
96     }
97     for (index = 0; 1; index = next_index) {
98         code =
99             ubik_Call(KAM_ListEntry, conn, 0, index, &next_index, &count,
100                       &name);
101         if (code) {
102             com_err(whoami, code, "calling KAM_ListEntry");
103             break;
104         }
105         if (!next_index)
106             break;
107         if (next_index < 0)
108             printf("next_index (%d) is negative: ", next_index);
109         if (strlen(name.name) == 0)
110             printf("name is zero length: ");
111         if (all)
112             DumpUser(name.name, NULL, showa, showkey, name.instance);
113         else
114             ka_PrintUserID("", name.name, name.instance, "\n");
115     }
116     return code;
117 }
118
119
120 int
121 ExamineUser(struct cmd_syndesc *as, char *arock)
122 {
123     int showkey = (as->parms[1].items != NULL);
124     return DumpUser(as->parms[0].items->data, arock, 0, showkey, NULL);
125 }
126
127
128 int
129 DumpUser(char *user, char *arock, int showadmin, int showkey, char *inst)
130 {
131     char name[MAXKTCNAMELEN];
132     char instance[MAXKTCNAMELEN];
133     Date now = time(0);
134     int code;
135     char bob[KA_TIMESTR_LEN];
136
137     struct kaentryinfo tentry;
138
139     code = ka_ParseLoginName(user, name, instance, 0);
140     if (code) {
141         com_err(whoami, code, "parsing user's name '%s'", user);
142         return KABADCMD;
143     }
144
145     if (!inst)
146         inst = instance;
147     code =
148         ubik_Call(KAM_GetEntry, conn, 0, name, inst, KAMAJORVERSION, &tentry);
149     if (code) {
150         com_err(whoami, code, "getting information for %s.%s", name, inst);
151         return code;
152     }
153     if (tentry.minor_version != KAMINORVERSION)
154         printf("Minor version number mismatch: got %d, expected %d\n",
155                tentry.minor_version, KAMINORVERSION);
156     if (showadmin && !(tentry.flags & KAFADMIN))
157         return 0;
158     ka_PrintUserID("\nUser data for ", name, inst, "");
159     {
160         char *prefix = " (";
161 #define NEWPREFIX "+"
162         if (tentry.flags & KAFADMIN) {
163             printf("%sADMIN", prefix);
164             prefix = NEWPREFIX;
165         }
166         if (tentry.flags & KAFNOTGS) {
167             printf("%sNOTGS", prefix);
168             prefix = NEWPREFIX;
169         }
170         if (tentry.flags & KAFNOCPW) {
171             printf("%sNOCPW", prefix);
172             prefix = NEWPREFIX;
173         }
174         if (tentry.flags & KAFNOSEAL) {
175             printf("%sNOSEAL", prefix);
176             prefix = NEWPREFIX;
177         }
178         if (tentry.flags & KAFNEWASSOC) {
179             printf("%sNEWASSOC", prefix);
180             prefix = NEWPREFIX;
181         }
182         if (tentry.flags & KAFASSOCROOT) {
183             printf("%sASSOCROOT", prefix);
184             prefix = NEWPREFIX;
185         }
186         if (tentry.flags & KAFASSOC) {
187             printf("%sASSOC", prefix);
188             prefix = NEWPREFIX;
189         }
190         if (tentry.user_expiration <= now) {
191             printf("%sexpired", prefix);
192             prefix = NEWPREFIX;
193         }
194         if (strcmp(prefix, NEWPREFIX) == 0)
195             printf(")\n");
196         else
197             printf("\n");
198     }
199     if ((!ka_KeyIsZero((char *)&tentry.key, sizeof(tentry.key))) && (showkey)) {
200         printf("  key (%d):", tentry.key_version);
201         ka_PrintBytes((char *)&tentry.key, sizeof(tentry.key));
202     } else {
203         if (tentry.keyCheckSum == 0)
204             printf("  key version is %d", tentry.key_version);
205         else
206             printf("  key (%d) cksum is %u", tentry.key_version,
207                    tentry.keyCheckSum);
208     }
209     ka_timestr(tentry.change_password_time, bob, KA_TIMESTR_LEN);
210     printf(", last cpw: %s\n", bob);
211     if (!tentry.misc_auth_bytes) {
212         printf("  password will never expire.\n");
213         printf
214             ("  An unlimited number of unsuccessful authentications is permitted.\n");
215     } else {
216         unsigned char misc_stuff[4];
217         afs_uint32 temp;
218
219         temp = tentry.misc_auth_bytes;
220 /*
221       temp = ntohl(tentry.misc_auth_bytes);
222 */
223         unpack_long(temp, misc_stuff);
224
225         if (!misc_stuff[0]) {
226             printf("  password will never expire.\n");
227         } else {
228             ka_timestr((tentry.change_password_time +
229                         misc_stuff[0] * 24 * 60 * 60), bob, KA_TIMESTR_LEN);
230             printf("  password will expire: %s\n", bob);
231         }
232
233         if (!misc_stuff[2])
234             printf
235                 ("  An unlimited number of unsuccessful authentications is permitted.\n");
236         else {
237             printf
238                 ("  %d consecutive unsuccessful authentications are permitted.\n",
239                  misc_stuff[2]);
240
241             if (!misc_stuff[3])
242                 printf("  The lock time for this user is not limited.\n");
243             else
244                 printf("  The lock time for this user is %4.1f minutes.\n",
245                        (float)((unsigned int)misc_stuff[3] << 9) / 60.0);
246
247             if (!(misc_stuff[1] & KA_ISLOCKED)
248                 || !ka_islocked(name, instance, &temp))
249                 printf("  User is not locked.\n");
250             else if (temp == (afs_uint32) (-1L))
251                 printf("  User is locked forever.\n");
252             else {
253                 ka_timestr(temp, bob, KA_TIMESTR_LEN);
254                 printf("  User is locked until %s\n", bob);
255             }
256         }
257
258     }
259     {
260         char exp[KA_TIMESTR_LEN];
261         ka_timestr(tentry.user_expiration, exp, KA_TIMESTR_LEN);
262         if (tentry.user_expiration < now)
263             printf("  DISABLED entry at %s.", exp);
264         else if (tentry.user_expiration == NEVERDATE)
265             printf("  entry never expires.");
266         else
267             printf("  entry expires on %s.", exp);
268     }
269     printf("  Max ticket lifetime %.2f hours.\n",
270            tentry.max_ticket_lifetime / 3600.0);
271     ka_timestr(tentry.modification_time, bob, KA_TIMESTR_LEN);
272     printf("  last mod on %s by ", bob);
273     ka_PrintUserID("", tentry.modification_user.name,
274                    tentry.modification_user.instance, "\n");
275     if ((tentry.reserved3 & 0xffff0000) == 0x12340000) {
276         int short reused = (short)tentry.reserved3;
277         if (!reused) {
278             printf("  permit password reuse\n");
279         } else {
280             printf("  don't permit password reuse\n");
281         }
282     }
283     return 0;
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", error_table_name(code), 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, char *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         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, char *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         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", &f);
416         else if (*str == '0')   /* assume octal */
417             sscanf(str, "%lo", &f);
418         else                    /* just assume hex */
419             sscanf(str, "%lx", &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                 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, name,
519                           instance, &tempwhen, /*spares */ 0, 0, 0,
520                           0);
521         if (code) {
522             if (seriouserror(code))
523                 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, char *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         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, name, instance,
556                              /*spares */ 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             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, char *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         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         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, char *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             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, &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, char *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         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 #ifdef AFS_S390_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         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         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         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
970 GetTicket(struct cmd_syndesc *as, char *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         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             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         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
1016 GetPassword(struct cmd_syndesc *as, char *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         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, char *arock)
1069 {
1070     int code;
1071     struct ktc_encryptionKey key;
1072
1073     code = ubik_Call(KAM_GetRandomKey, conn, 0, &key);
1074     if (code)
1075         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("%0.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, char *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", dynamics.host, bob);
1118
1119 #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)
1120     print_stat(Authenticate);
1121     print_stat(ChangePassword);
1122     print_stat(GetTicket);
1123     print_stat(CreateUser);
1124     print_stat(SetPassword);
1125     print_stat(SetFields);
1126     print_stat(DeleteUser);
1127     print_stat(GetEntry);
1128     print_stat(ListEntry);
1129     print_stat(GetStats);
1130     print_stat(GetPassword);
1131     print_stat(GetRandomKey);
1132     print_stat(Debug);
1133     print_stat(UAuthenticate);
1134     print_stat(UGetTicket);
1135
1136 #if (KAMAJORVERSION>5)
1137     print cpu stats printf("%d string checks\n", dynamics.string_checks);
1138 #else
1139     printf("Used %.3f seconds of CPU time.\n",
1140            dynamics.string_checks / 1000.0);
1141 #endif
1142     printf("%d admin accounts\n", admins);
1143     return 0;
1144 }
1145
1146 int
1147 DebugInfo(struct cmd_syndesc *as, char *arock)
1148 {
1149     int code;
1150     struct ka_debugInfo info;
1151     int i;
1152     Date start, now;
1153     int timeOffset;
1154     char bob[KA_TIMESTR_LEN];
1155
1156     start = time(0);
1157     if (as->parms[0].items) {
1158         struct ubik_client *iConn;
1159         code =
1160             ka_SingleServerConn(cell, as->parms[0].items->data,
1161                                 KA_MAINTENANCE_SERVICE, 0, &iConn);
1162         if (code) {
1163             struct afsconf_cell cellinfo;
1164
1165             com_err(whoami, code, "couldn't find host %s in cell %s",
1166                     as->parms[0].items->data, cell);
1167             code = ka_GetServers(cell, &cellinfo);
1168             if (code)
1169                 com_err(whoami, code, "getting servers in cell %s", cell);
1170             else {
1171                 printf("Servers in cell %s, are:\n", cell);
1172                 for (i = 0; i < cellinfo.numServers; i++)
1173                     printf("  %s\n", cellinfo.hostName[i]);
1174             }
1175             return code;
1176         }
1177         code = ubik_Call(KAM_Debug, iConn, 0, KAMAJORVERSION, 0, &info);
1178         ubik_ClientDestroy(iConn);
1179     } else
1180         code = ubik_Call(KAM_Debug, conn, 0, KAMAJORVERSION, 0, &info);
1181
1182     if (code) {
1183         com_err(whoami, code, "call to Debug failed");
1184         return code;
1185     }
1186     now = time(0);
1187
1188     if (info.minorVersion != KAMINORVERSION)
1189         printf("Minor version number mismatch: got %d, expected %d\n",
1190                info.minorVersion, KAMINORVERSION);
1191
1192     timeOffset = info.
1193 #if (KAMAJORVERSION>5)
1194         now
1195 #else
1196         reserved1
1197 #endif
1198         - now;
1199     if (timeOffset < 0)
1200         timeOffset = -timeOffset;
1201     if (timeOffset > 60) {
1202         printf
1203             ("WARNING: Large server client clock skew: %d seconds. Call itself took %d seconds.\n",
1204              timeOffset, now - start);
1205     }
1206     ka_timestr(info.startTime, bob, KA_TIMESTR_LEN);
1207     printf("From host %lx started %sat %s:\n", 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", info.cheader_lock,
1222                info.keycache_lock);
1223     printf("Last authentication for %s, last admin user was %s\n",
1224            info.lastAuth, info.lastAdmin);
1225     printf("Last TGS op was a %s ticket was for %s\n", info.lastTGSServer,
1226            info.lastTGS);
1227     printf("Last UDP TGS was a %s ticket for %s.  UDP Authenticate for %s\n",
1228            info.lastUTGSServer, info.lastUTGS, info.lastUAuth);
1229     printf("key cache size %d, used %d.\n", info.kcSize, info.kcUsed);
1230     if (info.kcUsed > KADEBUGKCINFOSIZE) {
1231         printf("insufficient room to return all key cache entries!\n");
1232         info.kcUsed = KADEBUGKCINFOSIZE;
1233     }
1234     for (i = 0; i < info.kcUsed; i++)
1235         ka_timestr(info.kcInfo[i].used, bob, KA_TIMESTR_LEN);
1236     printf("%32s %c %2x(%2x) used %s\n", info.kcInfo[i].principal,
1237            (info.kcInfo[i].primary ? '*' : ' '), info.kcInfo[i].kvno,
1238            info.kcInfo[i].keycksum, bob);
1239     return 0;
1240 }
1241
1242 int
1243 Interactive(struct cmd_syndesc *as, char *arock)
1244 {
1245     finished = 0;
1246     return 0;
1247 }
1248
1249 int
1250 Quit(struct cmd_syndesc *as, char *arock)
1251 {
1252     finished = 1;
1253     return 0;
1254 }
1255
1256 int
1257 MyAfterProc(struct cmd_syndesc *as)
1258 {
1259     if (!strcmp(as->name, "help"))
1260         return;
1261
1262     /* Determine if we need to destory the ubik connection.
1263      * Closing it avoids resends of packets. 
1264      */
1265     if (conn) {
1266         ubik_ClientDestroy(conn);
1267         conn = 0;
1268     }
1269
1270     return 0;
1271 }
1272
1273 int init = 0, noauth;
1274 char name[MAXKTCNAMELEN];
1275 char instance[MAXKTCNAMELEN];
1276 char newCell[MAXKTCREALMLEN];
1277 afs_int32 serverList[MAXSERVERS];
1278
1279 int
1280 NoAuth(struct cmd_syndesc *as, char *arock)
1281 {
1282     noauth = 1;
1283     return 0;
1284 }
1285
1286 static int
1287 MyBeforeProc(struct cmd_syndesc *as, char *arock)
1288 {
1289     extern struct passwd *getpwuid();
1290     struct passwd *pw;
1291     struct ktc_encryptionKey key;
1292     struct ktc_principal auth_server, auth_token, client;
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         code = 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                 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             pw = getpwuid(getuid());
1353             if (pw == 0) {
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             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                 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 = 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                     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, &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 *)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                     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         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             com_err(whoami, code,
1497                     "making unauthenticated connection to AuthServer");
1498     }
1499     if (code) {
1500         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 = 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                         com_err(whoami, code, "prompting for %s", p + 1);
1526                         return code;
1527                     }
1528                     ip = (struct cmd_item *)malloc(sizeof(struct cmd_item));
1529                     ip->data = (char *)malloc(strlen(password) + 1);
1530                     ip->next = 0;
1531                     strcpy(ip->data, password);
1532                     as->parms[i].items = ip;
1533                 }
1534             }
1535     if (!conn) {                /* if all else fails... */
1536         code = NoAuth(0, 0);    /* get unauthenticated conn */
1537         if (code)
1538             return code;
1539     }
1540     return 0;
1541 }
1542
1543 /* These are some helpful command that deal with the cache managers tokens. */
1544
1545 static
1546 ForgetTicket(struct cmd_syndesc *as, char *arock)
1547 {
1548     afs_int32 code;
1549
1550 #ifdef notdef
1551     struct ktc_principal server;
1552
1553     if (as->parms[0].items) {
1554         char *name = as->parms[0].items->data;
1555         code =
1556             ka_ParseLoginName(name, server.name, server.instance,
1557                               server.cell);
1558         if (code) {
1559             com_err(whoami, code, "couldn't interpret name '%s'", name);
1560             return code;
1561         }
1562         if (server.cell[0] == 0) {
1563             if (code = DefaultCell())
1564                 return code;
1565             strcpy(server.cell, cell);
1566         } else {
1567             code = ka_ExpandCell(server.cell, server.cell, 0 /*local */ );
1568             if (code) {
1569                 com_err(whoami, code, "Can't expand cell name");
1570                 return code;
1571             }
1572         }
1573         code = ktc_ForgetToken(&server);
1574         if (code) {
1575             com_err(whoami, code, "couldn't remove tokens for %s",
1576                     PrintedPrincipal(&server));
1577             return code;
1578         }
1579     } else {
1580         if (!as->parms[1].items) {
1581             fprintf(stderr, "Must specify server name or -all\n");
1582             return KABADCMD;
1583         }
1584         code = ktc_ForgetAllTokens();
1585         if (code) {
1586             com_err(whoami, code, "couldn't delete all tokens");
1587             return code;
1588         }
1589     }
1590 #endif
1591     code = ktc_ForgetAllTokens();
1592     if (code) {
1593         com_err(whoami, code, "couldn't delete all tokens");
1594         return code;
1595     }
1596     return 0;
1597 }
1598
1599 static
1600 ListTickets(struct cmd_syndesc *as, char *arock)
1601 {
1602     afs_int32 code = 0;
1603     int index, newIndex;
1604     struct ktc_principal server;
1605     int verbose = 0;
1606
1607     if (as->parms[1].items)
1608         verbose = 1;
1609     if (as->parms[0].items) {
1610         char *name = as->parms[0].items->data;
1611         code =
1612             ka_ParseLoginName(name, server.name, server.instance,
1613                               server.cell);
1614         if (code) {
1615             com_err(whoami, code, "couldn't interpret name '%s'", name);
1616             return code;
1617         }
1618         if (server.cell[0] == 0) {
1619             if (code = DefaultCell())
1620                 return code;
1621             strcpy(server.cell, cell);
1622         } else {
1623             code = ka_ExpandCell(server.cell, server.cell, 0 /*local */ );
1624             if (code) {
1625                 com_err(whoami, code, "Can't expand cell name");
1626                 return code;
1627             }
1628         }
1629         code = ListTicket(&server, verbose);
1630     } else
1631         for (index = 0;; index = newIndex) {
1632             code = ktc_ListTokens(index, &newIndex, &server);
1633             if (code) {
1634                 if (code == KTC_NOENT)
1635                     code = 0;   /* end of list */
1636                 break;
1637             }
1638             code = ListTicket(&server, verbose);
1639         }
1640     return code;
1641 }
1642
1643 static void
1644 add_std_args(register struct cmd_syndesc *ts)
1645 {
1646     cmd_Seek(ts, 12);
1647     /* 12 */ cmd_AddParm(ts, "-admin_username", CMD_SINGLE, CMD_OPTIONAL,
1648                          "admin principal to use for authentication");
1649     /* 13 */ cmd_AddParm(ts, "-password_for_admin", CMD_SINGLE, CMD_OPTIONAL,
1650                          "admin password");
1651     /* 14 */ cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
1652     /* 15 */ cmd_AddParm(ts, "-servers", CMD_LIST, CMD_OPTIONAL,
1653                          "explicit list of authentication servers");
1654     /* 16 */ cmd_AddParm(ts, "-noauth", CMD_FLAG, CMD_OPTIONAL,
1655                          "don't authenticate");
1656 }
1657
1658 afs_int32
1659 ka_AdminInteractive(int cmd_argc, char *cmd_argv[])
1660 {
1661     register int code;
1662     register struct cmd_syndesc *ts;
1663
1664     char line[BUFSIZ];
1665     afs_int32 argc;
1666     char *argv[32];
1667
1668     strncpy(myName, *cmd_argv, 509);
1669
1670     cmd_SetBeforeProc(MyBeforeProc, NULL);
1671     cmd_SetAfterProc(MyAfterProc, NULL);
1672
1673     ts = cmd_CreateSyntax("interactive", Interactive, 0,
1674                           "enter interactive mode");
1675     add_std_args(ts);
1676
1677     ts = cmd_CreateSyntax("noauthentication", NoAuth, 0,
1678                           "connect to AuthServer w/o using token");
1679
1680     ts = cmd_CreateSyntax("list", ListUsers, 0, "list all users in database");
1681     cmd_AddParm(ts, "-long", CMD_FLAG, CMD_OPTIONAL,
1682                 "show detailed info about each user");
1683     cmd_AddParm(ts, "-showadmin", CMD_FLAG, CMD_OPTIONAL,
1684                 "show all cell administrators");
1685     cmd_AddParm(ts, "-showkey", CMD_FLAG, CMD_OPTIONAL,
1686                 "show the user's actual key rather than the checksum");
1687     add_std_args(ts);
1688     cmd_CreateAlias(ts, "ls");
1689
1690     ts = cmd_CreateSyntax("examine", ExamineUser, 0,
1691                           "examine the entry for a user");
1692     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1693     cmd_AddParm(ts, "-showkey", CMD_FLAG, CMD_OPTIONAL,
1694                 "show the user's actual key rather than the checksum");
1695     add_std_args(ts);
1696
1697     ts = cmd_CreateSyntax("create", CreateUser, 0,
1698                           "create an entry for a user");
1699     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1700     cmd_AddParm(ts, "-initial_password", CMD_SINGLE, CMD_OPTIONAL,
1701                 "initial password");
1702     add_std_args(ts);
1703
1704     ts = cmd_CreateSyntax("delete", DeleteUser, 0, "delete a user");
1705     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1706     add_std_args(ts);
1707     cmd_CreateAlias(ts, "rm");
1708
1709     ts = cmd_CreateSyntax("setfields", SetFields, 0,
1710                           "set various fields in a user's entry");
1711     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1712     cmd_AddParm(ts, "-flags", CMD_SINGLE, CMD_OPTIONAL,
1713                 "hex flag value or flag name expression");
1714     cmd_AddParm(ts, "-expiration", CMD_SINGLE, CMD_OPTIONAL,
1715                 "date of account expiration");
1716     cmd_AddParm(ts, "-lifetime", CMD_SINGLE, CMD_OPTIONAL,
1717                 "maximum ticket lifetime");
1718     cmd_AddParm(ts, "-pwexpires", CMD_SINGLE, CMD_OPTIONAL,
1719                 "number days password is valid ([0..254])");
1720     cmd_AddParm(ts, "-reuse", CMD_SINGLE, CMD_OPTIONAL,
1721                 "permit password reuse (yes/no)");
1722     cmd_AddParm(ts, "-attempts", CMD_SINGLE, CMD_OPTIONAL,
1723                 "maximum successive failed login tries ([0..254])");
1724     cmd_AddParm(ts, "-locktime", CMD_SINGLE, CMD_OPTIONAL,
1725                 "failure penalty [hh:mm or minutes]");
1726 #if ASSOCIATES
1727     cmd_AddParm(ts, "-associates", CMD_SINGLE, CMD_OPTIONAL,
1728                 "maximum associate instances");
1729 #endif
1730     add_std_args(ts);
1731     cmd_CreateAlias(ts, "sf");
1732
1733
1734     ts = cmd_CreateSyntax("unlock", Unlock, 0,
1735                           "Enable authentication ID after max failed attempts exceeded");
1736     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "authentication ID");
1737     add_std_args(ts);
1738
1739
1740     ts = cmd_CreateSyntax("stringtokey", StringToKey, 0,
1741                           "convert a string to a key");
1742     cmd_AddParm(ts, "-string", CMD_SINGLE, 0, "password string");
1743     cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
1744
1745     ts = cmd_CreateSyntax("setpassword", SetPassword, 0,
1746                           "set a user's password");
1747     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1748     cmd_AddParm(ts, "-new_password", CMD_SINGLE, CMD_OPTIONAL,
1749                 "new password");
1750     cmd_Seek(ts, 3);
1751     cmd_AddParm(ts, "-kvno", CMD_SINGLE, CMD_OPTIONAL, "key version number");
1752     add_std_args(ts);
1753     cmd_CreateAlias(ts, "sp");
1754 #ifdef CMD_PARSER_AMBIG_FIX
1755     cmd_CreateAlias(ts, "setpasswd");
1756 #endif
1757
1758     /* set a user's key */
1759     ts = cmd_CreateSyntax("setkey", SetPassword, 0, (char *)CMD_HIDDEN);
1760     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1761     cmd_Seek(ts, 2);
1762     cmd_AddParm(ts, "-new_key", CMD_SINGLE, 0, "eight byte new key");
1763     cmd_Seek(ts, 3);
1764     cmd_AddParm(ts, "-kvno", CMD_SINGLE, CMD_OPTIONAL, "key version number");
1765     add_std_args(ts);
1766
1767     /* get a user's password */
1768     ts = cmd_CreateSyntax("getpassword", GetPassword, 0, (char *)CMD_HIDDEN);
1769     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1770     /* don't take standard args */
1771     /* add_std_args (ts); */
1772 #ifdef CMD_PARSER_AMBIG_FIX
1773     cmd_CreateAlias(ts, "getpasswd");
1774 #endif
1775
1776     /* get a random key */
1777     ts = cmd_CreateSyntax("getrandomkey", GetRandomKey, 0,
1778                           (char *)CMD_HIDDEN);
1779     add_std_args(ts);
1780
1781     /* get a ticket for a specific server */
1782     ts = cmd_CreateSyntax("getticket", GetTicket, 0, (char *)CMD_HIDDEN);
1783     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of server");
1784     cmd_AddParm(ts, "-lifetime", CMD_SINGLE, CMD_OPTIONAL, "ticket lifetime");
1785     add_std_args(ts);
1786
1787     ts = cmd_CreateSyntax("statistics", Statistics, 0,
1788                           "show statistics for AuthServer");
1789     add_std_args(ts);
1790
1791     /* show debugging info from AuthServer */
1792     ts = cmd_CreateSyntax("debuginfo", DebugInfo, 0, (char *)CMD_HIDDEN);
1793     cmd_AddParm(ts, "-hostname", CMD_SINGLE, CMD_OPTIONAL,
1794                 "authentication server host name");
1795     add_std_args(ts);
1796
1797     ts = cmd_CreateSyntax("forgetticket", ForgetTicket, 0,
1798                           "delete user's tickets");
1799 #ifdef notdef
1800     cmd_AddParm(ts, "-name", CMD_SINGLE, (CMD_OPTIONAL | CMD_HIDE),
1801                 "name of server");
1802 #endif
1803     cmd_AddParm(ts, "-all", CMD_FLAG, CMD_OPTIONAL, "delete all tickets");
1804
1805     ts = cmd_CreateSyntax("listtickets", ListTickets, 0,
1806                           "show all cache manager tickets");
1807     cmd_AddParm(ts, "-name", CMD_SINGLE, CMD_OPTIONAL, "name of server");
1808     cmd_AddParm(ts, "-long", CMD_FLAG, CMD_OPTIONAL,
1809                 "show session key and ticket");
1810
1811     ts = cmd_CreateSyntax("quit", Quit, 0, "exit program");
1812
1813     finished = 1;
1814     conn = 0;                   /* no connection yet */
1815     zero_argc = cmd_argc;
1816     zero_argv = cmd_argv;
1817
1818     strcpy(whoami, "kas");
1819
1820     if (code = cmd_Dispatch(cmd_argc, cmd_argv)) {
1821         return code;
1822     }
1823
1824     while (!finished) {
1825         char *s;
1826         int i;
1827
1828         printf("ka> ");
1829         s = fgets(line, sizeof(line), stdin);
1830         if (s == NULL)
1831             return 0;           /* EOF on input */
1832         for (i = strlen(line) - 1; i >= 0 && isspace(line[i]); i--)
1833             line[i] = 0;
1834         if (i < 0)
1835             continue;           /* blank line */
1836
1837         code =
1838             cmd_ParseLine(line, argv, &argc, sizeof(argv) / sizeof(argv[0]));
1839         if (code) {
1840             com_err(whoami, code, "parsing line: '%s'", line);
1841             return code;
1842         }
1843         code = cmd_Dispatch(argc, argv);
1844         cmd_FreeArgv(argv);
1845     }
1846     return code;
1847 }