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>
21 #include <afs/opr_assert.h>
25 #include <hcrypto/des.h>
26 #include <hcrypto/ui.h>
32 #define UBIK_LEGACY_CALLITER 1
35 #include <afs/cellconfig.h>
37 #include <afs/com_err.h>
38 #include <afs/afsutil.h>
41 #include "kauth_internal.h"
46 #define CMD_PARSER_AMBIG_FIX 1 /* allow ambiguous aliases */
48 #define KA_SIXHOURS (6*3600)
50 static struct ubik_client *conn;
51 static char cell[MAXKTCREALMLEN] = "";
52 static char whoami[32];
53 static char passwd[BUFSIZ];
54 static char myName[510]; /* almost like whoami save with path and without : */
58 static char **zero_argv;
59 afs_uint32 ka_islocked(char *, char *, afs_uint32 *);
68 code = ka_ExpandCell(0, cell, 0 /*local */ );
70 afs_com_err(whoami, code, "Can't expand cell name");
75 /* These are the command operation procedures. */
78 DumpUser(char *user, char *arock, int showadmin, int showkey, char *inst)
80 char name[MAXKTCNAMELEN];
81 char instance[MAXKTCNAMELEN];
84 char bob[KA_TIMESTR_LEN];
86 struct kaentryinfo tentry;
88 code = ka_ParseLoginName(user, name, instance, 0);
90 afs_com_err(whoami, code, "parsing user's name '%s'", user);
97 ubik_KAM_GetEntry(conn, 0, name, inst, KAMAJORVERSION, &tentry);
99 afs_com_err(whoami, code, "getting information for %s.%s", name, inst);
102 if (tentry.minor_version != KAMINORVERSION)
103 printf("Minor version number mismatch: got %d, expected %d\n",
104 tentry.minor_version, KAMINORVERSION);
105 if (showadmin && !(tentry.flags & KAFADMIN))
107 ka_PrintUserID("\nUser data for ", name, inst, "");
110 #define NEWPREFIX "+"
111 if (tentry.flags & KAFADMIN) {
112 printf("%sADMIN", prefix);
115 if (tentry.flags & KAFNOTGS) {
116 printf("%sNOTGS", prefix);
119 if (tentry.flags & KAFNOCPW) {
120 printf("%sNOCPW", prefix);
123 if (tentry.flags & KAFNOSEAL) {
124 printf("%sNOSEAL", prefix);
127 if (tentry.flags & KAFNEWASSOC) {
128 printf("%sNEWASSOC", prefix);
131 if (tentry.flags & KAFASSOCROOT) {
132 printf("%sASSOCROOT", prefix);
135 if (tentry.flags & KAFASSOC) {
136 printf("%sASSOC", prefix);
139 if (tentry.user_expiration <= now) {
140 printf("%sexpired", prefix);
143 if (strcmp(prefix, NEWPREFIX) == 0)
148 if ((!ka_KeyIsZero((char *)&tentry.key, sizeof(tentry.key))) && (showkey)) {
149 printf(" key (%d):", tentry.key_version);
150 ka_PrintBytes((char *)&tentry.key, sizeof(tentry.key));
152 if (tentry.keyCheckSum == 0)
153 printf(" key version is %d", tentry.key_version);
155 printf(" key (%d) cksum is %u", tentry.key_version,
158 ka_timestr(tentry.change_password_time, bob, KA_TIMESTR_LEN);
159 printf(", last cpw: %s\n", bob);
160 if (!tentry.misc_auth_bytes) {
161 printf(" password will never expire.\n");
163 (" An unlimited number of unsuccessful authentications is permitted.\n");
165 unsigned char misc_stuff[4];
168 temp = tentry.misc_auth_bytes;
170 temp = ntohl(tentry.misc_auth_bytes);
172 unpack_long(temp, misc_stuff);
174 if (!misc_stuff[0]) {
175 printf(" password will never expire.\n");
177 ka_timestr((tentry.change_password_time +
178 misc_stuff[0] * 24 * 60 * 60), bob, KA_TIMESTR_LEN);
179 printf(" password will expire: %s\n", bob);
184 (" An unlimited number of unsuccessful authentications is permitted.\n");
187 (" %d consecutive unsuccessful authentications are permitted.\n",
191 printf(" The lock time for this user is not limited.\n");
193 printf(" The lock time for this user is %4.1f minutes.\n",
194 (float)((unsigned int)misc_stuff[3] << 9) / 60.0);
196 if (!(misc_stuff[1] & KA_ISLOCKED)
197 || !ka_islocked(name, instance, &temp))
198 printf(" User is not locked.\n");
199 else if (temp == (afs_uint32) (-1L))
200 printf(" User is locked forever.\n");
202 ka_timestr(temp, bob, KA_TIMESTR_LEN);
203 printf(" User is locked until %s\n", bob);
209 char exp[KA_TIMESTR_LEN];
210 ka_timestr(tentry.user_expiration, exp, KA_TIMESTR_LEN);
211 if (tentry.user_expiration < now)
212 printf(" DISABLED entry at %s.", exp);
213 else if (tentry.user_expiration == NEVERDATE)
214 printf(" entry never expires.");
216 printf(" entry expires on %s.", exp);
218 printf(" Max ticket lifetime %.2f hours.\n",
219 tentry.max_ticket_lifetime / 3600.0);
220 ka_timestr(tentry.modification_time, bob, KA_TIMESTR_LEN);
221 printf(" last mod on %s by ", bob);
222 ka_PrintUserID("", tentry.modification_user.name,
223 tentry.modification_user.instance, "\n");
224 if ((tentry.reserved3 & 0xffff0000) == 0x12340000) {
225 int short reused = (short)tentry.reserved3;
227 printf(" permit password reuse\n");
229 printf(" don't permit password reuse\n");
236 ListUsers(struct cmd_syndesc *as, void *arock)
241 afs_int32 next_index;
242 int code, all = 0, showa = 0;
243 int showkey = (as->parms[2].items != NULL);
245 if (as->parms[0].items)
247 if (as->parms[1].items) {
251 for (index = 0; 1; index = next_index) {
253 ubik_KAM_ListEntry(conn, 0, index, &next_index, &count,
256 afs_com_err(whoami, code, "calling KAM_ListEntry");
262 printf("next_index (%d) is negative: ", next_index);
263 if (strlen(name.name) == 0)
264 printf("name is zero length: ");
266 DumpUser(name.name, NULL, showa, showkey, name.instance);
268 ka_PrintUserID("", name.name, name.instance, "\n");
275 ExamineUser(struct cmd_syndesc *as, void *arock)
277 int showkey = (as->parms[1].items != NULL);
278 return DumpUser(as->parms[0].items->data, arock, 0, showkey, NULL);
288 handle_errors(int code, /* error code to handle */
289 struct OKerrors OKlist[], /* list of errors & messages that should be ignored */
291 { /* set this if we should retry, clear otherwise */
294 for (i = 0; OKlist[i].code; i++) {
295 if (OKlist[i].code == code) {
296 printf("%s\n", OKlist[i].msg);
297 *persist = 0; /* we're done */
302 printf(" : [%s] %s", afs_error_table_name(code), afs_error_message(code));
305 printf(", wait one second\n");
309 case RX_CALL_TIMEOUT:
310 printf(" (retrying)\n");
315 *persist = 0; /* don't retry these errors */
320 CreateUser(struct cmd_syndesc *as, void *arock)
323 char name[MAXKTCNAMELEN];
324 char instance[MAXKTCNAMELEN];
325 struct ktc_encryptionKey key;
328 struct OKerrors OKlist[2];
331 code = ka_ParseLoginName(as->parms[0].items->data, name, instance, 0);
333 afs_com_err(whoami, code, "parsing user's name '%s'",
334 as->parms[0].items->data);
337 ka_StringToKey(as->parms[1].items->data, cell, &key);
340 code = ubik_KAM_CreateUser(conn, 0, name, instance,
341 *ktc_to_EncryptionKey(&key));
344 ka_PrintUserID("Creating user ", name, instance, " ");
345 code = handle_errors(code, OKlist, &persist);
351 DeleteUser(struct cmd_syndesc *as, void *arock)
354 char name[MAXKTCNAMELEN];
355 char instance[MAXKTCNAMELEN];
358 struct OKerrors OKlist[2];
360 code = ka_ParseLoginName(as->parms[0].items->data, name, instance, 0);
362 afs_com_err(whoami, code, "parsing user's name '%s'",
363 as->parms[0].items->data);
368 code = ubik_KAM_DeleteUser(conn, 0, name, instance);
371 ka_PrintUserID("Deleting user ", name, instance, " ");
372 code = handle_errors(code, OKlist, &persist);
378 read_time_interval(char *str, afs_int32 * seconds)
384 str = strncpy(buf, str, sizeof(buf));
385 s = strchr(str, ':');
389 *s++ = '\0'; /* separate hours and minutes */
390 sec = atoi(str) * 3600 + atoi(s) * 60;
397 parse_flags(char *name, char *inst, char *str, afs_int32 * flags)
399 struct kaentryinfo tentry;
405 int addop; /* 1=add bit; 0=remove bit */
409 str = lcstring(bitspec, str, sizeof(bitspec));
411 if (strncmp(str, "0x", 2) == 0) /* 0x => hex */
412 sscanf(str, "0x%lx", (long unsigned int *) &f);
413 else if (*str == '0') /* assume octal */
414 sscanf(str, "%lo", (long unsigned int *) &f);
415 else /* just assume hex */
416 sscanf(str, "%lx", (long unsigned int *) &f);
423 if (strchr("+-", *str))
424 addop = (*str++ == '+');
425 else if (*str == '_') {
431 ubik_KAM_GetEntry(conn, 0, name, inst, KAMAJORVERSION,
434 afs_com_err(whoami, code,
435 "could get current flag value for %s.%s", name, inst);
452 if (strcmp(bit, "admin") == 0)
454 else if (strcmp(bit, "noadmin") == 0)
455 flag = KAFADMIN, addop = !addop;
456 else if (strcmp(bit, "notgs") == 0)
458 else if (strcmp(bit, "tgs") == 0)
459 flag = KAFNOTGS, addop = !addop;
460 else if (strcmp(bit, "noseal") == 0)
462 else if (strcmp(bit, "seal") == 0)
463 flag = KAFNOSEAL, addop = !addop;
464 else if (strcmp(bit, "nocpw") == 0)
466 else if (strcmp(bit, "cpw") == 0)
467 flag = KAFNOCPW, addop = !addop;
468 else if (strcmp(bit, "newassoc") == 0)
470 else if (strcmp(bit, "nonewassoc") == 0)
471 flag = KAFNEWASSOC, addop = !addop;
474 ("Illegal bit name: %s; choices are: [no]admin, [no]tgs, [no]seal, [no]cpw\n",
487 addop = 1; /* get next op */
488 else if ((*str == '-') || (*str == '_'))
491 printf("Illegal combination operator: %c\n", *str);
497 *flags = (f & KAF_SETTABLE_FLAGS) | KAFNORMAL;
501 #define seriouserror(code) ((code <0) || ((code != UNOSERVERS) && (code != UNOQUORUM) && code != UNOTSYNC))
503 /* return MAXLONG if locked forever */
505 ka_islocked(char *name, char *instance, afs_uint32 * when)
515 ubik_CallIter(KAM_LockStatus, conn, UPUBIKONLY, &count, (long) name,
516 (long) instance, (long) &tempwhen, 0, 0, 0,
517 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
519 if (seriouserror(code))
520 afs_com_err(whoami, code, NULL);
521 } else if (tempwhen) { /* user is locked */
522 if (!*when || tempwhen < *when) {
526 } else /* ! tempwhen ==> user is not locked */
529 } while (code != UNOSERVERS);
535 Unlock(struct cmd_syndesc *as, void *arock)
537 afs_int32 code, rcode = 0;
540 char name[MAXKTCNAMELEN];
541 char instance[MAXKTCNAMELEN];
543 code = ka_ParseLoginName(as->parms[0].items->data, name, instance, 0);
545 afs_com_err(whoami, code, "parsing user's name '%s'",
546 as->parms[0].items->data);
552 code = ubik_CallIter(KAM_Unlock, conn, 0, &count, (long) name, (long) instance,
553 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
554 if (code && (code != UNOSERVERS)) {
556 if (conn && conn->conns[count - 1]
557 && rx_PeerOf(conn->conns[count - 1])) {
558 server = rx_PeerOf(conn->conns[count - 1])->host;
560 afs_com_err(whoami, code,
561 "so %s.%s may still be locked (on server %d.%d.%d.%d)",
562 name, instance, ((server >> 24) & 0xFF),
563 ((server >> 16) & 0xFF), ((server >> 8) & 0xFF),
570 } while (code != UNOSERVERS);
576 SetFields(struct cmd_syndesc *as, void *arock)
579 char name[MAXKTCNAMELEN];
580 char instance[MAXKTCNAMELEN];
584 afs_int32 lifetime = 0;
585 afs_int32 maxAssociates = -1;
586 afs_int32 pwexpiry = 0;
587 afs_int32 was_spare = 0;
588 char misc_auth_bytes[4];
591 code = ka_ParseLoginName(as->parms[0].items->data, name, instance, 0);
593 afs_com_err(whoami, code, "parsing user's name '%s'",
594 as->parms[0].items->data);
598 if (as->parms[1].items) {
599 code = parse_flags(name, instance, as->parms[1].items->data, &flags);
602 ("Illegal flag specification: %s, should be of the form <'='|'+'|'-'|'_'>bitname{<'+'|'-'>bitname}*\n",
603 as->parms[1].items->data);
607 if (as->parms[2].items) {
609 char *s = strncpy(buf, as->parms[2].items->data, sizeof(buf));
610 code = ktime_DateToInt32(s, &expiration);
612 printf("Illegal time format %s: %s\n", as->parms[2].items->data,
613 ktime_GetDateUsage());
616 if (expiration == 0) {
617 fprintf(stderr, "Expiration time must be after (about) 1970.\n");
620 if (expiration < time(0)) {
622 "Warning: expiration being set into the past, account will be disabled.\n");
628 if (as->parms[3].items) {
629 code = read_time_interval(as->parms[3].items->data, &lifetime);
634 /* no point in doing this any sooner than necessary */
635 for (i = 0; i < 4; misc_auth_bytes[i++] = 0);
637 if (as->parms[4].items) {
638 pwexpiry = strtol(as->parms[4].items->data, &end, 10);
641 "Password lifetime specified must be a non-negative decimal integer.\n");
644 if (pwexpiry < 0 || pwexpiry > 254) {
646 "Password lifetime range must be [0..254] days.\n");
647 fprintf(stderr, "Zero represents an unlimited lifetime.\n");
651 misc_auth_bytes[0] = pwexpiry + 1;
654 if (as->parms[5].items) {
656 reuse = (as->parms[5].items->data);
658 if (!strcmp(reuse, "yes")) {
659 misc_auth_bytes[1] = KA_REUSEPW;
660 } else if (strcmp(reuse, "no")) {
662 "must specify \"yes\" or \"no\": \"yes\" assumed\n");
663 misc_auth_bytes[1] = KA_REUSEPW;
665 misc_auth_bytes[1] = KA_NOREUSEPW;
669 if (as->parms[6].items) {
672 nfailures = strtol(as->parms[6].items->data, &end, 10);
674 if (*end != '\0' || nfailures < 0 || nfailures > 254) {
675 fprintf(stderr, "Failure limit must be in [0..254].\n");
676 fprintf(stderr, "Zero represents unlimited login attempts.\n");
679 misc_auth_bytes[2] = nfailures + 1;
682 if (as->parms[7].items) {
683 int locktime, hrs, mins;
687 s = as->parms[7].items->data;
689 sscanf(s, "%d:%d", &hrs, &mins);
691 sscanf(s, "%d", &mins);
693 locktime = hrs * 60 + mins;
694 if (hrs < 0 || hrs > 36 || mins < 0) {
696 "Lockout times must be either minutes or hh:mm.\n");
697 fprintf(stderr, "Lockout times must be less than 36 hours.\n");
699 } else if (locktime > 36 * 60) {
701 "Lockout times must be either minutes or hh:mm.\n");
702 fprintf(stderr, "Lockout times must be less than 36 hours.\n");
704 "Continuing with lock time of exactly 36 hours...\n");
707 locktime = (locktime * 60 + 511) >> 9; /* ceil(l*60/512) */
708 misc_auth_bytes[3] = locktime + 1; /* will be 1 if user said 0 */
711 if (as->parms[8].items) {
712 maxAssociates = atoi(as->parms[6].items->data);
713 if (maxAssociates < 0) {
714 printf("Illegal maximum number of associates\n");
719 was_spare = pack_long(misc_auth_bytes);
721 if (was_spare || flags || expiration || lifetime || (maxAssociates >= 0))
723 ubik_KAM_SetFields(conn, 0, name, instance, flags,
724 expiration, lifetime, maxAssociates, was_spare,
727 printf("Must specify one of the optional parameters\n");
731 afs_com_err(whoami, code, "calling KAM_SetFields for %s.%s", name,
737 StringToKey(struct cmd_syndesc *as, void *arock)
740 char realm[MAXKTCREALMLEN];
741 struct ktc_encryptionKey key;
743 if (as->parms[1].items) {
744 code = ka_ExpandCell(as->parms[1].items->data, realm, 0 /*local */ );
746 afs_com_err(whoami, code,
747 "expanding %s as cell name, attempting to continue",
748 as->parms[1].items->data);
750 ucstring(realm, realm, sizeof(realm));
752 if ((code = DefaultCell()))
754 ucstring(realm, cell, sizeof(realm));
756 ka_StringToKey(as->parms[0].items->data, realm, &key);
758 printf("Converting %s in realm '%s' yields key='",
759 as->parms[0].items->data, realm);
760 ka_PrintBytes((char *)&key, sizeof(key));
763 DES_string_to_key(as->parms[0].items->data, ktc_to_cblockptr(&key));
765 printf("Converting %s with the DES string to key yields key='",
766 as->parms[0].items->data);
767 ka_PrintBytes((char *)&key, sizeof(key));
774 SetPassword(struct cmd_syndesc *as, void *arock)
777 char name[MAXKTCNAMELEN];
778 char instance[MAXKTCNAMELEN];
779 char realm[MAXKTCREALMLEN];
780 struct ktc_encryptionKey key;
783 code = ka_ParseLoginName(as->parms[0].items->data, name, instance, realm);
785 afs_com_err(whoami, code, "parsing user's name '%s'",
786 as->parms[0].items->data);
790 if (strlen(realm) == 0)
791 ucstring(realm, cell, sizeof(realm));
793 if (as->parms[1].items && as->parms[2].items) {
794 printf("Can't specify both a password and a key\n");
796 } else if (as->parms[1].items) {
797 (void)init_child(myName);
798 (void)give_to_child(passwd); /* old password */
799 code = password_bad(as->parms[1].items->data);
800 (void)terminate_child();
803 ka_StringToKey(as->parms[1].items->data, realm, &key);
804 } else if (as->parms[2].items) {
805 if (ka_ReadBytes(as->parms[2].items->data, (char *)&key, sizeof(key))
807 printf("Key must be 8 bytes: '%s' was too long\n",
808 as->parms[2].items->data);
812 printf("Must specify new password or key\n");
817 if (as->parms[3].items)
818 sscanf(as->parms[3].items->data, "%d", &kvno);
820 code = ubik_KAM_SetPassword(conn, 0, name, instance, kvno,
821 *ktc_to_EncryptionKey(&key));
823 afs_com_err(whoami, code, "so can't set password for %s.%s", name,
828 #define PrintPrincipal(p,n,l) \
829 PrintName((p)->name, (p)->instance, (p)->cell, l, n)
832 PrintName(char *name, char *inst, char *acell, int buflen, char *buf)
835 int left; /* if ConvertBytes stops early */
844 left = ka_ConvertBytes(buf, buflen, name, strlen(name));
848 afs_com_err(whoami, code, "PrintName: principal name was '%s'.'%s'@'%s'",
855 if (nlen + len + 1 >= buflen)
858 left = ka_ConvertBytes(buf + nlen, buflen - nlen, inst, len);
866 char *lcell = ka_LocalCell();
869 if (strcmp(acell, lcell) != 0) {
870 /* only append cell if not the local cell */
871 if (nlen + len + 1 >= buflen)
874 left = ka_ConvertBytes(buf + nlen, buflen - nlen, acell, len);
883 #define PrintedPrincipal(p) PrintedName ((p)->name, (p)->instance, (p)->cell)
885 /* PrintedName - returned a pointer to a static string in which the formated
886 * name has been stored. */
889 PrintedName(char *name, char *inst, char *cell)
891 static char printedName[128];
893 code = PrintName(name, inst, cell, sizeof(printedName), printedName);
897 strncpy(printedName, name, sizeof(printedName));
898 printedName[sizeof(printedName) - 8] = 0;
899 strcat(printedName, "<error>");
905 ListTicket(struct ktc_principal *server, int verbose)
908 struct ktc_token token; /* the token we're printing */
909 struct ktc_principal client;
910 char UserName[sizeof(struct ktc_principal)];
911 char ServerName[sizeof(struct ktc_principal)];
912 afs_int32 now = time(0);
913 char bob[KA_TIMESTR_LEN];
915 /* get the ticket info itself */
916 code = ktc_GetToken(server, &token, sizeof(token), &client);
918 afs_com_err(whoami, code, "failed to get token info for server %s",
919 PrintedPrincipal(server));
922 code = PrintPrincipal(&client, UserName, sizeof(UserName));
925 /* spaces are printed as "\040" */
926 if (UserName[0] == 0)
928 else if (strncmp(UserName, "AFS\\040ID\\040", 13) == 0) {
929 printf("User's (AFS ID %s) tokens", UserName + 13);
930 } else if (strncmp(UserName, "Unix\\040UID\\040", 15) == 0) {
933 printf("User %s's tokens", UserName);
935 code = PrintPrincipal(server, ServerName, sizeof(ServerName));
938 printf(" for %s ", ServerName);
940 if (token.startTime > now) {
941 ka_timestr(token.startTime, bob, KA_TIMESTR_LEN);
942 printf("[>> POSTDATED 'till %s <<]", bob);
945 if (token.endTime <= now)
946 printf("[>> Expired <<]\n");
948 ka_timestr(token.endTime, bob, KA_TIMESTR_LEN);
949 printf("[Expires %s]\n", bob);
952 printf("SessionKey: ");
953 ka_PrintBytes((char *)&token.sessionKey, sizeof(token.sessionKey));
954 printf("\nTicket (kvno = %d, len = %d): ", token.kvno,
956 ka_PrintBytes((char *)token.ticket, token.ticketLen);
963 GetTicket(struct cmd_syndesc *as, void *arock)
966 struct ktc_principal server;
967 struct ktc_token token;
968 afs_int32 life = KA_SIXHOURS;
970 if (as->parms[1].items) {
971 code = read_time_interval(as->parms[1].items->data, &life);
976 ka_ParseLoginName(as->parms[0].items->data, server.name,
977 server.instance, server.cell);
979 afs_com_err(whoami, code, "parsing user's name '%s'",
980 as->parms[0].items->data);
983 if (server.cell[0] == 0) {
984 if ((code = DefaultCell()))
986 strcpy(server.cell, cell);
988 code = ka_ExpandCell(server.cell, server.cell, 0 /*local */ );
990 afs_com_err(whoami, code, "Can't expand cell name");
995 token.ticketLen = 0; /* in case there are no tokens */
997 ka_GetServerToken(server.name, server.instance, server.cell, life,
998 &token, /*new */ 1, /*dosetpag */ 0);
1000 afs_com_err(whoami, code, "getting ticket for %s",
1001 PrintedPrincipal(&server));
1003 code = ListTicket(&server, /*verbose */ 1);
1009 GetPassword(struct cmd_syndesc *as, void *arock)
1012 char name[MAXKTCNAMELEN];
1013 struct ktc_encryptionKey key;
1014 static struct ubik_client *lpbkConn = 0;
1016 /* no instance allowed */
1017 code = ka_ParseLoginName(as->parms[0].items->data, name, 0, 0);
1020 afs_com_err(whoami, code,
1021 "getting %s's password via loopback connection to GetPassword",
1023 /* if we got a timeout, print a clarification, too */
1026 "%s: please note that this command must be run locally on a database server machine.\n",
1031 if (lpbkConn == 0) {
1032 struct rx_connection *conns[2];
1033 struct rx_securityClass *sc;
1034 int si; /* security class index */
1039 sc = rxnull_NewClientSecurityObject();
1040 si = RX_SCINDEX_NULL;
1042 rx_NewConnection(htonl(INADDR_LOOPBACK), htons(AFSCONF_KAUTHPORT),
1043 KA_MAINTENANCE_SERVICE, sc, si);
1045 code = ubik_ClientInit(conns, &lpbkConn);
1049 code = ubik_KAM_GetPassword(lpbkConn, 0, name,
1050 ktc_to_EncryptionKey(&key));
1051 /* Lets close down the ubik_Client connection now */
1052 ubik_ClientDestroy(lpbkConn);
1056 ka_PrintBytes((char *)&key, sizeof(key));
1062 GetRandomKey(struct cmd_syndesc *as, void *arock)
1065 struct ktc_encryptionKey key;
1067 code = ubik_KAM_GetRandomKey(conn, 0, ktc_to_EncryptionKey(&key));
1069 afs_com_err(whoami, code, "so can't get random key");
1073 ka_PrintBytes((char *)&key, sizeof(key));
1075 for (i = 0; i < sizeof(key); i++) {
1076 printf("%.2x", ((char *)&key)[i] & 0xff);
1088 Statistics(struct cmd_syndesc *as, void *arock)
1094 char bob[KA_TIMESTR_LEN];
1097 ubik_KAM_GetStats(conn, 0, KAMAJORVERSION, &admins, &statics,
1100 printf("call to GetStats failed: %s\n", ka_ErrorString(code));
1103 if (statics.minor_version != KAMINORVERSION)
1104 printf("Minor version number mismatch: got %d, expected %d\n",
1105 statics.minor_version, KAMINORVERSION);
1106 printf("%d allocs, %d frees, %d password changes\n", statics.allocs,
1107 statics.frees, statics.cpws);
1108 printf("Hash table utilization = %f%%\n",
1109 (double)dynamics.hashTableUtilization / 100.0);
1110 ka_timestr(dynamics.start_time, bob, KA_TIMESTR_LEN);
1111 printf("From host %lx started at %s:\n",
1112 afs_printable_uint32_lu(dynamics.host), bob);
1114 #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)
1115 print_stat(Authenticate);
1116 print_stat(ChangePassword);
1117 print_stat(GetTicket);
1118 print_stat(CreateUser);
1119 print_stat(SetPassword);
1120 print_stat(SetFields);
1121 print_stat(DeleteUser);
1122 print_stat(GetEntry);
1123 print_stat(ListEntry);
1124 print_stat(GetStats);
1125 print_stat(GetPassword);
1126 print_stat(GetRandomKey);
1128 print_stat(UAuthenticate);
1129 print_stat(UGetTicket);
1131 #if (KAMAJORVERSION>5)
1132 print cpu stats printf("%d string checks\n", dynamics.string_checks);
1134 printf("Used %.3f seconds of CPU time.\n",
1135 dynamics.string_checks / 1000.0);
1137 printf("%d admin accounts\n", admins);
1142 DebugInfo(struct cmd_syndesc *as, void *arock)
1145 struct ka_debugInfo info;
1149 char bob[KA_TIMESTR_LEN];
1152 if (as->parms[0].items) {
1153 struct ubik_client *iConn;
1155 ka_SingleServerConn(cell, as->parms[0].items->data,
1156 KA_MAINTENANCE_SERVICE, 0, &iConn);
1158 struct afsconf_cell cellinfo;
1160 afs_com_err(whoami, code, "couldn't find host %s in cell %s",
1161 as->parms[0].items->data, cell);
1162 code = ka_GetServers(cell, &cellinfo);
1164 afs_com_err(whoami, code, "getting servers in cell %s", cell);
1166 printf("Servers in cell %s, are:\n", cell);
1167 for (i = 0; i < cellinfo.numServers; i++)
1168 printf(" %s\n", cellinfo.hostName[i]);
1172 code = ubik_KAM_Debug(iConn, 0, KAMAJORVERSION, 0, &info);
1173 ubik_ClientDestroy(iConn);
1175 code = ubik_KAM_Debug(conn, 0, KAMAJORVERSION, 0, &info);
1178 afs_com_err(whoami, code, "call to Debug failed");
1183 if (info.minorVersion != KAMINORVERSION)
1184 printf("Minor version number mismatch: got %d, expected %d\n",
1185 info.minorVersion, KAMINORVERSION);
1188 #if (KAMAJORVERSION>5)
1195 timeOffset = -timeOffset;
1196 if (timeOffset > 60) {
1198 ("WARNING: Large server client clock skew: %d seconds. Call itself took %d seconds.\n",
1199 timeOffset, now - start);
1201 ka_timestr(info.startTime, bob, KA_TIMESTR_LEN);
1202 printf("From host %lx started %sat %s:\n",
1203 afs_printable_uint32_lu(info.host),
1204 (info.noAuth ? "w/o authorization " : ""), bob);
1205 ka_timestr(info.lastTrans, bob, KA_TIMESTR_LEN);
1206 printf("Last trans was %s at %s\n", info.lastOperation, bob);
1207 ka_timestr(info.dbHeaderRead, bob, KA_TIMESTR_LEN);
1208 printf("Header last read %s.\n", bob);
1209 printf("db version=%d, keyVersion=%d, key cache version=%d\n",
1210 info.dbVersion, info.dbSpecialKeysVersion, info.kcVersion);
1211 printf("db ptrs: free %d, eof %d, kvno %d.\n", info.dbFreePtr,
1212 info.dbEofPtr, info.dbKvnoPtr);
1213 ka_timestr(info.nextAutoCPW, bob, KA_TIMESTR_LEN);
1214 printf("Next autoCPW at %s or in %d updates.\n", bob,
1215 info.updatesRemaining);
1216 if (info.cheader_lock || info.keycache_lock)
1217 printf("locks: cheader %08lx, keycache %08lx\n",
1218 afs_printable_uint32_lu(info.cheader_lock),
1219 afs_printable_uint32_lu(info.keycache_lock));
1220 printf("Last authentication for %s, last admin user was %s\n",
1221 info.lastAuth, info.lastAdmin);
1222 printf("Last TGS op was a %s ticket was for %s\n", info.lastTGSServer,
1224 printf("Last UDP TGS was a %s ticket for %s. UDP Authenticate for %s\n",
1225 info.lastUTGSServer, info.lastUTGS, info.lastUAuth);
1226 printf("key cache size %d, used %d.\n", info.kcSize, info.kcUsed);
1227 if (info.kcUsed > KADEBUGKCINFOSIZE) {
1228 printf("insufficient room to return all key cache entries!\n");
1229 info.kcUsed = KADEBUGKCINFOSIZE;
1231 for (i = 0; i < info.kcUsed; i++)
1232 ka_timestr(info.kcInfo[i].used, bob, KA_TIMESTR_LEN);
1233 printf("%32s %c %2x(%2x) used %s\n", info.kcInfo[i].principal,
1234 (info.kcInfo[i].primary ? '*' : ' '), info.kcInfo[i].kvno,
1235 info.kcInfo[i].keycksum, bob);
1240 Interactive(struct cmd_syndesc *as, void *arock)
1247 Quit(struct cmd_syndesc *as, void *arock)
1254 MyAfterProc(struct cmd_syndesc *as, void *arock)
1256 if (!strcmp(as->name, "help"))
1259 /* Determine if we need to destory the ubik connection.
1260 * Closing it avoids resends of packets.
1263 ubik_ClientDestroy(conn);
1270 int init = 0, noauth;
1271 char name[MAXKTCNAMELEN];
1272 char instance[MAXKTCNAMELEN];
1273 char newCell[MAXKTCREALMLEN];
1274 afs_uint32 serverList[MAXSERVERS];
1277 NoAuth(struct cmd_syndesc *as, void *arock)
1284 MyBeforeProc(struct cmd_syndesc *as, void *arock)
1286 struct ktc_encryptionKey key;
1287 struct ktc_principal auth_server, client;
1288 struct ktc_token auth_token;
1289 char realm[MAXKTCREALMLEN];
1291 struct ktc_token token, *pToken;
1292 int i, acode, code = 0;
1295 char *ws = strrchr(as->a0name, '/');
1297 ws++; /* skip everything before the "/" */
1300 if (strlen(ws) > 0) {
1301 strncpy(whoami, ws, sizeof(whoami));
1302 if (strlen(whoami) + 1 >= sizeof(whoami))
1303 strcpy(whoami, "kas:");
1305 strcat(whoami, ":");
1308 /* append sub-command name */
1309 strncat(whoami, as->name, sizeof(whoami) - strlen(whoami) - 1);
1312 if (as->parms[12].name == 0)
1315 assert(as->parms[13].name && as->parms[14].name && as->parms[15].name
1316 && as->parms[16].name);
1318 /* MyAfterProc() destroys the conn, but just to be sure */
1320 code = ubik_ClientDestroy(conn);
1324 if (!init || as->parms[12].items || as->parms[13].items
1325 || as->parms[14].items || as->parms[15].items
1326 || as->parms[16].items) {
1327 strcpy(instance, "");
1328 strcpy(newCell, "");
1330 if (as->parms[12].items) { /* -admin_username */
1332 ka_ParseLoginName(as->parms[12].items->data, name, instance,
1335 afs_com_err(whoami, code, "parsing user's name '%s'",
1336 as->parms[12].items->data);
1341 DWORD len = MAXKTCNAMELEN;
1342 if (!GetUserName((LPTSTR) name, &len)) {
1343 printf("Can't get user name \n");
1347 /* No explicit name provided: use Unix uid. */
1348 struct passwd *pw = getpwuid(getuid());
1350 printf("Can't figure out your name from your user id.\n");
1353 strncpy(name, pw->pw_name, sizeof(name));
1357 if (as->parms[14].items) { /* -cell */
1358 if (strlen(newCell) > 0) {
1359 printf("Duplicate cell specification not allowed\n");
1361 strncpy(newCell, as->parms[14].items->data, sizeof(newCell));
1364 code = ka_ExpandCell(newCell, newCell, 0 /*local */ );
1366 afs_com_err(whoami, code, "Can't expand cell name");
1369 strcpy(cell, newCell);
1371 if (as->parms[15].items) { /* -servers */
1372 struct cmd_item *ip;
1373 char *ap[MAXSERVERS + 2];
1377 for (ip = as->parms[15].items, i = 2; ip; ip = ip->next, i++)
1379 code = ubik_ParseClientList(i, ap, serverList);
1381 afs_com_err(whoami, code, "could not parse server list");
1384 ka_ExplicitCell(cell, serverList);
1387 noauth = (as->parms[16].items ? 1 : 0); /* -noauth */
1392 token.ticketLen = 0; /* in case there are no tokens */
1393 if (!noauth) { /* Will prompt for a password */
1394 /* first see if there's already an admin ticket */
1396 ka_GetAdminToken(0, 0, cell, 0, KA_SIXHOURS, &token,
1398 if (code) { /* if not then get key and try again */
1399 if (as->parms[13].items) { /* if password specified */
1400 strncpy(passwd, as->parms[13].items->data, sizeof(passwd));
1401 memset(as->parms[13].items->data, 0,
1402 strlen(as->parms[13].items->data));
1404 char msg[MAXKTCNAMELEN + 50];
1405 if (as->parms[12].items)
1406 sprintf(msg, "Administrator's (%s) Password: ", name);
1408 sprintf(msg, "Password for %s: ", name);
1409 code = UI_UTIL_read_pw_string(passwd, sizeof(passwd), msg, 0);
1412 else if (strlen(passwd) == 0)
1413 code = KANULLPASSWORD;
1415 afs_com_err(whoami, code, "reading password");
1419 ka_StringToKey(passwd, cell, &key);
1421 ka_GetAdminToken(name, instance, cell, &key, KA_SIXHOURS,
1422 &token, 0 /* !new */ );
1423 if (code == KABADREQUEST) {
1424 DES_string_to_key(passwd, ktc_to_cblockptr(&key));
1426 ka_GetAdminToken(name, instance, cell, &key, KA_SIXHOURS,
1427 &token, 0 /* !new */ );
1429 if ((code == KABADREQUEST) && (strlen(passwd) > 8)) {
1430 /* try with only the first 8 characters incase they set
1431 * their password with an old style passwd program. */
1433 ka_StringToKey(passwd, cell, &key);
1435 ka_GetAdminToken(name, instance, cell, &key, KA_SIXHOURS,
1436 &token, 0 /* !new */ );
1439 "Warning: you have typed a password longer than 8 characters, but only the\n");
1441 "first 8 characters were actually significant. If you change your password\n");
1443 "again this warning message will go away.\n");
1450 reason = "password was incorrect";
1453 reason = "Authentication Server was unavailable";
1456 reason = (char *)afs_error_message(code);
1459 "%s: Auth. as %s to AuthServer failed: %s\nProceeding w/o authentication\n",
1460 whoami, PrintedName(name, instance, cell), reason);
1462 /* get an Authentication token while were at it. */
1463 if (ka_CellToRealm(cell, realm, 0) != 0)
1465 strcpy(auth_server.name, KA_TGS_NAME);
1466 strcpy(auth_server.instance, realm);
1467 strcpy(auth_server.cell, cell);
1469 (&auth_server, &auth_token, sizeof(struct ktc_token),
1472 ka_GetAuthToken(name, instance, cell, &key,
1473 MAXKTCTICKETLIFETIME, (afs_int32 *) 0
1474 /*Don't need pwd expiration info here */
1476 if (acode && (acode != code)) /* codes are usually the same */
1477 afs_com_err(whoami, code,
1478 "getting Authentication token for %s",
1479 PrintedName(name, instance, cell));
1481 memset(&key, 0, sizeof(key));
1485 pToken = ((token.ticketLen == 0) ? 0 : &token);
1486 code = ka_AuthServerConn(cell, KA_MAINTENANCE_SERVICE, pToken, &conn);
1487 if (code && pToken) {
1488 afs_com_err(whoami, code,
1489 "connecting to AuthServer: now trying w/o authentication");
1490 code = ka_AuthServerConn(cell, KA_MAINTENANCE_SERVICE, 0, &conn);
1492 afs_com_err(whoami, code,
1493 "making unauthenticated connection to AuthServer");
1496 afs_com_err(whoami, code,
1497 "Couldn't establish connection to Authentication Server");
1501 /* now default unspecified password by prompting from terminal */
1502 if (as->nParms >= 12)
1503 for (i = 0; i < 12; i++)
1504 if (as->parms[i].name && (as->parms[i].items == 0)) {
1505 char *p = as->parms[i].name; /* parameter name */
1506 int l = strlen(p); /* length of name */
1507 /* does parameter end in "password" */
1508 if (strcmp(p + (l - 8), "password") == 0) {
1510 char password[BUFSIZ];
1511 struct cmd_item *ip;
1515 code = UI_UTIL_read_pw_string(password, sizeof(password), msg, 1);
1518 else if (strlen(password) == 0)
1519 code = KANULLPASSWORD;
1521 afs_com_err(whoami, code, "prompting for %s", p + 1);
1524 ip = (struct cmd_item *)malloc(sizeof(struct cmd_item));
1525 ip->data = (char *)malloc(strlen(password) + 1);
1527 strcpy(ip->data, password);
1528 as->parms[i].items = ip;
1531 if (!conn) { /* if all else fails... */
1532 code = NoAuth(0, 0); /* get unauthenticated conn */
1539 /* These are some helpful command that deal with the cache managers tokens. */
1542 ForgetTicket(struct cmd_syndesc *as, void *arock)
1547 struct ktc_principal server;
1549 if (as->parms[0].items) {
1550 char *name = as->parms[0].items->data;
1552 ka_ParseLoginName(name, server.name, server.instance,
1555 afs_com_err(whoami, code, "couldn't interpret name '%s'", name);
1558 if (server.cell[0] == 0) {
1559 if (code = DefaultCell())
1561 strcpy(server.cell, cell);
1563 code = ka_ExpandCell(server.cell, server.cell, 0 /*local */ );
1565 afs_com_err(whoami, code, "Can't expand cell name");
1569 code = ktc_ForgetToken(&server);
1571 afs_com_err(whoami, code, "couldn't remove tokens for %s",
1572 PrintedPrincipal(&server));
1576 if (!as->parms[1].items) {
1577 fprintf(stderr, "Must specify server name or -all\n");
1580 code = ktc_ForgetAllTokens();
1582 afs_com_err(whoami, code, "couldn't delete all tokens");
1587 code = ktc_ForgetAllTokens();
1589 afs_com_err(whoami, code, "couldn't delete all tokens");
1596 ListTickets(struct cmd_syndesc *as, void *arock)
1599 int index, newIndex;
1600 struct ktc_principal server;
1603 if (as->parms[1].items)
1605 if (as->parms[0].items) {
1606 char *name = as->parms[0].items->data;
1608 ka_ParseLoginName(name, server.name, server.instance,
1611 afs_com_err(whoami, code, "couldn't interpret name '%s'", name);
1614 if (server.cell[0] == 0) {
1615 if ((code = DefaultCell()))
1617 strcpy(server.cell, cell);
1619 code = ka_ExpandCell(server.cell, server.cell, 0 /*local */ );
1621 afs_com_err(whoami, code, "Can't expand cell name");
1625 code = ListTicket(&server, verbose);
1627 for (index = 0;; index = newIndex) {
1628 code = ktc_ListTokens(index, &newIndex, &server);
1630 if (code == KTC_NOENT)
1631 code = 0; /* end of list */
1634 code = ListTicket(&server, verbose);
1640 add_std_args(struct cmd_syndesc *ts)
1643 /* 12 */ cmd_AddParm(ts, "-admin_username", CMD_SINGLE, CMD_OPTIONAL,
1644 "admin principal to use for authentication");
1645 /* 13 */ cmd_AddParm(ts, "-password_for_admin", CMD_SINGLE, CMD_OPTIONAL,
1647 /* 14 */ cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
1648 /* 15 */ cmd_AddParm(ts, "-servers", CMD_LIST, CMD_OPTIONAL,
1649 "explicit list of authentication servers");
1650 /* 16 */ cmd_AddParm(ts, "-noauth", CMD_FLAG, CMD_OPTIONAL,
1651 "don't authenticate");
1655 ka_AdminInteractive(int cmd_argc, char *cmd_argv[])
1658 struct cmd_syndesc *ts;
1664 strncpy(myName, *cmd_argv, 509);
1666 cmd_SetBeforeProc(MyBeforeProc, NULL);
1667 cmd_SetAfterProc(MyAfterProc, NULL);
1669 ts = cmd_CreateSyntax("interactive", Interactive, NULL,
1670 "enter interactive mode");
1673 ts = cmd_CreateSyntax("noauthentication", NoAuth, NULL,
1674 "connect to AuthServer w/o using token");
1676 ts = cmd_CreateSyntax("list", ListUsers, NULL,
1677 "list all users in database");
1678 cmd_AddParm(ts, "-long", CMD_FLAG, CMD_OPTIONAL,
1679 "show detailed info about each user");
1680 cmd_AddParm(ts, "-showadmin", CMD_FLAG, CMD_OPTIONAL,
1681 "show all cell administrators");
1682 cmd_AddParm(ts, "-showkey", CMD_FLAG, CMD_OPTIONAL,
1683 "show the user's actual key rather than the checksum");
1685 cmd_CreateAlias(ts, "ls");
1687 ts = cmd_CreateSyntax("examine", ExamineUser, NULL,
1688 "examine the entry for a user");
1689 cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1690 cmd_AddParm(ts, "-showkey", CMD_FLAG, CMD_OPTIONAL,
1691 "show the user's actual key rather than the checksum");
1694 ts = cmd_CreateSyntax("create", CreateUser, NULL,
1695 "create an entry for a user");
1696 cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1697 cmd_AddParm(ts, "-initial_password", CMD_SINGLE, CMD_OPTIONAL,
1698 "initial password");
1701 ts = cmd_CreateSyntax("delete", DeleteUser, NULL, "delete a user");
1702 cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1704 cmd_CreateAlias(ts, "rm");
1706 ts = cmd_CreateSyntax("setfields", SetFields, NULL,
1707 "set various fields in a user's entry");
1708 cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1709 cmd_AddParm(ts, "-flags", CMD_SINGLE, CMD_OPTIONAL,
1710 "hex flag value or flag name expression");
1711 cmd_AddParm(ts, "-expiration", CMD_SINGLE, CMD_OPTIONAL,
1712 "date of account expiration");
1713 cmd_AddParm(ts, "-lifetime", CMD_SINGLE, CMD_OPTIONAL,
1714 "maximum ticket lifetime");
1715 cmd_AddParm(ts, "-pwexpires", CMD_SINGLE, CMD_OPTIONAL,
1716 "number days password is valid ([0..254])");
1717 cmd_AddParm(ts, "-reuse", CMD_SINGLE, CMD_OPTIONAL,
1718 "permit password reuse (yes/no)");
1719 cmd_AddParm(ts, "-attempts", CMD_SINGLE, CMD_OPTIONAL,
1720 "maximum successive failed login tries ([0..254])");
1721 cmd_AddParm(ts, "-locktime", CMD_SINGLE, CMD_OPTIONAL,
1722 "failure penalty [hh:mm or minutes]");
1724 cmd_AddParm(ts, "-associates", CMD_SINGLE, CMD_OPTIONAL,
1725 "maximum associate instances");
1728 cmd_CreateAlias(ts, "sf");
1731 ts = cmd_CreateSyntax("unlock", Unlock, NULL,
1732 "Enable authentication ID after max failed attempts exceeded");
1733 cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "authentication ID");
1737 ts = cmd_CreateSyntax("stringtokey", StringToKey, NULL,
1738 "convert a string to a key");
1739 cmd_AddParm(ts, "-string", CMD_SINGLE, 0, "password string");
1740 cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
1742 ts = cmd_CreateSyntax("setpassword", SetPassword, NULL,
1743 "set a user's password");
1744 cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1745 cmd_AddParm(ts, "-new_password", CMD_SINGLE, CMD_OPTIONAL,
1748 cmd_AddParm(ts, "-kvno", CMD_SINGLE, CMD_OPTIONAL, "key version number");
1750 cmd_CreateAlias(ts, "sp");
1751 #ifdef CMD_PARSER_AMBIG_FIX
1752 cmd_CreateAlias(ts, "setpasswd");
1755 /* set a user's key */
1756 ts = cmd_CreateSyntax("setkey", SetPassword, NULL, (char *)CMD_HIDDEN);
1757 cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1759 cmd_AddParm(ts, "-new_key", CMD_SINGLE, 0, "eight byte new key");
1761 cmd_AddParm(ts, "-kvno", CMD_SINGLE, CMD_OPTIONAL, "key version number");
1764 /* get a user's password */
1765 ts = cmd_CreateSyntax("getpassword", GetPassword, NULL, (char *)CMD_HIDDEN);
1766 cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1767 /* don't take standard args */
1768 /* add_std_args (ts); */
1769 #ifdef CMD_PARSER_AMBIG_FIX
1770 cmd_CreateAlias(ts, "getpasswd");
1773 /* get a random key */
1774 ts = cmd_CreateSyntax("getrandomkey", GetRandomKey, NULL,
1775 (char *)CMD_HIDDEN);
1778 /* get a ticket for a specific server */
1779 ts = cmd_CreateSyntax("getticket", GetTicket, NULL, (char *)CMD_HIDDEN);
1780 cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of server");
1781 cmd_AddParm(ts, "-lifetime", CMD_SINGLE, CMD_OPTIONAL, "ticket lifetime");
1784 ts = cmd_CreateSyntax("statistics", Statistics, NULL,
1785 "show statistics for AuthServer");
1788 /* show debugging info from AuthServer */
1789 ts = cmd_CreateSyntax("debuginfo", DebugInfo, NULL, (char *)CMD_HIDDEN);
1790 cmd_AddParm(ts, "-hostname", CMD_SINGLE, CMD_OPTIONAL,
1791 "authentication server host name");
1794 ts = cmd_CreateSyntax("forgetticket", ForgetTicket, NULL,
1795 "delete user's tickets");
1797 cmd_AddParm(ts, "-name", CMD_SINGLE, (CMD_OPTIONAL | CMD_HIDE),
1800 cmd_AddParm(ts, "-all", CMD_FLAG, CMD_OPTIONAL, "delete all tickets");
1802 ts = cmd_CreateSyntax("listtickets", ListTickets, NULL,
1803 "show all cache manager tickets");
1804 cmd_AddParm(ts, "-name", CMD_SINGLE, CMD_OPTIONAL, "name of server");
1805 cmd_AddParm(ts, "-long", CMD_FLAG, CMD_OPTIONAL,
1806 "show session key and ticket");
1808 ts = cmd_CreateSyntax("quit", Quit, NULL, "exit program");
1811 conn = 0; /* no connection yet */
1812 zero_argc = cmd_argc;
1813 zero_argv = cmd_argv;
1815 strcpy(whoami, "kas");
1817 if ((code = cmd_Dispatch(cmd_argc, cmd_argv))) {
1826 s = fgets(line, sizeof(line), stdin);
1828 return 0; /* EOF on input */
1829 for (i = strlen(line) - 1; i >= 0 && isspace(line[i]); i--)
1832 continue; /* blank line */
1835 cmd_ParseLine(line, argv, &argc, sizeof(argv) / sizeof(argv[0]));
1837 afs_com_err(whoami, code, "parsing line: '%s'", line);
1840 code = cmd_Dispatch(argc, argv);