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 ((char *)&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 ((char *)&key, sizeof(key));
710 des_string_to_key (as->parms[0].items->data, &key);
712 printf ("Converting %s with the DES string to key yields key='",
713 as->parms[0].items->data);
714 ka_PrintBytes (&key, sizeof(key));
721 struct cmd_syndesc *as,
725 char name[MAXKTCNAMELEN];
726 char instance[MAXKTCNAMELEN];
727 char realm[MAXKTCREALMLEN];
728 struct ktc_encryptionKey key;
731 code = ka_ParseLoginName (as->parms[0].items->data, name, instance, realm);
733 com_err (whoami, code, "parsing user's name '%s'",
734 as->parms[0].items->data);
738 if (strlen(realm) == 0)
739 ucstring (realm, cell, sizeof(realm));
741 if (as->parms[1].items && as->parms[2].items) {
742 printf ("Can't specify both a password and a key\n");
745 else if (as->parms[1].items) {
746 (void) init_child(myName);
747 (void) give_to_child(passwd); /* old password */
748 code = password_bad(as->parms[1].items->data);
749 (void) terminate_child();
752 ka_StringToKey (as->parms[1].items->data, realm, &key);
754 else if (as->parms[2].items) {
755 if (ka_ReadBytes (as->parms[2].items->data, (char *)&key, sizeof(key))
757 printf ("Key must be 8 bytes: '%s' was too long\n",
758 as->parms[2].items->data);
763 printf ("Must specify new password or key\n");
768 if (as->parms[3].items)
769 sscanf (as->parms[3].items->data, "%d", &kvno);
771 code = ubik_Call (KAM_SetPassword, conn, 0, name, instance, kvno, key);
772 if (code) com_err (whoami, code,
773 "so can't set password for %s.%s", name, instance);
777 #define PrintPrincipal(p,n,l) \
778 PrintName((p)->name, (p)->instance, (p)->cell, l, n)
780 static afs_int32 PrintName (
788 int left; /* if ConvertBytes stops early */
791 if (name == 0) name = "";
792 if (inst == 0) inst = "";
793 if (acell == 0) acell = "";
794 left = ka_ConvertBytes(buf, buflen, name, strlen(name));
798 com_err (whoami, code,
799 "PrintName: principal name was '%s'.'%s'@'%s'",
806 if (nlen + len + 1 >= buflen) goto bad_name;
808 left = ka_ConvertBytes(buf+nlen, buflen-nlen, inst, len);
809 if (left) goto bad_name;
815 char *lcell = ka_LocalCell();
816 if (lcell == 0) lcell = "";
817 if (strcmp (acell, lcell) != 0) {
818 /* only append cell if not the local cell */
819 if (nlen + len + 1 >= buflen) goto bad_name;
821 left = ka_ConvertBytes(buf+nlen, buflen-nlen, acell, len);
822 if (left) goto bad_name;
829 #define PrintedPrincipal(p) PrintedName ((p)->name, (p)->instance, (p)->cell)
831 /* PrintedName - returned a pointer to a static string in which the formated
832 * name has been stored. */
834 static char *PrintedName (
839 static char printedName[128];
841 code = PrintName (name, inst, cell, sizeof(printedName), printedName);
843 if (name == 0) name = "";
844 strncpy (printedName, name, sizeof(printedName));
845 printedName[sizeof(printedName)-8] = 0;
846 strcat (printedName, "<error>");
851 static afs_int32 ListTicket (
852 struct ktc_principal *server,
856 struct ktc_token token; /* the token we're printing */
857 struct ktc_principal client;
858 char UserName[sizeof(struct ktc_principal)];
859 char ServerName[sizeof(struct ktc_principal)];
860 afs_int32 now = time(0);
861 char bob[KA_TIMESTR_LEN];
863 /* get the ticket info itself */
864 code = ktc_GetToken (server, &token, sizeof(token), &client);
866 com_err (whoami, code, "failed to get token info for server %s",
867 PrintedPrincipal (server));
870 code = PrintPrincipal (&client, UserName, sizeof(UserName));
871 if (code) return code;
872 /* spaces are printed as "\040" */
873 if (UserName[0] == 0)
875 else if (strncmp(UserName, "AFS\\040ID\\040", 13) == 0) {
876 printf("User's (AFS ID %s) tokens", UserName+13);
878 else if (strncmp(UserName, "Unix\\040UID\\040", 15) == 0) {
882 printf("User %s's tokens", UserName);
884 code = PrintPrincipal (server, ServerName, sizeof(ServerName));
885 if (code) return code;
886 printf(" for %s ", ServerName);
888 if (token.startTime > now) {
889 ka_timestr(token.startTime,bob,KA_TIMESTR_LEN);
890 printf("[>> POSTDATED 'till %s <<]",bob);
893 if (token.endTime <= now)
894 printf("[>> Expired <<]\n");
896 ka_timestr(token.endTime,bob,KA_TIMESTR_LEN);
897 printf("[Expires %s]\n", bob);
900 printf ("SessionKey: ");
901 ka_PrintBytes ((char *)&token.sessionKey, sizeof(token.sessionKey));
902 printf ("\nTicket (kvno = %d, len = %d): ", token.kvno,
904 ka_PrintBytes ((char *)token.ticket, token.ticketLen);
911 struct cmd_syndesc *as,
915 struct ktc_principal server;
916 struct ktc_token token;
917 afs_int32 life = KA_SIXHOURS;
919 if (as->parms[1].items) {
920 code = read_time_interval (as->parms[1].items->data, &life);
921 if (code) return KABADCMD;
923 code = ka_ParseLoginName (as->parms[0].items->data,
924 server.name, server.instance, server.cell);
926 com_err (whoami, code, "parsing user's name '%s'",
927 as->parms[0].items->data);
930 if (server.cell[0] == 0) {
931 if (code = DefaultCell()) return code;
932 strcpy (server.cell, cell);
934 code = ka_ExpandCell (server.cell, server.cell, 0/*local*/);
936 com_err (whoami, code, "Can't expand cell name");
941 token.ticketLen = 0; /* in case there are no tokens */
942 code = ka_GetServerToken (server.name, server.instance, server.cell,
943 life, &token, /*new*/1, /*dosetpag*/0);
944 if (code) com_err (whoami, code,
945 "getting ticket for %s", PrintedPrincipal (&server));
947 code = ListTicket (&server, /*verbose*/1);
953 struct cmd_syndesc *as,
957 char name[MAXKTCNAMELEN];
958 struct ktc_encryptionKey key;
959 static struct ubik_client *lpbkConn = 0;
961 /* no instance allowed */
962 code = ka_ParseLoginName (as->parms[0].items->data, name, 0, 0);
965 com_err (whoami, code,
966 "getting %s's password via loopback connection to GetPassword", name);
967 /* if we got a timeout, print a clarification, too */
969 fprintf(stderr, "%s: please note that this command must be run locally on a database server machine.\n", whoami);
974 struct rx_connection *conns[2];
975 struct rx_securityClass *sc;
976 int si; /* security class index */
979 if (code) goto abort;
980 sc = (struct rx_securityClass *) rxnull_NewClientSecurityObject();
981 si = RX_SCINDEX_NULL;
982 conns[0] = rx_NewConnection (htonl(INADDR_LOOPBACK), htons(AFSCONF_KAUTHPORT),
983 KA_MAINTENANCE_SERVICE, sc, si);
985 code = ubik_ClientInit(conns, &lpbkConn);
986 if (code) goto abort;
988 code = ubik_Call (KAM_GetPassword, lpbkConn, 0, name, &key);
989 /* Lets close down the ubik_Client connection now */
990 ubik_ClientDestroy(lpbkConn);
991 if (code) goto abort;
993 ka_PrintBytes ((char *)&key, sizeof(key));
999 struct cmd_syndesc *as,
1003 struct ktc_encryptionKey key;
1005 code = ubik_Call (KAM_GetRandomKey, conn, 0, &key);
1006 if (code) com_err(whoami, code, "so can't get random key");
1010 ka_PrintBytes ((char *)&key, sizeof(key));
1012 for (i=0; i<sizeof(key); i++) {
1013 printf ("%0.2x", ((char *)&key)[i] & 0xff);
1014 if (i==3) printf (" ");
1015 else if (i!=7) printf (".");
1023 struct cmd_syndesc *as,
1030 char bob[KA_TIMESTR_LEN];
1032 code = ubik_Call (KAM_GetStats, conn, 0,
1033 KAMAJORVERSION, &admins, &statics, &dynamics);
1035 printf ("call to GetStats failed: %s\n", ka_ErrorString(code));
1038 if (statics.minor_version != KAMINORVERSION)
1039 printf ("Minor version number mismatch: got %d, expected %d\n",
1040 statics.minor_version, KAMINORVERSION);
1041 printf ("%d allocs, %d frees, %d password changes\n",
1042 statics.allocs, statics.frees, statics.cpws);
1043 printf ("Hash table utilization = %f%%\n",
1044 (double)dynamics.hashTableUtilization / 100.0);
1045 ka_timestr(dynamics.start_time,bob,KA_TIMESTR_LEN);
1046 printf ("From host %lx started at %s:\n", dynamics.host, bob);
1048 #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)
1049 print_stat (Authenticate);
1050 print_stat (ChangePassword);
1051 print_stat (GetTicket);
1052 print_stat (CreateUser);
1053 print_stat (SetPassword);
1054 print_stat (SetFields);
1055 print_stat (DeleteUser);
1056 print_stat (GetEntry);
1057 print_stat (ListEntry);
1058 print_stat (GetStats);
1059 print_stat (GetPassword);
1060 print_stat (GetRandomKey);
1062 print_stat (UAuthenticate);
1063 print_stat (UGetTicket);
1065 #if (KAMAJORVERSION>5)
1067 printf ("%d string checks\n", dynamics.string_checks);
1069 printf ("Used %.3f seconds of CPU time.\n", dynamics.string_checks/1000.0);
1071 printf ("%d admin accounts\n", admins);
1076 struct cmd_syndesc *as,
1080 struct ka_debugInfo info;
1084 char bob[KA_TIMESTR_LEN];
1087 if (as->parms[0].items) {
1088 struct ubik_client *iConn;
1089 code = ka_SingleServerConn (cell, as->parms[0].items->data, KA_MAINTENANCE_SERVICE, 0, &iConn);
1091 struct afsconf_cell cellinfo;
1093 com_err (whoami, code, "couldn't find host %s in cell %s",
1094 as->parms[0].items->data, cell);
1095 code = ka_GetServers (cell, &cellinfo);
1096 if (code) com_err (whoami, code, "getting servers in cell %s", cell);
1098 printf ("Servers in cell %s, are:\n", cell);
1099 for (i=0; i<cellinfo.numServers; i++)
1100 printf (" %s\n", cellinfo.hostName[i]);
1104 code = ubik_Call (KAM_Debug, iConn, 0, KAMAJORVERSION, 0, &info);
1105 ubik_ClientDestroy (iConn);
1107 else code = ubik_Call (KAM_Debug, conn, 0, KAMAJORVERSION, 0, &info);
1110 com_err (whoami, code, "call to Debug failed");
1115 if (info.minorVersion != KAMINORVERSION)
1116 printf ("Minor version number mismatch: got %d, expected %d\n",
1117 info.minorVersion, KAMINORVERSION);
1120 #if (KAMAJORVERSION>5)
1126 if (timeOffset < 0) timeOffset = -timeOffset;
1127 if (timeOffset > 60) {
1128 printf ("WARNING: Large server client clock skew: %d seconds. Call itself took %d seconds.\n", timeOffset, now-start);
1130 ka_timestr(info.startTime,bob,KA_TIMESTR_LEN);
1131 printf ("From host %lx started %sat %s:\n",
1132 info.host, (info.noAuth ? "w/o authorization " : ""),
1134 ka_timestr (info.lastTrans,bob,KA_TIMESTR_LEN);
1135 printf ("Last trans was %s at %s\n", info.lastOperation, bob);
1136 ka_timestr (info.dbHeaderRead,bob,KA_TIMESTR_LEN);
1137 printf ("Header last read %s.\n", bob);
1138 printf ("db version=%d, keyVersion=%d, key cache version=%d\n",
1139 info.dbVersion, info.dbSpecialKeysVersion, info.kcVersion);
1140 printf ("db ptrs: free %d, eof %d, kvno %d.\n",
1141 info.dbFreePtr, info.dbEofPtr, info.dbKvnoPtr);
1142 ka_timestr (info.nextAutoCPW,bob,KA_TIMESTR_LEN);
1143 printf ("Next autoCPW at %s or in %d updates.\n",
1144 bob, info.updatesRemaining);
1145 if (info.cheader_lock || info.keycache_lock)
1146 printf ("locks: cheader %08lx, keycache %08lx\n",
1147 info.cheader_lock, info.keycache_lock);
1148 printf ("Last authentication for %s, last admin user was %s\n",
1149 info.lastAuth, info.lastAdmin);
1150 printf ("Last TGS op was a %s ticket was for %s\n",
1151 info.lastTGSServer, info.lastTGS);
1152 printf ("Last UDP TGS was a %s ticket for %s. UDP Authenticate for %s\n",
1153 info.lastUTGSServer, info.lastUTGS, info.lastUAuth);
1154 printf ("key cache size %d, used %d.\n",
1155 info.kcSize, info.kcUsed);
1156 if (info.kcUsed > KADEBUGKCINFOSIZE) {
1157 printf("insufficient room to return all key cache entries!\n");
1158 info.kcUsed = KADEBUGKCINFOSIZE;
1160 for (i=0; i<info.kcUsed; i++)
1161 ka_timestr(info.kcInfo[i].used,bob,KA_TIMESTR_LEN);
1162 printf ("%32s %c %2x(%2x) used %s\n",
1163 info.kcInfo[i].principal, (info.kcInfo[i].primary?'*':' '),
1164 info.kcInfo[i].kvno, info.kcInfo[i].keycksum,
1170 struct cmd_syndesc *as,
1178 struct cmd_syndesc *as,
1186 struct cmd_syndesc *as)
1188 if (!strcmp(as->name,"help")) return;
1190 /* Determine if we need to destory the ubik connection.
1191 * Closing it avoids resends of packets.
1194 ubik_ClientDestroy(conn);
1201 int init = 0, noauth;
1202 char name[MAXKTCNAMELEN];
1203 char instance[MAXKTCNAMELEN];
1204 char newCell[MAXKTCREALMLEN];
1205 afs_int32 serverList[MAXSERVERS];
1208 struct cmd_syndesc *as,
1215 static int MyBeforeProc(
1216 struct cmd_syndesc *as,
1219 extern struct passwd *getpwuid();
1221 struct ktc_encryptionKey key;
1222 struct ktc_principal auth_server, auth_token, client;
1223 char realm[MAXKTCREALMLEN];
1225 struct ktc_token token, *pToken;
1226 int i, acode, code = 0;
1228 { char *ws = strrchr (as->a0name, '/');
1229 if (ws) ws++; /* skip everything before the "/" */
1230 else ws = as->a0name;
1231 if (strlen(ws) > 0) {
1232 strncpy (whoami, ws, sizeof(whoami));
1233 if (strlen (whoami)+1 >= sizeof(whoami)) strcpy (whoami, "kas:");
1234 else strcat (whoami, ":");
1235 } else whoami[0] = 0;
1236 /* append sub-command name */
1237 strncat (whoami, as->name, sizeof(whoami) - strlen(whoami) -1);
1240 if (as->parms[12].name == 0) return 0;
1242 assert (as->parms[13].name && as->parms[14].name &&
1243 as->parms[15].name && as->parms[16].name);
1245 /* MyAfterProc() destroys the conn, but just to be sure */
1247 code = ubik_ClientDestroy (conn);
1251 if (!init || as->parms[12].items || as->parms[13].items ||
1252 as->parms[14].items || as->parms[15].items ||
1253 as->parms[16].items) {
1254 strcpy (instance, "");
1255 strcpy (newCell, "");
1257 if (as->parms[12].items) { /* -admin_username */
1258 code = ka_ParseLoginName (as->parms[12].items->data, name, instance, newCell);
1260 com_err (whoami, code, "parsing user's name '%s'", as->parms[12].items->data);
1265 DWORD len = MAXKTCNAMELEN;
1266 if (!GetUserName((LPTSTR)name, &len)) {
1267 printf("Can't get user name \n");
1271 /* No explicit name provided: use Unix uid. */
1272 pw = getpwuid(getuid());
1274 printf ("Can't figure out your name from your user id.\n");
1277 strncpy (name, pw->pw_name, sizeof(name));
1281 if (as->parms[14].items) { /* -cell */
1282 if (strlen(newCell) > 0) {
1283 printf ("Duplicate cell specification not allowed\n");
1285 strncpy (newCell, as->parms[14].items->data, sizeof(newCell));
1288 code = ka_ExpandCell (newCell, newCell, 0/*local*/);
1290 com_err (whoami, code, "Can't expand cell name");
1293 strcpy (cell, newCell);
1295 if (as->parms[15].items) { /* -servers */
1296 struct cmd_item *ip;
1297 char *ap[MAXSERVERS+2];
1301 for (ip = as->parms[15].items, i=2; ip; ip=ip->next, i++)
1303 code = ubik_ParseClientList(i, ap, serverList);
1305 com_err (whoami, code, "could not parse server list");
1308 ka_ExplicitCell (cell, serverList);
1311 noauth = (as->parms[16].items ? 1 : 0); /* -noauth */
1316 token.ticketLen = 0; /* in case there are no tokens */
1317 if (!noauth) { /* Will prompt for a password */
1318 /* first see if there's already an admin ticket */
1319 code = ka_GetAdminToken (0, 0, cell, 0, KA_SIXHOURS, &token, 0/* !new */);
1320 if (code) { /* if not then get key and try again */
1321 if (as->parms[13].items) { /* if password specified */
1322 strncpy (passwd, as->parms[13].items->data, sizeof(passwd));
1323 bzero (as->parms[13].items->data, strlen (as->parms[13].items->data));
1325 char msg[MAXKTCNAMELEN+50];
1326 if (as->parms[12].items) sprintf (msg, "Administrator's (%s) Password: ", name);
1327 else sprintf (msg, "Password for %s: ", name);
1328 code = read_pw_string (passwd, sizeof(passwd), msg, 0);
1329 if (code) code = KAREADPW;
1330 else if (strlen(passwd) == 0) code = KANULLPASSWORD;
1332 com_err (whoami, code, "reading password");
1336 ka_StringToKey (passwd, cell, &key);
1337 code = ka_GetAdminToken (name, instance, cell, &key, KA_SIXHOURS,
1338 &token, 0/* !new */);
1339 if (code == KABADREQUEST) {
1340 des_string_to_key (passwd, &key);
1341 code = ka_GetAdminToken (name, instance, cell, &key, KA_SIXHOURS,
1342 &token, 0/* !new */);
1344 if ((code == KABADREQUEST) && (strlen(passwd) > 8)) {
1345 /* try with only the first 8 characters incase they set
1346 * their password with an old style passwd program. */
1348 ka_StringToKey (passwd, cell, &key);
1349 code = ka_GetAdminToken (name, instance, cell, &key,
1350 KA_SIXHOURS, &token, 0/* !new */);
1352 fprintf (stderr, "Warning: you have typed a password longer than 8 characters, but only the\n");
1353 fprintf (stderr, "first 8 characters were actually significant. If you change your password\n");
1354 fprintf (stderr, "again this warning message will go away.\n");
1361 reason = "password was incorrect";
1364 reason = "Authentication Server was unavailable";
1367 reason = (char *)error_message (code);
1369 fprintf (stderr, "%s: Auth. as %s to AuthServer failed: %s\nProceeding w/o authentication\n",
1370 whoami, PrintedName(name,instance,cell), reason);
1372 /* get an Authentication token while were at it. */
1373 if (ka_CellToRealm(cell, realm, 0) != 0) realm[0] = '\0';
1374 strcpy(auth_server.name, KA_TGS_NAME);
1375 strcpy(auth_server.instance, realm);
1376 strcpy(auth_server.cell, cell);
1377 if (ktc_GetToken(&auth_server, &auth_token, sizeof(struct ktc_token), &client) != 0) {
1378 acode = ka_GetAuthToken (name, instance, cell, &key,
1379 MAXKTCTICKETLIFETIME,
1380 (afs_int32 *)0 /*Don't need pwd expiration info here*/);
1381 if (acode && (acode != code)) /* codes are usually the same */
1382 com_err (whoami, code,
1383 "getting Authentication token for %s",
1384 PrintedName (name, instance, cell));
1386 bzero (&key, sizeof(key));
1390 pToken = ((token.ticketLen == 0) ? 0 : &token);
1391 code = ka_AuthServerConn (cell, KA_MAINTENANCE_SERVICE, pToken, &conn);
1392 if (code && pToken) {
1393 com_err (whoami, code,
1394 "connecting to AuthServer: now trying w/o authentication");
1395 code = ka_AuthServerConn (cell, KA_MAINTENANCE_SERVICE, 0, &conn);
1396 if (code) com_err (whoami, code, "making unauthenticated connection to AuthServer");
1399 com_err (whoami, code, "Couldn't establish connection to Authentication Server");
1403 /* now default unspecified password by prompting from terminal */
1404 if (as->nParms >= 12) for (i=0; i<12; i++)
1405 if (as->parms[i].name && (as->parms[i].items == 0)) {
1406 char *p = as->parms[i].name; /* parameter name */
1407 int l = strlen (p); /* length of name */
1408 /* does parameter end in "password" */
1409 if (strcmp (p+(l-8), "password") == 0) {
1411 char password[BUFSIZ];
1412 struct cmd_item *ip;
1416 code = read_pw_string (password, sizeof(password), msg, 1);
1417 if (code) code = KAREADPW;
1418 else if (strlen(password) == 0) code = KANULLPASSWORD;
1420 com_err (whoami, code, "prompting for %s", p+1);
1423 ip = (struct cmd_item *)malloc (sizeof(struct cmd_item));
1424 ip->data = (char *)malloc (strlen(password)+1);
1426 strcpy (ip->data, password);
1427 as->parms[i].items = ip;
1430 if (!conn) { /* if all else fails... */
1431 code = NoAuth (0,0); /* get unauthenticated conn */
1432 if (code) return code;
1437 /* These are some helpful command that deal with the cache managers tokens. */
1439 static ForgetTicket (
1440 struct cmd_syndesc *as,
1444 struct ktc_principal server;
1447 if (as->parms[0].items) {
1448 char *name = as->parms[0].items->data;
1449 code = ka_ParseLoginName
1450 (name, server.name, server.instance, server.cell);
1452 com_err (whoami, code, "couldn't interpret name '%s'", name);
1455 if (server.cell[0] == 0) {
1456 if (code = DefaultCell()) return code;
1457 strcpy (server.cell, cell);
1459 code = ka_ExpandCell (server.cell, server.cell, 0/*local*/);
1461 com_err (whoami, code, "Can't expand cell name");
1465 code = ktc_ForgetToken (&server);
1467 com_err (whoami, code, "couldn't remove tokens for %s",
1468 PrintedPrincipal (&server));
1473 if (!as->parms[1].items) {
1474 fprintf (stderr, "Must specify server name or -all\n");
1477 code = ktc_ForgetAllTokens();
1479 com_err (whoami, code, "couldn't delete all tokens");
1484 code = ktc_ForgetAllTokens();
1486 com_err (whoami, code, "couldn't delete all tokens");
1492 static ListTickets (
1493 struct cmd_syndesc *as,
1497 int index, newIndex;
1498 struct ktc_principal server;
1501 if (as->parms[1].items) verbose = 1;
1502 if (as->parms[0].items) {
1503 char *name = as->parms[0].items->data;
1504 code = ka_ParseLoginName
1505 (name, server.name, server.instance, server.cell);
1507 com_err (whoami, code, "couldn't interpret name '%s'", name);
1510 if (server.cell[0] == 0) {
1511 if (code = DefaultCell()) return code;
1512 strcpy (server.cell, cell);
1514 code = ka_ExpandCell (server.cell, server.cell, 0/*local*/);
1516 com_err (whoami, code, "Can't expand cell name");
1520 code = ListTicket (&server, verbose);
1522 else for (index = 0; ; index = newIndex) {
1523 code = ktc_ListTokens(index, &newIndex, &server);
1525 if (code == KTC_NOENT) code = 0; /* end of list */
1528 code = ListTicket(&server, verbose);
1533 static void add_std_args (register struct cmd_syndesc *ts)
1536 /* 12 */ cmd_AddParm (ts, "-admin_username", CMD_SINGLE, CMD_OPTIONAL,
1537 "admin principal to use for authentication");
1538 /* 13 */ cmd_AddParm (ts, "-password_for_admin", CMD_SINGLE, CMD_OPTIONAL,
1540 /* 14 */ cmd_AddParm (ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
1541 /* 15 */ cmd_AddParm (ts, "-servers", CMD_LIST, CMD_OPTIONAL,
1542 "explicit list of authentication servers");
1543 /* 16 */ cmd_AddParm (ts, "-noauth", CMD_FLAG, CMD_OPTIONAL,
1544 "don't authenticate");
1547 afs_int32 ka_AdminInteractive (
1552 register struct cmd_syndesc *ts;
1558 strncpy(myName, *cmd_argv, 509);
1560 cmd_SetBeforeProc(MyBeforeProc, (char *) 0);
1561 cmd_SetAfterProc(MyAfterProc, (char *) 0);
1563 ts = cmd_CreateSyntax ("interactive", Interactive, 0, "enter interactive mode");
1566 ts = cmd_CreateSyntax ("noauthentication", NoAuth, 0, "connect to AuthServer w/o using token");
1568 ts = cmd_CreateSyntax ("list", ListUsers, 0, "list all users in database");
1569 cmd_AddParm (ts, "-long", CMD_FLAG, CMD_OPTIONAL, "show detailed info about each user");
1570 cmd_AddParm (ts, "-showadmin", CMD_FLAG, CMD_OPTIONAL, "show all cell administrators");
1571 cmd_AddParm (ts, "-showkey", CMD_FLAG, CMD_OPTIONAL, "show the user's actual key rather than the checksum");
1573 cmd_CreateAlias (ts, "ls");
1575 ts = cmd_CreateSyntax ("examine", ExamineUser, 0, "examine the entry for a user");
1576 cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of user");
1577 cmd_AddParm (ts, "-showkey", CMD_FLAG, CMD_OPTIONAL, "show the user's actual key rather than the checksum");
1580 ts = cmd_CreateSyntax ("create", CreateUser, 0, "create an entry for a user");
1581 cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of user");
1582 cmd_AddParm (ts, "-initial_password", CMD_SINGLE, CMD_OPTIONAL, "initial password");
1585 ts = cmd_CreateSyntax ("delete", DeleteUser, 0, "delete a user");
1586 cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of user");
1588 cmd_CreateAlias (ts, "rm");
1590 ts = cmd_CreateSyntax ("setfields", SetFields, 0, "set various fields in a user's entry");
1591 cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of user");
1592 cmd_AddParm (ts, "-flags", CMD_SINGLE, CMD_OPTIONAL, "hex flag value or flag name expression");
1593 cmd_AddParm (ts, "-expiration", CMD_SINGLE, CMD_OPTIONAL, "date of account expiration");
1594 cmd_AddParm (ts, "-lifetime", CMD_SINGLE, CMD_OPTIONAL, "maximum ticket lifetime");
1595 cmd_AddParm (ts, "-pwexpires", CMD_SINGLE, CMD_OPTIONAL, "number days password is valid ([0..254])");
1596 cmd_AddParm (ts, "-reuse", CMD_SINGLE, CMD_OPTIONAL, "permit password reuse (yes/no)");
1597 cmd_AddParm (ts, "-attempts", CMD_SINGLE, CMD_OPTIONAL, "maximum successive failed login tries ([0..254])");
1598 cmd_AddParm (ts, "-locktime", CMD_SINGLE, CMD_OPTIONAL, "failure penalty [hh:mm or minutes]");
1600 cmd_AddParm (ts, "-associates", CMD_SINGLE, CMD_OPTIONAL, "maximum associate instances");
1603 cmd_CreateAlias (ts, "sf");
1606 ts = cmd_CreateSyntax ("unlock", Unlock, 0, "Enable authentication ID after max failed attempts exceeded");
1607 cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "authentication ID");
1611 ts = cmd_CreateSyntax ("stringtokey", StringToKey, 0, "convert a string to a key");
1612 cmd_AddParm (ts, "-string", CMD_SINGLE, 0, "password string");
1613 cmd_AddParm (ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
1615 ts = cmd_CreateSyntax ("setpassword", SetPassword, 0, "set a user's password");
1616 cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of user");
1617 cmd_AddParm (ts, "-new_password", CMD_SINGLE, CMD_OPTIONAL, "new password");
1619 cmd_AddParm (ts, "-kvno", CMD_SINGLE, CMD_OPTIONAL, "key version number");
1621 cmd_CreateAlias (ts, "sp");
1622 #ifdef CMD_PARSER_AMBIG_FIX
1623 cmd_CreateAlias (ts, "setpasswd");
1626 /* set a user's key */
1627 ts = cmd_CreateSyntax ("setkey", SetPassword, 0, (char *) CMD_HIDDEN);
1628 cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of user");
1630 cmd_AddParm (ts, "-new_key", CMD_SINGLE, 0, "eight byte new key");
1632 cmd_AddParm (ts, "-kvno", CMD_SINGLE, CMD_OPTIONAL, "key version number");
1635 /* get a user's password */
1636 ts = cmd_CreateSyntax ("getpassword", GetPassword, 0, (char *) CMD_HIDDEN);
1637 cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of user");
1638 /* don't take standard args */
1639 /* add_std_args (ts); */
1640 #ifdef CMD_PARSER_AMBIG_FIX
1641 cmd_CreateAlias (ts, "getpasswd");
1644 /* get a random key */
1645 ts = cmd_CreateSyntax ("getrandomkey", GetRandomKey, 0, (char *) CMD_HIDDEN);
1648 /* get a ticket for a specific server */
1649 ts = cmd_CreateSyntax ("getticket", GetTicket, 0, (char *) CMD_HIDDEN);
1650 cmd_AddParm (ts, "-name", CMD_SINGLE, 0, "name of server");
1651 cmd_AddParm (ts, "-lifetime", CMD_SINGLE, CMD_OPTIONAL, "ticket lifetime");
1654 ts = cmd_CreateSyntax ("statistics", Statistics, 0, "show statistics for AuthServer");
1657 /* show debugging info from AuthServer */
1658 ts = cmd_CreateSyntax ("debuginfo", DebugInfo, 0, (char *) CMD_HIDDEN);
1659 cmd_AddParm (ts, "-hostname", CMD_SINGLE, CMD_OPTIONAL, "authentication server host name");
1662 ts = cmd_CreateSyntax ("forgetticket", ForgetTicket, 0, "delete user's tickets");
1664 cmd_AddParm (ts, "-name", CMD_SINGLE, (CMD_OPTIONAL | CMD_HIDE), "name of server");
1666 cmd_AddParm (ts, "-all", CMD_FLAG, CMD_OPTIONAL, "delete all tickets");
1668 ts = cmd_CreateSyntax ("listtickets", ListTickets, 0, "show all cache manager tickets");
1669 cmd_AddParm (ts, "-name", CMD_SINGLE, CMD_OPTIONAL, "name of server");
1670 cmd_AddParm (ts, "-long", CMD_FLAG, CMD_OPTIONAL, "show session key and ticket");
1672 ts = cmd_CreateSyntax ("quit", Quit, 0, "exit program");
1675 conn = 0; /* no connection yet */
1676 zero_argc = cmd_argc;
1677 zero_argv = cmd_argv;
1679 strcpy (whoami, "kas");
1681 if (code = cmd_Dispatch(cmd_argc, cmd_argv)) {
1690 s = fgets (line, sizeof(line), stdin);
1691 if (s == NULL) return 0; /* EOF on input */
1692 for (i=strlen(line)-1; i>=0 && isspace(line[i]); i--) line[i]=0;
1693 if (i < 0) continue; /* blank line */
1695 code = cmd_ParseLine (line, argv, &argc, sizeof(argv)/sizeof(argv[0]));
1697 com_err (whoami, code, "parsing line: '%s'", line);
1700 code = cmd_Dispatch (argc, argv);
1701 cmd_FreeArgv (argv);