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