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>
17 #include <afs/debug.h>
21 /* These two needed for rxgen output to work */
22 #include <sys/types.h>
33 #include <afs/cellconfig.h>
35 #include <afs/com_err.h>
36 #include <afs/afsutil.h>
43 #define CMD_PARSER_AMBIG_FIX 1 /* allow ambiguous aliases */
45 extern char *ktime_GetDateUsage();
47 #define KA_SIXHOURS (6*3600)
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 : */
57 static char **zero_argv;
58 afs_uint32 ka_islocked();
60 afs_int32 DefaultCell (void)
64 if (cell[0] != 0) return 0;
65 code = ka_ExpandCell (0, cell, 0/*local*/);
67 com_err (whoami, code, "Can't expand cell name");
72 /* These are the command operation procedures. */
75 struct cmd_syndesc *as,
82 int code, all=0, showa = 0;
83 int showkey = (as->parms[2].items != NULL);
85 if (as->parms[0].items)
87 if (as->parms[1].items) {
91 for (index = 0; 1; index = next_index) {
92 code = ubik_Call (KAM_ListEntry, conn, 0,
93 index, &next_index, &count, &name);
95 com_err (whoami, code, "calling KAM_ListEntry");
98 if (!next_index) break;
100 printf ("next_index (%d) is negative: ", next_index);
101 if (strlen(name.name) == 0) printf ("name is zero length: ");
103 DumpUser(name.name, (char *)0, showa, showkey, name.instance);
105 ka_PrintUserID ("", name.name, name.instance, "\n");
112 struct cmd_syndesc *as,
115 int showkey = (as->parms[1].items != NULL);
116 return DumpUser(as->parms[0].items->data, arock, 0, showkey, (char *)0);
127 char name[MAXKTCNAMELEN];
128 char instance[MAXKTCNAMELEN];
131 char bob[KA_TIMESTR_LEN];
133 struct kaentryinfo tentry;
135 code = ka_ParseLoginName (user, name, instance, 0);
137 com_err (whoami, code, "parsing user's name '%s'", user);
143 code = ubik_Call (KAM_GetEntry, conn, 0, name, inst,
144 KAMAJORVERSION, &tentry);
146 com_err (whoami, code,
147 "getting information for %s.%s", name, inst);
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))
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");
169 if ((!ka_KeyIsZero((char *) &tentry.key, sizeof(tentry.key))) &&
171 printf (" key (%d):", tentry.key_version);
172 ka_PrintBytes (&tentry.key, sizeof(tentry.key));
175 if (tentry.keyCheckSum == 0)
176 printf (" key version is %d", tentry.key_version);
178 printf (" key (%d) cksum is %u",
179 tentry.key_version, tentry.keyCheckSum);
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");
188 unsigned char misc_stuff[4];
191 temp = tentry.misc_auth_bytes;
193 temp = ntohl(tentry.misc_auth_bytes);
195 unpack_long(temp, misc_stuff);
197 if (!misc_stuff[0]) {
198 printf (" password will never expire.\n");
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);
206 printf (" An unlimited number of unsuccessful authentications is permitted.\n");
208 printf (" %d consecutive unsuccessful authentications are permitted.\n", misc_stuff[2]);
211 printf (" The lock time for this user is not limited.\n");
213 printf (" The lock time for this user is %4.1f minutes.\n",
214 (float) ((unsigned int) misc_stuff[3] << 9) / 60.0);
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");
221 ka_timestr(temp,bob,KA_TIMESTR_LEN);
222 printf (" User is locked until %s\n",bob);
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);
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;
244 printf(" permit password reuse\n");
246 printf(" don't permit password reuse\n");
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 */
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 */
272 printf (" : [%s] %s", error_table_name(code), error_message(code));
275 printf (", wait one second\n");
279 case RX_CALL_TIMEOUT:
280 printf (" (retrying)\n");
285 *persist = 0; /* don't retry these errors */
290 struct cmd_syndesc *as,
294 char name[MAXKTCNAMELEN];
295 char instance[MAXKTCNAMELEN];
296 struct ktc_encryptionKey key;
299 struct OKerrors OKlist[2];
302 code = ka_ParseLoginName (as->parms[0].items->data, name, instance, 0);
304 com_err (whoami, code, "parsing user's name '%s'",
305 as->parms[0].items->data);
308 ka_StringToKey (as->parms[1].items->data, cell, &key);
311 code = ubik_Call (KAM_CreateUser, conn, 0, name, instance, key);
313 ka_PrintUserID ("Creating user ", name, instance, " ");
314 code = handle_errors (code, OKlist, &persist);
320 struct cmd_syndesc *as,
324 char name[MAXKTCNAMELEN];
325 char instance[MAXKTCNAMELEN];
328 struct OKerrors OKlist[2];
330 code = ka_ParseLoginName (as->parms[0].items->data, name, instance, 0);
332 com_err (whoami, code, "parsing user's name '%s'",
333 as->parms[0].items->data);
338 code = ubik_Call (KAM_DeleteUser, conn, 0, name, instance);
340 ka_PrintUserID ("Deleting user ", name, instance, " ");
341 code = handle_errors (code, OKlist, &persist);
346 static int read_time_interval (
354 str = strncpy (buf, str, sizeof(buf));
355 s = strchr (str, ':');
356 if (s == 0) sec = atoi (str);
358 *s++ = '\0'; /* separate hours and minutes */
359 sec = atoi(str)*3600 + atoi(s)*60;
371 struct kaentryinfo tentry;
377 int addop; /* 1=add bit; 0=remove bit */
381 str = lcstring (bitspec, str, sizeof(bitspec));
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);
397 if (strchr ("+-", *str)) addop = (*str++ == '+');
398 else if (*str == '_') {addop = 0; str++;}
400 code = ubik_Call (KAM_GetEntry, conn, 0,
401 name, inst, KAMAJORVERSION, &tentry);
403 com_err (whoami, code,
404 "could get current flag value for %s.%s", name, inst);
413 if (isupper (c)) c = tolower(c);
414 if (!islower(c)) break;
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;
430 printf ("Illegal bit name: %s; choices are: [no]admin, [no]tgs, [no]seal, [no]cpw\n", bit);
434 if (addop) f |= flag;
437 if (*str == 0) break;
438 if (*str == '+') addop = 1; /* get next op */
439 else if ((*str == '-') || (*str == '_')) addop = 0;
441 printf ("Illegal combination operator: %c\n", *str);
447 *flags = (f & KAF_SETTABLE_FLAGS) | KAFNORMAL;
450 #define seriouserror(code) ((code <0) || ((code != UNOSERVERS) && (code != UNOQUORUM) && code != UNOTSYNC))
452 /* return MAXLONG if locked forever */
453 afs_uint32 ka_islocked (
465 code = ubik_CallIter (KAM_LockStatus, conn, UPUBIKONLY, &count,
466 name, instance, &tempwhen, /*spares*/0,0,0,0);
468 if (seriouserror(code))
469 com_err (whoami, code, "");
471 else if (tempwhen) { /* user is locked */
472 if (!*when || tempwhen < *when) {
477 else /* ! tempwhen ==> user is not locked */
480 } while (code != UNOSERVERS);
486 struct cmd_syndesc *as,
489 afs_int32 code, rcode=0;
492 char name[MAXKTCNAMELEN];
493 char instance[MAXKTCNAMELEN];
495 code = ka_ParseLoginName (as->parms[0].items->data, name, instance, 0);
497 com_err (whoami, code, "parsing user's name '%s'", as->parms[0].items->data);
503 code = ubik_CallIter (KAM_Unlock, conn, 0, &count, name, instance,
505 if (code && (code != UNOSERVERS)) {
507 if (conn && conn->conns[count-1] && conn->conns[count-1]->peer) {
508 server = conn->conns[count-1]->peer->host;
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));
519 } while (code != UNOSERVERS);
525 struct cmd_syndesc *as,
529 char name[MAXKTCNAMELEN];
530 char instance[MAXKTCNAMELEN];
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];
540 code = ka_ParseLoginName (as->parms[0].items->data, name, instance, 0);
542 com_err (whoami, code, "parsing user's name '%s'",
543 as->parms[0].items->data);
547 if (as->parms[1].items) {
548 code = parse_flags (name, instance, as->parms[1].items->data, &flags);
550 printf ("Illegal flag specification: %s, should be of the form <'='|'+'|'-'|'_'>bitname{<'+'|'-'>bitname}*\n", as->parms[1].items->data);
554 if (as->parms[2].items) {
556 char *s = strncpy (buf, as->parms[2].items->data, sizeof(buf));
557 code = ktime_DateToInt32 (s, &expiration);
559 printf ("Illegal time format %s: %s\n",
560 as->parms[2].items->data, ktime_GetDateUsage());
563 if (expiration == 0) {
564 fprintf (stderr, "Expiration time must be after (about) 1970.\n");
567 if (expiration < time(0)) {
568 fprintf (stderr, "Warning: expiration being set into the past, account will be disabled.\n");
574 if (as->parms[3].items) {
575 code = read_time_interval (as->parms[3].items->data, &lifetime);
576 if (code) return KABADCMD;
579 /* no point in doing this any sooner than necessary */
580 for (i=0;i<4;misc_auth_bytes[i++] = 0);
582 if (as->parms[4].items) {
583 if (isint(as->parms[4].items->data))
584 pwexpiry = atoi (as->parms[4].items->data);
586 fprintf(stderr,"Password lifetime specified must be a non-negative decimal integer.\n");
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");
595 misc_auth_bytes[0] = pwexpiry+1;
599 if (as->parms[5].items) {
601 reuse = (as->parms[5].items->data);
603 if (!strcmp(reuse, "yes")) {
604 misc_auth_bytes[1] = KA_REUSEPW;
606 else if (strcmp(reuse, "no")) {
607 fprintf(stderr,"must specify \"yes\" or \"no\": \"yes\" assumed\n");
608 misc_auth_bytes[1] = KA_REUSEPW;
611 misc_auth_bytes[1] = KA_NOREUSEPW;
615 if (as->parms[6].items) {
619 if (isint(as->parms[6].items->data) &&
620 ((nfailures = atoi(as->parms[6].items->data)) < 255)) {
621 misc_auth_bytes[2] = nfailures+1;
624 fprintf(stderr,"Failure limit must be in [0..254].\n");
625 fprintf(stderr,"Zero represents unlimited login attempts.\n");
630 if (as->parms[7].items) {
631 int locktime, hrs, mins;
635 s = as->parms[7].items->data;
637 sscanf(s, "%d:%d", &hrs, &mins);
639 sscanf(s, "%d", &mins);
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");
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");
653 locktime = (locktime * 60 + 511) >> 9; /* ceil(l*60/512) */
654 misc_auth_bytes[3] = locktime +1; /* will be 1 if user said 0 */
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");
666 was_spare = pack_long(misc_auth_bytes);
668 if (was_spare || flags || expiration || lifetime || (maxAssociates >= 0))
670 (KAM_SetFields, conn, 0,
671 name, instance, flags, expiration, lifetime, maxAssociates,
672 was_spare, /* spare */ 0);
674 printf ("Must specify one of the optional parameters\n");
677 if (code) com_err (whoami, code,
678 "calling KAM_SetFields for %s.%s", name, instance);
683 struct cmd_syndesc *as,
687 char realm[MAXKTCREALMLEN];
688 struct ktc_encryptionKey key;
690 if (as->parms[1].items) {
691 code = ka_ExpandCell (as->parms[1].items->data, realm, 0/*local*/);
693 com_err (whoami, code,
694 "expanding %s as cell name, attempting to continue",
695 as->parms[1].items->data);
697 ucstring (realm, realm, sizeof(realm));
700 if (code = DefaultCell()) return code;
701 ucstring (realm, cell, sizeof(realm));
703 ka_StringToKey (as->parms[0].items->data, realm, &key);
705 printf ("Converting %s in realm '%s' yields key='",
706 as->parms[0].items->data, realm);
707 ka_PrintBytes (&key, sizeof(key));
714 struct cmd_syndesc *as,
718 char name[MAXKTCNAMELEN];
719 char instance[MAXKTCNAMELEN];
720 char realm[MAXKTCREALMLEN];
721 struct ktc_encryptionKey key;
724 code = ka_ParseLoginName (as->parms[0].items->data, name, instance, realm);
726 com_err (whoami, code, "parsing user's name '%s'",
727 as->parms[0].items->data);
731 if (strlen(realm) == 0)
732 ucstring (realm, cell, sizeof(realm));
734 if (as->parms[1].items && as->parms[2].items) {
735 printf ("Can't specify both a password and a key\n");
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();
745 ka_StringToKey (as->parms[1].items->data, realm, &key);
747 else if (as->parms[2].items) {
748 if (ka_ReadBytes (as->parms[2].items->data, &key, sizeof(key)) != 8) {
749 printf ("Key must be 8 bytes: '%s' was too long\n",
750 as->parms[2].items->data);
755 printf ("Must specify new password or key\n");
760 if (as->parms[3].items)
761 sscanf (as->parms[3].items->data, "%d", &kvno);
763 code = ubik_Call (KAM_SetPassword, conn, 0, name, instance, kvno, key);
764 if (code) com_err (whoami, code,
765 "so can't set password for %s.%s", name, instance);
769 #define PrintPrincipal(p,n,l) \
770 PrintName((p)->name, (p)->instance, (p)->cell, l, n)
772 static afs_int32 PrintName (
780 int left; /* if ConvertBytes stops early */
783 if (name == 0) name = "";
784 if (inst == 0) inst = "";
785 if (acell == 0) acell = "";
786 left = ka_ConvertBytes(buf, buflen, name, strlen(name));
790 com_err (whoami, code,
791 "PrintName: principal name was '%s'.'%s'@'%s'",
798 if (nlen + len + 1 >= buflen) goto bad_name;
800 left = ka_ConvertBytes(buf+nlen, buflen-nlen, inst, len);
801 if (left) goto bad_name;
807 char *lcell = ka_LocalCell();
808 if (lcell == 0) lcell = "";
809 if (strcmp (acell, lcell) != 0) {
810 /* only append cell if not the local cell */
811 if (nlen + len + 1 >= buflen) goto bad_name;
813 left = ka_ConvertBytes(buf+nlen, buflen-nlen, acell, len);
814 if (left) goto bad_name;
821 #define PrintedPrincipal(p) PrintedName ((p)->name, (p)->instance, (p)->cell)
823 /* PrintedName - returned a pointer to a static string in which the formated
824 * name has been stored. */
826 static char *PrintedName (
831 static char printedName[128];
833 code = PrintName (name, inst, cell, sizeof(printedName), printedName);
835 if (name == 0) name = "";
836 strncpy (printedName, name, sizeof(printedName));
837 printedName[sizeof(printedName)-8] = 0;
838 strcat (printedName, "<error>");
843 static afs_int32 ListTicket (
844 struct ktc_principal *server,
848 struct ktc_token token; /* the token we're printing */
849 struct ktc_principal client;
850 char UserName[sizeof(struct ktc_principal)];
851 char ServerName[sizeof(struct ktc_principal)];
852 afs_int32 now = time(0);
853 char bob[KA_TIMESTR_LEN];
855 /* get the ticket info itself */
856 code = ktc_GetToken (server, &token, sizeof(token), &client);
858 com_err (whoami, code, "failed to get token info for server %s",
859 PrintedPrincipal (server));
862 code = PrintPrincipal (&client, UserName, sizeof(UserName));
863 if (code) return code;
864 /* spaces are printed as "\040" */
865 if (UserName[0] == 0)
867 else if (strncmp(UserName, "AFS\\040ID\\040", 13) == 0) {
868 printf("User's (AFS ID %s) tokens", UserName+13);
870 else if (strncmp(UserName, "Unix\\040UID\\040", 15) == 0) {
874 printf("User %s's tokens", UserName);
876 code = PrintPrincipal (server, ServerName, sizeof(ServerName));
877 if (code) return code;
878 printf(" for %s ", ServerName);
880 if (token.startTime > now) {
881 ka_timestr(token.startTime,bob,KA_TIMESTR_LEN);
882 printf("[>> POSTDATED 'till %s <<]",bob);
885 if (token.endTime <= now)
886 printf("[>> Expired <<]\n");
888 ka_timestr(token.endTime,bob,KA_TIMESTR_LEN);
889 printf("[Expires %s]\n", bob);
892 printf ("SessionKey: ");
893 ka_PrintBytes (&token.sessionKey, sizeof(token.sessionKey));
894 printf ("\nTicket (kvno = %d, len = %d): ", token.kvno,
896 ka_PrintBytes (token.ticket, token.ticketLen);
903 struct cmd_syndesc *as,
907 struct ktc_principal server;
908 struct ktc_token token;
909 afs_int32 life = KA_SIXHOURS;
911 if (as->parms[1].items) {
912 code = read_time_interval (as->parms[1].items->data, &life);
913 if (code) return KABADCMD;
915 code = ka_ParseLoginName (as->parms[0].items->data,
916 server.name, server.instance, server.cell);
918 com_err (whoami, code, "parsing user's name '%s'",
919 as->parms[0].items->data);
922 if (server.cell[0] == 0) {
923 if (code = DefaultCell()) return code;
924 strcpy (server.cell, cell);
926 code = ka_ExpandCell (server.cell, server.cell, 0/*local*/);
928 com_err (whoami, code, "Can't expand cell name");
933 token.ticketLen = 0; /* in case there are no tokens */
934 code = ka_GetServerToken (server.name, server.instance, server.cell,
935 life, &token, /*new*/1, /*dosetpag*/0);
936 if (code) com_err (whoami, code,
937 "getting ticket for %s", PrintedPrincipal (&server));
939 code = ListTicket (&server, /*verbose*/1);
945 struct cmd_syndesc *as,
949 char name[MAXKTCNAMELEN];
950 struct ktc_encryptionKey key;
951 static struct ubik_client *lpbkConn = 0;
953 /* no instance allowed */
954 code = ka_ParseLoginName (as->parms[0].items->data, name, 0, 0);
957 com_err (whoami, code,
958 "getting %s's password via loopback connection to GetPassword", name);
959 /* if we got a timeout, print a clarification, too */
961 fprintf(stderr, "%s: please note that this command must be run locally on a database server machine.\n", whoami);
966 struct rx_connection *conns[2];
967 struct rx_securityClass *sc;
968 int si; /* security class index */
971 if (code) goto abort;
972 sc = (struct rx_securityClass *) rxnull_NewClientSecurityObject();
973 si = RX_SCINDEX_NULL;
974 conns[0] = rx_NewConnection (htonl(INADDR_LOOPBACK), htons(AFSCONF_KAUTHPORT),
975 KA_MAINTENANCE_SERVICE, sc, si);
977 code = ubik_ClientInit(conns, &lpbkConn);
978 if (code) goto abort;
980 code = ubik_Call (KAM_GetPassword, lpbkConn, 0, name, &key);
981 /* Lets close down the ubik_Client connection now */
982 ubik_ClientDestroy(lpbkConn);
983 if (code) goto abort;
985 ka_PrintBytes (&key, sizeof(key));
991 struct cmd_syndesc *as,
995 struct ktc_encryptionKey key;
997 code = ubik_Call (KAM_GetRandomKey, conn, 0, &key);
998 if (code) com_err(whoami, code, "so can't get random key");
1002 ka_PrintBytes (&key, sizeof(key));
1004 for (i=0; i<sizeof(key); i++) {
1005 printf ("%0.2x", ((char *)&key)[i] & 0xff);
1006 if (i==3) printf (" ");
1007 else if (i!=7) printf (".");
1015 struct cmd_syndesc *as,
1022 char bob[KA_TIMESTR_LEN];
1024 code = ubik_Call (KAM_GetStats, conn, 0,
1025 KAMAJORVERSION, &admins, &statics, &dynamics);
1027 printf ("call to GetStats failed: %s\n", ka_ErrorString(code));
1030 if (statics.minor_version != KAMINORVERSION)
1031 printf ("Minor version number mismatch: got %d, expected %d\n",
1032 statics.minor_version, KAMINORVERSION);
1033 printf ("%d allocs, %d frees, %d password changes\n",
1034 statics.allocs, statics.frees, statics.cpws);
1035 printf ("Hash table utilization = %f%%\n",
1036 (double)dynamics.hashTableUtilization / 100.0);
1037 ka_timestr(dynamics.start_time,bob,KA_TIMESTR_LEN);
1038 printf ("From host %lx started at %s:\n", dynamics.host, bob);
1040 #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)
1041 print_stat (Authenticate);
1042 print_stat (ChangePassword);
1043 print_stat (GetTicket);
1044 print_stat (CreateUser);
1045 print_stat (SetPassword);
1046 print_stat (SetFields);
1047 print_stat (DeleteUser);
1048 print_stat (GetEntry);
1049 print_stat (ListEntry);
1050 print_stat (GetStats);
1051 print_stat (GetPassword);
1052 print_stat (GetRandomKey);
1054 print_stat (UAuthenticate);
1055 print_stat (UGetTicket);
1057 #if (KAMAJORVERSION>5)
1059 printf ("%d string checks\n", dynamics.string_checks);
1061 printf ("Used %.3f seconds of CPU time.\n", dynamics.string_checks/1000.0);
1063 printf ("%d admin accounts\n", admins);
1068 struct cmd_syndesc *as,
1072 struct ka_debugInfo info;
1076 char bob[KA_TIMESTR_LEN];
1079 if (as->parms[0].items) {
1080 struct ubik_client *iConn;
1081 code = ka_SingleServerConn (cell, as->parms[0].items->data, KA_MAINTENANCE_SERVICE, 0, &iConn);
1083 struct afsconf_cell cellinfo;
1085 com_err (whoami, code, "couldn't find host %s in cell %s",
1086 as->parms[0].items->data, cell);
1087 code = ka_GetServers (cell, &cellinfo);
1088 if (code) com_err (whoami, code, "getting servers in cell %s", cell);
1090 printf ("Servers in cell %s, are:\n", cell);
1091 for (i=0; i<cellinfo.numServers; i++)
1092 printf (" %s\n", cellinfo.hostName[i]);
1096 code = ubik_Call (KAM_Debug, iConn, 0, KAMAJORVERSION, 0, &info);
1097 ubik_ClientDestroy (iConn);
1099 else code = ubik_Call (KAM_Debug, conn, 0, KAMAJORVERSION, 0, &info);
1102 com_err (whoami, code, "call to Debug failed");
1107 if (info.minorVersion != KAMINORVERSION)
1108 printf ("Minor version number mismatch: got %d, expected %d\n",
1109 info.minorVersion, KAMINORVERSION);
1112 #if (KAMAJORVERSION>5)
1118 if (timeOffset < 0) timeOffset = -timeOffset;
1119 if (timeOffset > 60) {
1120 printf ("WARNING: Large server client clock skew: %d seconds. Call itself took %d seconds.\n", timeOffset, now-start);
1122 ka_timestr(info.startTime,bob,KA_TIMESTR_LEN);
1123 printf ("From host %lx started %sat %s:\n",
1124 info.host, (info.noAuth ? "w/o authorization " : ""),
1126 ka_timestr (info.lastTrans,bob,KA_TIMESTR_LEN);
1127 printf ("Last trans was %s at %s\n", info.lastOperation, bob);
1128 ka_timestr (info.dbHeaderRead,bob,KA_TIMESTR_LEN);
1129 printf ("Header last read %s.\n", bob);
1130 printf ("db version=%d, keyVersion=%d, key cache version=%d\n",
1131 info.dbVersion, info.dbSpecialKeysVersion, info.kcVersion);
1132 printf ("db ptrs: free %d, eof %d, kvno %d.\n",
1133 info.dbFreePtr, info.dbEofPtr, info.dbKvnoPtr);
1134 ka_timestr (info.nextAutoCPW,bob,KA_TIMESTR_LEN);
1135 printf ("Next autoCPW at %s or in %d updates.\n",
1136 bob, info.updatesRemaining);
1137 if (info.cheader_lock || info.keycache_lock)
1138 printf ("locks: cheader %08lx, keycache %08lx\n",
1139 info.cheader_lock, info.keycache_lock);
1140 printf ("Last authentication for %s, last admin user was %s\n",
1141 info.lastAuth, info.lastAdmin);
1142 printf ("Last TGS op was a %s ticket was for %s\n",
1143 info.lastTGSServer, info.lastTGS);
1144 printf ("Last UDP TGS was a %s ticket for %s. UDP Authenticate for %s\n",
1145 info.lastUTGSServer, info.lastUTGS, info.lastUAuth);
1146 printf ("key cache size %d, used %d.\n",
1147 info.kcSize, info.kcUsed);
1148 if (info.kcUsed > KADEBUGKCINFOSIZE) {
1149 printf("insufficient room to return all key cache entries!\n");
1150 info.kcUsed = KADEBUGKCINFOSIZE;
1152 for (i=0; i<info.kcUsed; i++)
1153 ka_timestr(info.kcInfo[i].used,bob,KA_TIMESTR_LEN);
1154 printf ("%32s %c %2x(%2x) used %s\n",
1155 info.kcInfo[i].principal, (info.kcInfo[i].primary?'*':' '),
1156 info.kcInfo[i].kvno, info.kcInfo[i].keycksum,
1162 struct cmd_syndesc *as,
1170 struct cmd_syndesc *as,
1178 struct cmd_syndesc *as)
1180 if (!strcmp(as->name,"help")) return;
1182 /* Determine if we need to destory the ubik connection.
1183 * Closing it avoids resends of packets.
1186 ubik_ClientDestroy(conn);
1193 int init = 0, noauth;
1194 char name[MAXKTCNAMELEN];
1195 char instance[MAXKTCNAMELEN];
1196 char newCell[MAXKTCREALMLEN];
1197 afs_int32 serverList[MAXSERVERS];
1200 struct cmd_syndesc *as,
1207 static int MyBeforeProc(
1208 struct cmd_syndesc *as,
1211 extern struct passwd *getpwuid();
1213 struct ktc_encryptionKey key;
1214 struct ktc_principal auth_server, auth_token, client;
1215 char realm[MAXKTCREALMLEN];
1217 struct ktc_token token, *pToken;
1218 int i, acode, code = 0;
1220 { char *ws = strrchr (as->a0name, '/');
1221 if (ws) ws++; /* skip everything before the "/" */
1222 else ws = as->a0name;
1223 if (strlen(ws) > 0) {
1224 strncpy (whoami, ws, sizeof(whoami));
1225 if (strlen (whoami)+1 >= sizeof(whoami)) strcpy (whoami, "kas:");
1226 else strcat (whoami, ":");
1227 } else whoami[0] = 0;
1228 /* append sub-command name */
1229 strncat (whoami, as->name, sizeof(whoami) - strlen(whoami) -1);
1232 if (as->parms[12].name == 0) return 0;
1234 assert (as->parms[13].name && as->parms[14].name &&
1235 as->parms[15].name && as->parms[16].name);
1237 /* MyAfterProc() destroys the conn, but just to be sure */
1239 code = ubik_ClientDestroy (conn);
1243 if (!init || as->parms[12].items || as->parms[13].items ||
1244 as->parms[14].items || as->parms[15].items ||
1245 as->parms[16].items) {
1246 strcpy (instance, "");
1247 strcpy (newCell, "");
1249 if (as->parms[12].items) { /* -admin_username */
1250 code = ka_ParseLoginName (as->parms[12].items->data, name, instance, newCell);
1252 com_err (whoami, code, "parsing user's name '%s'", as->parms[12].items->data);
1257 DWORD len = MAXKTCNAMELEN;
1258 if (!GetUserName((LPTSTR)name, &len)) {
1259 printf("Can't get user name \n");
1263 /* No explicit name provided: use Unix uid. */
1264 pw = getpwuid(getuid());
1266 printf ("Can't figure out your name from your user id.\n");
1269 strncpy (name, pw->pw_name, sizeof(name));
1273 if (as->parms[14].items) { /* -cell */
1274 if (strlen(newCell) > 0) {
1275 printf ("Duplicate cell specification not allowed\n");
1277 strncpy (newCell, as->parms[14].items->data, sizeof(newCell));
1280 code = ka_ExpandCell (newCell, newCell, 0/*local*/);
1282 com_err (whoami, code, "Can't expand cell name");
1285 strcpy (cell, newCell);
1287 if (as->parms[15].items) { /* -servers */
1288 struct cmd_item *ip;
1289 char *ap[MAXSERVERS+2];
1293 for (ip = as->parms[15].items, i=2; ip; ip=ip->next, i++)
1295 code = ubik_ParseClientList(i, ap, serverList);
1297 com_err (whoami, code, "could not parse server list");
1300 ka_ExplicitCell (cell, serverList);
1303 noauth = (as->parms[16].items ? 1 : 0); /* -noauth */
1308 token.ticketLen = 0; /* in case there are no tokens */
1309 if (!noauth) { /* Will prompt for a password */
1310 /* first see if there's already an admin ticket */
1311 code = ka_GetAdminToken (0, 0, cell, 0, KA_SIXHOURS, &token, 0/* !new */);
1312 if (code) { /* if not then get key and try again */
1313 if (as->parms[13].items) { /* if password specified */
1314 strncpy (passwd, as->parms[13].items->data, sizeof(passwd));
1315 bzero (as->parms[13].items->data, strlen (as->parms[13].items->data));
1317 char msg[MAXKTCNAMELEN+50];
1318 if (as->parms[12].items) sprintf (msg, "Administrator's (%s) Password: ", name);
1319 else sprintf (msg, "Password for %s: ", name);
1320 code = read_pw_string (passwd, sizeof(passwd), msg, 0);
1321 if (code) code = KAREADPW;
1322 else if (strlen(passwd) == 0) code = KANULLPASSWORD;
1324 com_err (whoami, code, "reading password");
1328 ka_StringToKey (passwd, cell, &key);
1329 code = ka_GetAdminToken (name, instance, cell, &key, KA_SIXHOURS,
1330 &token, 0/* !new */);
1331 if ((code == KABADREQUEST) && (strlen(passwd) > 8)) {
1332 /* try with only the first 8 characters incase they set
1333 * their password with an old style passwd program. */
1335 ka_StringToKey (passwd, cell, &key);
1336 code = ka_GetAdminToken (name, instance, cell, &key,
1337 KA_SIXHOURS, &token, 0/* !new */);
1339 fprintf (stderr, "Warning: you have typed a password longer than 8 characters, but only the\n");
1340 fprintf (stderr, "first 8 characters were actually significant. If you change your password\n");
1341 fprintf (stderr, "again this warning message will go away.\n");
1348 reason = "password was incorrect";
1351 reason = "Authentication Server was unavailable";
1354 reason = (char *)error_message (code);
1356 fprintf (stderr, "%s: Auth. as %s to AuthServer failed: %s\nProceeding w/o authentication\n",
1357 whoami, PrintedName(name,instance,cell), reason);
1359 /* get an Authentication token while were at it. */
1360 if (ka_CellToRealm(cell, realm, 0) != 0) realm[0] = '\0';
1361 strcpy(auth_server.name, KA_TGS_NAME);
1362 strcpy(auth_server.instance, realm);
1363 strcpy(auth_server.cell, cell);
1364 if (ktc_GetToken(&auth_server, &auth_token, sizeof(struct ktc_token), &client) != 0) {
1365 acode = ka_GetAuthToken (name, instance, cell, &key,
1366 MAXKTCTICKETLIFETIME,
1367 (afs_int32 *)0 /*Don't need pwd expiration info here*/);
1368 if (acode && (acode != code)) /* codes are usually the same */
1369 com_err (whoami, code,
1370 "getting Authentication token for %s",
1371 PrintedName (name, instance, cell));
1373 bzero (&key, sizeof(key));
1377 pToken = ((token.ticketLen == 0) ? 0 : &token);
1378 code = ka_AuthServerConn (cell, KA_MAINTENANCE_SERVICE, pToken, &conn);
1379 if (code && pToken) {
1380 com_err (whoami, code,
1381 "connecting to AuthServer: now trying w/o authentication");
1382 code = ka_AuthServerConn (cell, KA_MAINTENANCE_SERVICE, 0, &conn);
1383 if (code) com_err (whoami, code, "making unauthenticated connection to AuthServer");
1386 com_err (whoami, code, "Couldn't establish connection to Authentication Server");
1390 /* now default unspecified password by prompting from terminal */
1391 if (as->nParms >= 12) for (i=0; i<12; i++)
1392 if (as->parms[i].name && (as->parms[i].items == 0)) {
1393 char *p = as->parms[i].name; /* parameter name */
1394 int l = strlen (p); /* length of name */
1395 /* does parameter end in "password" */
1396 if (strcmp (p+(l-8), "password") == 0) {
1398 char password[BUFSIZ];
1399 struct cmd_item *ip;
1403 code = read_pw_string (password, sizeof(password), msg, 1);
1404 if (code) code = KAREADPW;
1405 else if (strlen(password) == 0) code = KANULLPASSWORD;
1407 com_err (whoami, code, "prompting for %s", p+1);
1410 ip = (struct cmd_item *)malloc (sizeof(struct cmd_item));
1411 ip->data = (char *)malloc (strlen(password)+1);
1413 strcpy (ip->data, password);
1414 as->parms[i].items = ip;
1417 if (!conn) { /* if all else fails... */
1418 code = NoAuth (0,0); /* get unauthenticated conn */
1419 if (code) return code;
1424 /* These are some helpful command that deal with the cache managers tokens. */
1426 static ForgetTicket (
1427 struct cmd_syndesc *as,
1431 struct ktc_principal server;
1434 if (as->parms[0].items) {
1435 char *name = as->parms[0].items->data;
1436 code = ka_ParseLoginName
1437 (name, server.name, server.instance, server.cell);
1439 com_err (whoami, code, "couldn't interpret name '%s'", name);
1442 if (server.cell[0] == 0) {
1443 if (code = DefaultCell()) return code;
1444 strcpy (server.cell, cell);
1446 code = ka_ExpandCell (server.cell, server.cell, 0/*local*/);
1448 com_err (whoami, code, "Can't expand cell name");
1452 code = ktc_ForgetToken (&server);
1454 com_err (whoami, code, "couldn't remove tokens for %s",
1455 PrintedPrincipal (&server));
1460 if (!as->parms[1].items) {
1461 fprintf (stderr, "Must specify server name or -all\n");
1464 code = ktc_ForgetAllTokens();
1466 com_err (whoami, code, "couldn't delete all tokens");
1471 code = ktc_ForgetAllTokens();
1473 com_err (whoami, code, "couldn't delete all tokens");
1479 static ListTickets (
1480 struct cmd_syndesc *as,
1484 int index, newIndex;
1485 struct ktc_principal server;
1488 if (as->parms[1].items) verbose = 1;
1489 if (as->parms[0].items) {
1490 char *name = as->parms[0].items->data;
1491 code = ka_ParseLoginName
1492 (name, server.name, server.instance, server.cell);
1494 com_err (whoami, code, "couldn't interpret name '%s'", name);
1497 if (server.cell[0] == 0) {
1498 if (code = DefaultCell()) return code;
1499 strcpy (server.cell, cell);
1501 code = ka_ExpandCell (server.cell, server.cell, 0/*local*/);
1503 com_err (whoami, code, "Can't expand cell name");
1507 code = ListTicket (&server, verbose);
1509 else for (index = 0; ; index = newIndex) {
1510 code = ktc_ListTokens(index, &newIndex, &server);
1512 if (code == KTC_NOENT) code = 0; /* end of list */
1515 code = ListTicket(&server, verbose);
1520 static void add_std_args (register struct cmd_syndesc *ts)
1523 /* 12 */ cmd_AddParm (ts, "-admin_username", CMD_SINGLE, CMD_OPTIONAL,
1524 "admin principal to use for authentication");
1525 /* 13 */ cmd_AddParm (ts, "-password_for_admin", CMD_SINGLE, CMD_OPTIONAL,
1527 /* 14 */ cmd_AddParm (ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
1528 /* 15 */ cmd_AddParm (ts, "-servers", CMD_LIST, CMD_OPTIONAL,
1529 "explicit list of authentication servers");
1530 /* 16 */ cmd_AddParm (ts, "-noauth", CMD_FLAG, CMD_OPTIONAL,
1531 "don't authenticate");
1534 afs_int32 ka_AdminInteractive (
1539 register struct cmd_syndesc *ts;
1545 strncpy(myName, *cmd_argv, 509);
1547 cmd_SetBeforeProc(MyBeforeProc, (char *) 0);
1548 cmd_SetAfterProc(MyAfterProc, (char *) 0);
1550 ts = cmd_CreateSyntax ("interactive", Interactive, 0, "enter interactive mode");
1553 ts = cmd_CreateSyntax ("noauthentication", NoAuth, 0, "connect to AuthServer w/o using token");
1555 ts = cmd_CreateSyntax ("list", ListUsers, 0, "list all users in database");
1556 cmd_AddParm (ts, "-long", CMD_FLAG, CMD_OPTIONAL, "show detailed info about each user");
1557 cmd_AddParm (ts, "-showadmin", CMD_FLAG, CMD_OPTIONAL, "show all cell administrators");
1558 cmd_AddParm (ts, "-showkey", CMD_FLAG, CMD_OPTIONAL, "show the user's actual key rather than the checksum");
1560 cmd_CreateAlias (ts, "ls");
1562 ts = cmd_CreateSyntax ("examine", ExamineUser, 0, "examine the entry for a user");
1563 cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of user");
1564 cmd_AddParm (ts, "-showkey", CMD_FLAG, CMD_OPTIONAL, "show the user's actual key rather than the checksum");
1567 ts = cmd_CreateSyntax ("create", CreateUser, 0, "create an entry for a user");
1568 cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of user");
1569 cmd_AddParm (ts, "-initial_password", CMD_SINGLE, CMD_OPTIONAL, "initial password");
1572 ts = cmd_CreateSyntax ("delete", DeleteUser, 0, "delete a user");
1573 cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of user");
1575 cmd_CreateAlias (ts, "rm");
1577 ts = cmd_CreateSyntax ("setfields", SetFields, 0, "set various fields in a user's entry");
1578 cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of user");
1579 cmd_AddParm (ts, "-flags", CMD_SINGLE, CMD_OPTIONAL, "hex flag value or flag name expression");
1580 cmd_AddParm (ts, "-expiration", CMD_SINGLE, CMD_OPTIONAL, "date of account expiration");
1581 cmd_AddParm (ts, "-lifetime", CMD_SINGLE, CMD_OPTIONAL, "maximum ticket lifetime");
1582 cmd_AddParm (ts, "-pwexpires", CMD_SINGLE, CMD_OPTIONAL, "number days password is valid ([0..254])");
1583 cmd_AddParm (ts, "-reuse", CMD_SINGLE, CMD_OPTIONAL, "permit password reuse (yes/no)");
1584 cmd_AddParm (ts, "-attempts", CMD_SINGLE, CMD_OPTIONAL, "maximum successive failed login tries ([0..254])");
1585 cmd_AddParm (ts, "-locktime", CMD_SINGLE, CMD_OPTIONAL, "failure penalty [hh:mm or minutes]");
1587 cmd_AddParm (ts, "-associates", CMD_SINGLE, CMD_OPTIONAL, "maximum associate instances");
1590 cmd_CreateAlias (ts, "sf");
1593 ts = cmd_CreateSyntax ("unlock", Unlock, 0, "Enable authentication ID after max failed attempts exceeded");
1594 cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "authentication ID");
1598 ts = cmd_CreateSyntax ("stringtokey", StringToKey, 0, "convert a string to a key");
1599 cmd_AddParm (ts, "-string", CMD_SINGLE, 0, "password string");
1600 cmd_AddParm (ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
1602 ts = cmd_CreateSyntax ("setpassword", SetPassword, 0, "set a user's password");
1603 cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of user");
1604 cmd_AddParm (ts, "-new_password", CMD_SINGLE, CMD_OPTIONAL, "new password");
1606 cmd_AddParm (ts, "-kvno", CMD_SINGLE, CMD_OPTIONAL, "key version number");
1608 cmd_CreateAlias (ts, "sp");
1609 #ifdef CMD_PARSER_AMBIG_FIX
1610 cmd_CreateAlias (ts, "setpasswd");
1613 /* set a user's key */
1614 ts = cmd_CreateSyntax ("setkey", SetPassword, 0, (char *) CMD_HIDDEN);
1615 cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of user");
1617 cmd_AddParm (ts, "-new_key", CMD_SINGLE, 0, "eight byte new key");
1619 cmd_AddParm (ts, "-kvno", CMD_SINGLE, CMD_OPTIONAL, "key version number");
1622 /* get a user's password */
1623 ts = cmd_CreateSyntax ("getpassword", GetPassword, 0, (char *) CMD_HIDDEN);
1624 cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of user");
1625 /* don't take standard args */
1626 /* add_std_args (ts); */
1627 #ifdef CMD_PARSER_AMBIG_FIX
1628 cmd_CreateAlias (ts, "getpasswd");
1631 /* get a random key */
1632 ts = cmd_CreateSyntax ("getrandomkey", GetRandomKey, 0, (char *) CMD_HIDDEN);
1635 /* get a ticket for a specific server */
1636 ts = cmd_CreateSyntax ("getticket", GetTicket, 0, (char *) CMD_HIDDEN);
1637 cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of server");
1638 cmd_AddParm (ts, "-lifetime", CMD_SINGLE, CMD_OPTIONAL, "ticket lifetime");
1641 ts = cmd_CreateSyntax ("statistics", Statistics, 0, "show statistics for AuthServer");
1644 /* show debugging info from AuthServer */
1645 ts = cmd_CreateSyntax ("debuginfo", DebugInfo, 0, (char *) CMD_HIDDEN);
1646 cmd_AddParm (ts, "-hostname", CMD_SINGLE, CMD_OPTIONAL, "authentication server host name");
1649 ts = cmd_CreateSyntax ("forgetticket", ForgetTicket, 0, "delete user's tickets");
1651 cmd_AddParm (ts, "-name", CMD_SINGLE, (CMD_OPTIONAL | CMD_HIDE), "name of server");
1653 cmd_AddParm (ts, "-all", CMD_FLAG, CMD_OPTIONAL, "delete all tickets");
1655 ts = cmd_CreateSyntax ("listtickets", ListTickets, 0, "show all cache manager tickets");
1656 cmd_AddParm (ts, "-name", CMD_SINGLE, CMD_OPTIONAL, "name of server");
1657 cmd_AddParm (ts, "-long", CMD_FLAG, CMD_OPTIONAL, "show session key and ticket");
1659 ts = cmd_CreateSyntax ("quit", Quit, 0, "exit program");
1662 conn = 0; /* no connection yet */
1663 zero_argc = cmd_argc;
1664 zero_argv = cmd_argv;
1666 strcpy (whoami, "kas");
1668 if (code = cmd_Dispatch(cmd_argc, cmd_argv)) {
1677 s = fgets (line, sizeof(line), stdin);
1678 if (s == NULL) return 0; /* EOF on input */
1679 for (i=strlen(line)-1; i>=0 && isspace(line[i]); i--) line[i]=0;
1680 if (i < 0) continue; /* blank line */
1682 code = cmd_ParseLine (line, argv, &argc, sizeof(argv)/sizeof(argv[0]));
1684 com_err (whoami, code, "parsing line: '%s'", line);
1687 code = cmd_Dispatch (argc, argv);
1688 cmd_FreeArgv (argv);