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