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>
50 #define CMD_PARSER_AMBIG_FIX 1 /* allow ambiguous aliases */
52 #define KA_SIXHOURS (6*3600)
54 static struct ubik_client *conn;
55 static char cell[MAXKTCREALMLEN] = "";
56 static char whoami[32];
57 static char passwd[BUFSIZ];
58 static char myName[510]; /* almost like whoami save with path and without : */
62 static char **zero_argv;
63 afs_uint32 ka_islocked(char *, char *, afs_uint32 *);
72 code = ka_ExpandCell(0, cell, 0 /*local */ );
74 afs_com_err(whoami, code, "Can't expand cell name");
79 /* These are the command operation procedures. */
82 DumpUser(char *user, char *arock, int showadmin, int showkey, char *inst)
84 char name[MAXKTCNAMELEN];
85 char instance[MAXKTCNAMELEN];
88 char bob[KA_TIMESTR_LEN];
90 struct kaentryinfo tentry;
92 code = ka_ParseLoginName(user, name, instance, 0);
94 afs_com_err(whoami, code, "parsing user's name '%s'", user);
101 ubik_Call(KAM_GetEntry, conn, 0, name, inst, KAMAJORVERSION, &tentry);
103 afs_com_err(whoami, code, "getting information for %s.%s", name, inst);
106 if (tentry.minor_version != KAMINORVERSION)
107 printf("Minor version number mismatch: got %d, expected %d\n",
108 tentry.minor_version, KAMINORVERSION);
109 if (showadmin && !(tentry.flags & KAFADMIN))
111 ka_PrintUserID("\nUser data for ", name, inst, "");
114 #define NEWPREFIX "+"
115 if (tentry.flags & KAFADMIN) {
116 printf("%sADMIN", prefix);
119 if (tentry.flags & KAFNOTGS) {
120 printf("%sNOTGS", prefix);
123 if (tentry.flags & KAFNOCPW) {
124 printf("%sNOCPW", prefix);
127 if (tentry.flags & KAFNOSEAL) {
128 printf("%sNOSEAL", prefix);
131 if (tentry.flags & KAFNEWASSOC) {
132 printf("%sNEWASSOC", prefix);
135 if (tentry.flags & KAFASSOCROOT) {
136 printf("%sASSOCROOT", prefix);
139 if (tentry.flags & KAFASSOC) {
140 printf("%sASSOC", prefix);
143 if (tentry.user_expiration <= now) {
144 printf("%sexpired", prefix);
147 if (strcmp(prefix, NEWPREFIX) == 0)
152 if ((!ka_KeyIsZero((char *)&tentry.key, sizeof(tentry.key))) && (showkey)) {
153 printf(" key (%d):", tentry.key_version);
154 ka_PrintBytes((char *)&tentry.key, sizeof(tentry.key));
156 if (tentry.keyCheckSum == 0)
157 printf(" key version is %d", tentry.key_version);
159 printf(" key (%d) cksum is %u", tentry.key_version,
162 ka_timestr(tentry.change_password_time, bob, KA_TIMESTR_LEN);
163 printf(", last cpw: %s\n", bob);
164 if (!tentry.misc_auth_bytes) {
165 printf(" password will never expire.\n");
167 (" An unlimited number of unsuccessful authentications is permitted.\n");
169 unsigned char misc_stuff[4];
172 temp = tentry.misc_auth_bytes;
174 temp = ntohl(tentry.misc_auth_bytes);
176 unpack_long(temp, misc_stuff);
178 if (!misc_stuff[0]) {
179 printf(" password will never expire.\n");
181 ka_timestr((tentry.change_password_time +
182 misc_stuff[0] * 24 * 60 * 60), bob, KA_TIMESTR_LEN);
183 printf(" password will expire: %s\n", bob);
188 (" An unlimited number of unsuccessful authentications is permitted.\n");
191 (" %d consecutive unsuccessful authentications are permitted.\n",
195 printf(" The lock time for this user is not limited.\n");
197 printf(" The lock time for this user is %4.1f minutes.\n",
198 (float)((unsigned int)misc_stuff[3] << 9) / 60.0);
200 if (!(misc_stuff[1] & KA_ISLOCKED)
201 || !ka_islocked(name, instance, &temp))
202 printf(" User is not locked.\n");
203 else if (temp == (afs_uint32) (-1L))
204 printf(" User is locked forever.\n");
206 ka_timestr(temp, bob, KA_TIMESTR_LEN);
207 printf(" User is locked until %s\n", bob);
213 char exp[KA_TIMESTR_LEN];
214 ka_timestr(tentry.user_expiration, exp, KA_TIMESTR_LEN);
215 if (tentry.user_expiration < now)
216 printf(" DISABLED entry at %s.", exp);
217 else if (tentry.user_expiration == NEVERDATE)
218 printf(" entry never expires.");
220 printf(" entry expires on %s.", exp);
222 printf(" Max ticket lifetime %.2f hours.\n",
223 tentry.max_ticket_lifetime / 3600.0);
224 ka_timestr(tentry.modification_time, bob, KA_TIMESTR_LEN);
225 printf(" last mod on %s by ", bob);
226 ka_PrintUserID("", tentry.modification_user.name,
227 tentry.modification_user.instance, "\n");
228 if ((tentry.reserved3 & 0xffff0000) == 0x12340000) {
229 int short reused = (short)tentry.reserved3;
231 printf(" permit password reuse\n");
233 printf(" don't permit password reuse\n");
240 ListUsers(struct cmd_syndesc *as, void *arock)
245 afs_int32 next_index;
246 int code, all = 0, showa = 0;
247 int showkey = (as->parms[2].items != NULL);
249 if (as->parms[0].items)
251 if (as->parms[1].items) {
255 for (index = 0; 1; index = next_index) {
257 ubik_Call(KAM_ListEntry, conn, 0, index, &next_index, &count,
260 afs_com_err(whoami, code, "calling KAM_ListEntry");
266 printf("next_index (%d) is negative: ", next_index);
267 if (strlen(name.name) == 0)
268 printf("name is zero length: ");
270 DumpUser(name.name, NULL, showa, showkey, name.instance);
272 ka_PrintUserID("", name.name, name.instance, "\n");
279 ExamineUser(struct cmd_syndesc *as, void *arock)
281 int showkey = (as->parms[1].items != NULL);
282 return DumpUser(as->parms[0].items->data, arock, 0, showkey, NULL);
292 handle_errors(int code, /* error code to handle */
293 struct OKerrors OKlist[], /* list of errors & messages that should be ignored */
295 { /* set this if we should retry, clear otherwise */
298 for (i = 0; OKlist[i].code; i++) {
299 if (OKlist[i].code == code) {
300 printf("%s\n", OKlist[i].msg);
301 *persist = 0; /* we're done */
306 printf(" : [%s] %s", afs_error_table_name(code), afs_error_message(code));
309 printf(", wait one second\n");
313 case RX_CALL_TIMEOUT:
314 printf(" (retrying)\n");
319 *persist = 0; /* don't retry these errors */
324 CreateUser(struct cmd_syndesc *as, void *arock)
327 char name[MAXKTCNAMELEN];
328 char instance[MAXKTCNAMELEN];
329 struct ktc_encryptionKey key;
332 struct OKerrors OKlist[2];
335 code = ka_ParseLoginName(as->parms[0].items->data, name, instance, 0);
337 afs_com_err(whoami, code, "parsing user's name '%s'",
338 as->parms[0].items->data);
341 ka_StringToKey(as->parms[1].items->data, cell, &key);
344 code = ubik_Call(KAM_CreateUser, conn, 0, name, instance, key);
347 ka_PrintUserID("Creating user ", name, instance, " ");
348 code = handle_errors(code, OKlist, &persist);
354 DeleteUser(struct cmd_syndesc *as, void *arock)
357 char name[MAXKTCNAMELEN];
358 char instance[MAXKTCNAMELEN];
361 struct OKerrors OKlist[2];
363 code = ka_ParseLoginName(as->parms[0].items->data, name, instance, 0);
365 afs_com_err(whoami, code, "parsing user's name '%s'",
366 as->parms[0].items->data);
371 code = ubik_Call(KAM_DeleteUser, conn, 0, name, instance);
374 ka_PrintUserID("Deleting user ", name, instance, " ");
375 code = handle_errors(code, OKlist, &persist);
381 read_time_interval(char *str, afs_int32 * seconds)
387 str = strncpy(buf, str, sizeof(buf));
388 s = strchr(str, ':');
392 *s++ = '\0'; /* separate hours and minutes */
393 sec = atoi(str) * 3600 + atoi(s) * 60;
400 parse_flags(char *name, char *inst, char *str, afs_int32 * flags)
402 struct kaentryinfo tentry;
408 int addop; /* 1=add bit; 0=remove bit */
412 str = lcstring(bitspec, str, sizeof(bitspec));
414 if (strncmp(str, "0x", 2) == 0) /* 0x => hex */
415 sscanf(str, "0x%lx", (long unsigned int *) &f);
416 else if (*str == '0') /* assume octal */
417 sscanf(str, "%lo", (long unsigned int *) &f);
418 else /* just assume hex */
419 sscanf(str, "%lx", (long unsigned int *) &f);
426 if (strchr("+-", *str))
427 addop = (*str++ == '+');
428 else if (*str == '_') {
434 ubik_Call(KAM_GetEntry, conn, 0, name, inst, KAMAJORVERSION,
437 afs_com_err(whoami, code,
438 "could get current flag value for %s.%s", name, inst);
455 if (strcmp(bit, "admin") == 0)
457 else if (strcmp(bit, "noadmin") == 0)
458 flag = KAFADMIN, addop = !addop;
459 else if (strcmp(bit, "notgs") == 0)
461 else if (strcmp(bit, "tgs") == 0)
462 flag = KAFNOTGS, addop = !addop;
463 else if (strcmp(bit, "noseal") == 0)
465 else if (strcmp(bit, "seal") == 0)
466 flag = KAFNOSEAL, addop = !addop;
467 else if (strcmp(bit, "nocpw") == 0)
469 else if (strcmp(bit, "cpw") == 0)
470 flag = KAFNOCPW, addop = !addop;
471 else if (strcmp(bit, "newassoc") == 0)
473 else if (strcmp(bit, "nonewassoc") == 0)
474 flag = KAFNEWASSOC, addop = !addop;
477 ("Illegal bit name: %s; choices are: [no]admin, [no]tgs, [no]seal, [no]cpw\n",
490 addop = 1; /* get next op */
491 else if ((*str == '-') || (*str == '_'))
494 printf("Illegal combination operator: %c\n", *str);
500 *flags = (f & KAF_SETTABLE_FLAGS) | KAFNORMAL;
504 #define seriouserror(code) ((code <0) || ((code != UNOSERVERS) && (code != UNOQUORUM) && code != UNOTSYNC))
506 /* return MAXLONG if locked forever */
508 ka_islocked(char *name, char *instance, afs_uint32 * when)
518 ubik_CallIter(KAM_LockStatus, conn, UPUBIKONLY, &count, (long) name,
519 (long) instance, (long) &tempwhen, 0, 0, 0,
520 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
522 if (seriouserror(code))
523 afs_com_err(whoami, code, "");
524 } else if (tempwhen) { /* user is locked */
525 if (!*when || tempwhen < *when) {
529 } else /* ! tempwhen ==> user is not locked */
532 } while (code != UNOSERVERS);
538 Unlock(struct cmd_syndesc *as, void *arock)
540 afs_int32 code, rcode = 0;
543 char name[MAXKTCNAMELEN];
544 char instance[MAXKTCNAMELEN];
546 code = ka_ParseLoginName(as->parms[0].items->data, name, instance, 0);
548 afs_com_err(whoami, code, "parsing user's name '%s'",
549 as->parms[0].items->data);
555 code = ubik_CallIter(KAM_Unlock, conn, 0, &count, (long) name, (long) instance,
556 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
557 if (code && (code != UNOSERVERS)) {
559 if (conn && conn->conns[count - 1]
560 && conn->conns[count - 1]->peer) {
561 server = conn->conns[count - 1]->peer->host;
563 afs_com_err(whoami, code,
564 "so %s.%s may still be locked (on server %d.%d.%d.%d)",
565 name, instance, ((server >> 24) & 0xFF),
566 ((server >> 16) & 0xFF), ((server >> 8) & 0xFF),
573 } while (code != UNOSERVERS);
579 SetFields(struct cmd_syndesc *as, void *arock)
582 char name[MAXKTCNAMELEN];
583 char instance[MAXKTCNAMELEN];
586 afs_int32 lifetime = 0;
587 afs_int32 maxAssociates = -1;
588 afs_int32 pwexpiry = 0;
589 afs_int32 was_spare = 0;
590 char misc_auth_bytes[4];
593 code = ka_ParseLoginName(as->parms[0].items->data, name, instance, 0);
595 afs_com_err(whoami, code, "parsing user's name '%s'",
596 as->parms[0].items->data);
600 if (as->parms[1].items) {
601 code = parse_flags(name, instance, as->parms[1].items->data, &flags);
604 ("Illegal flag specification: %s, should be of the form <'='|'+'|'-'|'_'>bitname{<'+'|'-'>bitname}*\n",
605 as->parms[1].items->data);
609 if (as->parms[2].items) {
611 char *s = strncpy(buf, as->parms[2].items->data, sizeof(buf));
612 code = ktime_DateToInt32(s, &expiration);
614 printf("Illegal time format %s: %s\n", as->parms[2].items->data,
615 ktime_GetDateUsage());
618 if (expiration == 0) {
619 fprintf(stderr, "Expiration time must be after (about) 1970.\n");
622 if (expiration < time(0)) {
624 "Warning: expiration being set into the past, account will be disabled.\n");
630 if (as->parms[3].items) {
631 code = read_time_interval(as->parms[3].items->data, &lifetime);
636 /* no point in doing this any sooner than necessary */
637 for (i = 0; i < 4; misc_auth_bytes[i++] = 0);
639 if (as->parms[4].items) {
640 if (util_isint(as->parms[4].items->data))
641 pwexpiry = atoi(as->parms[4].items->data);
644 "Password lifetime specified must be a non-negative decimal integer.\n");
647 if (pwexpiry < 0 || pwexpiry > 254) {
649 "Password lifetime range must be [0..254] days.\n");
650 fprintf(stderr, "Zero represents an unlimited lifetime.\n");
653 misc_auth_bytes[0] = pwexpiry + 1;
657 if (as->parms[5].items) {
659 reuse = (as->parms[5].items->data);
661 if (!strcmp(reuse, "yes")) {
662 misc_auth_bytes[1] = KA_REUSEPW;
663 } else if (strcmp(reuse, "no")) {
665 "must specify \"yes\" or \"no\": \"yes\" assumed\n");
666 misc_auth_bytes[1] = KA_REUSEPW;
668 misc_auth_bytes[1] = KA_NOREUSEPW;
672 if (as->parms[6].items) {
676 if (util_isint(as->parms[6].items->data)
677 && ((nfailures = atoi(as->parms[6].items->data)) < 255)) {
678 misc_auth_bytes[2] = nfailures + 1;
680 fprintf(stderr, "Failure limit must be in [0..254].\n");
681 fprintf(stderr, "Zero represents unlimited login attempts.\n");
686 if (as->parms[7].items) {
687 int locktime, hrs, mins;
691 s = as->parms[7].items->data;
693 sscanf(s, "%d:%d", &hrs, &mins);
695 sscanf(s, "%d", &mins);
697 locktime = hrs * 60 + mins;
698 if (hrs < 0 || hrs > 36 || mins < 0) {
700 "Lockout times must be either minutes or hh:mm.\n");
701 fprintf(stderr, "Lockout times must be less than 36 hours.\n");
703 } else if (locktime > 36 * 60) {
705 "Lockout times must be either minutes or hh:mm.\n");
706 fprintf(stderr, "Lockout times must be less than 36 hours.\n");
708 "Continuing with lock time of exactly 36 hours...\n");
711 locktime = (locktime * 60 + 511) >> 9; /* ceil(l*60/512) */
712 misc_auth_bytes[3] = locktime + 1; /* will be 1 if user said 0 */
715 if (as->parms[8].items) {
716 maxAssociates = atoi(as->parms[6].items->data);
717 if (maxAssociates < 0) {
718 printf("Illegal maximum number of associates\n");
723 was_spare = pack_long(misc_auth_bytes);
725 if (was_spare || flags || expiration || lifetime || (maxAssociates >= 0))
727 ubik_Call(KAM_SetFields, conn, 0, name, instance, flags,
728 expiration, lifetime, maxAssociates, was_spare,
731 printf("Must specify one of the optional parameters\n");
735 afs_com_err(whoami, code, "calling KAM_SetFields for %s.%s", name,
741 StringToKey(struct cmd_syndesc *as, void *arock)
744 char realm[MAXKTCREALMLEN];
745 struct ktc_encryptionKey key;
747 if (as->parms[1].items) {
748 code = ka_ExpandCell(as->parms[1].items->data, realm, 0 /*local */ );
750 afs_com_err(whoami, code,
751 "expanding %s as cell name, attempting to continue",
752 as->parms[1].items->data);
754 ucstring(realm, realm, sizeof(realm));
756 if ((code = DefaultCell()))
758 ucstring(realm, cell, sizeof(realm));
760 ka_StringToKey(as->parms[0].items->data, realm, &key);
762 printf("Converting %s in realm '%s' yields key='",
763 as->parms[0].items->data, realm);
764 ka_PrintBytes((char *)&key, sizeof(key));
767 des_string_to_key(as->parms[0].items->data, ktc_to_cblockptr(&key));
769 printf("Converting %s with the DES string to key yields key='",
770 as->parms[0].items->data);
771 ka_PrintBytes((char *)&key, sizeof(key));
778 SetPassword(struct cmd_syndesc *as, void *arock)
781 char name[MAXKTCNAMELEN];
782 char instance[MAXKTCNAMELEN];
783 char realm[MAXKTCREALMLEN];
784 struct ktc_encryptionKey key;
787 code = ka_ParseLoginName(as->parms[0].items->data, name, instance, realm);
789 afs_com_err(whoami, code, "parsing user's name '%s'",
790 as->parms[0].items->data);
794 if (strlen(realm) == 0)
795 ucstring(realm, cell, sizeof(realm));
797 if (as->parms[1].items && as->parms[2].items) {
798 printf("Can't specify both a password and a key\n");
800 } else if (as->parms[1].items) {
801 (void)init_child(myName);
802 (void)give_to_child(passwd); /* old password */
803 code = password_bad(as->parms[1].items->data);
804 (void)terminate_child();
807 ka_StringToKey(as->parms[1].items->data, realm, &key);
808 } else if (as->parms[2].items) {
809 if (ka_ReadBytes(as->parms[2].items->data, (char *)&key, sizeof(key))
811 printf("Key must be 8 bytes: '%s' was too long\n",
812 as->parms[2].items->data);
816 printf("Must specify new password or key\n");
821 if (as->parms[3].items)
822 sscanf(as->parms[3].items->data, "%d", &kvno);
824 #if defined(AFS_S390_LINUX20_ENV) && !defined(AFS_S390X_LINUX20_ENV)
825 code = ubik_Call(KAM_SetPassword, conn, 0, name, instance, kvno, 0, key);
827 code = ubik_Call(KAM_SetPassword, conn, 0, name, instance, kvno, key);
830 afs_com_err(whoami, code, "so can't set password for %s.%s", name,
835 #define PrintPrincipal(p,n,l) \
836 PrintName((p)->name, (p)->instance, (p)->cell, l, n)
839 PrintName(char *name, char *inst, char *acell, int buflen, char *buf)
842 int left; /* if ConvertBytes stops early */
851 left = ka_ConvertBytes(buf, buflen, name, strlen(name));
855 afs_com_err(whoami, code, "PrintName: principal name was '%s'.'%s'@'%s'",
862 if (nlen + len + 1 >= buflen)
865 left = ka_ConvertBytes(buf + nlen, buflen - nlen, inst, len);
873 char *lcell = ka_LocalCell();
876 if (strcmp(acell, lcell) != 0) {
877 /* only append cell if not the local cell */
878 if (nlen + len + 1 >= buflen)
881 left = ka_ConvertBytes(buf + nlen, buflen - nlen, acell, len);
890 #define PrintedPrincipal(p) PrintedName ((p)->name, (p)->instance, (p)->cell)
892 /* PrintedName - returned a pointer to a static string in which the formated
893 * name has been stored. */
896 PrintedName(char *name, char *inst, char *cell)
898 static char printedName[128];
900 code = PrintName(name, inst, cell, sizeof(printedName), printedName);
904 strncpy(printedName, name, sizeof(printedName));
905 printedName[sizeof(printedName) - 8] = 0;
906 strcat(printedName, "<error>");
912 ListTicket(struct ktc_principal *server, int verbose)
915 struct ktc_token token; /* the token we're printing */
916 struct ktc_principal client;
917 char UserName[sizeof(struct ktc_principal)];
918 char ServerName[sizeof(struct ktc_principal)];
919 afs_int32 now = time(0);
920 char bob[KA_TIMESTR_LEN];
922 /* get the ticket info itself */
923 code = ktc_GetToken(server, &token, sizeof(token), &client);
925 afs_com_err(whoami, code, "failed to get token info for server %s",
926 PrintedPrincipal(server));
929 code = PrintPrincipal(&client, UserName, sizeof(UserName));
932 /* spaces are printed as "\040" */
933 if (UserName[0] == 0)
935 else if (strncmp(UserName, "AFS\\040ID\\040", 13) == 0) {
936 printf("User's (AFS ID %s) tokens", UserName + 13);
937 } else if (strncmp(UserName, "Unix\\040UID\\040", 15) == 0) {
940 printf("User %s's tokens", UserName);
942 code = PrintPrincipal(server, ServerName, sizeof(ServerName));
945 printf(" for %s ", ServerName);
947 if (token.startTime > now) {
948 ka_timestr(token.startTime, bob, KA_TIMESTR_LEN);
949 printf("[>> POSTDATED 'till %s <<]", bob);
952 if (token.endTime <= now)
953 printf("[>> Expired <<]\n");
955 ka_timestr(token.endTime, bob, KA_TIMESTR_LEN);
956 printf("[Expires %s]\n", bob);
959 printf("SessionKey: ");
960 ka_PrintBytes((char *)&token.sessionKey, sizeof(token.sessionKey));
961 printf("\nTicket (kvno = %d, len = %d): ", token.kvno,
963 ka_PrintBytes((char *)token.ticket, token.ticketLen);
970 GetTicket(struct cmd_syndesc *as, void *arock)
973 struct ktc_principal server;
974 struct ktc_token token;
975 afs_int32 life = KA_SIXHOURS;
977 if (as->parms[1].items) {
978 code = read_time_interval(as->parms[1].items->data, &life);
983 ka_ParseLoginName(as->parms[0].items->data, server.name,
984 server.instance, server.cell);
986 afs_com_err(whoami, code, "parsing user's name '%s'",
987 as->parms[0].items->data);
990 if (server.cell[0] == 0) {
991 if ((code = DefaultCell()))
993 strcpy(server.cell, cell);
995 code = ka_ExpandCell(server.cell, server.cell, 0 /*local */ );
997 afs_com_err(whoami, code, "Can't expand cell name");
1002 token.ticketLen = 0; /* in case there are no tokens */
1004 ka_GetServerToken(server.name, server.instance, server.cell, life,
1005 &token, /*new */ 1, /*dosetpag */ 0);
1007 afs_com_err(whoami, code, "getting ticket for %s",
1008 PrintedPrincipal(&server));
1010 code = ListTicket(&server, /*verbose */ 1);
1016 GetPassword(struct cmd_syndesc *as, void *arock)
1019 char name[MAXKTCNAMELEN];
1020 struct ktc_encryptionKey key;
1021 static struct ubik_client *lpbkConn = 0;
1023 /* no instance allowed */
1024 code = ka_ParseLoginName(as->parms[0].items->data, name, 0, 0);
1027 afs_com_err(whoami, code,
1028 "getting %s's password via loopback connection to GetPassword",
1030 /* if we got a timeout, print a clarification, too */
1033 "%s: please note that this command must be run locally on a database server machine.\n",
1038 if (lpbkConn == 0) {
1039 struct rx_connection *conns[2];
1040 struct rx_securityClass *sc;
1041 int si; /* security class index */
1046 sc = rxnull_NewClientSecurityObject();
1047 si = RX_SCINDEX_NULL;
1049 rx_NewConnection(htonl(INADDR_LOOPBACK), htons(AFSCONF_KAUTHPORT),
1050 KA_MAINTENANCE_SERVICE, sc, si);
1052 code = ubik_ClientInit(conns, &lpbkConn);
1056 code = ubik_Call(KAM_GetPassword, lpbkConn, 0, name, &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_Call(KAM_GetRandomKey, conn, 0, &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_Call(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_Call(KAM_Debug, iConn, 0, KAMAJORVERSION, 0, &info);
1179 ubik_ClientDestroy(iConn);
1181 code = ubik_Call(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_int32 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, auth_token, client;
1294 char realm[MAXKTCREALMLEN];
1296 struct ktc_token token, *pToken;
1297 int i, acode, code = 0;
1300 char *ws = strrchr(as->a0name, '/');
1302 ws++; /* skip everything before the "/" */
1305 if (strlen(ws) > 0) {
1306 strncpy(whoami, ws, sizeof(whoami));
1307 if (strlen(whoami) + 1 >= sizeof(whoami))
1308 strcpy(whoami, "kas:");
1310 strcat(whoami, ":");
1313 /* append sub-command name */
1314 strncat(whoami, as->name, sizeof(whoami) - strlen(whoami) - 1);
1317 if (as->parms[12].name == 0)
1320 assert(as->parms[13].name && as->parms[14].name && as->parms[15].name
1321 && as->parms[16].name);
1323 /* MyAfterProc() destroys the conn, but just to be sure */
1325 code = ubik_ClientDestroy(conn);
1329 if (!init || as->parms[12].items || as->parms[13].items
1330 || as->parms[14].items || as->parms[15].items
1331 || as->parms[16].items) {
1332 strcpy(instance, "");
1333 strcpy(newCell, "");
1335 if (as->parms[12].items) { /* -admin_username */
1337 ka_ParseLoginName(as->parms[12].items->data, name, instance,
1340 afs_com_err(whoami, code, "parsing user's name '%s'",
1341 as->parms[12].items->data);
1346 DWORD len = MAXKTCNAMELEN;
1347 if (!GetUserName((LPTSTR) name, &len)) {
1348 printf("Can't get user name \n");
1352 /* No explicit name provided: use Unix uid. */
1353 struct passwd *pw = getpwuid(getuid());
1355 printf("Can't figure out your name from your user id.\n");
1358 strncpy(name, pw->pw_name, sizeof(name));
1362 if (as->parms[14].items) { /* -cell */
1363 if (strlen(newCell) > 0) {
1364 printf("Duplicate cell specification not allowed\n");
1366 strncpy(newCell, as->parms[14].items->data, sizeof(newCell));
1369 code = ka_ExpandCell(newCell, newCell, 0 /*local */ );
1371 afs_com_err(whoami, code, "Can't expand cell name");
1374 strcpy(cell, newCell);
1376 if (as->parms[15].items) { /* -servers */
1377 struct cmd_item *ip;
1378 char *ap[MAXSERVERS + 2];
1382 for (ip = as->parms[15].items, i = 2; ip; ip = ip->next, i++)
1384 code = ubik_ParseClientList(i, ap, serverList);
1386 afs_com_err(whoami, code, "could not parse server list");
1389 ka_ExplicitCell(cell, serverList);
1392 noauth = (as->parms[16].items ? 1 : 0); /* -noauth */
1397 token.ticketLen = 0; /* in case there are no tokens */
1398 if (!noauth) { /* Will prompt for a password */
1399 /* first see if there's already an admin ticket */
1401 ka_GetAdminToken(0, 0, cell, 0, KA_SIXHOURS, &token,
1403 if (code) { /* if not then get key and try again */
1404 if (as->parms[13].items) { /* if password specified */
1405 strncpy(passwd, as->parms[13].items->data, sizeof(passwd));
1406 memset(as->parms[13].items->data, 0,
1407 strlen(as->parms[13].items->data));
1409 char msg[MAXKTCNAMELEN + 50];
1410 if (as->parms[12].items)
1411 sprintf(msg, "Administrator's (%s) Password: ", name);
1413 sprintf(msg, "Password for %s: ", name);
1414 code = read_pw_string(passwd, sizeof(passwd), msg, 0);
1417 else if (strlen(passwd) == 0)
1418 code = KANULLPASSWORD;
1420 afs_com_err(whoami, code, "reading password");
1424 ka_StringToKey(passwd, cell, &key);
1426 ka_GetAdminToken(name, instance, cell, &key, KA_SIXHOURS,
1427 &token, 0 /* !new */ );
1428 if (code == KABADREQUEST) {
1429 des_string_to_key(passwd, ktc_to_cblockptr(&key));
1431 ka_GetAdminToken(name, instance, cell, &key, KA_SIXHOURS,
1432 &token, 0 /* !new */ );
1434 if ((code == KABADREQUEST) && (strlen(passwd) > 8)) {
1435 /* try with only the first 8 characters incase they set
1436 * their password with an old style passwd program. */
1438 ka_StringToKey(passwd, cell, &key);
1440 ka_GetAdminToken(name, instance, cell, &key, KA_SIXHOURS,
1441 &token, 0 /* !new */ );
1444 "Warning: you have typed a password longer than 8 characters, but only the\n");
1446 "first 8 characters were actually significant. If you change your password\n");
1448 "again this warning message will go away.\n");
1455 reason = "password was incorrect";
1458 reason = "Authentication Server was unavailable";
1461 reason = (char *)afs_error_message(code);
1464 "%s: Auth. as %s to AuthServer failed: %s\nProceeding w/o authentication\n",
1465 whoami, PrintedName(name, instance, cell), reason);
1467 /* get an Authentication token while were at it. */
1468 if (ka_CellToRealm(cell, realm, 0) != 0)
1470 strcpy(auth_server.name, KA_TGS_NAME);
1471 strcpy(auth_server.instance, realm);
1472 strcpy(auth_server.cell, cell);
1474 (&auth_server, &auth_token, sizeof(struct ktc_token),
1477 ka_GetAuthToken(name, instance, cell, &key,
1478 MAXKTCTICKETLIFETIME, (afs_int32 *) 0
1479 /*Don't need pwd expiration info here */
1481 if (acode && (acode != code)) /* codes are usually the same */
1482 afs_com_err(whoami, code,
1483 "getting Authentication token for %s",
1484 PrintedName(name, instance, cell));
1486 memset(&key, 0, sizeof(key));
1490 pToken = ((token.ticketLen == 0) ? 0 : &token);
1491 code = ka_AuthServerConn(cell, KA_MAINTENANCE_SERVICE, pToken, &conn);
1492 if (code && pToken) {
1493 afs_com_err(whoami, code,
1494 "connecting to AuthServer: now trying w/o authentication");
1495 code = ka_AuthServerConn(cell, KA_MAINTENANCE_SERVICE, 0, &conn);
1497 afs_com_err(whoami, code,
1498 "making unauthenticated connection to AuthServer");
1501 afs_com_err(whoami, code,
1502 "Couldn't establish connection to Authentication Server");
1506 /* now default unspecified password by prompting from terminal */
1507 if (as->nParms >= 12)
1508 for (i = 0; i < 12; i++)
1509 if (as->parms[i].name && (as->parms[i].items == 0)) {
1510 char *p = as->parms[i].name; /* parameter name */
1511 int l = strlen(p); /* length of name */
1512 /* does parameter end in "password" */
1513 if (strcmp(p + (l - 8), "password") == 0) {
1515 char password[BUFSIZ];
1516 struct cmd_item *ip;
1520 code = read_pw_string(password, sizeof(password), msg, 1);
1523 else if (strlen(password) == 0)
1524 code = KANULLPASSWORD;
1526 afs_com_err(whoami, code, "prompting for %s", p + 1);
1529 ip = (struct cmd_item *)malloc(sizeof(struct cmd_item));
1530 ip->data = (char *)malloc(strlen(password) + 1);
1532 strcpy(ip->data, password);
1533 as->parms[i].items = ip;
1536 if (!conn) { /* if all else fails... */
1537 code = NoAuth(0, 0); /* get unauthenticated conn */
1544 /* These are some helpful command that deal with the cache managers tokens. */
1547 ForgetTicket(struct cmd_syndesc *as, void *arock)
1552 struct ktc_principal server;
1554 if (as->parms[0].items) {
1555 char *name = as->parms[0].items->data;
1557 ka_ParseLoginName(name, server.name, server.instance,
1560 afs_com_err(whoami, code, "couldn't interpret name '%s'", name);
1563 if (server.cell[0] == 0) {
1564 if (code = DefaultCell())
1566 strcpy(server.cell, cell);
1568 code = ka_ExpandCell(server.cell, server.cell, 0 /*local */ );
1570 afs_com_err(whoami, code, "Can't expand cell name");
1574 code = ktc_ForgetToken(&server);
1576 afs_com_err(whoami, code, "couldn't remove tokens for %s",
1577 PrintedPrincipal(&server));
1581 if (!as->parms[1].items) {
1582 fprintf(stderr, "Must specify server name or -all\n");
1585 code = ktc_ForgetAllTokens();
1587 afs_com_err(whoami, code, "couldn't delete all tokens");
1592 code = ktc_ForgetAllTokens();
1594 afs_com_err(whoami, code, "couldn't delete all tokens");
1601 ListTickets(struct cmd_syndesc *as, void *arock)
1604 int index, newIndex;
1605 struct ktc_principal server;
1608 if (as->parms[1].items)
1610 if (as->parms[0].items) {
1611 char *name = as->parms[0].items->data;
1613 ka_ParseLoginName(name, server.name, server.instance,
1616 afs_com_err(whoami, code, "couldn't interpret name '%s'", name);
1619 if (server.cell[0] == 0) {
1620 if ((code = DefaultCell()))
1622 strcpy(server.cell, cell);
1624 code = ka_ExpandCell(server.cell, server.cell, 0 /*local */ );
1626 afs_com_err(whoami, code, "Can't expand cell name");
1630 code = ListTicket(&server, verbose);
1632 for (index = 0;; index = newIndex) {
1633 code = ktc_ListTokens(index, &newIndex, &server);
1635 if (code == KTC_NOENT)
1636 code = 0; /* end of list */
1639 code = ListTicket(&server, verbose);
1645 add_std_args(register struct cmd_syndesc *ts)
1648 /* 12 */ cmd_AddParm(ts, "-admin_username", CMD_SINGLE, CMD_OPTIONAL,
1649 "admin principal to use for authentication");
1650 /* 13 */ cmd_AddParm(ts, "-password_for_admin", CMD_SINGLE, CMD_OPTIONAL,
1652 /* 14 */ cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
1653 /* 15 */ cmd_AddParm(ts, "-servers", CMD_LIST, CMD_OPTIONAL,
1654 "explicit list of authentication servers");
1655 /* 16 */ cmd_AddParm(ts, "-noauth", CMD_FLAG, CMD_OPTIONAL,
1656 "don't authenticate");
1660 ka_AdminInteractive(int cmd_argc, char *cmd_argv[])
1663 register struct cmd_syndesc *ts;
1669 strncpy(myName, *cmd_argv, 509);
1671 cmd_SetBeforeProc(MyBeforeProc, NULL);
1672 cmd_SetAfterProc(MyAfterProc, NULL);
1674 ts = cmd_CreateSyntax("interactive", Interactive, NULL,
1675 "enter interactive mode");
1678 ts = cmd_CreateSyntax("noauthentication", NoAuth, NULL,
1679 "connect to AuthServer w/o using token");
1681 ts = cmd_CreateSyntax("list", ListUsers, NULL,
1682 "list all users in database");
1683 cmd_AddParm(ts, "-long", CMD_FLAG, CMD_OPTIONAL,
1684 "show detailed info about each user");
1685 cmd_AddParm(ts, "-showadmin", CMD_FLAG, CMD_OPTIONAL,
1686 "show all cell administrators");
1687 cmd_AddParm(ts, "-showkey", CMD_FLAG, CMD_OPTIONAL,
1688 "show the user's actual key rather than the checksum");
1690 cmd_CreateAlias(ts, "ls");
1692 ts = cmd_CreateSyntax("examine", ExamineUser, NULL,
1693 "examine the entry for a user");
1694 cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1695 cmd_AddParm(ts, "-showkey", CMD_FLAG, CMD_OPTIONAL,
1696 "show the user's actual key rather than the checksum");
1699 ts = cmd_CreateSyntax("create", CreateUser, NULL,
1700 "create an entry for a user");
1701 cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1702 cmd_AddParm(ts, "-initial_password", CMD_SINGLE, CMD_OPTIONAL,
1703 "initial password");
1706 ts = cmd_CreateSyntax("delete", DeleteUser, NULL, "delete a user");
1707 cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1709 cmd_CreateAlias(ts, "rm");
1711 ts = cmd_CreateSyntax("setfields", SetFields, NULL,
1712 "set various fields in a user's entry");
1713 cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1714 cmd_AddParm(ts, "-flags", CMD_SINGLE, CMD_OPTIONAL,
1715 "hex flag value or flag name expression");
1716 cmd_AddParm(ts, "-expiration", CMD_SINGLE, CMD_OPTIONAL,
1717 "date of account expiration");
1718 cmd_AddParm(ts, "-lifetime", CMD_SINGLE, CMD_OPTIONAL,
1719 "maximum ticket lifetime");
1720 cmd_AddParm(ts, "-pwexpires", CMD_SINGLE, CMD_OPTIONAL,
1721 "number days password is valid ([0..254])");
1722 cmd_AddParm(ts, "-reuse", CMD_SINGLE, CMD_OPTIONAL,
1723 "permit password reuse (yes/no)");
1724 cmd_AddParm(ts, "-attempts", CMD_SINGLE, CMD_OPTIONAL,
1725 "maximum successive failed login tries ([0..254])");
1726 cmd_AddParm(ts, "-locktime", CMD_SINGLE, CMD_OPTIONAL,
1727 "failure penalty [hh:mm or minutes]");
1729 cmd_AddParm(ts, "-associates", CMD_SINGLE, CMD_OPTIONAL,
1730 "maximum associate instances");
1733 cmd_CreateAlias(ts, "sf");
1736 ts = cmd_CreateSyntax("unlock", Unlock, NULL,
1737 "Enable authentication ID after max failed attempts exceeded");
1738 cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "authentication ID");
1742 ts = cmd_CreateSyntax("stringtokey", StringToKey, NULL,
1743 "convert a string to a key");
1744 cmd_AddParm(ts, "-string", CMD_SINGLE, 0, "password string");
1745 cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
1747 ts = cmd_CreateSyntax("setpassword", SetPassword, NULL,
1748 "set a user's password");
1749 cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1750 cmd_AddParm(ts, "-new_password", CMD_SINGLE, CMD_OPTIONAL,
1753 cmd_AddParm(ts, "-kvno", CMD_SINGLE, CMD_OPTIONAL, "key version number");
1755 cmd_CreateAlias(ts, "sp");
1756 #ifdef CMD_PARSER_AMBIG_FIX
1757 cmd_CreateAlias(ts, "setpasswd");
1760 /* set a user's key */
1761 ts = cmd_CreateSyntax("setkey", SetPassword, NULL, (char *)CMD_HIDDEN);
1762 cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1764 cmd_AddParm(ts, "-new_key", CMD_SINGLE, 0, "eight byte new key");
1766 cmd_AddParm(ts, "-kvno", CMD_SINGLE, CMD_OPTIONAL, "key version number");
1769 /* get a user's password */
1770 ts = cmd_CreateSyntax("getpassword", GetPassword, NULL, (char *)CMD_HIDDEN);
1771 cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1772 /* don't take standard args */
1773 /* add_std_args (ts); */
1774 #ifdef CMD_PARSER_AMBIG_FIX
1775 cmd_CreateAlias(ts, "getpasswd");
1778 /* get a random key */
1779 ts = cmd_CreateSyntax("getrandomkey", GetRandomKey, NULL,
1780 (char *)CMD_HIDDEN);
1783 /* get a ticket for a specific server */
1784 ts = cmd_CreateSyntax("getticket", GetTicket, NULL, (char *)CMD_HIDDEN);
1785 cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of server");
1786 cmd_AddParm(ts, "-lifetime", CMD_SINGLE, CMD_OPTIONAL, "ticket lifetime");
1789 ts = cmd_CreateSyntax("statistics", Statistics, NULL,
1790 "show statistics for AuthServer");
1793 /* show debugging info from AuthServer */
1794 ts = cmd_CreateSyntax("debuginfo", DebugInfo, NULL, (char *)CMD_HIDDEN);
1795 cmd_AddParm(ts, "-hostname", CMD_SINGLE, CMD_OPTIONAL,
1796 "authentication server host name");
1799 ts = cmd_CreateSyntax("forgetticket", ForgetTicket, NULL,
1800 "delete user's tickets");
1802 cmd_AddParm(ts, "-name", CMD_SINGLE, (CMD_OPTIONAL | CMD_HIDE),
1805 cmd_AddParm(ts, "-all", CMD_FLAG, CMD_OPTIONAL, "delete all tickets");
1807 ts = cmd_CreateSyntax("listtickets", ListTickets, NULL,
1808 "show all cache manager tickets");
1809 cmd_AddParm(ts, "-name", CMD_SINGLE, CMD_OPTIONAL, "name of server");
1810 cmd_AddParm(ts, "-long", CMD_FLAG, CMD_OPTIONAL,
1811 "show session key and ticket");
1813 ts = cmd_CreateSyntax("quit", Quit, NULL, "exit program");
1816 conn = 0; /* no connection yet */
1817 zero_argc = cmd_argc;
1818 zero_argv = cmd_argv;
1820 strcpy(whoami, "kas");
1822 if ((code = cmd_Dispatch(cmd_argc, cmd_argv))) {
1831 s = fgets(line, sizeof(line), stdin);
1833 return 0; /* EOF on input */
1834 for (i = strlen(line) - 1; i >= 0 && isspace(line[i]); i--)
1837 continue; /* blank line */
1840 cmd_ParseLine(line, argv, &argc, sizeof(argv) / sizeof(argv[0]));
1842 afs_com_err(whoami, code, "parsing line: '%s'", line);
1845 code = cmd_Dispatch(argc, argv);