1 /* Copyright (C) 1990, 1989 Transarc Corporation - All rights reserved */
3 * For copyright information, see IPL which you accepted in order to
4 * download this software.
8 /* These routines provide administrative tools for managing the AuthServer.
9 There is an interactive routine that can be used to examine the database and
10 make small changes as well as subroutines to permit specialized programs to
11 update the database, change the server passwords, etc. */
13 #include <afs/param.h>
15 #include <afs/debug.h>
19 /* These two needed for rxgen output to work */
20 #include <sys/types.h>
31 #include <afs/cellconfig.h>
33 #include <afs/com_err.h>
34 #include <afs/afsutil.h>
41 #define CMD_PARSER_AMBIG_FIX 1 /* allow ambiguous aliases */
43 extern char *ktime_GetDateUsage();
45 #define KA_SIXHOURS (6*3600)
47 static struct ubik_client *conn;
48 static char cell[MAXKTCREALMLEN] = "";
49 static char whoami[32];
50 static char passwd[BUFSIZ];
51 static char myName[510]; /* almost like whoami save with path and without : */
55 static char **zero_argv;
56 afs_uint32 ka_islocked();
58 afs_int32 DefaultCell (void)
62 if (cell[0] != 0) return 0;
63 code = ka_ExpandCell (0, cell, 0/*local*/);
65 com_err (whoami, code, "Can't expand cell name");
70 /* These are the command operation procedures. */
73 struct cmd_syndesc *as,
80 int code, all=0, showa = 0;
81 int showkey = (as->parms[2].items != NULL);
83 if (as->parms[0].items)
85 if (as->parms[1].items) {
89 for (index = 0; 1; index = next_index) {
90 code = ubik_Call (KAM_ListEntry, conn, 0,
91 index, &next_index, &count, &name);
93 com_err (whoami, code, "calling KAM_ListEntry");
96 if (!next_index) break;
98 printf ("next_index (%d) is negative: ", next_index);
99 if (strlen(name.name) == 0) printf ("name is zero length: ");
101 DumpUser(name.name, (char *)0, showa, showkey, name.instance);
103 ka_PrintUserID ("", name.name, name.instance, "\n");
110 struct cmd_syndesc *as,
113 int showkey = (as->parms[1].items != NULL);
114 return DumpUser(as->parms[0].items->data, arock, 0, showkey, (char *)0);
125 char name[MAXKTCNAMELEN];
126 char instance[MAXKTCNAMELEN];
129 char bob[KA_TIMESTR_LEN];
131 struct kaentryinfo tentry;
133 code = ka_ParseLoginName (user, name, instance, 0);
135 com_err (whoami, code, "parsing user's name '%s'", user);
141 code = ubik_Call (KAM_GetEntry, conn, 0, name, inst,
142 KAMAJORVERSION, &tentry);
144 com_err (whoami, code,
145 "getting information for %s.%s", name, inst);
148 if (tentry.minor_version != KAMINORVERSION)
149 printf ("Minor version number mismatch: got %d, expected %d\n",
150 tentry.minor_version, KAMINORVERSION);
151 if (showadmin && !(tentry.flags & KAFADMIN))
153 ka_PrintUserID ("\nUser data for ", name, inst, "");
154 { char *prefix = " (";
155 #define NEWPREFIX "+"
156 if (tentry.flags & KAFADMIN) { printf ("%sADMIN", prefix); prefix = NEWPREFIX; }
157 if (tentry.flags & KAFNOTGS) { printf ("%sNOTGS", prefix); prefix = NEWPREFIX; }
158 if (tentry.flags & KAFNOCPW) { printf ("%sNOCPW", prefix); prefix = NEWPREFIX; }
159 if (tentry.flags & KAFNOSEAL) { printf ("%sNOSEAL", prefix); prefix = NEWPREFIX; }
160 if (tentry.flags & KAFNEWASSOC) { printf ("%sNEWASSOC", prefix); prefix = NEWPREFIX; }
161 if (tentry.flags & KAFASSOCROOT) { printf ("%sASSOCROOT", prefix); prefix = NEWPREFIX; }
162 if (tentry.flags & KAFASSOC) { printf ("%sASSOC", prefix); prefix = NEWPREFIX; }
163 if (tentry.user_expiration <= now) { printf ("%sexpired", prefix); prefix = NEWPREFIX; }
164 if (strcmp (prefix, NEWPREFIX) == 0) printf (")\n");
167 if ((!ka_KeyIsZero((char *) &tentry.key, sizeof(tentry.key))) &&
169 printf (" key (%d):", tentry.key_version);
170 ka_PrintBytes (&tentry.key, sizeof(tentry.key));
173 if (tentry.keyCheckSum == 0)
174 printf (" key version is %d", tentry.key_version);
176 printf (" key (%d) cksum is %u",
177 tentry.key_version, tentry.keyCheckSum);
179 ka_timestr(tentry.change_password_time,bob,KA_TIMESTR_LEN);
180 printf (", last cpw: %s\n", bob);
181 if (!tentry.misc_auth_bytes) {
182 printf (" password will never expire.\n");
183 printf (" An unlimited number of unsuccessful authentications is permitted.\n");
186 unsigned char misc_stuff[4];
189 temp = tentry.misc_auth_bytes;
191 temp = ntohl(tentry.misc_auth_bytes);
193 unpack_long(temp, misc_stuff);
195 if (!misc_stuff[0]) {
196 printf (" password will never expire.\n");
199 ka_timestr((tentry.change_password_time + misc_stuff[0]*24*60*60), bob, KA_TIMESTR_LEN);
200 printf (" password will expire: %s\n", bob);
204 printf (" An unlimited number of unsuccessful authentications is permitted.\n");
206 printf (" %d consecutive unsuccessful authentications are permitted.\n", misc_stuff[2]);
209 printf (" The lock time for this user is not limited.\n");
211 printf (" The lock time for this user is %4.1f minutes.\n",
212 (float) ((unsigned int) misc_stuff[3] << 9) / 60.0);
214 if (!(misc_stuff[1] & KA_ISLOCKED) || !ka_islocked(name, instance, &temp))
215 printf (" User is not locked.\n");
216 else if (temp == (afs_uint32) (-1L))
217 printf (" User is locked forever.\n");
219 ka_timestr(temp,bob,KA_TIMESTR_LEN);
220 printf (" User is locked until %s\n",bob);
225 { char exp[KA_TIMESTR_LEN];
226 ka_timestr (tentry.user_expiration, exp, KA_TIMESTR_LEN);
227 if (tentry.user_expiration < now)
228 printf (" DISABLED entry at %s.", exp);
229 else if (tentry.user_expiration == NEVERDATE)
230 printf (" entry never expires.");
231 else printf (" entry expires on %s.", exp);
233 printf (" Max ticket lifetime %.2f hours.\n",
234 tentry.max_ticket_lifetime / 3600.0);
235 ka_timestr (tentry.modification_time,bob,KA_TIMESTR_LEN);
236 printf (" last mod on %s by ", bob);
237 ka_PrintUserID ("", tentry.modification_user.name,
238 tentry.modification_user.instance, "\n");
239 if ((tentry.reserved3 & 0xffff0000) == 0x12340000) {
240 int short reused = (short)tentry.reserved3;
242 printf(" permit password reuse\n");
244 printf(" don't permit password reuse\n");
256 int code, /* error code to handle */
257 struct OKerrors OKlist[], /* list of errors & messages that should be ignored */
258 int *persist) /* set this if we should retry, clear otherwise */
262 for (i=0; OKlist[i].code; i++) {
263 if (OKlist[i].code == code) {
264 printf ("%s\n", OKlist[i].msg);
265 *persist = 0; /* we're done */
270 printf (" : [%s] %s", error_table_name(code), error_message(code));
273 printf (", wait one second\n");
277 case RX_CALL_TIMEOUT:
278 printf (" (retrying)\n");
283 *persist = 0; /* don't retry these errors */
288 struct cmd_syndesc *as,
292 char name[MAXKTCNAMELEN];
293 char instance[MAXKTCNAMELEN];
294 struct ktc_encryptionKey key;
297 struct OKerrors OKlist[2];
300 code = ka_ParseLoginName (as->parms[0].items->data, name, instance, 0);
302 com_err (whoami, code, "parsing user's name '%s'",
303 as->parms[0].items->data);
306 ka_StringToKey (as->parms[1].items->data, cell, &key);
309 code = ubik_Call (KAM_CreateUser, conn, 0, name, instance, key);
311 ka_PrintUserID ("Creating user ", name, instance, " ");
312 code = handle_errors (code, OKlist, &persist);
318 struct cmd_syndesc *as,
322 char name[MAXKTCNAMELEN];
323 char instance[MAXKTCNAMELEN];
326 struct OKerrors OKlist[2];
328 code = ka_ParseLoginName (as->parms[0].items->data, name, instance, 0);
330 com_err (whoami, code, "parsing user's name '%s'",
331 as->parms[0].items->data);
336 code = ubik_Call (KAM_DeleteUser, conn, 0, name, instance);
338 ka_PrintUserID ("Deleting user ", name, instance, " ");
339 code = handle_errors (code, OKlist, &persist);
344 static int read_time_interval (
352 str = strncpy (buf, str, sizeof(buf));
353 s = strchr (str, ':');
354 if (s == 0) sec = atoi (str);
356 *s++ = '\0'; /* separate hours and minutes */
357 sec = atoi(str)*3600 + atoi(s)*60;
369 struct kaentryinfo tentry;
375 int addop; /* 1=add bit; 0=remove bit */
379 str = lcstring (bitspec, str, sizeof(bitspec));
381 if (strncmp(str, "0x", 2) == 0) /* 0x => hex */
382 sscanf (str, "0x%lx", &f);
383 else if (*str == '0') /* assume octal */
384 sscanf (str, "%lo", &f);
385 else /* just assume hex */
386 sscanf (str, "%lx", &f);
395 if (strchr ("+-", *str)) addop = (*str++ == '+');
396 else if (*str == '_') {addop = 0; str++;}
398 code = ubik_Call (KAM_GetEntry, conn, 0,
399 name, inst, KAMAJORVERSION, &tentry);
401 com_err (whoami, code,
402 "could get current flag value for %s.%s", name, inst);
411 if (isupper (c)) c = tolower(c);
412 if (!islower(c)) break;
417 if (strcmp (bit, "admin") == 0) flag = KAFADMIN;
418 else if (strcmp (bit, "noadmin") == 0) flag = KAFADMIN, addop = !addop;
419 else if (strcmp (bit, "notgs") == 0) flag = KAFNOTGS;
420 else if (strcmp (bit, "tgs") == 0) flag = KAFNOTGS, addop = !addop;
421 else if (strcmp (bit, "noseal") == 0) flag = KAFNOSEAL;
422 else if (strcmp (bit, "seal") == 0) flag = KAFNOSEAL, addop = !addop;
423 else if (strcmp (bit, "nocpw") == 0) flag = KAFNOCPW;
424 else if (strcmp (bit, "cpw") == 0) flag = KAFNOCPW, addop = !addop;
425 else if (strcmp (bit, "newassoc") == 0) flag = KAFNEWASSOC;
426 else if (strcmp (bit, "nonewassoc") == 0) flag = KAFNEWASSOC, addop = !addop;
428 printf ("Illegal bit name: %s; choices are: [no]admin, [no]tgs, [no]seal, [no]cpw\n", bit);
432 if (addop) f |= flag;
435 if (*str == 0) break;
436 if (*str == '+') addop = 1; /* get next op */
437 else if ((*str == '-') || (*str == '_')) addop = 0;
439 printf ("Illegal combination operator: %c\n", *str);
445 *flags = (f & KAF_SETTABLE_FLAGS) | KAFNORMAL;
448 #define seriouserror(code) ((code <0) || ((code != UNOSERVERS) && (code != UNOQUORUM) && code != UNOTSYNC))
450 /* return MAXLONG if locked forever */
451 afs_uint32 ka_islocked (
463 code = ubik_CallIter (KAM_LockStatus, conn, UPUBIKONLY, &count,
464 name, instance, &tempwhen, /*spares*/0,0,0,0);
466 if (seriouserror(code))
467 com_err (whoami, code, "");
469 else if (tempwhen) { /* user is locked */
470 if (!*when || tempwhen < *when) {
475 else /* ! tempwhen ==> user is not locked */
478 } while (code != UNOSERVERS);
484 struct cmd_syndesc *as,
487 afs_int32 code, rcode=0;
490 char name[MAXKTCNAMELEN];
491 char instance[MAXKTCNAMELEN];
493 code = ka_ParseLoginName (as->parms[0].items->data, name, instance, 0);
495 com_err (whoami, code, "parsing user's name '%s'", as->parms[0].items->data);
501 code = ubik_CallIter (KAM_Unlock, conn, 0, &count, name, instance,
503 if (code && (code != UNOSERVERS)) {
505 if (conn && conn->conns[count-1] && conn->conns[count-1]->peer) {
506 server = conn->conns[count-1]->peer->host;
508 com_err (whoami, code,
509 "so %s.%s may still be locked (on server %d.%d.%d.%d)",
510 name, instance, ((server>>24)&0xFF), ((server>>16)&0xFF),
511 ((server>>8)&0xFF), (server&0xFF));
517 } while (code != UNOSERVERS);
523 struct cmd_syndesc *as,
527 char name[MAXKTCNAMELEN];
528 char instance[MAXKTCNAMELEN];
531 afs_int32 lifetime = 0;
532 afs_int32 maxAssociates = -1;
533 afs_int32 pwexpiry = 0;
534 afs_int32 was_spare = 0;
535 char misc_auth_bytes[4];
538 code = ka_ParseLoginName (as->parms[0].items->data, name, instance, 0);
540 com_err (whoami, code, "parsing user's name '%s'",
541 as->parms[0].items->data);
545 if (as->parms[1].items) {
546 code = parse_flags (name, instance, as->parms[1].items->data, &flags);
548 printf ("Illegal flag specification: %s, should be of the form <'='|'+'|'-'|'_'>bitname{<'+'|'-'>bitname}*\n", as->parms[1].items->data);
552 if (as->parms[2].items) {
554 char *s = strncpy (buf, as->parms[2].items->data, sizeof(buf));
555 code = ktime_DateToInt32 (s, &expiration);
557 printf ("Illegal time format %s: %s\n",
558 as->parms[2].items->data, ktime_GetDateUsage());
561 if (expiration == 0) {
562 fprintf (stderr, "Expiration time must be after (about) 1970.\n");
565 if (expiration < time(0)) {
566 fprintf (stderr, "Warning: expiration being set into the past, account will be disabled.\n");
572 if (as->parms[3].items) {
573 code = read_time_interval (as->parms[3].items->data, &lifetime);
574 if (code) return KABADCMD;
577 /* no point in doing this any sooner than necessary */
578 for (i=0;i<4;misc_auth_bytes[i++] = 0);
580 if (as->parms[4].items) {
581 if (isint(as->parms[4].items->data))
582 pwexpiry = atoi (as->parms[4].items->data);
584 fprintf(stderr,"Password lifetime specified must be a non-negative decimal integer.\n");
587 if (pwexpiry <0 || pwexpiry >254) {
588 fprintf(stderr,"Password lifetime range must be [0..254] days.\n");
589 fprintf(stderr,"Zero represents an unlimited lifetime.\n");
593 misc_auth_bytes[0] = pwexpiry+1;
597 if (as->parms[5].items) {
599 reuse = (as->parms[5].items->data);
601 if (!strcmp(reuse, "yes")) {
602 misc_auth_bytes[1] = KA_REUSEPW;
604 else if (strcmp(reuse, "no")) {
605 fprintf(stderr,"must specify \"yes\" or \"no\": \"yes\" assumed\n");
606 misc_auth_bytes[1] = KA_REUSEPW;
609 misc_auth_bytes[1] = KA_NOREUSEPW;
613 if (as->parms[6].items) {
617 if (isint(as->parms[6].items->data) &&
618 ((nfailures = atoi(as->parms[6].items->data)) < 255)) {
619 misc_auth_bytes[2] = nfailures+1;
622 fprintf(stderr,"Failure limit must be in [0..254].\n");
623 fprintf(stderr,"Zero represents unlimited login attempts.\n");
628 if (as->parms[7].items) {
629 int locktime, hrs, mins;
633 s = as->parms[7].items->data;
635 sscanf(s, "%d:%d", &hrs, &mins);
637 sscanf(s, "%d", &mins);
639 locktime = hrs*60 + mins;
640 if (hrs < 0 || hrs > 36 || mins < 0) {
641 fprintf(stderr,"Lockout times must be either minutes or hh:mm.\n");
642 fprintf(stderr,"Lockout times must be less than 36 hours.\n");
645 else if (locktime > 36*60 ) {
646 fprintf(stderr,"Lockout times must be either minutes or hh:mm.\n");
647 fprintf(stderr,"Lockout times must be less than 36 hours.\n");
648 fprintf(stderr,"Continuing with lock time of exactly 36 hours...\n");
651 locktime = (locktime * 60 + 511) >> 9; /* ceil(l*60/512) */
652 misc_auth_bytes[3] = locktime +1; /* will be 1 if user said 0 */
656 if (as->parms[8].items) {
657 maxAssociates = atoi (as->parms[6].items->data);
658 if (maxAssociates < 0) {
659 printf ("Illegal maximum number of associates\n");
664 was_spare = pack_long(misc_auth_bytes);
666 if (was_spare || flags || expiration || lifetime || (maxAssociates >= 0))
668 (KAM_SetFields, conn, 0,
669 name, instance, flags, expiration, lifetime, maxAssociates,
670 was_spare, /* spare */ 0);
672 printf ("Must specify one of the optional parameters\n");
675 if (code) com_err (whoami, code,
676 "calling KAM_SetFields for %s.%s", name, instance);
681 struct cmd_syndesc *as,
685 char realm[MAXKTCREALMLEN];
686 struct ktc_encryptionKey key;
688 if (as->parms[1].items) {
689 code = ka_ExpandCell (as->parms[1].items->data, realm, 0/*local*/);
691 com_err (whoami, code,
692 "expanding %s as cell name, attempting to continue",
693 as->parms[1].items->data);
695 ucstring (realm, realm, sizeof(realm));
698 if (code = DefaultCell()) return code;
699 ucstring (realm, cell, sizeof(realm));
701 ka_StringToKey (as->parms[0].items->data, realm, &key);
703 printf ("Converting %s in realm '%s' yields key='",
704 as->parms[0].items->data, realm);
705 ka_PrintBytes (&key, sizeof(key));
712 struct cmd_syndesc *as,
716 char name[MAXKTCNAMELEN];
717 char instance[MAXKTCNAMELEN];
718 char realm[MAXKTCREALMLEN];
719 struct ktc_encryptionKey key;
722 code = ka_ParseLoginName (as->parms[0].items->data, name, instance, realm);
724 com_err (whoami, code, "parsing user's name '%s'",
725 as->parms[0].items->data);
729 if (strlen(realm) == 0)
730 ucstring (realm, cell, sizeof(realm));
732 if (as->parms[1].items && as->parms[2].items) {
733 printf ("Can't specify both a password and a key\n");
736 else if (as->parms[1].items) {
737 (void) init_child(myName);
738 (void) give_to_child(passwd); /* old password */
739 code = password_bad(as->parms[1].items->data);
740 (void) terminate_child();
743 ka_StringToKey (as->parms[1].items->data, realm, &key);
745 else if (as->parms[2].items) {
746 if (ka_ReadBytes (as->parms[2].items->data, &key, sizeof(key)) != 8) {
747 printf ("Key must be 8 bytes: '%s' was too long\n",
748 as->parms[2].items->data);
753 printf ("Must specify new password or key\n");
758 if (as->parms[3].items)
759 sscanf (as->parms[3].items->data, "%d", &kvno);
761 code = ubik_Call (KAM_SetPassword, conn, 0, name, instance, kvno, key);
762 if (code) com_err (whoami, code,
763 "so can't set password for %s.%s", name, instance);
767 #define PrintPrincipal(p,n,l) \
768 PrintName((p)->name, (p)->instance, (p)->cell, l, n)
770 static afs_int32 PrintName (
778 int left; /* if ConvertBytes stops early */
781 if (name == 0) name = "";
782 if (inst == 0) inst = "";
783 if (acell == 0) acell = "";
784 left = ka_ConvertBytes(buf, buflen, name, strlen(name));
788 com_err (whoami, code,
789 "PrintName: principal name was '%s'.'%s'@'%s'",
796 if (nlen + len + 1 >= buflen) goto bad_name;
798 left = ka_ConvertBytes(buf+nlen, buflen-nlen, inst, len);
799 if (left) goto bad_name;
805 char *lcell = ka_LocalCell();
806 if (lcell == 0) lcell = "";
807 if (strcmp (acell, lcell) != 0) {
808 /* only append cell if not the local cell */
809 if (nlen + len + 1 >= buflen) goto bad_name;
811 left = ka_ConvertBytes(buf+nlen, buflen-nlen, acell, len);
812 if (left) goto bad_name;
819 #define PrintedPrincipal(p) PrintedName ((p)->name, (p)->instance, (p)->cell)
821 /* PrintedName - returned a pointer to a static string in which the formated
822 * name has been stored. */
824 static char *PrintedName (
829 static char printedName[128];
831 code = PrintName (name, inst, cell, sizeof(printedName), printedName);
833 if (name == 0) name = "";
834 strncpy (printedName, name, sizeof(printedName));
835 printedName[sizeof(printedName)-8] = 0;
836 strcat (printedName, "<error>");
841 static afs_int32 ListTicket (
842 struct ktc_principal *server,
846 struct ktc_token token; /* the token we're printing */
847 struct ktc_principal client;
848 char UserName[sizeof(struct ktc_principal)];
849 char ServerName[sizeof(struct ktc_principal)];
850 afs_int32 now = time(0);
851 char bob[KA_TIMESTR_LEN];
853 /* get the ticket info itself */
854 code = ktc_GetToken (server, &token, sizeof(token), &client);
856 com_err (whoami, code, "failed to get token info for server %s",
857 PrintedPrincipal (server));
860 code = PrintPrincipal (&client, UserName, sizeof(UserName));
861 if (code) return code;
862 /* spaces are printed as "\040" */
863 if (UserName[0] == 0)
865 else if (strncmp(UserName, "AFS\\040ID\\040", 13) == 0) {
866 printf("User's (AFS ID %s) tokens", UserName+13);
868 else if (strncmp(UserName, "Unix\\040UID\\040", 15) == 0) {
872 printf("User %s's tokens", UserName);
874 code = PrintPrincipal (server, ServerName, sizeof(ServerName));
875 if (code) return code;
876 printf(" for %s ", ServerName);
878 if (token.startTime > now) {
879 ka_timestr(token.startTime,bob,KA_TIMESTR_LEN);
880 printf("[>> POSTDATED 'till %s <<]",bob);
883 if (token.endTime <= now)
884 printf("[>> Expired <<]\n");
886 ka_timestr(token.endTime,bob,KA_TIMESTR_LEN);
887 printf("[Expires %s]\n", bob);
890 printf ("SessionKey: ");
891 ka_PrintBytes (&token.sessionKey, sizeof(token.sessionKey));
892 printf ("\nTicket (kvno = %d, len = %d): ", token.kvno,
894 ka_PrintBytes (token.ticket, token.ticketLen);
901 struct cmd_syndesc *as,
905 struct ktc_principal server;
906 struct ktc_token token;
907 afs_int32 life = KA_SIXHOURS;
909 if (as->parms[1].items) {
910 code = read_time_interval (as->parms[1].items->data, &life);
911 if (code) return KABADCMD;
913 code = ka_ParseLoginName (as->parms[0].items->data,
914 server.name, server.instance, server.cell);
916 com_err (whoami, code, "parsing user's name '%s'",
917 as->parms[0].items->data);
920 if (server.cell[0] == 0) {
921 if (code = DefaultCell()) return code;
922 strcpy (server.cell, cell);
924 code = ka_ExpandCell (server.cell, server.cell, 0/*local*/);
926 com_err (whoami, code, "Can't expand cell name");
931 token.ticketLen = 0; /* in case there are no tokens */
932 code = ka_GetServerToken (server.name, server.instance, server.cell,
933 life, &token, /*new*/1, /*dosetpag*/0);
934 if (code) com_err (whoami, code,
935 "getting ticket for %s", PrintedPrincipal (&server));
937 code = ListTicket (&server, /*verbose*/1);
943 struct cmd_syndesc *as,
947 char name[MAXKTCNAMELEN];
948 struct ktc_encryptionKey key;
949 static struct ubik_client *lpbkConn = 0;
951 /* no instance allowed */
952 code = ka_ParseLoginName (as->parms[0].items->data, name, 0, 0);
955 com_err (whoami, code,
956 "getting %s's password via loopback connection to GetPassword", name);
957 /* if we got a timeout, print a clarification, too */
959 fprintf(stderr, "%s: please note that this command must be run locally on a database server machine.\n", whoami);
964 struct rx_connection *conns[2];
965 struct rx_securityClass *sc;
966 int si; /* security class index */
969 if (code) goto abort;
970 sc = (struct rx_securityClass *) rxnull_NewClientSecurityObject();
971 si = RX_SCINDEX_NULL;
972 conns[0] = rx_NewConnection (htonl(INADDR_LOOPBACK), htons(AFSCONF_KAUTHPORT),
973 KA_MAINTENANCE_SERVICE, sc, si);
975 code = ubik_ClientInit(conns, &lpbkConn);
976 if (code) goto abort;
978 code = ubik_Call (KAM_GetPassword, lpbkConn, 0, name, &key);
979 /* Lets close down the ubik_Client connection now */
980 ubik_ClientDestroy(lpbkConn);
981 if (code) goto abort;
983 ka_PrintBytes (&key, sizeof(key));
989 struct cmd_syndesc *as,
993 struct ktc_encryptionKey key;
995 code = ubik_Call (KAM_GetRandomKey, conn, 0, &key);
996 if (code) com_err(whoami, code, "so can't get random key");
1000 ka_PrintBytes (&key, sizeof(key));
1002 for (i=0; i<sizeof(key); i++) {
1003 printf ("%0.2x", ((char *)&key)[i] & 0xff);
1004 if (i==3) printf (" ");
1005 else if (i!=7) printf (".");
1013 struct cmd_syndesc *as,
1020 char bob[KA_TIMESTR_LEN];
1022 code = ubik_Call (KAM_GetStats, conn, 0,
1023 KAMAJORVERSION, &admins, &statics, &dynamics);
1025 printf ("call to GetStats failed: %s\n", ka_ErrorString(code));
1028 if (statics.minor_version != KAMINORVERSION)
1029 printf ("Minor version number mismatch: got %d, expected %d\n",
1030 statics.minor_version, KAMINORVERSION);
1031 printf ("%d allocs, %d frees, %d password changes\n",
1032 statics.allocs, statics.frees, statics.cpws);
1033 printf ("Hash table utilization = %f%%\n",
1034 (double)dynamics.hashTableUtilization / 100.0);
1035 ka_timestr(dynamics.start_time,bob,KA_TIMESTR_LEN);
1036 printf ("From host %lx started at %s:\n", dynamics.host, bob);
1038 #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)
1039 print_stat (Authenticate);
1040 print_stat (ChangePassword);
1041 print_stat (GetTicket);
1042 print_stat (CreateUser);
1043 print_stat (SetPassword);
1044 print_stat (SetFields);
1045 print_stat (DeleteUser);
1046 print_stat (GetEntry);
1047 print_stat (ListEntry);
1048 print_stat (GetStats);
1049 print_stat (GetPassword);
1050 print_stat (GetRandomKey);
1052 print_stat (UAuthenticate);
1053 print_stat (UGetTicket);
1055 #if (KAMAJORVERSION>5)
1057 printf ("%d string checks\n", dynamics.string_checks);
1059 printf ("Used %.3f seconds of CPU time.\n", dynamics.string_checks/1000.0);
1061 printf ("%d admin accounts\n", admins);
1066 struct cmd_syndesc *as,
1070 struct ka_debugInfo info;
1074 char bob[KA_TIMESTR_LEN];
1077 if (as->parms[0].items) {
1078 struct ubik_client *iConn;
1079 code = ka_SingleServerConn (cell, as->parms[0].items->data, KA_MAINTENANCE_SERVICE, 0, &iConn);
1081 struct afsconf_cell cellinfo;
1083 com_err (whoami, code, "couldn't find host %s in cell %s",
1084 as->parms[0].items->data, cell);
1085 code = ka_GetServers (cell, &cellinfo);
1086 if (code) com_err (whoami, code, "getting servers in cell %s", cell);
1088 printf ("Servers in cell %s, are:\n", cell);
1089 for (i=0; i<cellinfo.numServers; i++)
1090 printf (" %s\n", cellinfo.hostName[i]);
1094 code = ubik_Call (KAM_Debug, iConn, 0, KAMAJORVERSION, 0, &info);
1095 ubik_ClientDestroy (iConn);
1097 else code = ubik_Call (KAM_Debug, conn, 0, KAMAJORVERSION, 0, &info);
1100 com_err (whoami, code, "call to Debug failed");
1105 if (info.minorVersion != KAMINORVERSION)
1106 printf ("Minor version number mismatch: got %d, expected %d\n",
1107 info.minorVersion, KAMINORVERSION);
1110 #if (KAMAJORVERSION>5)
1116 if (timeOffset < 0) timeOffset = -timeOffset;
1117 if (timeOffset > 60) {
1118 printf ("WARNING: Large server client clock skew: %d seconds. Call itself took %d seconds.\n", timeOffset, now-start);
1120 ka_timestr(info.startTime,bob,KA_TIMESTR_LEN);
1121 printf ("From host %lx started %sat %s:\n",
1122 info.host, (info.noAuth ? "w/o authorization " : ""),
1124 ka_timestr (info.lastTrans,bob,KA_TIMESTR_LEN);
1125 printf ("Last trans was %s at %s\n", info.lastOperation, bob);
1126 ka_timestr (info.dbHeaderRead,bob,KA_TIMESTR_LEN);
1127 printf ("Header last read %s.\n", bob);
1128 printf ("db version=%d, keyVersion=%d, key cache version=%d\n",
1129 info.dbVersion, info.dbSpecialKeysVersion, info.kcVersion);
1130 printf ("db ptrs: free %d, eof %d, kvno %d.\n",
1131 info.dbFreePtr, info.dbEofPtr, info.dbKvnoPtr);
1132 ka_timestr (info.nextAutoCPW,bob,KA_TIMESTR_LEN);
1133 printf ("Next autoCPW at %s or in %d updates.\n",
1134 bob, info.updatesRemaining);
1135 if (info.cheader_lock || info.keycache_lock)
1136 printf ("locks: cheader %08lx, keycache %08lx\n",
1137 info.cheader_lock, info.keycache_lock);
1138 printf ("Last authentication for %s, last admin user was %s\n",
1139 info.lastAuth, info.lastAdmin);
1140 printf ("Last TGS op was a %s ticket was for %s\n",
1141 info.lastTGSServer, info.lastTGS);
1142 printf ("Last UDP TGS was a %s ticket for %s. UDP Authenticate for %s\n",
1143 info.lastUTGSServer, info.lastUTGS, info.lastUAuth);
1144 printf ("key cache size %d, used %d.\n",
1145 info.kcSize, info.kcUsed);
1146 if (info.kcUsed > KADEBUGKCINFOSIZE) {
1147 printf("insufficient room to return all key cache entries!\n");
1148 info.kcUsed = KADEBUGKCINFOSIZE;
1150 for (i=0; i<info.kcUsed; i++)
1151 ka_timestr(info.kcInfo[i].used,bob,KA_TIMESTR_LEN);
1152 printf ("%32s %c %2x(%2x) used %s\n",
1153 info.kcInfo[i].principal, (info.kcInfo[i].primary?'*':' '),
1154 info.kcInfo[i].kvno, info.kcInfo[i].keycksum,
1160 struct cmd_syndesc *as,
1168 struct cmd_syndesc *as,
1176 struct cmd_syndesc *as)
1178 if (!strcmp(as->name,"help")) return;
1180 /* Determine if we need to destory the ubik connection.
1181 * Closing it avoids resends of packets.
1184 ubik_ClientDestroy(conn);
1191 int init = 0, noauth;
1192 char name[MAXKTCNAMELEN];
1193 char instance[MAXKTCNAMELEN];
1194 char newCell[MAXKTCREALMLEN];
1195 afs_int32 serverList[MAXSERVERS];
1198 struct cmd_syndesc *as,
1205 static int MyBeforeProc(
1206 struct cmd_syndesc *as,
1209 extern struct passwd *getpwuid();
1211 struct ktc_encryptionKey key;
1212 struct ktc_principal auth_server, auth_token, client;
1213 char realm[MAXKTCREALMLEN];
1215 struct ktc_token token, *pToken;
1216 int i, acode, code = 0;
1218 { char *ws = strrchr (as->a0name, '/');
1219 if (ws) ws++; /* skip everything before the "/" */
1220 else ws = as->a0name;
1221 if (strlen(ws) > 0) {
1222 strncpy (whoami, ws, sizeof(whoami));
1223 if (strlen (whoami)+1 >= sizeof(whoami)) strcpy (whoami, "kas:");
1224 else strcat (whoami, ":");
1225 } else whoami[0] = 0;
1226 /* append sub-command name */
1227 strncat (whoami, as->name, sizeof(whoami) - strlen(whoami) -1);
1230 if (as->parms[12].name == 0) return 0;
1232 assert (as->parms[13].name && as->parms[14].name &&
1233 as->parms[15].name && as->parms[16].name);
1235 /* MyAfterProc() destroys the conn, but just to be sure */
1237 code = ubik_ClientDestroy (conn);
1241 if (!init || as->parms[12].items || as->parms[13].items ||
1242 as->parms[14].items || as->parms[15].items ||
1243 as->parms[16].items) {
1244 strcpy (instance, "");
1245 strcpy (newCell, "");
1247 if (as->parms[12].items) { /* -admin_username */
1248 code = ka_ParseLoginName (as->parms[12].items->data, name, instance, newCell);
1250 com_err (whoami, code, "parsing user's name '%s'", as->parms[12].items->data);
1255 DWORD len = MAXKTCNAMELEN;
1256 if (!GetUserName((LPTSTR)name, &len)) {
1257 printf("Can't get user name \n");
1261 /* No explicit name provided: use Unix uid. */
1262 pw = getpwuid(getuid());
1264 printf ("Can't figure out your name from your user id.\n");
1267 strncpy (name, pw->pw_name, sizeof(name));
1271 if (as->parms[14].items) { /* -cell */
1272 if (strlen(newCell) > 0) {
1273 printf ("Duplicate cell specification not allowed\n");
1275 strncpy (newCell, as->parms[14].items->data, sizeof(newCell));
1278 code = ka_ExpandCell (newCell, newCell, 0/*local*/);
1280 com_err (whoami, code, "Can't expand cell name");
1283 strcpy (cell, newCell);
1285 if (as->parms[15].items) { /* -servers */
1286 struct cmd_item *ip;
1287 char *ap[MAXSERVERS+2];
1291 for (ip = as->parms[15].items, i=2; ip; ip=ip->next, i++)
1293 code = ubik_ParseClientList(i, ap, serverList);
1295 com_err (whoami, code, "could not parse server list");
1298 ka_ExplicitCell (cell, serverList);
1301 noauth = (as->parms[16].items ? 1 : 0); /* -noauth */
1306 token.ticketLen = 0; /* in case there are no tokens */
1307 if (!noauth) { /* Will prompt for a password */
1308 /* first see if there's already an admin ticket */
1309 code = ka_GetAdminToken (0, 0, cell, 0, KA_SIXHOURS, &token, 0/* !new */);
1310 if (code) { /* if not then get key and try again */
1311 if (as->parms[13].items) { /* if password specified */
1312 strncpy (passwd, as->parms[13].items->data, sizeof(passwd));
1313 bzero (as->parms[13].items->data, strlen (as->parms[13].items->data));
1315 char msg[MAXKTCNAMELEN+50];
1316 if (as->parms[12].items) sprintf (msg, "Administrator's (%s) Password: ", name);
1317 else sprintf (msg, "Password for %s: ", name);
1318 code = read_pw_string (passwd, sizeof(passwd), msg, 0);
1319 if (code) code = KAREADPW;
1320 else if (strlen(passwd) == 0) code = KANULLPASSWORD;
1322 com_err (whoami, code, "reading password");
1326 ka_StringToKey (passwd, cell, &key);
1327 code = ka_GetAdminToken (name, instance, cell, &key, KA_SIXHOURS,
1328 &token, 0/* !new */);
1329 if ((code == KABADREQUEST) && (strlen(passwd) > 8)) {
1330 /* try with only the first 8 characters incase they set
1331 * their password with an old style passwd program. */
1333 ka_StringToKey (passwd, cell, &key);
1334 code = ka_GetAdminToken (name, instance, cell, &key,
1335 KA_SIXHOURS, &token, 0/* !new */);
1337 fprintf (stderr, "Warning: you have typed a password longer than 8 characters, but only the\n");
1338 fprintf (stderr, "first 8 characters were actually significant. If you change your password\n");
1339 fprintf (stderr, "again this warning message will go away.\n");
1346 reason = "password was incorrect";
1349 reason = "Authentication Server was unavailable";
1352 reason = (char *)error_message (code);
1354 fprintf (stderr, "%s: Auth. as %s to AuthServer failed: %s\nProceeding w/o authentication\n",
1355 whoami, PrintedName(name,instance,cell), reason);
1357 /* get an Authentication token while were at it. */
1358 if (ka_CellToRealm(cell, realm, 0) != 0) realm[0] = '\0';
1359 strcpy(auth_server.name, KA_TGS_NAME);
1360 strcpy(auth_server.instance, realm);
1361 strcpy(auth_server.cell, cell);
1362 if (ktc_GetToken(&auth_server, &auth_token, sizeof(struct ktc_token), &client) != 0) {
1363 acode = ka_GetAuthToken (name, instance, cell, &key,
1364 MAXKTCTICKETLIFETIME,
1365 (afs_int32 *)0 /*Don't need pwd expiration info here*/);
1366 if (acode && (acode != code)) /* codes are usually the same */
1367 com_err (whoami, code,
1368 "getting Authentication token for %s",
1369 PrintedName (name, instance, cell));
1371 bzero (&key, sizeof(key));
1375 pToken = ((token.ticketLen == 0) ? 0 : &token);
1376 code = ka_AuthServerConn (cell, KA_MAINTENANCE_SERVICE, pToken, &conn);
1377 if (code && pToken) {
1378 com_err (whoami, code,
1379 "connecting to AuthServer: now trying w/o authentication");
1380 code = ka_AuthServerConn (cell, KA_MAINTENANCE_SERVICE, 0, &conn);
1381 if (code) com_err (whoami, code, "making unauthenticated connection to AuthServer");
1384 com_err (whoami, code, "Couldn't establish connection to Authentication Server");
1388 /* now default unspecified password by prompting from terminal */
1389 if (as->nParms >= 12) for (i=0; i<12; i++)
1390 if (as->parms[i].name && (as->parms[i].items == 0)) {
1391 char *p = as->parms[i].name; /* parameter name */
1392 int l = strlen (p); /* length of name */
1393 /* does parameter end in "password" */
1394 if (strcmp (p+(l-8), "password") == 0) {
1396 char password[BUFSIZ];
1397 struct cmd_item *ip;
1401 code = read_pw_string (password, sizeof(password), msg, 1);
1402 if (code) code = KAREADPW;
1403 else if (strlen(password) == 0) code = KANULLPASSWORD;
1405 com_err (whoami, code, "prompting for %s", p+1);
1408 ip = (struct cmd_item *)malloc (sizeof(struct cmd_item));
1409 ip->data = (char *)malloc (strlen(password)+1);
1411 strcpy (ip->data, password);
1412 as->parms[i].items = ip;
1415 if (!conn) { /* if all else fails... */
1416 code = NoAuth (0,0); /* get unauthenticated conn */
1417 if (code) return code;
1422 /* These are some helpful command that deal with the cache managers tokens. */
1424 static ForgetTicket (
1425 struct cmd_syndesc *as,
1429 struct ktc_principal server;
1432 if (as->parms[0].items) {
1433 char *name = as->parms[0].items->data;
1434 code = ka_ParseLoginName
1435 (name, server.name, server.instance, server.cell);
1437 com_err (whoami, code, "couldn't interpret name '%s'", name);
1440 if (server.cell[0] == 0) {
1441 if (code = DefaultCell()) return code;
1442 strcpy (server.cell, cell);
1444 code = ka_ExpandCell (server.cell, server.cell, 0/*local*/);
1446 com_err (whoami, code, "Can't expand cell name");
1450 code = ktc_ForgetToken (&server);
1452 com_err (whoami, code, "couldn't remove tokens for %s",
1453 PrintedPrincipal (&server));
1458 if (!as->parms[1].items) {
1459 fprintf (stderr, "Must specify server name or -all\n");
1462 code = ktc_ForgetAllTokens();
1464 com_err (whoami, code, "couldn't delete all tokens");
1469 code = ktc_ForgetAllTokens();
1471 com_err (whoami, code, "couldn't delete all tokens");
1477 static ListTickets (
1478 struct cmd_syndesc *as,
1482 int index, newIndex;
1483 struct ktc_principal server;
1486 if (as->parms[1].items) verbose = 1;
1487 if (as->parms[0].items) {
1488 char *name = as->parms[0].items->data;
1489 code = ka_ParseLoginName
1490 (name, server.name, server.instance, server.cell);
1492 com_err (whoami, code, "couldn't interpret name '%s'", name);
1495 if (server.cell[0] == 0) {
1496 if (code = DefaultCell()) return code;
1497 strcpy (server.cell, cell);
1499 code = ka_ExpandCell (server.cell, server.cell, 0/*local*/);
1501 com_err (whoami, code, "Can't expand cell name");
1505 code = ListTicket (&server, verbose);
1507 else for (index = 0; ; index = newIndex) {
1508 code = ktc_ListTokens(index, &newIndex, &server);
1510 if (code == KTC_NOENT) code = 0; /* end of list */
1513 code = ListTicket(&server, verbose);
1518 static void add_std_args (register struct cmd_syndesc *ts)
1521 /* 12 */ cmd_AddParm (ts, "-admin_username", CMD_SINGLE, CMD_OPTIONAL,
1522 "admin principal to use for authentication");
1523 /* 13 */ cmd_AddParm (ts, "-password_for_admin", CMD_SINGLE, CMD_OPTIONAL,
1525 /* 14 */ cmd_AddParm (ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
1526 /* 15 */ cmd_AddParm (ts, "-servers", CMD_LIST, CMD_OPTIONAL,
1527 "explicit list of authentication servers");
1528 /* 16 */ cmd_AddParm (ts, "-noauth", CMD_FLAG, CMD_OPTIONAL,
1529 "don't authenticate");
1532 afs_int32 ka_AdminInteractive (
1537 register struct cmd_syndesc *ts;
1543 strncpy(myName, *cmd_argv, 509);
1545 cmd_SetBeforeProc(MyBeforeProc, (char *) 0);
1546 cmd_SetAfterProc(MyAfterProc, (char *) 0);
1548 ts = cmd_CreateSyntax ("interactive", Interactive, 0, "enter interactive mode");
1551 ts = cmd_CreateSyntax ("noauthentication", NoAuth, 0, "connect to AuthServer w/o using token");
1553 ts = cmd_CreateSyntax ("list", ListUsers, 0, "list all users in database");
1554 cmd_AddParm (ts, "-long", CMD_FLAG, CMD_OPTIONAL, "show detailed info about each user");
1555 cmd_AddParm (ts, "-showadmin", CMD_FLAG, CMD_OPTIONAL, "show all cell administrators");
1556 cmd_AddParm (ts, "-showkey", CMD_FLAG, CMD_OPTIONAL, "show the user's actual key rather than the checksum");
1558 cmd_CreateAlias (ts, "ls");
1560 ts = cmd_CreateSyntax ("examine", ExamineUser, 0, "examine the entry for a user");
1561 cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of user");
1562 cmd_AddParm (ts, "-showkey", CMD_FLAG, CMD_OPTIONAL, "show the user's actual key rather than the checksum");
1565 ts = cmd_CreateSyntax ("create", CreateUser, 0, "create an entry for a user");
1566 cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of user");
1567 cmd_AddParm (ts, "-initial_password", CMD_SINGLE, CMD_OPTIONAL, "initial password");
1570 ts = cmd_CreateSyntax ("delete", DeleteUser, 0, "delete a user");
1571 cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of user");
1573 cmd_CreateAlias (ts, "rm");
1575 ts = cmd_CreateSyntax ("setfields", SetFields, 0, "set various fields in a user's entry");
1576 cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of user");
1577 cmd_AddParm (ts, "-flags", CMD_SINGLE, CMD_OPTIONAL, "hex flag value or flag name expression");
1578 cmd_AddParm (ts, "-expiration", CMD_SINGLE, CMD_OPTIONAL, "date of account expiration");
1579 cmd_AddParm (ts, "-lifetime", CMD_SINGLE, CMD_OPTIONAL, "maximum ticket lifetime");
1580 cmd_AddParm (ts, "-pwexpires", CMD_SINGLE, CMD_OPTIONAL, "number days password is valid ([0..254])");
1581 cmd_AddParm (ts, "-reuse", CMD_SINGLE, CMD_OPTIONAL, "permit password reuse (yes/no)");
1582 cmd_AddParm (ts, "-attempts", CMD_SINGLE, CMD_OPTIONAL, "maximum successive failed login tries ([0..254])");
1583 cmd_AddParm (ts, "-locktime", CMD_SINGLE, CMD_OPTIONAL, "failure penalty [hh:mm or minutes]");
1585 cmd_AddParm (ts, "-associates", CMD_SINGLE, CMD_OPTIONAL, "maximum associate instances");
1588 cmd_CreateAlias (ts, "sf");
1591 ts = cmd_CreateSyntax ("unlock", Unlock, 0, "Enable authentication ID after max failed attempts exceeded");
1592 cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "authentication ID");
1596 ts = cmd_CreateSyntax ("stringtokey", StringToKey, 0, "convert a string to a key");
1597 cmd_AddParm (ts, "-string", CMD_SINGLE, 0, "password string");
1598 cmd_AddParm (ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
1600 ts = cmd_CreateSyntax ("setpassword", SetPassword, 0, "set a user's password");
1601 cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of user");
1602 cmd_AddParm (ts, "-new_password", CMD_SINGLE, CMD_OPTIONAL, "new password");
1604 cmd_AddParm (ts, "-kvno", CMD_SINGLE, CMD_OPTIONAL, "key version number");
1606 cmd_CreateAlias (ts, "sp");
1607 #ifdef CMD_PARSER_AMBIG_FIX
1608 cmd_CreateAlias (ts, "setpasswd");
1611 /* set a user's key */
1612 ts = cmd_CreateSyntax ("setkey", SetPassword, 0, (char *) CMD_HIDDEN);
1613 cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of user");
1615 cmd_AddParm (ts, "-new_key", CMD_SINGLE, 0, "eight byte new key");
1617 cmd_AddParm (ts, "-kvno", CMD_SINGLE, CMD_OPTIONAL, "key version number");
1620 /* get a user's password */
1621 ts = cmd_CreateSyntax ("getpassword", GetPassword, 0, (char *) CMD_HIDDEN);
1622 cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of user");
1623 /* don't take standard args */
1624 /* add_std_args (ts); */
1625 #ifdef CMD_PARSER_AMBIG_FIX
1626 cmd_CreateAlias (ts, "getpasswd");
1629 /* get a random key */
1630 ts = cmd_CreateSyntax ("getrandomkey", GetRandomKey, 0, (char *) CMD_HIDDEN);
1633 /* get a ticket for a specific server */
1634 ts = cmd_CreateSyntax ("getticket", GetTicket, 0, (char *) CMD_HIDDEN);
1635 cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of server");
1636 cmd_AddParm (ts, "-lifetime", CMD_SINGLE, CMD_OPTIONAL, "ticket lifetime");
1639 ts = cmd_CreateSyntax ("statistics", Statistics, 0, "show statistics for AuthServer");
1642 /* show debugging info from AuthServer */
1643 ts = cmd_CreateSyntax ("debuginfo", DebugInfo, 0, (char *) CMD_HIDDEN);
1644 cmd_AddParm (ts, "-hostname", CMD_SINGLE, CMD_OPTIONAL, "authentication server host name");
1647 ts = cmd_CreateSyntax ("forgetticket", ForgetTicket, 0, "delete user's tickets");
1649 cmd_AddParm (ts, "-name", CMD_SINGLE, (CMD_OPTIONAL | CMD_HIDE), "name of server");
1651 cmd_AddParm (ts, "-all", CMD_FLAG, CMD_OPTIONAL, "delete all tickets");
1653 ts = cmd_CreateSyntax ("listtickets", ListTickets, 0, "show all cache manager tickets");
1654 cmd_AddParm (ts, "-name", CMD_SINGLE, CMD_OPTIONAL, "name of server");
1655 cmd_AddParm (ts, "-long", CMD_FLAG, CMD_OPTIONAL, "show session key and ticket");
1657 ts = cmd_CreateSyntax ("quit", Quit, 0, "exit program");
1660 conn = 0; /* no connection yet */
1661 zero_argc = cmd_argc;
1662 zero_argv = cmd_argv;
1664 strcpy (whoami, "kas");
1666 if (code = cmd_Dispatch(cmd_argc, cmd_argv)) {
1675 s = fgets (line, sizeof(line), stdin);
1676 if (s == NULL) return 0; /* EOF on input */
1677 for (i=strlen(line)-1; i>=0 && isspace(line[i]); i--) line[i]=0;
1678 if (i < 0) continue; /* blank line */
1680 code = cmd_ParseLine (line, argv, &argc, sizeof(argv)/sizeof(argv[0]));
1682 com_err (whoami, code, "parsing line: '%s'", line);
1685 code = cmd_Dispatch (argc, argv);
1686 cmd_FreeArgv (argv);