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 <afsconfig.h>
16 #include <afs/param.h>
20 #include <afs/debug.h>
24 /* These two needed for rxgen output to work */
25 #include <sys/types.h>
32 #define UBIK_LEGACY_CALLITER 1
38 #include <afs/cellconfig.h>
40 #include <afs/com_err.h>
41 #include <afs/afsutil.h>
43 #include <des_prototypes.h>
46 #include "kauth_internal.h"
51 #define CMD_PARSER_AMBIG_FIX 1 /* allow ambiguous aliases */
53 #define KA_SIXHOURS (6*3600)
55 static struct ubik_client *conn;
56 static char cell[MAXKTCREALMLEN] = "";
57 static char whoami[32];
58 static char passwd[BUFSIZ];
59 static char myName[510]; /* almost like whoami save with path and without : */
63 static char **zero_argv;
64 afs_uint32 ka_islocked(char *, char *, afs_uint32 *);
73 code = ka_ExpandCell(0, cell, 0 /*local */ );
75 afs_com_err(whoami, code, "Can't expand cell name");
80 /* These are the command operation procedures. */
83 DumpUser(char *user, char *arock, int showadmin, int showkey, char *inst)
85 char name[MAXKTCNAMELEN];
86 char instance[MAXKTCNAMELEN];
89 char bob[KA_TIMESTR_LEN];
91 struct kaentryinfo tentry;
93 code = ka_ParseLoginName(user, name, instance, 0);
95 afs_com_err(whoami, code, "parsing user's name '%s'", user);
102 ubik_KAM_GetEntry(conn, 0, name, inst, KAMAJORVERSION, &tentry);
104 afs_com_err(whoami, code, "getting information for %s.%s", name, inst);
107 if (tentry.minor_version != KAMINORVERSION)
108 printf("Minor version number mismatch: got %d, expected %d\n",
109 tentry.minor_version, KAMINORVERSION);
110 if (showadmin && !(tentry.flags & KAFADMIN))
112 ka_PrintUserID("\nUser data for ", name, inst, "");
115 #define NEWPREFIX "+"
116 if (tentry.flags & KAFADMIN) {
117 printf("%sADMIN", prefix);
120 if (tentry.flags & KAFNOTGS) {
121 printf("%sNOTGS", prefix);
124 if (tentry.flags & KAFNOCPW) {
125 printf("%sNOCPW", prefix);
128 if (tentry.flags & KAFNOSEAL) {
129 printf("%sNOSEAL", prefix);
132 if (tentry.flags & KAFNEWASSOC) {
133 printf("%sNEWASSOC", prefix);
136 if (tentry.flags & KAFASSOCROOT) {
137 printf("%sASSOCROOT", prefix);
140 if (tentry.flags & KAFASSOC) {
141 printf("%sASSOC", prefix);
144 if (tentry.user_expiration <= now) {
145 printf("%sexpired", prefix);
148 if (strcmp(prefix, NEWPREFIX) == 0)
153 if ((!ka_KeyIsZero((char *)&tentry.key, sizeof(tentry.key))) && (showkey)) {
154 printf(" key (%d):", tentry.key_version);
155 ka_PrintBytes((char *)&tentry.key, sizeof(tentry.key));
157 if (tentry.keyCheckSum == 0)
158 printf(" key version is %d", tentry.key_version);
160 printf(" key (%d) cksum is %u", tentry.key_version,
163 ka_timestr(tentry.change_password_time, bob, KA_TIMESTR_LEN);
164 printf(", last cpw: %s\n", bob);
165 if (!tentry.misc_auth_bytes) {
166 printf(" password will never expire.\n");
168 (" An unlimited number of unsuccessful authentications is permitted.\n");
170 unsigned char misc_stuff[4];
173 temp = tentry.misc_auth_bytes;
175 temp = ntohl(tentry.misc_auth_bytes);
177 unpack_long(temp, misc_stuff);
179 if (!misc_stuff[0]) {
180 printf(" password will never expire.\n");
182 ka_timestr((tentry.change_password_time +
183 misc_stuff[0] * 24 * 60 * 60), bob, KA_TIMESTR_LEN);
184 printf(" password will expire: %s\n", bob);
189 (" An unlimited number of unsuccessful authentications is permitted.\n");
192 (" %d consecutive unsuccessful authentications are permitted.\n",
196 printf(" The lock time for this user is not limited.\n");
198 printf(" The lock time for this user is %4.1f minutes.\n",
199 (float)((unsigned int)misc_stuff[3] << 9) / 60.0);
201 if (!(misc_stuff[1] & KA_ISLOCKED)
202 || !ka_islocked(name, instance, &temp))
203 printf(" User is not locked.\n");
204 else if (temp == (afs_uint32) (-1L))
205 printf(" User is locked forever.\n");
207 ka_timestr(temp, bob, KA_TIMESTR_LEN);
208 printf(" User is locked until %s\n", bob);
214 char exp[KA_TIMESTR_LEN];
215 ka_timestr(tentry.user_expiration, exp, KA_TIMESTR_LEN);
216 if (tentry.user_expiration < now)
217 printf(" DISABLED entry at %s.", exp);
218 else if (tentry.user_expiration == NEVERDATE)
219 printf(" entry never expires.");
221 printf(" entry expires on %s.", exp);
223 printf(" Max ticket lifetime %.2f hours.\n",
224 tentry.max_ticket_lifetime / 3600.0);
225 ka_timestr(tentry.modification_time, bob, KA_TIMESTR_LEN);
226 printf(" last mod on %s by ", bob);
227 ka_PrintUserID("", tentry.modification_user.name,
228 tentry.modification_user.instance, "\n");
229 if ((tentry.reserved3 & 0xffff0000) == 0x12340000) {
230 int short reused = (short)tentry.reserved3;
232 printf(" permit password reuse\n");
234 printf(" don't permit password reuse\n");
241 ListUsers(struct cmd_syndesc *as, void *arock)
246 afs_int32 next_index;
247 int code, all = 0, showa = 0;
248 int showkey = (as->parms[2].items != NULL);
250 if (as->parms[0].items)
252 if (as->parms[1].items) {
256 for (index = 0; 1; index = next_index) {
258 ubik_KAM_ListEntry(conn, 0, index, &next_index, &count,
261 afs_com_err(whoami, code, "calling KAM_ListEntry");
267 printf("next_index (%d) is negative: ", next_index);
268 if (strlen(name.name) == 0)
269 printf("name is zero length: ");
271 DumpUser(name.name, NULL, showa, showkey, name.instance);
273 ka_PrintUserID("", name.name, name.instance, "\n");
280 ExamineUser(struct cmd_syndesc *as, void *arock)
282 int showkey = (as->parms[1].items != NULL);
283 return DumpUser(as->parms[0].items->data, arock, 0, showkey, NULL);
293 handle_errors(int code, /* error code to handle */
294 struct OKerrors OKlist[], /* list of errors & messages that should be ignored */
296 { /* set this if we should retry, clear otherwise */
299 for (i = 0; OKlist[i].code; i++) {
300 if (OKlist[i].code == code) {
301 printf("%s\n", OKlist[i].msg);
302 *persist = 0; /* we're done */
307 printf(" : [%s] %s", afs_error_table_name(code), afs_error_message(code));
310 printf(", wait one second\n");
314 case RX_CALL_TIMEOUT:
315 printf(" (retrying)\n");
320 *persist = 0; /* don't retry these errors */
325 CreateUser(struct cmd_syndesc *as, void *arock)
328 char name[MAXKTCNAMELEN];
329 char instance[MAXKTCNAMELEN];
330 struct ktc_encryptionKey key;
333 struct OKerrors OKlist[2];
336 code = ka_ParseLoginName(as->parms[0].items->data, name, instance, 0);
338 afs_com_err(whoami, code, "parsing user's name '%s'",
339 as->parms[0].items->data);
342 ka_StringToKey(as->parms[1].items->data, cell, &key);
345 code = ubik_KAM_CreateUser(conn, 0, name, instance,
346 *ktc_to_EncryptionKey(&key));
349 ka_PrintUserID("Creating user ", name, instance, " ");
350 code = handle_errors(code, OKlist, &persist);
356 DeleteUser(struct cmd_syndesc *as, void *arock)
359 char name[MAXKTCNAMELEN];
360 char instance[MAXKTCNAMELEN];
363 struct OKerrors OKlist[2];
365 code = ka_ParseLoginName(as->parms[0].items->data, name, instance, 0);
367 afs_com_err(whoami, code, "parsing user's name '%s'",
368 as->parms[0].items->data);
373 code = ubik_KAM_DeleteUser(conn, 0, name, instance);
376 ka_PrintUserID("Deleting user ", name, instance, " ");
377 code = handle_errors(code, OKlist, &persist);
383 read_time_interval(char *str, afs_int32 * seconds)
389 str = strncpy(buf, str, sizeof(buf));
390 s = strchr(str, ':');
394 *s++ = '\0'; /* separate hours and minutes */
395 sec = atoi(str) * 3600 + atoi(s) * 60;
402 parse_flags(char *name, char *inst, char *str, afs_int32 * flags)
404 struct kaentryinfo tentry;
410 int addop; /* 1=add bit; 0=remove bit */
414 str = lcstring(bitspec, str, sizeof(bitspec));
416 if (strncmp(str, "0x", 2) == 0) /* 0x => hex */
417 sscanf(str, "0x%lx", (long unsigned int *) &f);
418 else if (*str == '0') /* assume octal */
419 sscanf(str, "%lo", (long unsigned int *) &f);
420 else /* just assume hex */
421 sscanf(str, "%lx", (long unsigned int *) &f);
428 if (strchr("+-", *str))
429 addop = (*str++ == '+');
430 else if (*str == '_') {
436 ubik_KAM_GetEntry(conn, 0, name, inst, KAMAJORVERSION,
439 afs_com_err(whoami, code,
440 "could get current flag value for %s.%s", name, inst);
457 if (strcmp(bit, "admin") == 0)
459 else if (strcmp(bit, "noadmin") == 0)
460 flag = KAFADMIN, addop = !addop;
461 else if (strcmp(bit, "notgs") == 0)
463 else if (strcmp(bit, "tgs") == 0)
464 flag = KAFNOTGS, addop = !addop;
465 else if (strcmp(bit, "noseal") == 0)
467 else if (strcmp(bit, "seal") == 0)
468 flag = KAFNOSEAL, addop = !addop;
469 else if (strcmp(bit, "nocpw") == 0)
471 else if (strcmp(bit, "cpw") == 0)
472 flag = KAFNOCPW, addop = !addop;
473 else if (strcmp(bit, "newassoc") == 0)
475 else if (strcmp(bit, "nonewassoc") == 0)
476 flag = KAFNEWASSOC, addop = !addop;
479 ("Illegal bit name: %s; choices are: [no]admin, [no]tgs, [no]seal, [no]cpw\n",
492 addop = 1; /* get next op */
493 else if ((*str == '-') || (*str == '_'))
496 printf("Illegal combination operator: %c\n", *str);
502 *flags = (f & KAF_SETTABLE_FLAGS) | KAFNORMAL;
506 #define seriouserror(code) ((code <0) || ((code != UNOSERVERS) && (code != UNOQUORUM) && code != UNOTSYNC))
508 /* return MAXLONG if locked forever */
510 ka_islocked(char *name, char *instance, afs_uint32 * when)
520 ubik_CallIter(KAM_LockStatus, conn, UPUBIKONLY, &count, (long) name,
521 (long) instance, (long) &tempwhen, 0, 0, 0,
522 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
524 if (seriouserror(code))
525 afs_com_err(whoami, code, NULL);
526 } else if (tempwhen) { /* user is locked */
527 if (!*when || tempwhen < *when) {
531 } else /* ! tempwhen ==> user is not locked */
534 } while (code != UNOSERVERS);
540 Unlock(struct cmd_syndesc *as, void *arock)
542 afs_int32 code, rcode = 0;
545 char name[MAXKTCNAMELEN];
546 char instance[MAXKTCNAMELEN];
548 code = ka_ParseLoginName(as->parms[0].items->data, name, instance, 0);
550 afs_com_err(whoami, code, "parsing user's name '%s'",
551 as->parms[0].items->data);
557 code = ubik_CallIter(KAM_Unlock, conn, 0, &count, (long) name, (long) instance,
558 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
559 if (code && (code != UNOSERVERS)) {
561 if (conn && conn->conns[count - 1]
562 && conn->conns[count - 1]->peer) {
563 server = conn->conns[count - 1]->peer->host;
565 afs_com_err(whoami, code,
566 "so %s.%s may still be locked (on server %d.%d.%d.%d)",
567 name, instance, ((server >> 24) & 0xFF),
568 ((server >> 16) & 0xFF), ((server >> 8) & 0xFF),
575 } while (code != UNOSERVERS);
581 SetFields(struct cmd_syndesc *as, void *arock)
584 char name[MAXKTCNAMELEN];
585 char instance[MAXKTCNAMELEN];
588 afs_int32 lifetime = 0;
589 afs_int32 maxAssociates = -1;
590 afs_int32 pwexpiry = 0;
591 afs_int32 was_spare = 0;
592 char misc_auth_bytes[4];
595 code = ka_ParseLoginName(as->parms[0].items->data, name, instance, 0);
597 afs_com_err(whoami, code, "parsing user's name '%s'",
598 as->parms[0].items->data);
602 if (as->parms[1].items) {
603 code = parse_flags(name, instance, as->parms[1].items->data, &flags);
606 ("Illegal flag specification: %s, should be of the form <'='|'+'|'-'|'_'>bitname{<'+'|'-'>bitname}*\n",
607 as->parms[1].items->data);
611 if (as->parms[2].items) {
613 char *s = strncpy(buf, as->parms[2].items->data, sizeof(buf));
614 code = ktime_DateToInt32(s, &expiration);
616 printf("Illegal time format %s: %s\n", as->parms[2].items->data,
617 ktime_GetDateUsage());
620 if (expiration == 0) {
621 fprintf(stderr, "Expiration time must be after (about) 1970.\n");
624 if (expiration < time(0)) {
626 "Warning: expiration being set into the past, account will be disabled.\n");
632 if (as->parms[3].items) {
633 code = read_time_interval(as->parms[3].items->data, &lifetime);
638 /* no point in doing this any sooner than necessary */
639 for (i = 0; i < 4; misc_auth_bytes[i++] = 0);
641 if (as->parms[4].items) {
642 if (util_isint(as->parms[4].items->data))
643 pwexpiry = atoi(as->parms[4].items->data);
646 "Password lifetime specified must be a non-negative decimal integer.\n");
649 if (pwexpiry < 0 || pwexpiry > 254) {
651 "Password lifetime range must be [0..254] days.\n");
652 fprintf(stderr, "Zero represents an unlimited lifetime.\n");
655 misc_auth_bytes[0] = pwexpiry + 1;
659 if (as->parms[5].items) {
661 reuse = (as->parms[5].items->data);
663 if (!strcmp(reuse, "yes")) {
664 misc_auth_bytes[1] = KA_REUSEPW;
665 } else if (strcmp(reuse, "no")) {
667 "must specify \"yes\" or \"no\": \"yes\" assumed\n");
668 misc_auth_bytes[1] = KA_REUSEPW;
670 misc_auth_bytes[1] = KA_NOREUSEPW;
674 if (as->parms[6].items) {
678 if (util_isint(as->parms[6].items->data)
679 && ((nfailures = atoi(as->parms[6].items->data)) < 255)) {
680 misc_auth_bytes[2] = nfailures + 1;
682 fprintf(stderr, "Failure limit must be in [0..254].\n");
683 fprintf(stderr, "Zero represents unlimited login attempts.\n");
688 if (as->parms[7].items) {
689 int locktime, hrs, mins;
693 s = as->parms[7].items->data;
695 sscanf(s, "%d:%d", &hrs, &mins);
697 sscanf(s, "%d", &mins);
699 locktime = hrs * 60 + mins;
700 if (hrs < 0 || hrs > 36 || mins < 0) {
702 "Lockout times must be either minutes or hh:mm.\n");
703 fprintf(stderr, "Lockout times must be less than 36 hours.\n");
705 } else if (locktime > 36 * 60) {
707 "Lockout times must be either minutes or hh:mm.\n");
708 fprintf(stderr, "Lockout times must be less than 36 hours.\n");
710 "Continuing with lock time of exactly 36 hours...\n");
713 locktime = (locktime * 60 + 511) >> 9; /* ceil(l*60/512) */
714 misc_auth_bytes[3] = locktime + 1; /* will be 1 if user said 0 */
717 if (as->parms[8].items) {
718 maxAssociates = atoi(as->parms[6].items->data);
719 if (maxAssociates < 0) {
720 printf("Illegal maximum number of associates\n");
725 was_spare = pack_long(misc_auth_bytes);
727 if (was_spare || flags || expiration || lifetime || (maxAssociates >= 0))
729 ubik_KAM_SetFields(conn, 0, name, instance, flags,
730 expiration, lifetime, maxAssociates, was_spare,
733 printf("Must specify one of the optional parameters\n");
737 afs_com_err(whoami, code, "calling KAM_SetFields for %s.%s", name,
743 StringToKey(struct cmd_syndesc *as, void *arock)
746 char realm[MAXKTCREALMLEN];
747 struct ktc_encryptionKey key;
749 if (as->parms[1].items) {
750 code = ka_ExpandCell(as->parms[1].items->data, realm, 0 /*local */ );
752 afs_com_err(whoami, code,
753 "expanding %s as cell name, attempting to continue",
754 as->parms[1].items->data);
756 ucstring(realm, realm, sizeof(realm));
758 if ((code = DefaultCell()))
760 ucstring(realm, cell, sizeof(realm));
762 ka_StringToKey(as->parms[0].items->data, realm, &key);
764 printf("Converting %s in realm '%s' yields key='",
765 as->parms[0].items->data, realm);
766 ka_PrintBytes((char *)&key, sizeof(key));
769 des_string_to_key(as->parms[0].items->data, ktc_to_cblockptr(&key));
771 printf("Converting %s with the DES string to key yields key='",
772 as->parms[0].items->data);
773 ka_PrintBytes((char *)&key, sizeof(key));
780 SetPassword(struct cmd_syndesc *as, void *arock)
783 char name[MAXKTCNAMELEN];
784 char instance[MAXKTCNAMELEN];
785 char realm[MAXKTCREALMLEN];
786 struct ktc_encryptionKey key;
789 code = ka_ParseLoginName(as->parms[0].items->data, name, instance, realm);
791 afs_com_err(whoami, code, "parsing user's name '%s'",
792 as->parms[0].items->data);
796 if (strlen(realm) == 0)
797 ucstring(realm, cell, sizeof(realm));
799 if (as->parms[1].items && as->parms[2].items) {
800 printf("Can't specify both a password and a key\n");
802 } else if (as->parms[1].items) {
803 (void)init_child(myName);
804 (void)give_to_child(passwd); /* old password */
805 code = password_bad(as->parms[1].items->data);
806 (void)terminate_child();
809 ka_StringToKey(as->parms[1].items->data, realm, &key);
810 } else if (as->parms[2].items) {
811 if (ka_ReadBytes(as->parms[2].items->data, (char *)&key, sizeof(key))
813 printf("Key must be 8 bytes: '%s' was too long\n",
814 as->parms[2].items->data);
818 printf("Must specify new password or key\n");
823 if (as->parms[3].items)
824 sscanf(as->parms[3].items->data, "%d", &kvno);
826 code = ubik_KAM_SetPassword(conn, 0, name, instance, kvno,
827 *ktc_to_EncryptionKey(&key));
829 afs_com_err(whoami, code, "so can't set password for %s.%s", name,
834 #define PrintPrincipal(p,n,l) \
835 PrintName((p)->name, (p)->instance, (p)->cell, l, n)
838 PrintName(char *name, char *inst, char *acell, int buflen, char *buf)
841 int left; /* if ConvertBytes stops early */
850 left = ka_ConvertBytes(buf, buflen, name, strlen(name));
854 afs_com_err(whoami, code, "PrintName: principal name was '%s'.'%s'@'%s'",
861 if (nlen + len + 1 >= buflen)
864 left = ka_ConvertBytes(buf + nlen, buflen - nlen, inst, len);
872 char *lcell = ka_LocalCell();
875 if (strcmp(acell, lcell) != 0) {
876 /* only append cell if not the local cell */
877 if (nlen + len + 1 >= buflen)
880 left = ka_ConvertBytes(buf + nlen, buflen - nlen, acell, len);
889 #define PrintedPrincipal(p) PrintedName ((p)->name, (p)->instance, (p)->cell)
891 /* PrintedName - returned a pointer to a static string in which the formated
892 * name has been stored. */
895 PrintedName(char *name, char *inst, char *cell)
897 static char printedName[128];
899 code = PrintName(name, inst, cell, sizeof(printedName), printedName);
903 strncpy(printedName, name, sizeof(printedName));
904 printedName[sizeof(printedName) - 8] = 0;
905 strcat(printedName, "<error>");
911 ListTicket(struct ktc_principal *server, int verbose)
914 struct ktc_token token; /* the token we're printing */
915 struct ktc_principal client;
916 char UserName[sizeof(struct ktc_principal)];
917 char ServerName[sizeof(struct ktc_principal)];
918 afs_int32 now = time(0);
919 char bob[KA_TIMESTR_LEN];
921 /* get the ticket info itself */
922 code = ktc_GetToken(server, &token, sizeof(token), &client);
924 afs_com_err(whoami, code, "failed to get token info for server %s",
925 PrintedPrincipal(server));
928 code = PrintPrincipal(&client, UserName, sizeof(UserName));
931 /* spaces are printed as "\040" */
932 if (UserName[0] == 0)
934 else if (strncmp(UserName, "AFS\\040ID\\040", 13) == 0) {
935 printf("User's (AFS ID %s) tokens", UserName + 13);
936 } else if (strncmp(UserName, "Unix\\040UID\\040", 15) == 0) {
939 printf("User %s's tokens", UserName);
941 code = PrintPrincipal(server, ServerName, sizeof(ServerName));
944 printf(" for %s ", ServerName);
946 if (token.startTime > now) {
947 ka_timestr(token.startTime, bob, KA_TIMESTR_LEN);
948 printf("[>> POSTDATED 'till %s <<]", bob);
951 if (token.endTime <= now)
952 printf("[>> Expired <<]\n");
954 ka_timestr(token.endTime, bob, KA_TIMESTR_LEN);
955 printf("[Expires %s]\n", bob);
958 printf("SessionKey: ");
959 ka_PrintBytes((char *)&token.sessionKey, sizeof(token.sessionKey));
960 printf("\nTicket (kvno = %d, len = %d): ", token.kvno,
962 ka_PrintBytes((char *)token.ticket, token.ticketLen);
969 GetTicket(struct cmd_syndesc *as, void *arock)
972 struct ktc_principal server;
973 struct ktc_token token;
974 afs_int32 life = KA_SIXHOURS;
976 if (as->parms[1].items) {
977 code = read_time_interval(as->parms[1].items->data, &life);
982 ka_ParseLoginName(as->parms[0].items->data, server.name,
983 server.instance, server.cell);
985 afs_com_err(whoami, code, "parsing user's name '%s'",
986 as->parms[0].items->data);
989 if (server.cell[0] == 0) {
990 if ((code = DefaultCell()))
992 strcpy(server.cell, cell);
994 code = ka_ExpandCell(server.cell, server.cell, 0 /*local */ );
996 afs_com_err(whoami, code, "Can't expand cell name");
1001 token.ticketLen = 0; /* in case there are no tokens */
1003 ka_GetServerToken(server.name, server.instance, server.cell, life,
1004 &token, /*new */ 1, /*dosetpag */ 0);
1006 afs_com_err(whoami, code, "getting ticket for %s",
1007 PrintedPrincipal(&server));
1009 code = ListTicket(&server, /*verbose */ 1);
1015 GetPassword(struct cmd_syndesc *as, void *arock)
1018 char name[MAXKTCNAMELEN];
1019 struct ktc_encryptionKey key;
1020 static struct ubik_client *lpbkConn = 0;
1022 /* no instance allowed */
1023 code = ka_ParseLoginName(as->parms[0].items->data, name, 0, 0);
1026 afs_com_err(whoami, code,
1027 "getting %s's password via loopback connection to GetPassword",
1029 /* if we got a timeout, print a clarification, too */
1032 "%s: please note that this command must be run locally on a database server machine.\n",
1037 if (lpbkConn == 0) {
1038 struct rx_connection *conns[2];
1039 struct rx_securityClass *sc;
1040 int si; /* security class index */
1045 sc = rxnull_NewClientSecurityObject();
1046 si = RX_SCINDEX_NULL;
1048 rx_NewConnection(htonl(INADDR_LOOPBACK), htons(AFSCONF_KAUTHPORT),
1049 KA_MAINTENANCE_SERVICE, sc, si);
1051 code = ubik_ClientInit(conns, &lpbkConn);
1055 code = ubik_KAM_GetPassword(lpbkConn, 0, name,
1056 ktc_to_EncryptionKey(&key));
1057 /* Lets close down the ubik_Client connection now */
1058 ubik_ClientDestroy(lpbkConn);
1062 ka_PrintBytes((char *)&key, sizeof(key));
1068 GetRandomKey(struct cmd_syndesc *as, void *arock)
1071 struct ktc_encryptionKey key;
1073 code = ubik_KAM_GetRandomKey(conn, 0, ktc_to_EncryptionKey(&key));
1075 afs_com_err(whoami, code, "so can't get random key");
1079 ka_PrintBytes((char *)&key, sizeof(key));
1081 for (i = 0; i < sizeof(key); i++) {
1082 printf("%.2x", ((char *)&key)[i] & 0xff);
1094 Statistics(struct cmd_syndesc *as, void *arock)
1100 char bob[KA_TIMESTR_LEN];
1103 ubik_KAM_GetStats(conn, 0, KAMAJORVERSION, &admins, &statics,
1106 printf("call to GetStats failed: %s\n", ka_ErrorString(code));
1109 if (statics.minor_version != KAMINORVERSION)
1110 printf("Minor version number mismatch: got %d, expected %d\n",
1111 statics.minor_version, KAMINORVERSION);
1112 printf("%d allocs, %d frees, %d password changes\n", statics.allocs,
1113 statics.frees, statics.cpws);
1114 printf("Hash table utilization = %f%%\n",
1115 (double)dynamics.hashTableUtilization / 100.0);
1116 ka_timestr(dynamics.start_time, bob, KA_TIMESTR_LEN);
1117 printf("From host %lx started at %s:\n",
1118 afs_printable_uint32_lu(dynamics.host), bob);
1120 #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)
1121 print_stat(Authenticate);
1122 print_stat(ChangePassword);
1123 print_stat(GetTicket);
1124 print_stat(CreateUser);
1125 print_stat(SetPassword);
1126 print_stat(SetFields);
1127 print_stat(DeleteUser);
1128 print_stat(GetEntry);
1129 print_stat(ListEntry);
1130 print_stat(GetStats);
1131 print_stat(GetPassword);
1132 print_stat(GetRandomKey);
1134 print_stat(UAuthenticate);
1135 print_stat(UGetTicket);
1137 #if (KAMAJORVERSION>5)
1138 print cpu stats printf("%d string checks\n", dynamics.string_checks);
1140 printf("Used %.3f seconds of CPU time.\n",
1141 dynamics.string_checks / 1000.0);
1143 printf("%d admin accounts\n", admins);
1148 DebugInfo(struct cmd_syndesc *as, void *arock)
1151 struct ka_debugInfo info;
1155 char bob[KA_TIMESTR_LEN];
1158 if (as->parms[0].items) {
1159 struct ubik_client *iConn;
1161 ka_SingleServerConn(cell, as->parms[0].items->data,
1162 KA_MAINTENANCE_SERVICE, 0, &iConn);
1164 struct afsconf_cell cellinfo;
1166 afs_com_err(whoami, code, "couldn't find host %s in cell %s",
1167 as->parms[0].items->data, cell);
1168 code = ka_GetServers(cell, &cellinfo);
1170 afs_com_err(whoami, code, "getting servers in cell %s", cell);
1172 printf("Servers in cell %s, are:\n", cell);
1173 for (i = 0; i < cellinfo.numServers; i++)
1174 printf(" %s\n", cellinfo.hostName[i]);
1178 code = ubik_KAM_Debug(iConn, 0, KAMAJORVERSION, 0, &info);
1179 ubik_ClientDestroy(iConn);
1181 code = ubik_KAM_Debug(conn, 0, KAMAJORVERSION, 0, &info);
1184 afs_com_err(whoami, code, "call to Debug failed");
1189 if (info.minorVersion != KAMINORVERSION)
1190 printf("Minor version number mismatch: got %d, expected %d\n",
1191 info.minorVersion, KAMINORVERSION);
1194 #if (KAMAJORVERSION>5)
1201 timeOffset = -timeOffset;
1202 if (timeOffset > 60) {
1204 ("WARNING: Large server client clock skew: %d seconds. Call itself took %d seconds.\n",
1205 timeOffset, now - start);
1207 ka_timestr(info.startTime, bob, KA_TIMESTR_LEN);
1208 printf("From host %lx started %sat %s:\n",
1209 afs_printable_uint32_lu(info.host),
1210 (info.noAuth ? "w/o authorization " : ""), bob);
1211 ka_timestr(info.lastTrans, bob, KA_TIMESTR_LEN);
1212 printf("Last trans was %s at %s\n", info.lastOperation, bob);
1213 ka_timestr(info.dbHeaderRead, bob, KA_TIMESTR_LEN);
1214 printf("Header last read %s.\n", bob);
1215 printf("db version=%d, keyVersion=%d, key cache version=%d\n",
1216 info.dbVersion, info.dbSpecialKeysVersion, info.kcVersion);
1217 printf("db ptrs: free %d, eof %d, kvno %d.\n", info.dbFreePtr,
1218 info.dbEofPtr, info.dbKvnoPtr);
1219 ka_timestr(info.nextAutoCPW, bob, KA_TIMESTR_LEN);
1220 printf("Next autoCPW at %s or in %d updates.\n", bob,
1221 info.updatesRemaining);
1222 if (info.cheader_lock || info.keycache_lock)
1223 printf("locks: cheader %08lx, keycache %08lx\n",
1224 afs_printable_uint32_lu(info.cheader_lock),
1225 afs_printable_uint32_lu(info.keycache_lock));
1226 printf("Last authentication for %s, last admin user was %s\n",
1227 info.lastAuth, info.lastAdmin);
1228 printf("Last TGS op was a %s ticket was for %s\n", info.lastTGSServer,
1230 printf("Last UDP TGS was a %s ticket for %s. UDP Authenticate for %s\n",
1231 info.lastUTGSServer, info.lastUTGS, info.lastUAuth);
1232 printf("key cache size %d, used %d.\n", info.kcSize, info.kcUsed);
1233 if (info.kcUsed > KADEBUGKCINFOSIZE) {
1234 printf("insufficient room to return all key cache entries!\n");
1235 info.kcUsed = KADEBUGKCINFOSIZE;
1237 for (i = 0; i < info.kcUsed; i++)
1238 ka_timestr(info.kcInfo[i].used, bob, KA_TIMESTR_LEN);
1239 printf("%32s %c %2x(%2x) used %s\n", info.kcInfo[i].principal,
1240 (info.kcInfo[i].primary ? '*' : ' '), info.kcInfo[i].kvno,
1241 info.kcInfo[i].keycksum, bob);
1246 Interactive(struct cmd_syndesc *as, void *arock)
1253 Quit(struct cmd_syndesc *as, void *arock)
1260 MyAfterProc(struct cmd_syndesc *as, void *arock)
1262 if (!strcmp(as->name, "help"))
1265 /* Determine if we need to destory the ubik connection.
1266 * Closing it avoids resends of packets.
1269 ubik_ClientDestroy(conn);
1276 int init = 0, noauth;
1277 char name[MAXKTCNAMELEN];
1278 char instance[MAXKTCNAMELEN];
1279 char newCell[MAXKTCREALMLEN];
1280 afs_uint32 serverList[MAXSERVERS];
1283 NoAuth(struct cmd_syndesc *as, void *arock)
1290 MyBeforeProc(struct cmd_syndesc *as, void *arock)
1292 struct ktc_encryptionKey key;
1293 struct ktc_principal auth_server, client;
1294 struct ktc_token auth_token;
1295 char realm[MAXKTCREALMLEN];
1297 struct ktc_token token, *pToken;
1298 int i, acode, code = 0;
1301 char *ws = strrchr(as->a0name, '/');
1303 ws++; /* skip everything before the "/" */
1306 if (strlen(ws) > 0) {
1307 strncpy(whoami, ws, sizeof(whoami));
1308 if (strlen(whoami) + 1 >= sizeof(whoami))
1309 strcpy(whoami, "kas:");
1311 strcat(whoami, ":");
1314 /* append sub-command name */
1315 strncat(whoami, as->name, sizeof(whoami) - strlen(whoami) - 1);
1318 if (as->parms[12].name == 0)
1321 assert(as->parms[13].name && as->parms[14].name && as->parms[15].name
1322 && as->parms[16].name);
1324 /* MyAfterProc() destroys the conn, but just to be sure */
1326 code = ubik_ClientDestroy(conn);
1330 if (!init || as->parms[12].items || as->parms[13].items
1331 || as->parms[14].items || as->parms[15].items
1332 || as->parms[16].items) {
1333 strcpy(instance, "");
1334 strcpy(newCell, "");
1336 if (as->parms[12].items) { /* -admin_username */
1338 ka_ParseLoginName(as->parms[12].items->data, name, instance,
1341 afs_com_err(whoami, code, "parsing user's name '%s'",
1342 as->parms[12].items->data);
1347 DWORD len = MAXKTCNAMELEN;
1348 if (!GetUserName((LPTSTR) name, &len)) {
1349 printf("Can't get user name \n");
1353 /* No explicit name provided: use Unix uid. */
1354 struct passwd *pw = getpwuid(getuid());
1356 printf("Can't figure out your name from your user id.\n");
1359 strncpy(name, pw->pw_name, sizeof(name));
1363 if (as->parms[14].items) { /* -cell */
1364 if (strlen(newCell) > 0) {
1365 printf("Duplicate cell specification not allowed\n");
1367 strncpy(newCell, as->parms[14].items->data, sizeof(newCell));
1370 code = ka_ExpandCell(newCell, newCell, 0 /*local */ );
1372 afs_com_err(whoami, code, "Can't expand cell name");
1375 strcpy(cell, newCell);
1377 if (as->parms[15].items) { /* -servers */
1378 struct cmd_item *ip;
1379 char *ap[MAXSERVERS + 2];
1383 for (ip = as->parms[15].items, i = 2; ip; ip = ip->next, i++)
1385 code = ubik_ParseClientList(i, ap, serverList);
1387 afs_com_err(whoami, code, "could not parse server list");
1390 ka_ExplicitCell(cell, serverList);
1393 noauth = (as->parms[16].items ? 1 : 0); /* -noauth */
1398 token.ticketLen = 0; /* in case there are no tokens */
1399 if (!noauth) { /* Will prompt for a password */
1400 /* first see if there's already an admin ticket */
1402 ka_GetAdminToken(0, 0, cell, 0, KA_SIXHOURS, &token,
1404 if (code) { /* if not then get key and try again */
1405 if (as->parms[13].items) { /* if password specified */
1406 strncpy(passwd, as->parms[13].items->data, sizeof(passwd));
1407 memset(as->parms[13].items->data, 0,
1408 strlen(as->parms[13].items->data));
1410 char msg[MAXKTCNAMELEN + 50];
1411 if (as->parms[12].items)
1412 sprintf(msg, "Administrator's (%s) Password: ", name);
1414 sprintf(msg, "Password for %s: ", name);
1415 code = read_pw_string(passwd, sizeof(passwd), msg, 0);
1418 else if (strlen(passwd) == 0)
1419 code = KANULLPASSWORD;
1421 afs_com_err(whoami, code, "reading password");
1425 ka_StringToKey(passwd, cell, &key);
1427 ka_GetAdminToken(name, instance, cell, &key, KA_SIXHOURS,
1428 &token, 0 /* !new */ );
1429 if (code == KABADREQUEST) {
1430 des_string_to_key(passwd, ktc_to_cblockptr(&key));
1432 ka_GetAdminToken(name, instance, cell, &key, KA_SIXHOURS,
1433 &token, 0 /* !new */ );
1435 if ((code == KABADREQUEST) && (strlen(passwd) > 8)) {
1436 /* try with only the first 8 characters incase they set
1437 * their password with an old style passwd program. */
1439 ka_StringToKey(passwd, cell, &key);
1441 ka_GetAdminToken(name, instance, cell, &key, KA_SIXHOURS,
1442 &token, 0 /* !new */ );
1445 "Warning: you have typed a password longer than 8 characters, but only the\n");
1447 "first 8 characters were actually significant. If you change your password\n");
1449 "again this warning message will go away.\n");
1456 reason = "password was incorrect";
1459 reason = "Authentication Server was unavailable";
1462 reason = (char *)afs_error_message(code);
1465 "%s: Auth. as %s to AuthServer failed: %s\nProceeding w/o authentication\n",
1466 whoami, PrintedName(name, instance, cell), reason);
1468 /* get an Authentication token while were at it. */
1469 if (ka_CellToRealm(cell, realm, 0) != 0)
1471 strcpy(auth_server.name, KA_TGS_NAME);
1472 strcpy(auth_server.instance, realm);
1473 strcpy(auth_server.cell, cell);
1475 (&auth_server, &auth_token, sizeof(struct ktc_token),
1478 ka_GetAuthToken(name, instance, cell, &key,
1479 MAXKTCTICKETLIFETIME, (afs_int32 *) 0
1480 /*Don't need pwd expiration info here */
1482 if (acode && (acode != code)) /* codes are usually the same */
1483 afs_com_err(whoami, code,
1484 "getting Authentication token for %s",
1485 PrintedName(name, instance, cell));
1487 memset(&key, 0, sizeof(key));
1491 pToken = ((token.ticketLen == 0) ? 0 : &token);
1492 code = ka_AuthServerConn(cell, KA_MAINTENANCE_SERVICE, pToken, &conn);
1493 if (code && pToken) {
1494 afs_com_err(whoami, code,
1495 "connecting to AuthServer: now trying w/o authentication");
1496 code = ka_AuthServerConn(cell, KA_MAINTENANCE_SERVICE, 0, &conn);
1498 afs_com_err(whoami, code,
1499 "making unauthenticated connection to AuthServer");
1502 afs_com_err(whoami, code,
1503 "Couldn't establish connection to Authentication Server");
1507 /* now default unspecified password by prompting from terminal */
1508 if (as->nParms >= 12)
1509 for (i = 0; i < 12; i++)
1510 if (as->parms[i].name && (as->parms[i].items == 0)) {
1511 char *p = as->parms[i].name; /* parameter name */
1512 int l = strlen(p); /* length of name */
1513 /* does parameter end in "password" */
1514 if (strcmp(p + (l - 8), "password") == 0) {
1516 char password[BUFSIZ];
1517 struct cmd_item *ip;
1521 code = read_pw_string(password, sizeof(password), msg, 1);
1524 else if (strlen(password) == 0)
1525 code = KANULLPASSWORD;
1527 afs_com_err(whoami, code, "prompting for %s", p + 1);
1530 ip = (struct cmd_item *)malloc(sizeof(struct cmd_item));
1531 ip->data = (char *)malloc(strlen(password) + 1);
1533 strcpy(ip->data, password);
1534 as->parms[i].items = ip;
1537 if (!conn) { /* if all else fails... */
1538 code = NoAuth(0, 0); /* get unauthenticated conn */
1545 /* These are some helpful command that deal with the cache managers tokens. */
1548 ForgetTicket(struct cmd_syndesc *as, void *arock)
1553 struct ktc_principal server;
1555 if (as->parms[0].items) {
1556 char *name = as->parms[0].items->data;
1558 ka_ParseLoginName(name, server.name, server.instance,
1561 afs_com_err(whoami, code, "couldn't interpret name '%s'", name);
1564 if (server.cell[0] == 0) {
1565 if (code = DefaultCell())
1567 strcpy(server.cell, cell);
1569 code = ka_ExpandCell(server.cell, server.cell, 0 /*local */ );
1571 afs_com_err(whoami, code, "Can't expand cell name");
1575 code = ktc_ForgetToken(&server);
1577 afs_com_err(whoami, code, "couldn't remove tokens for %s",
1578 PrintedPrincipal(&server));
1582 if (!as->parms[1].items) {
1583 fprintf(stderr, "Must specify server name or -all\n");
1586 code = ktc_ForgetAllTokens();
1588 afs_com_err(whoami, code, "couldn't delete all tokens");
1593 code = ktc_ForgetAllTokens();
1595 afs_com_err(whoami, code, "couldn't delete all tokens");
1602 ListTickets(struct cmd_syndesc *as, void *arock)
1605 int index, newIndex;
1606 struct ktc_principal server;
1609 if (as->parms[1].items)
1611 if (as->parms[0].items) {
1612 char *name = as->parms[0].items->data;
1614 ka_ParseLoginName(name, server.name, server.instance,
1617 afs_com_err(whoami, code, "couldn't interpret name '%s'", name);
1620 if (server.cell[0] == 0) {
1621 if ((code = DefaultCell()))
1623 strcpy(server.cell, cell);
1625 code = ka_ExpandCell(server.cell, server.cell, 0 /*local */ );
1627 afs_com_err(whoami, code, "Can't expand cell name");
1631 code = ListTicket(&server, verbose);
1633 for (index = 0;; index = newIndex) {
1634 code = ktc_ListTokens(index, &newIndex, &server);
1636 if (code == KTC_NOENT)
1637 code = 0; /* end of list */
1640 code = ListTicket(&server, verbose);
1646 add_std_args(struct cmd_syndesc *ts)
1649 /* 12 */ cmd_AddParm(ts, "-admin_username", CMD_SINGLE, CMD_OPTIONAL,
1650 "admin principal to use for authentication");
1651 /* 13 */ cmd_AddParm(ts, "-password_for_admin", CMD_SINGLE, CMD_OPTIONAL,
1653 /* 14 */ cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
1654 /* 15 */ cmd_AddParm(ts, "-servers", CMD_LIST, CMD_OPTIONAL,
1655 "explicit list of authentication servers");
1656 /* 16 */ cmd_AddParm(ts, "-noauth", CMD_FLAG, CMD_OPTIONAL,
1657 "don't authenticate");
1661 ka_AdminInteractive(int cmd_argc, char *cmd_argv[])
1664 struct cmd_syndesc *ts;
1670 strncpy(myName, *cmd_argv, 509);
1672 cmd_SetBeforeProc(MyBeforeProc, NULL);
1673 cmd_SetAfterProc(MyAfterProc, NULL);
1675 ts = cmd_CreateSyntax("interactive", Interactive, NULL,
1676 "enter interactive mode");
1679 ts = cmd_CreateSyntax("noauthentication", NoAuth, NULL,
1680 "connect to AuthServer w/o using token");
1682 ts = cmd_CreateSyntax("list", ListUsers, NULL,
1683 "list all users in database");
1684 cmd_AddParm(ts, "-long", CMD_FLAG, CMD_OPTIONAL,
1685 "show detailed info about each user");
1686 cmd_AddParm(ts, "-showadmin", CMD_FLAG, CMD_OPTIONAL,
1687 "show all cell administrators");
1688 cmd_AddParm(ts, "-showkey", CMD_FLAG, CMD_OPTIONAL,
1689 "show the user's actual key rather than the checksum");
1691 cmd_CreateAlias(ts, "ls");
1693 ts = cmd_CreateSyntax("examine", ExamineUser, NULL,
1694 "examine the entry for a user");
1695 cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1696 cmd_AddParm(ts, "-showkey", CMD_FLAG, CMD_OPTIONAL,
1697 "show the user's actual key rather than the checksum");
1700 ts = cmd_CreateSyntax("create", CreateUser, NULL,
1701 "create an entry for a user");
1702 cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1703 cmd_AddParm(ts, "-initial_password", CMD_SINGLE, CMD_OPTIONAL,
1704 "initial password");
1707 ts = cmd_CreateSyntax("delete", DeleteUser, NULL, "delete a user");
1708 cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1710 cmd_CreateAlias(ts, "rm");
1712 ts = cmd_CreateSyntax("setfields", SetFields, NULL,
1713 "set various fields in a user's entry");
1714 cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1715 cmd_AddParm(ts, "-flags", CMD_SINGLE, CMD_OPTIONAL,
1716 "hex flag value or flag name expression");
1717 cmd_AddParm(ts, "-expiration", CMD_SINGLE, CMD_OPTIONAL,
1718 "date of account expiration");
1719 cmd_AddParm(ts, "-lifetime", CMD_SINGLE, CMD_OPTIONAL,
1720 "maximum ticket lifetime");
1721 cmd_AddParm(ts, "-pwexpires", CMD_SINGLE, CMD_OPTIONAL,
1722 "number days password is valid ([0..254])");
1723 cmd_AddParm(ts, "-reuse", CMD_SINGLE, CMD_OPTIONAL,
1724 "permit password reuse (yes/no)");
1725 cmd_AddParm(ts, "-attempts", CMD_SINGLE, CMD_OPTIONAL,
1726 "maximum successive failed login tries ([0..254])");
1727 cmd_AddParm(ts, "-locktime", CMD_SINGLE, CMD_OPTIONAL,
1728 "failure penalty [hh:mm or minutes]");
1730 cmd_AddParm(ts, "-associates", CMD_SINGLE, CMD_OPTIONAL,
1731 "maximum associate instances");
1734 cmd_CreateAlias(ts, "sf");
1737 ts = cmd_CreateSyntax("unlock", Unlock, NULL,
1738 "Enable authentication ID after max failed attempts exceeded");
1739 cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "authentication ID");
1743 ts = cmd_CreateSyntax("stringtokey", StringToKey, NULL,
1744 "convert a string to a key");
1745 cmd_AddParm(ts, "-string", CMD_SINGLE, 0, "password string");
1746 cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
1748 ts = cmd_CreateSyntax("setpassword", SetPassword, NULL,
1749 "set a user's password");
1750 cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1751 cmd_AddParm(ts, "-new_password", CMD_SINGLE, CMD_OPTIONAL,
1754 cmd_AddParm(ts, "-kvno", CMD_SINGLE, CMD_OPTIONAL, "key version number");
1756 cmd_CreateAlias(ts, "sp");
1757 #ifdef CMD_PARSER_AMBIG_FIX
1758 cmd_CreateAlias(ts, "setpasswd");
1761 /* set a user's key */
1762 ts = cmd_CreateSyntax("setkey", SetPassword, NULL, (char *)CMD_HIDDEN);
1763 cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1765 cmd_AddParm(ts, "-new_key", CMD_SINGLE, 0, "eight byte new key");
1767 cmd_AddParm(ts, "-kvno", CMD_SINGLE, CMD_OPTIONAL, "key version number");
1770 /* get a user's password */
1771 ts = cmd_CreateSyntax("getpassword", GetPassword, NULL, (char *)CMD_HIDDEN);
1772 cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1773 /* don't take standard args */
1774 /* add_std_args (ts); */
1775 #ifdef CMD_PARSER_AMBIG_FIX
1776 cmd_CreateAlias(ts, "getpasswd");
1779 /* get a random key */
1780 ts = cmd_CreateSyntax("getrandomkey", GetRandomKey, NULL,
1781 (char *)CMD_HIDDEN);
1784 /* get a ticket for a specific server */
1785 ts = cmd_CreateSyntax("getticket", GetTicket, NULL, (char *)CMD_HIDDEN);
1786 cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of server");
1787 cmd_AddParm(ts, "-lifetime", CMD_SINGLE, CMD_OPTIONAL, "ticket lifetime");
1790 ts = cmd_CreateSyntax("statistics", Statistics, NULL,
1791 "show statistics for AuthServer");
1794 /* show debugging info from AuthServer */
1795 ts = cmd_CreateSyntax("debuginfo", DebugInfo, NULL, (char *)CMD_HIDDEN);
1796 cmd_AddParm(ts, "-hostname", CMD_SINGLE, CMD_OPTIONAL,
1797 "authentication server host name");
1800 ts = cmd_CreateSyntax("forgetticket", ForgetTicket, NULL,
1801 "delete user's tickets");
1803 cmd_AddParm(ts, "-name", CMD_SINGLE, (CMD_OPTIONAL | CMD_HIDE),
1806 cmd_AddParm(ts, "-all", CMD_FLAG, CMD_OPTIONAL, "delete all tickets");
1808 ts = cmd_CreateSyntax("listtickets", ListTickets, NULL,
1809 "show all cache manager tickets");
1810 cmd_AddParm(ts, "-name", CMD_SINGLE, CMD_OPTIONAL, "name of server");
1811 cmd_AddParm(ts, "-long", CMD_FLAG, CMD_OPTIONAL,
1812 "show session key and ticket");
1814 ts = cmd_CreateSyntax("quit", Quit, NULL, "exit program");
1817 conn = 0; /* no connection yet */
1818 zero_argc = cmd_argc;
1819 zero_argv = cmd_argv;
1821 strcpy(whoami, "kas");
1823 if ((code = cmd_Dispatch(cmd_argc, cmd_argv))) {
1832 s = fgets(line, sizeof(line), stdin);
1834 return 0; /* EOF on input */
1835 for (i = strlen(line) - 1; i >= 0 && isspace(line[i]); i--)
1838 continue; /* blank line */
1841 cmd_ParseLine(line, argv, &argc, sizeof(argv) / sizeof(argv[0]));
1843 afs_com_err(whoami, code, "parsing line: '%s'", line);
1846 code = cmd_Dispatch(argc, argv);