2 * Copyright 2000, International Business Machines Corporation and others.
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
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. */
15 #include <afs/param.h>
16 #include <afsconfig.h>
21 #include <afs/debug.h>
25 /* These two needed for rxgen output to work */
26 #include <sys/types.h>
37 #include <afs/cellconfig.h>
39 #include <afs/com_err.h>
40 #include <afs/afsutil.h>
47 #define CMD_PARSER_AMBIG_FIX 1 /* allow ambiguous aliases */
49 extern char *ktime_GetDateUsage();
51 #define KA_SIXHOURS (6*3600)
53 static struct ubik_client *conn;
54 static char cell[MAXKTCREALMLEN] = "";
55 static char whoami[32];
56 static char passwd[BUFSIZ];
57 static char myName[510]; /* almost like whoami save with path and without : */
61 static char **zero_argv;
62 afs_uint32 ka_islocked();
64 afs_int32 DefaultCell (void)
68 if (cell[0] != 0) return 0;
69 code = ka_ExpandCell (0, cell, 0/*local*/);
71 com_err (whoami, code, "Can't expand cell name");
76 /* These are the command operation procedures. */
79 struct cmd_syndesc *as,
86 int code, all=0, showa = 0;
87 int showkey = (as->parms[2].items != NULL);
89 if (as->parms[0].items)
91 if (as->parms[1].items) {
95 for (index = 0; 1; index = next_index) {
96 code = ubik_Call (KAM_ListEntry, conn, 0,
97 index, &next_index, &count, &name);
99 com_err (whoami, code, "calling KAM_ListEntry");
102 if (!next_index) break;
104 printf ("next_index (%d) is negative: ", next_index);
105 if (strlen(name.name) == 0) printf ("name is zero length: ");
107 DumpUser(name.name, (char *)0, showa, showkey, name.instance);
109 ka_PrintUserID ("", name.name, name.instance, "\n");
116 struct cmd_syndesc *as,
119 int showkey = (as->parms[1].items != NULL);
120 return DumpUser(as->parms[0].items->data, arock, 0, showkey, (char *)0);
131 char name[MAXKTCNAMELEN];
132 char instance[MAXKTCNAMELEN];
135 char bob[KA_TIMESTR_LEN];
137 struct kaentryinfo tentry;
139 code = ka_ParseLoginName (user, name, instance, 0);
141 com_err (whoami, code, "parsing user's name '%s'", user);
147 code = ubik_Call (KAM_GetEntry, conn, 0, name, inst,
148 KAMAJORVERSION, &tentry);
150 com_err (whoami, code,
151 "getting information for %s.%s", name, inst);
154 if (tentry.minor_version != KAMINORVERSION)
155 printf ("Minor version number mismatch: got %d, expected %d\n",
156 tentry.minor_version, KAMINORVERSION);
157 if (showadmin && !(tentry.flags & KAFADMIN))
159 ka_PrintUserID ("\nUser data for ", name, inst, "");
160 { char *prefix = " (";
161 #define NEWPREFIX "+"
162 if (tentry.flags & KAFADMIN) { printf ("%sADMIN", prefix); prefix = NEWPREFIX; }
163 if (tentry.flags & KAFNOTGS) { printf ("%sNOTGS", prefix); prefix = NEWPREFIX; }
164 if (tentry.flags & KAFNOCPW) { printf ("%sNOCPW", prefix); prefix = NEWPREFIX; }
165 if (tentry.flags & KAFNOSEAL) { printf ("%sNOSEAL", prefix); prefix = NEWPREFIX; }
166 if (tentry.flags & KAFNEWASSOC) { printf ("%sNEWASSOC", prefix); prefix = NEWPREFIX; }
167 if (tentry.flags & KAFASSOCROOT) { printf ("%sASSOCROOT", prefix); prefix = NEWPREFIX; }
168 if (tentry.flags & KAFASSOC) { printf ("%sASSOC", prefix); prefix = NEWPREFIX; }
169 if (tentry.user_expiration <= now) { printf ("%sexpired", prefix); prefix = NEWPREFIX; }
170 if (strcmp (prefix, NEWPREFIX) == 0) printf (")\n");
173 if ((!ka_KeyIsZero((char *) &tentry.key, sizeof(tentry.key))) &&
175 printf (" key (%d):", tentry.key_version);
176 ka_PrintBytes ((char *)&tentry.key, sizeof(tentry.key));
179 if (tentry.keyCheckSum == 0)
180 printf (" key version is %d", tentry.key_version);
182 printf (" key (%d) cksum is %u",
183 tentry.key_version, tentry.keyCheckSum);
185 ka_timestr(tentry.change_password_time,bob,KA_TIMESTR_LEN);
186 printf (", last cpw: %s\n", bob);
187 if (!tentry.misc_auth_bytes) {
188 printf (" password will never expire.\n");
189 printf (" An unlimited number of unsuccessful authentications is permitted.\n");
192 unsigned char misc_stuff[4];
195 temp = tentry.misc_auth_bytes;
197 temp = ntohl(tentry.misc_auth_bytes);
199 unpack_long(temp, misc_stuff);
201 if (!misc_stuff[0]) {
202 printf (" password will never expire.\n");
205 ka_timestr((tentry.change_password_time + misc_stuff[0]*24*60*60), bob, KA_TIMESTR_LEN);
206 printf (" password will expire: %s\n", bob);
210 printf (" An unlimited number of unsuccessful authentications is permitted.\n");
212 printf (" %d consecutive unsuccessful authentications are permitted.\n", misc_stuff[2]);
215 printf (" The lock time for this user is not limited.\n");
217 printf (" The lock time for this user is %4.1f minutes.\n",
218 (float) ((unsigned int) misc_stuff[3] << 9) / 60.0);
220 if (!(misc_stuff[1] & KA_ISLOCKED) || !ka_islocked(name, instance, &temp))
221 printf (" User is not locked.\n");
222 else if (temp == (afs_uint32) (-1L))
223 printf (" User is locked forever.\n");
225 ka_timestr(temp,bob,KA_TIMESTR_LEN);
226 printf (" User is locked until %s\n",bob);
231 { char exp[KA_TIMESTR_LEN];
232 ka_timestr (tentry.user_expiration, exp, KA_TIMESTR_LEN);
233 if (tentry.user_expiration < now)
234 printf (" DISABLED entry at %s.", exp);
235 else if (tentry.user_expiration == NEVERDATE)
236 printf (" entry never expires.");
237 else printf (" entry expires on %s.", exp);
239 printf (" Max ticket lifetime %.2f hours.\n",
240 tentry.max_ticket_lifetime / 3600.0);
241 ka_timestr (tentry.modification_time,bob,KA_TIMESTR_LEN);
242 printf (" last mod on %s by ", bob);
243 ka_PrintUserID ("", tentry.modification_user.name,
244 tentry.modification_user.instance, "\n");
245 if ((tentry.reserved3 & 0xffff0000) == 0x12340000) {
246 int short reused = (short)tentry.reserved3;
248 printf(" permit password reuse\n");
250 printf(" don't permit password reuse\n");
262 int code, /* error code to handle */
263 struct OKerrors OKlist[], /* list of errors & messages that should be ignored */
264 int *persist) /* set this if we should retry, clear otherwise */
268 for (i=0; OKlist[i].code; i++) {
269 if (OKlist[i].code == code) {
270 printf ("%s\n", OKlist[i].msg);
271 *persist = 0; /* we're done */
276 printf (" : [%s] %s", error_table_name(code), error_message(code));
279 printf (", wait one second\n");
283 case RX_CALL_TIMEOUT:
284 printf (" (retrying)\n");
289 *persist = 0; /* don't retry these errors */
294 struct cmd_syndesc *as,
298 char name[MAXKTCNAMELEN];
299 char instance[MAXKTCNAMELEN];
300 struct ktc_encryptionKey key;
303 struct OKerrors OKlist[2];
306 code = ka_ParseLoginName (as->parms[0].items->data, name, instance, 0);
308 com_err (whoami, code, "parsing user's name '%s'",
309 as->parms[0].items->data);
312 ka_StringToKey (as->parms[1].items->data, cell, &key);
315 code = ubik_Call (KAM_CreateUser, conn, 0, name, instance, key);
317 ka_PrintUserID ("Creating user ", name, instance, " ");
318 code = handle_errors (code, OKlist, &persist);
324 struct cmd_syndesc *as,
328 char name[MAXKTCNAMELEN];
329 char instance[MAXKTCNAMELEN];
332 struct OKerrors OKlist[2];
334 code = ka_ParseLoginName (as->parms[0].items->data, name, instance, 0);
336 com_err (whoami, code, "parsing user's name '%s'",
337 as->parms[0].items->data);
342 code = ubik_Call (KAM_DeleteUser, conn, 0, name, instance);
344 ka_PrintUserID ("Deleting user ", name, instance, " ");
345 code = handle_errors (code, OKlist, &persist);
350 static int read_time_interval (
358 str = strncpy (buf, str, sizeof(buf));
359 s = strchr (str, ':');
360 if (s == 0) sec = atoi (str);
362 *s++ = '\0'; /* separate hours and minutes */
363 sec = atoi(str)*3600 + atoi(s)*60;
375 struct kaentryinfo tentry;
381 int addop; /* 1=add bit; 0=remove bit */
385 str = lcstring (bitspec, str, sizeof(bitspec));
387 if (strncmp(str, "0x", 2) == 0) /* 0x => hex */
388 sscanf (str, "0x%lx", &f);
389 else if (*str == '0') /* assume octal */
390 sscanf (str, "%lo", &f);
391 else /* just assume hex */
392 sscanf (str, "%lx", &f);
401 if (strchr ("+-", *str)) addop = (*str++ == '+');
402 else if (*str == '_') {addop = 0; str++;}
404 code = ubik_Call (KAM_GetEntry, conn, 0,
405 name, inst, KAMAJORVERSION, &tentry);
407 com_err (whoami, code,
408 "could get current flag value for %s.%s", name, inst);
417 if (isupper (c)) c = tolower(c);
418 if (!islower(c)) break;
423 if (strcmp (bit, "admin") == 0) flag = KAFADMIN;
424 else if (strcmp (bit, "noadmin") == 0) flag = KAFADMIN, addop = !addop;
425 else if (strcmp (bit, "notgs") == 0) flag = KAFNOTGS;
426 else if (strcmp (bit, "tgs") == 0) flag = KAFNOTGS, addop = !addop;
427 else if (strcmp (bit, "noseal") == 0) flag = KAFNOSEAL;
428 else if (strcmp (bit, "seal") == 0) flag = KAFNOSEAL, addop = !addop;
429 else if (strcmp (bit, "nocpw") == 0) flag = KAFNOCPW;
430 else if (strcmp (bit, "cpw") == 0) flag = KAFNOCPW, addop = !addop;
431 else if (strcmp (bit, "newassoc") == 0) flag = KAFNEWASSOC;
432 else if (strcmp (bit, "nonewassoc") == 0) flag = KAFNEWASSOC, addop = !addop;
434 printf ("Illegal bit name: %s; choices are: [no]admin, [no]tgs, [no]seal, [no]cpw\n", bit);
438 if (addop) f |= flag;
441 if (*str == 0) break;
442 if (*str == '+') addop = 1; /* get next op */
443 else if ((*str == '-') || (*str == '_')) addop = 0;
445 printf ("Illegal combination operator: %c\n", *str);
451 *flags = (f & KAF_SETTABLE_FLAGS) | KAFNORMAL;
454 #define seriouserror(code) ((code <0) || ((code != UNOSERVERS) && (code != UNOQUORUM) && code != UNOTSYNC))
456 /* return MAXLONG if locked forever */
457 afs_uint32 ka_islocked (
469 code = ubik_CallIter (KAM_LockStatus, conn, UPUBIKONLY, &count,
470 name, instance, &tempwhen, /*spares*/0,0,0,0);
472 if (seriouserror(code))
473 com_err (whoami, code, "");
475 else if (tempwhen) { /* user is locked */
476 if (!*when || tempwhen < *when) {
481 else /* ! tempwhen ==> user is not locked */
484 } while (code != UNOSERVERS);
490 struct cmd_syndesc *as,
493 afs_int32 code, rcode=0;
496 char name[MAXKTCNAMELEN];
497 char instance[MAXKTCNAMELEN];
499 code = ka_ParseLoginName (as->parms[0].items->data, name, instance, 0);
501 com_err (whoami, code, "parsing user's name '%s'", as->parms[0].items->data);
507 code = ubik_CallIter (KAM_Unlock, conn, 0, &count, name, instance,
509 if (code && (code != UNOSERVERS)) {
511 if (conn && conn->conns[count-1] && conn->conns[count-1]->peer) {
512 server = conn->conns[count-1]->peer->host;
514 com_err (whoami, code,
515 "so %s.%s may still be locked (on server %d.%d.%d.%d)",
516 name, instance, ((server>>24)&0xFF), ((server>>16)&0xFF),
517 ((server>>8)&0xFF), (server&0xFF));
523 } while (code != UNOSERVERS);
529 struct cmd_syndesc *as,
533 char name[MAXKTCNAMELEN];
534 char instance[MAXKTCNAMELEN];
537 afs_int32 lifetime = 0;
538 afs_int32 maxAssociates = -1;
539 afs_int32 pwexpiry = 0;
540 afs_int32 was_spare = 0;
541 char misc_auth_bytes[4];
544 code = ka_ParseLoginName (as->parms[0].items->data, name, instance, 0);
546 com_err (whoami, code, "parsing user's name '%s'",
547 as->parms[0].items->data);
551 if (as->parms[1].items) {
552 code = parse_flags (name, instance, as->parms[1].items->data, &flags);
554 printf ("Illegal flag specification: %s, should be of the form <'='|'+'|'-'|'_'>bitname{<'+'|'-'>bitname}*\n", as->parms[1].items->data);
558 if (as->parms[2].items) {
560 char *s = strncpy (buf, as->parms[2].items->data, sizeof(buf));
561 code = ktime_DateToInt32 (s, &expiration);
563 printf ("Illegal time format %s: %s\n",
564 as->parms[2].items->data, ktime_GetDateUsage());
567 if (expiration == 0) {
568 fprintf (stderr, "Expiration time must be after (about) 1970.\n");
571 if (expiration < time(0)) {
572 fprintf (stderr, "Warning: expiration being set into the past, account will be disabled.\n");
578 if (as->parms[3].items) {
579 code = read_time_interval (as->parms[3].items->data, &lifetime);
580 if (code) return KABADCMD;
583 /* no point in doing this any sooner than necessary */
584 for (i=0;i<4;misc_auth_bytes[i++] = 0);
586 if (as->parms[4].items) {
587 if (isint(as->parms[4].items->data))
588 pwexpiry = atoi (as->parms[4].items->data);
590 fprintf(stderr,"Password lifetime specified must be a non-negative decimal integer.\n");
593 if (pwexpiry <0 || pwexpiry >254) {
594 fprintf(stderr,"Password lifetime range must be [0..254] days.\n");
595 fprintf(stderr,"Zero represents an unlimited lifetime.\n");
599 misc_auth_bytes[0] = pwexpiry+1;
603 if (as->parms[5].items) {
605 reuse = (as->parms[5].items->data);
607 if (!strcmp(reuse, "yes")) {
608 misc_auth_bytes[1] = KA_REUSEPW;
610 else if (strcmp(reuse, "no")) {
611 fprintf(stderr,"must specify \"yes\" or \"no\": \"yes\" assumed\n");
612 misc_auth_bytes[1] = KA_REUSEPW;
615 misc_auth_bytes[1] = KA_NOREUSEPW;
619 if (as->parms[6].items) {
623 if (isint(as->parms[6].items->data) &&
624 ((nfailures = atoi(as->parms[6].items->data)) < 255)) {
625 misc_auth_bytes[2] = nfailures+1;
628 fprintf(stderr,"Failure limit must be in [0..254].\n");
629 fprintf(stderr,"Zero represents unlimited login attempts.\n");
634 if (as->parms[7].items) {
635 int locktime, hrs, mins;
639 s = as->parms[7].items->data;
641 sscanf(s, "%d:%d", &hrs, &mins);
643 sscanf(s, "%d", &mins);
645 locktime = hrs*60 + mins;
646 if (hrs < 0 || hrs > 36 || mins < 0) {
647 fprintf(stderr,"Lockout times must be either minutes or hh:mm.\n");
648 fprintf(stderr,"Lockout times must be less than 36 hours.\n");
651 else if (locktime > 36*60 ) {
652 fprintf(stderr,"Lockout times must be either minutes or hh:mm.\n");
653 fprintf(stderr,"Lockout times must be less than 36 hours.\n");
654 fprintf(stderr,"Continuing with lock time of exactly 36 hours...\n");
657 locktime = (locktime * 60 + 511) >> 9; /* ceil(l*60/512) */
658 misc_auth_bytes[3] = locktime +1; /* will be 1 if user said 0 */
662 if (as->parms[8].items) {
663 maxAssociates = atoi (as->parms[6].items->data);
664 if (maxAssociates < 0) {
665 printf ("Illegal maximum number of associates\n");
670 was_spare = pack_long(misc_auth_bytes);
672 if (was_spare || flags || expiration || lifetime || (maxAssociates >= 0))
674 (KAM_SetFields, conn, 0,
675 name, instance, flags, expiration, lifetime, maxAssociates,
676 was_spare, /* spare */ 0);
678 printf ("Must specify one of the optional parameters\n");
681 if (code) com_err (whoami, code,
682 "calling KAM_SetFields for %s.%s", name, instance);
687 struct cmd_syndesc *as,
691 char realm[MAXKTCREALMLEN];
692 struct ktc_encryptionKey key;
694 if (as->parms[1].items) {
695 code = ka_ExpandCell (as->parms[1].items->data, realm, 0/*local*/);
697 com_err (whoami, code,
698 "expanding %s as cell name, attempting to continue",
699 as->parms[1].items->data);
701 ucstring (realm, realm, sizeof(realm));
704 if (code = DefaultCell()) return code;
705 ucstring (realm, cell, sizeof(realm));
707 ka_StringToKey (as->parms[0].items->data, realm, &key);
709 printf ("Converting %s in realm '%s' yields key='",
710 as->parms[0].items->data, realm);
711 ka_PrintBytes ((char *)&key, sizeof(key));
714 des_string_to_key (as->parms[0].items->data, &key);
716 printf ("Converting %s with the DES string to key yields key='",
717 as->parms[0].items->data);
718 ka_PrintBytes (&key, sizeof(key));
725 struct cmd_syndesc *as,
729 char name[MAXKTCNAMELEN];
730 char instance[MAXKTCNAMELEN];
731 char realm[MAXKTCREALMLEN];
732 struct ktc_encryptionKey key;
735 code = ka_ParseLoginName (as->parms[0].items->data, name, instance, realm);
737 com_err (whoami, code, "parsing user's name '%s'",
738 as->parms[0].items->data);
742 if (strlen(realm) == 0)
743 ucstring (realm, cell, sizeof(realm));
745 if (as->parms[1].items && as->parms[2].items) {
746 printf ("Can't specify both a password and a key\n");
749 else if (as->parms[1].items) {
750 (void) init_child(myName);
751 (void) give_to_child(passwd); /* old password */
752 code = password_bad(as->parms[1].items->data);
753 (void) terminate_child();
756 ka_StringToKey (as->parms[1].items->data, realm, &key);
758 else if (as->parms[2].items) {
759 if (ka_ReadBytes (as->parms[2].items->data, (char *)&key, sizeof(key))
761 printf ("Key must be 8 bytes: '%s' was too long\n",
762 as->parms[2].items->data);
767 printf ("Must specify new password or key\n");
772 if (as->parms[3].items)
773 sscanf (as->parms[3].items->data, "%d", &kvno);
775 #ifdef AFS_S390_LINUX20_ENV
776 code = ubik_Call (KAM_SetPassword, conn, 0, name, instance, kvno, 0, key);
778 code = ubik_Call (KAM_SetPassword, conn, 0, name, instance, kvno, key);
780 if (code) com_err (whoami, code,
781 "so can't set password for %s.%s", name, instance);
785 #define PrintPrincipal(p,n,l) \
786 PrintName((p)->name, (p)->instance, (p)->cell, l, n)
788 static afs_int32 PrintName (
796 int left; /* if ConvertBytes stops early */
799 if (name == 0) name = "";
800 if (inst == 0) inst = "";
801 if (acell == 0) acell = "";
802 left = ka_ConvertBytes(buf, buflen, name, strlen(name));
806 com_err (whoami, code,
807 "PrintName: principal name was '%s'.'%s'@'%s'",
814 if (nlen + len + 1 >= buflen) goto bad_name;
816 left = ka_ConvertBytes(buf+nlen, buflen-nlen, inst, len);
817 if (left) goto bad_name;
823 char *lcell = ka_LocalCell();
824 if (lcell == 0) lcell = "";
825 if (strcmp (acell, lcell) != 0) {
826 /* only append cell if not the local cell */
827 if (nlen + len + 1 >= buflen) goto bad_name;
829 left = ka_ConvertBytes(buf+nlen, buflen-nlen, acell, len);
830 if (left) goto bad_name;
837 #define PrintedPrincipal(p) PrintedName ((p)->name, (p)->instance, (p)->cell)
839 /* PrintedName - returned a pointer to a static string in which the formated
840 * name has been stored. */
842 static char *PrintedName (
847 static char printedName[128];
849 code = PrintName (name, inst, cell, sizeof(printedName), printedName);
851 if (name == 0) name = "";
852 strncpy (printedName, name, sizeof(printedName));
853 printedName[sizeof(printedName)-8] = 0;
854 strcat (printedName, "<error>");
859 static afs_int32 ListTicket (
860 struct ktc_principal *server,
864 struct ktc_token token; /* the token we're printing */
865 struct ktc_principal client;
866 char UserName[sizeof(struct ktc_principal)];
867 char ServerName[sizeof(struct ktc_principal)];
868 afs_int32 now = time(0);
869 char bob[KA_TIMESTR_LEN];
871 /* get the ticket info itself */
872 code = ktc_GetToken (server, &token, sizeof(token), &client);
874 com_err (whoami, code, "failed to get token info for server %s",
875 PrintedPrincipal (server));
878 code = PrintPrincipal (&client, UserName, sizeof(UserName));
879 if (code) return code;
880 /* spaces are printed as "\040" */
881 if (UserName[0] == 0)
883 else if (strncmp(UserName, "AFS\\040ID\\040", 13) == 0) {
884 printf("User's (AFS ID %s) tokens", UserName+13);
886 else if (strncmp(UserName, "Unix\\040UID\\040", 15) == 0) {
890 printf("User %s's tokens", UserName);
892 code = PrintPrincipal (server, ServerName, sizeof(ServerName));
893 if (code) return code;
894 printf(" for %s ", ServerName);
896 if (token.startTime > now) {
897 ka_timestr(token.startTime,bob,KA_TIMESTR_LEN);
898 printf("[>> POSTDATED 'till %s <<]",bob);
901 if (token.endTime <= now)
902 printf("[>> Expired <<]\n");
904 ka_timestr(token.endTime,bob,KA_TIMESTR_LEN);
905 printf("[Expires %s]\n", bob);
908 printf ("SessionKey: ");
909 ka_PrintBytes ((char *)&token.sessionKey, sizeof(token.sessionKey));
910 printf ("\nTicket (kvno = %d, len = %d): ", token.kvno,
912 ka_PrintBytes ((char *)token.ticket, token.ticketLen);
919 struct cmd_syndesc *as,
923 struct ktc_principal server;
924 struct ktc_token token;
925 afs_int32 life = KA_SIXHOURS;
927 if (as->parms[1].items) {
928 code = read_time_interval (as->parms[1].items->data, &life);
929 if (code) return KABADCMD;
931 code = ka_ParseLoginName (as->parms[0].items->data,
932 server.name, server.instance, server.cell);
934 com_err (whoami, code, "parsing user's name '%s'",
935 as->parms[0].items->data);
938 if (server.cell[0] == 0) {
939 if (code = DefaultCell()) return code;
940 strcpy (server.cell, cell);
942 code = ka_ExpandCell (server.cell, server.cell, 0/*local*/);
944 com_err (whoami, code, "Can't expand cell name");
949 token.ticketLen = 0; /* in case there are no tokens */
950 code = ka_GetServerToken (server.name, server.instance, server.cell,
951 life, &token, /*new*/1, /*dosetpag*/0);
952 if (code) com_err (whoami, code,
953 "getting ticket for %s", PrintedPrincipal (&server));
955 code = ListTicket (&server, /*verbose*/1);
961 struct cmd_syndesc *as,
965 char name[MAXKTCNAMELEN];
966 struct ktc_encryptionKey key;
967 static struct ubik_client *lpbkConn = 0;
969 /* no instance allowed */
970 code = ka_ParseLoginName (as->parms[0].items->data, name, 0, 0);
973 com_err (whoami, code,
974 "getting %s's password via loopback connection to GetPassword", name);
975 /* if we got a timeout, print a clarification, too */
977 fprintf(stderr, "%s: please note that this command must be run locally on a database server machine.\n", whoami);
982 struct rx_connection *conns[2];
983 struct rx_securityClass *sc;
984 int si; /* security class index */
987 if (code) goto abort;
988 sc = (struct rx_securityClass *) rxnull_NewClientSecurityObject();
989 si = RX_SCINDEX_NULL;
990 conns[0] = rx_NewConnection (htonl(INADDR_LOOPBACK), htons(AFSCONF_KAUTHPORT),
991 KA_MAINTENANCE_SERVICE, sc, si);
993 code = ubik_ClientInit(conns, &lpbkConn);
994 if (code) goto abort;
996 code = ubik_Call (KAM_GetPassword, lpbkConn, 0, name, &key);
997 /* Lets close down the ubik_Client connection now */
998 ubik_ClientDestroy(lpbkConn);
999 if (code) goto abort;
1001 ka_PrintBytes ((char *)&key, sizeof(key));
1007 struct cmd_syndesc *as,
1011 struct ktc_encryptionKey key;
1013 code = ubik_Call (KAM_GetRandomKey, conn, 0, &key);
1014 if (code) com_err(whoami, code, "so can't get random key");
1018 ka_PrintBytes ((char *)&key, sizeof(key));
1020 for (i=0; i<sizeof(key); i++) {
1021 printf ("%0.2x", ((char *)&key)[i] & 0xff);
1022 if (i==3) printf (" ");
1023 else if (i!=7) printf (".");
1031 struct cmd_syndesc *as,
1038 char bob[KA_TIMESTR_LEN];
1040 code = ubik_Call (KAM_GetStats, conn, 0,
1041 KAMAJORVERSION, &admins, &statics, &dynamics);
1043 printf ("call to GetStats failed: %s\n", ka_ErrorString(code));
1046 if (statics.minor_version != KAMINORVERSION)
1047 printf ("Minor version number mismatch: got %d, expected %d\n",
1048 statics.minor_version, KAMINORVERSION);
1049 printf ("%d allocs, %d frees, %d password changes\n",
1050 statics.allocs, statics.frees, statics.cpws);
1051 printf ("Hash table utilization = %f%%\n",
1052 (double)dynamics.hashTableUtilization / 100.0);
1053 ka_timestr(dynamics.start_time,bob,KA_TIMESTR_LEN);
1054 printf ("From host %lx started at %s:\n", dynamics.host, bob);
1056 #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)
1057 print_stat (Authenticate);
1058 print_stat (ChangePassword);
1059 print_stat (GetTicket);
1060 print_stat (CreateUser);
1061 print_stat (SetPassword);
1062 print_stat (SetFields);
1063 print_stat (DeleteUser);
1064 print_stat (GetEntry);
1065 print_stat (ListEntry);
1066 print_stat (GetStats);
1067 print_stat (GetPassword);
1068 print_stat (GetRandomKey);
1070 print_stat (UAuthenticate);
1071 print_stat (UGetTicket);
1073 #if (KAMAJORVERSION>5)
1075 printf ("%d string checks\n", dynamics.string_checks);
1077 printf ("Used %.3f seconds of CPU time.\n", dynamics.string_checks/1000.0);
1079 printf ("%d admin accounts\n", admins);
1084 struct cmd_syndesc *as,
1088 struct ka_debugInfo info;
1092 char bob[KA_TIMESTR_LEN];
1095 if (as->parms[0].items) {
1096 struct ubik_client *iConn;
1097 code = ka_SingleServerConn (cell, as->parms[0].items->data, KA_MAINTENANCE_SERVICE, 0, &iConn);
1099 struct afsconf_cell cellinfo;
1101 com_err (whoami, code, "couldn't find host %s in cell %s",
1102 as->parms[0].items->data, cell);
1103 code = ka_GetServers (cell, &cellinfo);
1104 if (code) com_err (whoami, code, "getting servers in cell %s", cell);
1106 printf ("Servers in cell %s, are:\n", cell);
1107 for (i=0; i<cellinfo.numServers; i++)
1108 printf (" %s\n", cellinfo.hostName[i]);
1112 code = ubik_Call (KAM_Debug, iConn, 0, KAMAJORVERSION, 0, &info);
1113 ubik_ClientDestroy (iConn);
1115 else code = ubik_Call (KAM_Debug, conn, 0, KAMAJORVERSION, 0, &info);
1118 com_err (whoami, code, "call to Debug failed");
1123 if (info.minorVersion != KAMINORVERSION)
1124 printf ("Minor version number mismatch: got %d, expected %d\n",
1125 info.minorVersion, KAMINORVERSION);
1128 #if (KAMAJORVERSION>5)
1134 if (timeOffset < 0) timeOffset = -timeOffset;
1135 if (timeOffset > 60) {
1136 printf ("WARNING: Large server client clock skew: %d seconds. Call itself took %d seconds.\n", timeOffset, now-start);
1138 ka_timestr(info.startTime,bob,KA_TIMESTR_LEN);
1139 printf ("From host %lx started %sat %s:\n",
1140 info.host, (info.noAuth ? "w/o authorization " : ""),
1142 ka_timestr (info.lastTrans,bob,KA_TIMESTR_LEN);
1143 printf ("Last trans was %s at %s\n", info.lastOperation, bob);
1144 ka_timestr (info.dbHeaderRead,bob,KA_TIMESTR_LEN);
1145 printf ("Header last read %s.\n", bob);
1146 printf ("db version=%d, keyVersion=%d, key cache version=%d\n",
1147 info.dbVersion, info.dbSpecialKeysVersion, info.kcVersion);
1148 printf ("db ptrs: free %d, eof %d, kvno %d.\n",
1149 info.dbFreePtr, info.dbEofPtr, info.dbKvnoPtr);
1150 ka_timestr (info.nextAutoCPW,bob,KA_TIMESTR_LEN);
1151 printf ("Next autoCPW at %s or in %d updates.\n",
1152 bob, info.updatesRemaining);
1153 if (info.cheader_lock || info.keycache_lock)
1154 printf ("locks: cheader %08lx, keycache %08lx\n",
1155 info.cheader_lock, info.keycache_lock);
1156 printf ("Last authentication for %s, last admin user was %s\n",
1157 info.lastAuth, info.lastAdmin);
1158 printf ("Last TGS op was a %s ticket was for %s\n",
1159 info.lastTGSServer, info.lastTGS);
1160 printf ("Last UDP TGS was a %s ticket for %s. UDP Authenticate for %s\n",
1161 info.lastUTGSServer, info.lastUTGS, info.lastUAuth);
1162 printf ("key cache size %d, used %d.\n",
1163 info.kcSize, info.kcUsed);
1164 if (info.kcUsed > KADEBUGKCINFOSIZE) {
1165 printf("insufficient room to return all key cache entries!\n");
1166 info.kcUsed = KADEBUGKCINFOSIZE;
1168 for (i=0; i<info.kcUsed; i++)
1169 ka_timestr(info.kcInfo[i].used,bob,KA_TIMESTR_LEN);
1170 printf ("%32s %c %2x(%2x) used %s\n",
1171 info.kcInfo[i].principal, (info.kcInfo[i].primary?'*':' '),
1172 info.kcInfo[i].kvno, info.kcInfo[i].keycksum,
1178 struct cmd_syndesc *as,
1186 struct cmd_syndesc *as,
1194 struct cmd_syndesc *as)
1196 if (!strcmp(as->name,"help")) return;
1198 /* Determine if we need to destory the ubik connection.
1199 * Closing it avoids resends of packets.
1202 ubik_ClientDestroy(conn);
1209 int init = 0, noauth;
1210 char name[MAXKTCNAMELEN];
1211 char instance[MAXKTCNAMELEN];
1212 char newCell[MAXKTCREALMLEN];
1213 afs_int32 serverList[MAXSERVERS];
1216 struct cmd_syndesc *as,
1223 static int MyBeforeProc(
1224 struct cmd_syndesc *as,
1227 extern struct passwd *getpwuid();
1229 struct ktc_encryptionKey key;
1230 struct ktc_principal auth_server, auth_token, client;
1231 char realm[MAXKTCREALMLEN];
1233 struct ktc_token token, *pToken;
1234 int i, acode, code = 0;
1236 { char *ws = strrchr (as->a0name, '/');
1237 if (ws) ws++; /* skip everything before the "/" */
1238 else ws = as->a0name;
1239 if (strlen(ws) > 0) {
1240 strncpy (whoami, ws, sizeof(whoami));
1241 if (strlen (whoami)+1 >= sizeof(whoami)) strcpy (whoami, "kas:");
1242 else strcat (whoami, ":");
1243 } else whoami[0] = 0;
1244 /* append sub-command name */
1245 strncat (whoami, as->name, sizeof(whoami) - strlen(whoami) -1);
1248 if (as->parms[12].name == 0) return 0;
1250 assert (as->parms[13].name && as->parms[14].name &&
1251 as->parms[15].name && as->parms[16].name);
1253 /* MyAfterProc() destroys the conn, but just to be sure */
1255 code = ubik_ClientDestroy (conn);
1259 if (!init || as->parms[12].items || as->parms[13].items ||
1260 as->parms[14].items || as->parms[15].items ||
1261 as->parms[16].items) {
1262 strcpy (instance, "");
1263 strcpy (newCell, "");
1265 if (as->parms[12].items) { /* -admin_username */
1266 code = ka_ParseLoginName (as->parms[12].items->data, name, instance, newCell);
1268 com_err (whoami, code, "parsing user's name '%s'", as->parms[12].items->data);
1273 DWORD len = MAXKTCNAMELEN;
1274 if (!GetUserName((LPTSTR)name, &len)) {
1275 printf("Can't get user name \n");
1279 /* No explicit name provided: use Unix uid. */
1280 pw = getpwuid(getuid());
1282 printf ("Can't figure out your name from your user id.\n");
1285 strncpy (name, pw->pw_name, sizeof(name));
1289 if (as->parms[14].items) { /* -cell */
1290 if (strlen(newCell) > 0) {
1291 printf ("Duplicate cell specification not allowed\n");
1293 strncpy (newCell, as->parms[14].items->data, sizeof(newCell));
1296 code = ka_ExpandCell (newCell, newCell, 0/*local*/);
1298 com_err (whoami, code, "Can't expand cell name");
1301 strcpy (cell, newCell);
1303 if (as->parms[15].items) { /* -servers */
1304 struct cmd_item *ip;
1305 char *ap[MAXSERVERS+2];
1309 for (ip = as->parms[15].items, i=2; ip; ip=ip->next, i++)
1311 code = ubik_ParseClientList(i, ap, serverList);
1313 com_err (whoami, code, "could not parse server list");
1316 ka_ExplicitCell (cell, serverList);
1319 noauth = (as->parms[16].items ? 1 : 0); /* -noauth */
1324 token.ticketLen = 0; /* in case there are no tokens */
1325 if (!noauth) { /* Will prompt for a password */
1326 /* first see if there's already an admin ticket */
1327 code = ka_GetAdminToken (0, 0, cell, 0, KA_SIXHOURS, &token, 0/* !new */);
1328 if (code) { /* if not then get key and try again */
1329 if (as->parms[13].items) { /* if password specified */
1330 strncpy (passwd, as->parms[13].items->data, sizeof(passwd));
1331 bzero (as->parms[13].items->data, strlen (as->parms[13].items->data));
1333 char msg[MAXKTCNAMELEN+50];
1334 if (as->parms[12].items) sprintf (msg, "Administrator's (%s) Password: ", name);
1335 else sprintf (msg, "Password for %s: ", name);
1336 code = read_pw_string (passwd, sizeof(passwd), msg, 0);
1337 if (code) code = KAREADPW;
1338 else if (strlen(passwd) == 0) code = KANULLPASSWORD;
1340 com_err (whoami, code, "reading password");
1344 ka_StringToKey (passwd, cell, &key);
1345 code = ka_GetAdminToken (name, instance, cell, &key, KA_SIXHOURS,
1346 &token, 0/* !new */);
1347 if (code == KABADREQUEST) {
1348 des_string_to_key (passwd, &key);
1349 code = ka_GetAdminToken (name, instance, cell, &key, KA_SIXHOURS,
1350 &token, 0/* !new */);
1352 if ((code == KABADREQUEST) && (strlen(passwd) > 8)) {
1353 /* try with only the first 8 characters incase they set
1354 * their password with an old style passwd program. */
1356 ka_StringToKey (passwd, cell, &key);
1357 code = ka_GetAdminToken (name, instance, cell, &key,
1358 KA_SIXHOURS, &token, 0/* !new */);
1360 fprintf (stderr, "Warning: you have typed a password longer than 8 characters, but only the\n");
1361 fprintf (stderr, "first 8 characters were actually significant. If you change your password\n");
1362 fprintf (stderr, "again this warning message will go away.\n");
1369 reason = "password was incorrect";
1372 reason = "Authentication Server was unavailable";
1375 reason = (char *)error_message (code);
1377 fprintf (stderr, "%s: Auth. as %s to AuthServer failed: %s\nProceeding w/o authentication\n",
1378 whoami, PrintedName(name,instance,cell), reason);
1380 /* get an Authentication token while were at it. */
1381 if (ka_CellToRealm(cell, realm, 0) != 0) realm[0] = '\0';
1382 strcpy(auth_server.name, KA_TGS_NAME);
1383 strcpy(auth_server.instance, realm);
1384 strcpy(auth_server.cell, cell);
1385 if (ktc_GetToken(&auth_server, &auth_token, sizeof(struct ktc_token), &client) != 0) {
1386 acode = ka_GetAuthToken (name, instance, cell, &key,
1387 MAXKTCTICKETLIFETIME,
1388 (afs_int32 *)0 /*Don't need pwd expiration info here*/);
1389 if (acode && (acode != code)) /* codes are usually the same */
1390 com_err (whoami, code,
1391 "getting Authentication token for %s",
1392 PrintedName (name, instance, cell));
1394 bzero (&key, sizeof(key));
1398 pToken = ((token.ticketLen == 0) ? 0 : &token);
1399 code = ka_AuthServerConn (cell, KA_MAINTENANCE_SERVICE, pToken, &conn);
1400 if (code && pToken) {
1401 com_err (whoami, code,
1402 "connecting to AuthServer: now trying w/o authentication");
1403 code = ka_AuthServerConn (cell, KA_MAINTENANCE_SERVICE, 0, &conn);
1404 if (code) com_err (whoami, code, "making unauthenticated connection to AuthServer");
1407 com_err (whoami, code, "Couldn't establish connection to Authentication Server");
1411 /* now default unspecified password by prompting from terminal */
1412 if (as->nParms >= 12) for (i=0; i<12; i++)
1413 if (as->parms[i].name && (as->parms[i].items == 0)) {
1414 char *p = as->parms[i].name; /* parameter name */
1415 int l = strlen (p); /* length of name */
1416 /* does parameter end in "password" */
1417 if (strcmp (p+(l-8), "password") == 0) {
1419 char password[BUFSIZ];
1420 struct cmd_item *ip;
1424 code = read_pw_string (password, sizeof(password), msg, 1);
1425 if (code) code = KAREADPW;
1426 else if (strlen(password) == 0) code = KANULLPASSWORD;
1428 com_err (whoami, code, "prompting for %s", p+1);
1431 ip = (struct cmd_item *)malloc (sizeof(struct cmd_item));
1432 ip->data = (char *)malloc (strlen(password)+1);
1434 strcpy (ip->data, password);
1435 as->parms[i].items = ip;
1438 if (!conn) { /* if all else fails... */
1439 code = NoAuth (0,0); /* get unauthenticated conn */
1440 if (code) return code;
1445 /* These are some helpful command that deal with the cache managers tokens. */
1447 static ForgetTicket (
1448 struct cmd_syndesc *as,
1452 struct ktc_principal server;
1455 if (as->parms[0].items) {
1456 char *name = as->parms[0].items->data;
1457 code = ka_ParseLoginName
1458 (name, server.name, server.instance, server.cell);
1460 com_err (whoami, code, "couldn't interpret name '%s'", name);
1463 if (server.cell[0] == 0) {
1464 if (code = DefaultCell()) return code;
1465 strcpy (server.cell, cell);
1467 code = ka_ExpandCell (server.cell, server.cell, 0/*local*/);
1469 com_err (whoami, code, "Can't expand cell name");
1473 code = ktc_ForgetToken (&server);
1475 com_err (whoami, code, "couldn't remove tokens for %s",
1476 PrintedPrincipal (&server));
1481 if (!as->parms[1].items) {
1482 fprintf (stderr, "Must specify server name or -all\n");
1485 code = ktc_ForgetAllTokens();
1487 com_err (whoami, code, "couldn't delete all tokens");
1492 code = ktc_ForgetAllTokens();
1494 com_err (whoami, code, "couldn't delete all tokens");
1500 static ListTickets (
1501 struct cmd_syndesc *as,
1505 int index, newIndex;
1506 struct ktc_principal server;
1509 if (as->parms[1].items) verbose = 1;
1510 if (as->parms[0].items) {
1511 char *name = as->parms[0].items->data;
1512 code = ka_ParseLoginName
1513 (name, server.name, server.instance, server.cell);
1515 com_err (whoami, code, "couldn't interpret name '%s'", name);
1518 if (server.cell[0] == 0) {
1519 if (code = DefaultCell()) return code;
1520 strcpy (server.cell, cell);
1522 code = ka_ExpandCell (server.cell, server.cell, 0/*local*/);
1524 com_err (whoami, code, "Can't expand cell name");
1528 code = ListTicket (&server, verbose);
1530 else for (index = 0; ; index = newIndex) {
1531 code = ktc_ListTokens(index, &newIndex, &server);
1533 if (code == KTC_NOENT) code = 0; /* end of list */
1536 code = ListTicket(&server, verbose);
1541 static void add_std_args (register struct cmd_syndesc *ts)
1544 /* 12 */ cmd_AddParm (ts, "-admin_username", CMD_SINGLE, CMD_OPTIONAL,
1545 "admin principal to use for authentication");
1546 /* 13 */ cmd_AddParm (ts, "-password_for_admin", CMD_SINGLE, CMD_OPTIONAL,
1548 /* 14 */ cmd_AddParm (ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
1549 /* 15 */ cmd_AddParm (ts, "-servers", CMD_LIST, CMD_OPTIONAL,
1550 "explicit list of authentication servers");
1551 /* 16 */ cmd_AddParm (ts, "-noauth", CMD_FLAG, CMD_OPTIONAL,
1552 "don't authenticate");
1555 afs_int32 ka_AdminInteractive (
1560 register struct cmd_syndesc *ts;
1566 strncpy(myName, *cmd_argv, 509);
1568 cmd_SetBeforeProc(MyBeforeProc, (char *) 0);
1569 cmd_SetAfterProc(MyAfterProc, (char *) 0);
1571 ts = cmd_CreateSyntax ("interactive", Interactive, 0, "enter interactive mode");
1574 ts = cmd_CreateSyntax ("noauthentication", NoAuth, 0, "connect to AuthServer w/o using token");
1576 ts = cmd_CreateSyntax ("list", ListUsers, 0, "list all users in database");
1577 cmd_AddParm (ts, "-long", CMD_FLAG, CMD_OPTIONAL, "show detailed info about each user");
1578 cmd_AddParm (ts, "-showadmin", CMD_FLAG, CMD_OPTIONAL, "show all cell administrators");
1579 cmd_AddParm (ts, "-showkey", CMD_FLAG, CMD_OPTIONAL, "show the user's actual key rather than the checksum");
1581 cmd_CreateAlias (ts, "ls");
1583 ts = cmd_CreateSyntax ("examine", ExamineUser, 0, "examine the entry for a user");
1584 cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of user");
1585 cmd_AddParm (ts, "-showkey", CMD_FLAG, CMD_OPTIONAL, "show the user's actual key rather than the checksum");
1588 ts = cmd_CreateSyntax ("create", CreateUser, 0, "create an entry for a user");
1589 cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of user");
1590 cmd_AddParm (ts, "-initial_password", CMD_SINGLE, CMD_OPTIONAL, "initial password");
1593 ts = cmd_CreateSyntax ("delete", DeleteUser, 0, "delete a user");
1594 cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of user");
1596 cmd_CreateAlias (ts, "rm");
1598 ts = cmd_CreateSyntax ("setfields", SetFields, 0, "set various fields in a user's entry");
1599 cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of user");
1600 cmd_AddParm (ts, "-flags", CMD_SINGLE, CMD_OPTIONAL, "hex flag value or flag name expression");
1601 cmd_AddParm (ts, "-expiration", CMD_SINGLE, CMD_OPTIONAL, "date of account expiration");
1602 cmd_AddParm (ts, "-lifetime", CMD_SINGLE, CMD_OPTIONAL, "maximum ticket lifetime");
1603 cmd_AddParm (ts, "-pwexpires", CMD_SINGLE, CMD_OPTIONAL, "number days password is valid ([0..254])");
1604 cmd_AddParm (ts, "-reuse", CMD_SINGLE, CMD_OPTIONAL, "permit password reuse (yes/no)");
1605 cmd_AddParm (ts, "-attempts", CMD_SINGLE, CMD_OPTIONAL, "maximum successive failed login tries ([0..254])");
1606 cmd_AddParm (ts, "-locktime", CMD_SINGLE, CMD_OPTIONAL, "failure penalty [hh:mm or minutes]");
1608 cmd_AddParm (ts, "-associates", CMD_SINGLE, CMD_OPTIONAL, "maximum associate instances");
1611 cmd_CreateAlias (ts, "sf");
1614 ts = cmd_CreateSyntax ("unlock", Unlock, 0, "Enable authentication ID after max failed attempts exceeded");
1615 cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "authentication ID");
1619 ts = cmd_CreateSyntax ("stringtokey", StringToKey, 0, "convert a string to a key");
1620 cmd_AddParm (ts, "-string", CMD_SINGLE, 0, "password string");
1621 cmd_AddParm (ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
1623 ts = cmd_CreateSyntax ("setpassword", SetPassword, 0, "set a user's password");
1624 cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of user");
1625 cmd_AddParm (ts, "-new_password", CMD_SINGLE, CMD_OPTIONAL, "new password");
1627 cmd_AddParm (ts, "-kvno", CMD_SINGLE, CMD_OPTIONAL, "key version number");
1629 cmd_CreateAlias (ts, "sp");
1630 #ifdef CMD_PARSER_AMBIG_FIX
1631 cmd_CreateAlias (ts, "setpasswd");
1634 /* set a user's key */
1635 ts = cmd_CreateSyntax ("setkey", SetPassword, 0, (char *) CMD_HIDDEN);
1636 cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of user");
1638 cmd_AddParm (ts, "-new_key", CMD_SINGLE, 0, "eight byte new key");
1640 cmd_AddParm (ts, "-kvno", CMD_SINGLE, CMD_OPTIONAL, "key version number");
1643 /* get a user's password */
1644 ts = cmd_CreateSyntax ("getpassword", GetPassword, 0, (char *) CMD_HIDDEN);
1645 cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of user");
1646 /* don't take standard args */
1647 /* add_std_args (ts); */
1648 #ifdef CMD_PARSER_AMBIG_FIX
1649 cmd_CreateAlias (ts, "getpasswd");
1652 /* get a random key */
1653 ts = cmd_CreateSyntax ("getrandomkey", GetRandomKey, 0, (char *) CMD_HIDDEN);
1656 /* get a ticket for a specific server */
1657 ts = cmd_CreateSyntax ("getticket", GetTicket, 0, (char *) CMD_HIDDEN);
1658 cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of server");
1659 cmd_AddParm (ts, "-lifetime", CMD_SINGLE, CMD_OPTIONAL, "ticket lifetime");
1662 ts = cmd_CreateSyntax ("statistics", Statistics, 0, "show statistics for AuthServer");
1665 /* show debugging info from AuthServer */
1666 ts = cmd_CreateSyntax ("debuginfo", DebugInfo, 0, (char *) CMD_HIDDEN);
1667 cmd_AddParm (ts, "-hostname", CMD_SINGLE, CMD_OPTIONAL, "authentication server host name");
1670 ts = cmd_CreateSyntax ("forgetticket", ForgetTicket, 0, "delete user's tickets");
1672 cmd_AddParm (ts, "-name", CMD_SINGLE, (CMD_OPTIONAL | CMD_HIDE), "name of server");
1674 cmd_AddParm (ts, "-all", CMD_FLAG, CMD_OPTIONAL, "delete all tickets");
1676 ts = cmd_CreateSyntax ("listtickets", ListTickets, 0, "show all cache manager tickets");
1677 cmd_AddParm (ts, "-name", CMD_SINGLE, CMD_OPTIONAL, "name of server");
1678 cmd_AddParm (ts, "-long", CMD_FLAG, CMD_OPTIONAL, "show session key and ticket");
1680 ts = cmd_CreateSyntax ("quit", Quit, 0, "exit program");
1683 conn = 0; /* no connection yet */
1684 zero_argc = cmd_argc;
1685 zero_argv = cmd_argv;
1687 strcpy (whoami, "kas");
1689 if (code = cmd_Dispatch(cmd_argc, cmd_argv)) {
1698 s = fgets (line, sizeof(line), stdin);
1699 if (s == NULL) return 0; /* EOF on input */
1700 for (i=strlen(line)-1; i>=0 && isspace(line[i]); i--) line[i]=0;
1701 if (i < 0) continue; /* blank line */
1703 code = cmd_ParseLine (line, argv, &argc, sizeof(argv)/sizeof(argv[0]));
1705 com_err (whoami, code, "parsing line: '%s'", line);
1708 code = cmd_Dispatch (argc, argv);
1709 cmd_FreeArgv (argv);