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>
31 #define UBIK_LEGACY_CALLITER 1
37 #include <afs/cellconfig.h>
39 #include <afs/com_err.h>
40 #include <afs/afsutil.h>
42 #include <des_prototypes.h>
49 #define CMD_PARSER_AMBIG_FIX 1 /* allow ambiguous aliases */
51 #define KA_SIXHOURS (6*3600)
53 static struct ubik_client *conn;
54 static char cell[MAXKTCREALMLEN] = "";
55 static char whoami[32];
56 static char passwd[BUFSIZ];
57 static char myName[510]; /* almost like whoami save with path and without : */
61 static char **zero_argv;
62 afs_uint32 ka_islocked(char *, char *, afs_uint32 *);
71 code = ka_ExpandCell(0, cell, 0 /*local */ );
73 afs_com_err(whoami, code, "Can't expand cell name");
78 /* These are the command operation procedures. */
81 DumpUser(char *user, char *arock, int showadmin, int showkey, char *inst)
83 char name[MAXKTCNAMELEN];
84 char instance[MAXKTCNAMELEN];
87 char bob[KA_TIMESTR_LEN];
89 struct kaentryinfo tentry;
91 code = ka_ParseLoginName(user, name, instance, 0);
93 afs_com_err(whoami, code, "parsing user's name '%s'", user);
100 ubik_Call(KAM_GetEntry, conn, 0, name, inst, KAMAJORVERSION, &tentry);
102 afs_com_err(whoami, code, "getting information for %s.%s", name, inst);
105 if (tentry.minor_version != KAMINORVERSION)
106 printf("Minor version number mismatch: got %d, expected %d\n",
107 tentry.minor_version, KAMINORVERSION);
108 if (showadmin && !(tentry.flags & KAFADMIN))
110 ka_PrintUserID("\nUser data for ", name, inst, "");
113 #define NEWPREFIX "+"
114 if (tentry.flags & KAFADMIN) {
115 printf("%sADMIN", prefix);
118 if (tentry.flags & KAFNOTGS) {
119 printf("%sNOTGS", prefix);
122 if (tentry.flags & KAFNOCPW) {
123 printf("%sNOCPW", prefix);
126 if (tentry.flags & KAFNOSEAL) {
127 printf("%sNOSEAL", prefix);
130 if (tentry.flags & KAFNEWASSOC) {
131 printf("%sNEWASSOC", prefix);
134 if (tentry.flags & KAFASSOCROOT) {
135 printf("%sASSOCROOT", prefix);
138 if (tentry.flags & KAFASSOC) {
139 printf("%sASSOC", prefix);
142 if (tentry.user_expiration <= now) {
143 printf("%sexpired", prefix);
146 if (strcmp(prefix, NEWPREFIX) == 0)
151 if ((!ka_KeyIsZero((char *)&tentry.key, sizeof(tentry.key))) && (showkey)) {
152 printf(" key (%d):", tentry.key_version);
153 ka_PrintBytes((char *)&tentry.key, sizeof(tentry.key));
155 if (tentry.keyCheckSum == 0)
156 printf(" key version is %d", tentry.key_version);
158 printf(" key (%d) cksum is %u", tentry.key_version,
161 ka_timestr(tentry.change_password_time, bob, KA_TIMESTR_LEN);
162 printf(", last cpw: %s\n", bob);
163 if (!tentry.misc_auth_bytes) {
164 printf(" password will never expire.\n");
166 (" An unlimited number of unsuccessful authentications is permitted.\n");
168 unsigned char misc_stuff[4];
171 temp = tentry.misc_auth_bytes;
173 temp = ntohl(tentry.misc_auth_bytes);
175 unpack_long(temp, misc_stuff);
177 if (!misc_stuff[0]) {
178 printf(" password will never expire.\n");
180 ka_timestr((tentry.change_password_time +
181 misc_stuff[0] * 24 * 60 * 60), bob, KA_TIMESTR_LEN);
182 printf(" password will expire: %s\n", bob);
187 (" An unlimited number of unsuccessful authentications is permitted.\n");
190 (" %d consecutive unsuccessful authentications are permitted.\n",
194 printf(" The lock time for this user is not limited.\n");
196 printf(" The lock time for this user is %4.1f minutes.\n",
197 (float)((unsigned int)misc_stuff[3] << 9) / 60.0);
199 if (!(misc_stuff[1] & KA_ISLOCKED)
200 || !ka_islocked(name, instance, &temp))
201 printf(" User is not locked.\n");
202 else if (temp == (afs_uint32) (-1L))
203 printf(" User is locked forever.\n");
205 ka_timestr(temp, bob, KA_TIMESTR_LEN);
206 printf(" User is locked until %s\n", bob);
212 char exp[KA_TIMESTR_LEN];
213 ka_timestr(tentry.user_expiration, exp, KA_TIMESTR_LEN);
214 if (tentry.user_expiration < now)
215 printf(" DISABLED entry at %s.", exp);
216 else if (tentry.user_expiration == NEVERDATE)
217 printf(" entry never expires.");
219 printf(" entry expires on %s.", exp);
221 printf(" Max ticket lifetime %.2f hours.\n",
222 tentry.max_ticket_lifetime / 3600.0);
223 ka_timestr(tentry.modification_time, bob, KA_TIMESTR_LEN);
224 printf(" last mod on %s by ", bob);
225 ka_PrintUserID("", tentry.modification_user.name,
226 tentry.modification_user.instance, "\n");
227 if ((tentry.reserved3 & 0xffff0000) == 0x12340000) {
228 int short reused = (short)tentry.reserved3;
230 printf(" permit password reuse\n");
232 printf(" don't permit password reuse\n");
239 ListUsers(struct cmd_syndesc *as, void *arock)
244 afs_int32 next_index;
245 int code, all = 0, showa = 0;
246 int showkey = (as->parms[2].items != NULL);
248 if (as->parms[0].items)
250 if (as->parms[1].items) {
254 for (index = 0; 1; index = next_index) {
256 ubik_Call(KAM_ListEntry, conn, 0, index, &next_index, &count,
259 afs_com_err(whoami, code, "calling KAM_ListEntry");
265 printf("next_index (%d) is negative: ", next_index);
266 if (strlen(name.name) == 0)
267 printf("name is zero length: ");
269 DumpUser(name.name, NULL, showa, showkey, name.instance);
271 ka_PrintUserID("", name.name, name.instance, "\n");
278 ExamineUser(struct cmd_syndesc *as, void *arock)
280 int showkey = (as->parms[1].items != NULL);
281 return DumpUser(as->parms[0].items->data, arock, 0, showkey, NULL);
291 handle_errors(int code, /* error code to handle */
292 struct OKerrors OKlist[], /* list of errors & messages that should be ignored */
294 { /* set this if we should retry, clear otherwise */
297 for (i = 0; OKlist[i].code; i++) {
298 if (OKlist[i].code == code) {
299 printf("%s\n", OKlist[i].msg);
300 *persist = 0; /* we're done */
305 printf(" : [%s] %s", afs_error_table_name(code), afs_error_message(code));
308 printf(", wait one second\n");
312 case RX_CALL_TIMEOUT:
313 printf(" (retrying)\n");
318 *persist = 0; /* don't retry these errors */
323 CreateUser(struct cmd_syndesc *as, void *arock)
326 char name[MAXKTCNAMELEN];
327 char instance[MAXKTCNAMELEN];
328 struct ktc_encryptionKey key;
331 struct OKerrors OKlist[2];
334 code = ka_ParseLoginName(as->parms[0].items->data, name, instance, 0);
336 afs_com_err(whoami, code, "parsing user's name '%s'",
337 as->parms[0].items->data);
340 ka_StringToKey(as->parms[1].items->data, cell, &key);
343 code = ubik_Call(KAM_CreateUser, conn, 0, name, instance, key);
346 ka_PrintUserID("Creating user ", name, instance, " ");
347 code = handle_errors(code, OKlist, &persist);
353 DeleteUser(struct cmd_syndesc *as, void *arock)
356 char name[MAXKTCNAMELEN];
357 char instance[MAXKTCNAMELEN];
360 struct OKerrors OKlist[2];
362 code = ka_ParseLoginName(as->parms[0].items->data, name, instance, 0);
364 afs_com_err(whoami, code, "parsing user's name '%s'",
365 as->parms[0].items->data);
370 code = ubik_Call(KAM_DeleteUser, conn, 0, name, instance);
373 ka_PrintUserID("Deleting user ", name, instance, " ");
374 code = handle_errors(code, OKlist, &persist);
380 read_time_interval(char *str, afs_int32 * seconds)
386 str = strncpy(buf, str, sizeof(buf));
387 s = strchr(str, ':');
391 *s++ = '\0'; /* separate hours and minutes */
392 sec = atoi(str) * 3600 + atoi(s) * 60;
399 parse_flags(char *name, char *inst, char *str, afs_int32 * flags)
401 struct kaentryinfo tentry;
407 int addop; /* 1=add bit; 0=remove bit */
411 str = lcstring(bitspec, str, sizeof(bitspec));
413 if (strncmp(str, "0x", 2) == 0) /* 0x => hex */
414 sscanf(str, "0x%lx", &f);
415 else if (*str == '0') /* assume octal */
416 sscanf(str, "%lo", &f);
417 else /* just assume hex */
418 sscanf(str, "%lx", &f);
425 if (strchr("+-", *str))
426 addop = (*str++ == '+');
427 else if (*str == '_') {
433 ubik_Call(KAM_GetEntry, conn, 0, name, inst, KAMAJORVERSION,
436 afs_com_err(whoami, code,
437 "could get current flag value for %s.%s", name, inst);
454 if (strcmp(bit, "admin") == 0)
456 else if (strcmp(bit, "noadmin") == 0)
457 flag = KAFADMIN, addop = !addop;
458 else if (strcmp(bit, "notgs") == 0)
460 else if (strcmp(bit, "tgs") == 0)
461 flag = KAFNOTGS, addop = !addop;
462 else if (strcmp(bit, "noseal") == 0)
464 else if (strcmp(bit, "seal") == 0)
465 flag = KAFNOSEAL, addop = !addop;
466 else if (strcmp(bit, "nocpw") == 0)
468 else if (strcmp(bit, "cpw") == 0)
469 flag = KAFNOCPW, addop = !addop;
470 else if (strcmp(bit, "newassoc") == 0)
472 else if (strcmp(bit, "nonewassoc") == 0)
473 flag = KAFNEWASSOC, addop = !addop;
476 ("Illegal bit name: %s; choices are: [no]admin, [no]tgs, [no]seal, [no]cpw\n",
489 addop = 1; /* get next op */
490 else if ((*str == '-') || (*str == '_'))
493 printf("Illegal combination operator: %c\n", *str);
499 *flags = (f & KAF_SETTABLE_FLAGS) | KAFNORMAL;
503 #define seriouserror(code) ((code <0) || ((code != UNOSERVERS) && (code != UNOQUORUM) && code != UNOTSYNC))
505 /* return MAXLONG if locked forever */
507 ka_islocked(char *name, char *instance, afs_uint32 * when)
517 ubik_CallIter(KAM_LockStatus, conn, UPUBIKONLY, &count, (long) name,
518 (long) instance, (long) &tempwhen, 0, 0, 0,
519 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
521 if (seriouserror(code))
522 afs_com_err(whoami, code, "");
523 } else if (tempwhen) { /* user is locked */
524 if (!*when || tempwhen < *when) {
528 } else /* ! tempwhen ==> user is not locked */
531 } while (code != UNOSERVERS);
537 Unlock(struct cmd_syndesc *as, void *arock)
539 afs_int32 code, rcode = 0;
542 char name[MAXKTCNAMELEN];
543 char instance[MAXKTCNAMELEN];
545 code = ka_ParseLoginName(as->parms[0].items->data, name, instance, 0);
547 afs_com_err(whoami, code, "parsing user's name '%s'",
548 as->parms[0].items->data);
554 code = ubik_CallIter(KAM_Unlock, conn, 0, &count, (long) name, (long) instance,
555 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
556 if (code && (code != UNOSERVERS)) {
558 if (conn && conn->conns[count - 1]
559 && conn->conns[count - 1]->peer) {
560 server = conn->conns[count - 1]->peer->host;
562 afs_com_err(whoami, code,
563 "so %s.%s may still be locked (on server %d.%d.%d.%d)",
564 name, instance, ((server >> 24) & 0xFF),
565 ((server >> 16) & 0xFF), ((server >> 8) & 0xFF),
572 } while (code != UNOSERVERS);
578 SetFields(struct cmd_syndesc *as, void *arock)
581 char name[MAXKTCNAMELEN];
582 char instance[MAXKTCNAMELEN];
585 afs_int32 lifetime = 0;
586 afs_int32 maxAssociates = -1;
587 afs_int32 pwexpiry = 0;
588 afs_int32 was_spare = 0;
589 char misc_auth_bytes[4];
592 code = ka_ParseLoginName(as->parms[0].items->data, name, instance, 0);
594 afs_com_err(whoami, code, "parsing user's name '%s'",
595 as->parms[0].items->data);
599 if (as->parms[1].items) {
600 code = parse_flags(name, instance, as->parms[1].items->data, &flags);
603 ("Illegal flag specification: %s, should be of the form <'='|'+'|'-'|'_'>bitname{<'+'|'-'>bitname}*\n",
604 as->parms[1].items->data);
608 if (as->parms[2].items) {
610 char *s = strncpy(buf, as->parms[2].items->data, sizeof(buf));
611 code = ktime_DateToInt32(s, &expiration);
613 printf("Illegal time format %s: %s\n", as->parms[2].items->data,
614 ktime_GetDateUsage());
617 if (expiration == 0) {
618 fprintf(stderr, "Expiration time must be after (about) 1970.\n");
621 if (expiration < time(0)) {
623 "Warning: expiration being set into the past, account will be disabled.\n");
629 if (as->parms[3].items) {
630 code = read_time_interval(as->parms[3].items->data, &lifetime);
635 /* no point in doing this any sooner than necessary */
636 for (i = 0; i < 4; misc_auth_bytes[i++] = 0);
638 if (as->parms[4].items) {
639 if (util_isint(as->parms[4].items->data))
640 pwexpiry = atoi(as->parms[4].items->data);
643 "Password lifetime specified must be a non-negative decimal integer.\n");
646 if (pwexpiry < 0 || pwexpiry > 254) {
648 "Password lifetime range must be [0..254] days.\n");
649 fprintf(stderr, "Zero represents an unlimited lifetime.\n");
652 misc_auth_bytes[0] = pwexpiry + 1;
656 if (as->parms[5].items) {
658 reuse = (as->parms[5].items->data);
660 if (!strcmp(reuse, "yes")) {
661 misc_auth_bytes[1] = KA_REUSEPW;
662 } else if (strcmp(reuse, "no")) {
664 "must specify \"yes\" or \"no\": \"yes\" assumed\n");
665 misc_auth_bytes[1] = KA_REUSEPW;
667 misc_auth_bytes[1] = KA_NOREUSEPW;
671 if (as->parms[6].items) {
675 if (util_isint(as->parms[6].items->data)
676 && ((nfailures = atoi(as->parms[6].items->data)) < 255)) {
677 misc_auth_bytes[2] = nfailures + 1;
679 fprintf(stderr, "Failure limit must be in [0..254].\n");
680 fprintf(stderr, "Zero represents unlimited login attempts.\n");
685 if (as->parms[7].items) {
686 int locktime, hrs, mins;
690 s = as->parms[7].items->data;
692 sscanf(s, "%d:%d", &hrs, &mins);
694 sscanf(s, "%d", &mins);
696 locktime = hrs * 60 + mins;
697 if (hrs < 0 || hrs > 36 || mins < 0) {
699 "Lockout times must be either minutes or hh:mm.\n");
700 fprintf(stderr, "Lockout times must be less than 36 hours.\n");
702 } else if (locktime > 36 * 60) {
704 "Lockout times must be either minutes or hh:mm.\n");
705 fprintf(stderr, "Lockout times must be less than 36 hours.\n");
707 "Continuing with lock time of exactly 36 hours...\n");
710 locktime = (locktime * 60 + 511) >> 9; /* ceil(l*60/512) */
711 misc_auth_bytes[3] = locktime + 1; /* will be 1 if user said 0 */
714 if (as->parms[8].items) {
715 maxAssociates = atoi(as->parms[6].items->data);
716 if (maxAssociates < 0) {
717 printf("Illegal maximum number of associates\n");
722 was_spare = pack_long(misc_auth_bytes);
724 if (was_spare || flags || expiration || lifetime || (maxAssociates >= 0))
726 ubik_Call(KAM_SetFields, conn, 0, name, instance, flags,
727 expiration, lifetime, maxAssociates, was_spare,
730 printf("Must specify one of the optional parameters\n");
734 afs_com_err(whoami, code, "calling KAM_SetFields for %s.%s", name,
740 StringToKey(struct cmd_syndesc *as, void *arock)
743 char realm[MAXKTCREALMLEN];
744 struct ktc_encryptionKey key;
746 if (as->parms[1].items) {
747 code = ka_ExpandCell(as->parms[1].items->data, realm, 0 /*local */ );
749 afs_com_err(whoami, code,
750 "expanding %s as cell name, attempting to continue",
751 as->parms[1].items->data);
753 ucstring(realm, realm, sizeof(realm));
755 if ((code = DefaultCell()))
757 ucstring(realm, cell, sizeof(realm));
759 ka_StringToKey(as->parms[0].items->data, realm, &key);
761 printf("Converting %s in realm '%s' yields key='",
762 as->parms[0].items->data, realm);
763 ka_PrintBytes((char *)&key, sizeof(key));
766 des_string_to_key(as->parms[0].items->data, &key);
768 printf("Converting %s with the DES string to key yields key='",
769 as->parms[0].items->data);
770 ka_PrintBytes((char *)&key, sizeof(key));
777 SetPassword(struct cmd_syndesc *as, void *arock)
780 char name[MAXKTCNAMELEN];
781 char instance[MAXKTCNAMELEN];
782 char realm[MAXKTCREALMLEN];
783 struct ktc_encryptionKey key;
786 code = ka_ParseLoginName(as->parms[0].items->data, name, instance, realm);
788 afs_com_err(whoami, code, "parsing user's name '%s'",
789 as->parms[0].items->data);
793 if (strlen(realm) == 0)
794 ucstring(realm, cell, sizeof(realm));
796 if (as->parms[1].items && as->parms[2].items) {
797 printf("Can't specify both a password and a key\n");
799 } else if (as->parms[1].items) {
800 (void)init_child(myName);
801 (void)give_to_child(passwd); /* old password */
802 code = password_bad(as->parms[1].items->data);
803 (void)terminate_child();
806 ka_StringToKey(as->parms[1].items->data, realm, &key);
807 } else if (as->parms[2].items) {
808 if (ka_ReadBytes(as->parms[2].items->data, (char *)&key, sizeof(key))
810 printf("Key must be 8 bytes: '%s' was too long\n",
811 as->parms[2].items->data);
815 printf("Must specify new password or key\n");
820 if (as->parms[3].items)
821 sscanf(as->parms[3].items->data, "%d", &kvno);
823 #if defined(AFS_S390_LINUX20_ENV) && !defined(AFS_S390X_LINUX20_ENV)
824 code = ubik_Call(KAM_SetPassword, conn, 0, name, instance, kvno, 0, key);
826 code = ubik_Call(KAM_SetPassword, conn, 0, name, instance, kvno, 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_Call(KAM_GetPassword, lpbkConn, 0, name, &key);
1056 /* Lets close down the ubik_Client connection now */
1057 ubik_ClientDestroy(lpbkConn);
1061 ka_PrintBytes((char *)&key, sizeof(key));
1067 GetRandomKey(struct cmd_syndesc *as, void *arock)
1070 struct ktc_encryptionKey key;
1072 code = ubik_Call(KAM_GetRandomKey, conn, 0, &key);
1074 afs_com_err(whoami, code, "so can't get random key");
1078 ka_PrintBytes((char *)&key, sizeof(key));
1080 for (i = 0; i < sizeof(key); i++) {
1081 printf("%0.2x", ((char *)&key)[i] & 0xff);
1093 Statistics(struct cmd_syndesc *as, void *arock)
1099 char bob[KA_TIMESTR_LEN];
1102 ubik_Call(KAM_GetStats, conn, 0, KAMAJORVERSION, &admins, &statics,
1105 printf("call to GetStats failed: %s\n", ka_ErrorString(code));
1108 if (statics.minor_version != KAMINORVERSION)
1109 printf("Minor version number mismatch: got %d, expected %d\n",
1110 statics.minor_version, KAMINORVERSION);
1111 printf("%d allocs, %d frees, %d password changes\n", statics.allocs,
1112 statics.frees, statics.cpws);
1113 printf("Hash table utilization = %f%%\n",
1114 (double)dynamics.hashTableUtilization / 100.0);
1115 ka_timestr(dynamics.start_time, bob, KA_TIMESTR_LEN);
1116 printf("From host %lx started at %s:\n",
1117 afs_cast_uint32(dynamics.host), bob);
1119 #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)
1120 print_stat(Authenticate);
1121 print_stat(ChangePassword);
1122 print_stat(GetTicket);
1123 print_stat(CreateUser);
1124 print_stat(SetPassword);
1125 print_stat(SetFields);
1126 print_stat(DeleteUser);
1127 print_stat(GetEntry);
1128 print_stat(ListEntry);
1129 print_stat(GetStats);
1130 print_stat(GetPassword);
1131 print_stat(GetRandomKey);
1133 print_stat(UAuthenticate);
1134 print_stat(UGetTicket);
1136 #if (KAMAJORVERSION>5)
1137 print cpu stats printf("%d string checks\n", dynamics.string_checks);
1139 printf("Used %.3f seconds of CPU time.\n",
1140 dynamics.string_checks / 1000.0);
1142 printf("%d admin accounts\n", admins);
1147 DebugInfo(struct cmd_syndesc *as, void *arock)
1150 struct ka_debugInfo info;
1154 char bob[KA_TIMESTR_LEN];
1157 if (as->parms[0].items) {
1158 struct ubik_client *iConn;
1160 ka_SingleServerConn(cell, as->parms[0].items->data,
1161 KA_MAINTENANCE_SERVICE, 0, &iConn);
1163 struct afsconf_cell cellinfo;
1165 afs_com_err(whoami, code, "couldn't find host %s in cell %s",
1166 as->parms[0].items->data, cell);
1167 code = ka_GetServers(cell, &cellinfo);
1169 afs_com_err(whoami, code, "getting servers in cell %s", cell);
1171 printf("Servers in cell %s, are:\n", cell);
1172 for (i = 0; i < cellinfo.numServers; i++)
1173 printf(" %s\n", cellinfo.hostName[i]);
1177 code = ubik_Call(KAM_Debug, iConn, 0, KAMAJORVERSION, 0, &info);
1178 ubik_ClientDestroy(iConn);
1180 code = ubik_Call(KAM_Debug, conn, 0, KAMAJORVERSION, 0, &info);
1183 afs_com_err(whoami, code, "call to Debug failed");
1188 if (info.minorVersion != KAMINORVERSION)
1189 printf("Minor version number mismatch: got %d, expected %d\n",
1190 info.minorVersion, KAMINORVERSION);
1193 #if (KAMAJORVERSION>5)
1200 timeOffset = -timeOffset;
1201 if (timeOffset > 60) {
1203 ("WARNING: Large server client clock skew: %d seconds. Call itself took %d seconds.\n",
1204 timeOffset, now - start);
1206 ka_timestr(info.startTime, bob, KA_TIMESTR_LEN);
1207 printf("From host %lx started %sat %s:\n",
1208 afs_cast_uint32(info.host),
1209 (info.noAuth ? "w/o authorization " : ""), bob);
1210 ka_timestr(info.lastTrans, bob, KA_TIMESTR_LEN);
1211 printf("Last trans was %s at %s\n", info.lastOperation, bob);
1212 ka_timestr(info.dbHeaderRead, bob, KA_TIMESTR_LEN);
1213 printf("Header last read %s.\n", bob);
1214 printf("db version=%d, keyVersion=%d, key cache version=%d\n",
1215 info.dbVersion, info.dbSpecialKeysVersion, info.kcVersion);
1216 printf("db ptrs: free %d, eof %d, kvno %d.\n", info.dbFreePtr,
1217 info.dbEofPtr, info.dbKvnoPtr);
1218 ka_timestr(info.nextAutoCPW, bob, KA_TIMESTR_LEN);
1219 printf("Next autoCPW at %s or in %d updates.\n", bob,
1220 info.updatesRemaining);
1221 if (info.cheader_lock || info.keycache_lock)
1222 printf("locks: cheader %08lx, keycache %08lx\n",
1223 afs_cast_uint32(info.cheader_lock),
1224 afs_cast_uint32(info.keycache_lock));
1225 printf("Last authentication for %s, last admin user was %s\n",
1226 info.lastAuth, info.lastAdmin);
1227 printf("Last TGS op was a %s ticket was for %s\n", info.lastTGSServer,
1229 printf("Last UDP TGS was a %s ticket for %s. UDP Authenticate for %s\n",
1230 info.lastUTGSServer, info.lastUTGS, info.lastUAuth);
1231 printf("key cache size %d, used %d.\n", info.kcSize, info.kcUsed);
1232 if (info.kcUsed > KADEBUGKCINFOSIZE) {
1233 printf("insufficient room to return all key cache entries!\n");
1234 info.kcUsed = KADEBUGKCINFOSIZE;
1236 for (i = 0; i < info.kcUsed; i++)
1237 ka_timestr(info.kcInfo[i].used, bob, KA_TIMESTR_LEN);
1238 printf("%32s %c %2x(%2x) used %s\n", info.kcInfo[i].principal,
1239 (info.kcInfo[i].primary ? '*' : ' '), info.kcInfo[i].kvno,
1240 info.kcInfo[i].keycksum, bob);
1245 Interactive(struct cmd_syndesc *as, void *arock)
1252 Quit(struct cmd_syndesc *as, void *arock)
1259 MyAfterProc(struct cmd_syndesc *as, void *arock)
1261 if (!strcmp(as->name, "help"))
1264 /* Determine if we need to destory the ubik connection.
1265 * Closing it avoids resends of packets.
1268 ubik_ClientDestroy(conn);
1275 int init = 0, noauth;
1276 char name[MAXKTCNAMELEN];
1277 char instance[MAXKTCNAMELEN];
1278 char newCell[MAXKTCREALMLEN];
1279 afs_int32 serverList[MAXSERVERS];
1282 NoAuth(struct cmd_syndesc *as, void *arock)
1289 MyBeforeProc(struct cmd_syndesc *as, void *arock)
1291 struct ktc_encryptionKey key;
1292 struct ktc_principal auth_server, auth_token, client;
1293 char realm[MAXKTCREALMLEN];
1295 struct ktc_token token, *pToken;
1296 int i, acode, code = 0;
1299 char *ws = strrchr(as->a0name, '/');
1301 ws++; /* skip everything before the "/" */
1304 if (strlen(ws) > 0) {
1305 strncpy(whoami, ws, sizeof(whoami));
1306 if (strlen(whoami) + 1 >= sizeof(whoami))
1307 strcpy(whoami, "kas:");
1309 strcat(whoami, ":");
1312 /* append sub-command name */
1313 strncat(whoami, as->name, sizeof(whoami) - strlen(whoami) - 1);
1316 if (as->parms[12].name == 0)
1319 assert(as->parms[13].name && as->parms[14].name && as->parms[15].name
1320 && as->parms[16].name);
1322 /* MyAfterProc() destroys the conn, but just to be sure */
1324 code = ubik_ClientDestroy(conn);
1328 if (!init || as->parms[12].items || as->parms[13].items
1329 || as->parms[14].items || as->parms[15].items
1330 || as->parms[16].items) {
1331 strcpy(instance, "");
1332 strcpy(newCell, "");
1334 if (as->parms[12].items) { /* -admin_username */
1336 ka_ParseLoginName(as->parms[12].items->data, name, instance,
1339 afs_com_err(whoami, code, "parsing user's name '%s'",
1340 as->parms[12].items->data);
1345 DWORD len = MAXKTCNAMELEN;
1346 if (!GetUserName((LPTSTR) name, &len)) {
1347 printf("Can't get user name \n");
1351 /* No explicit name provided: use Unix uid. */
1352 struct passwd *pw = getpwuid(getuid());
1354 printf("Can't figure out your name from your user id.\n");
1357 strncpy(name, pw->pw_name, sizeof(name));
1361 if (as->parms[14].items) { /* -cell */
1362 if (strlen(newCell) > 0) {
1363 printf("Duplicate cell specification not allowed\n");
1365 strncpy(newCell, as->parms[14].items->data, sizeof(newCell));
1368 code = ka_ExpandCell(newCell, newCell, 0 /*local */ );
1370 afs_com_err(whoami, code, "Can't expand cell name");
1373 strcpy(cell, newCell);
1375 if (as->parms[15].items) { /* -servers */
1376 struct cmd_item *ip;
1377 char *ap[MAXSERVERS + 2];
1381 for (ip = as->parms[15].items, i = 2; ip; ip = ip->next, i++)
1383 code = ubik_ParseClientList(i, ap, serverList);
1385 afs_com_err(whoami, code, "could not parse server list");
1388 ka_ExplicitCell(cell, serverList);
1391 noauth = (as->parms[16].items ? 1 : 0); /* -noauth */
1396 token.ticketLen = 0; /* in case there are no tokens */
1397 if (!noauth) { /* Will prompt for a password */
1398 /* first see if there's already an admin ticket */
1400 ka_GetAdminToken(0, 0, cell, 0, KA_SIXHOURS, &token,
1402 if (code) { /* if not then get key and try again */
1403 if (as->parms[13].items) { /* if password specified */
1404 strncpy(passwd, as->parms[13].items->data, sizeof(passwd));
1405 memset(as->parms[13].items->data, 0,
1406 strlen(as->parms[13].items->data));
1408 char msg[MAXKTCNAMELEN + 50];
1409 if (as->parms[12].items)
1410 sprintf(msg, "Administrator's (%s) Password: ", name);
1412 sprintf(msg, "Password for %s: ", name);
1413 code = read_pw_string(passwd, sizeof(passwd), msg, 0);
1416 else if (strlen(passwd) == 0)
1417 code = KANULLPASSWORD;
1419 afs_com_err(whoami, code, "reading password");
1423 ka_StringToKey(passwd, cell, &key);
1425 ka_GetAdminToken(name, instance, cell, &key, KA_SIXHOURS,
1426 &token, 0 /* !new */ );
1427 if (code == KABADREQUEST) {
1428 des_string_to_key(passwd, &key);
1430 ka_GetAdminToken(name, instance, cell, &key, KA_SIXHOURS,
1431 &token, 0 /* !new */ );
1433 if ((code == KABADREQUEST) && (strlen(passwd) > 8)) {
1434 /* try with only the first 8 characters incase they set
1435 * their password with an old style passwd program. */
1437 ka_StringToKey(passwd, cell, &key);
1439 ka_GetAdminToken(name, instance, cell, &key, KA_SIXHOURS,
1440 &token, 0 /* !new */ );
1443 "Warning: you have typed a password longer than 8 characters, but only the\n");
1445 "first 8 characters were actually significant. If you change your password\n");
1447 "again this warning message will go away.\n");
1454 reason = "password was incorrect";
1457 reason = "Authentication Server was unavailable";
1460 reason = (char *)afs_error_message(code);
1463 "%s: Auth. as %s to AuthServer failed: %s\nProceeding w/o authentication\n",
1464 whoami, PrintedName(name, instance, cell), reason);
1466 /* get an Authentication token while were at it. */
1467 if (ka_CellToRealm(cell, realm, 0) != 0)
1469 strcpy(auth_server.name, KA_TGS_NAME);
1470 strcpy(auth_server.instance, realm);
1471 strcpy(auth_server.cell, cell);
1473 (&auth_server, &auth_token, sizeof(struct ktc_token),
1476 ka_GetAuthToken(name, instance, cell, &key,
1477 MAXKTCTICKETLIFETIME, (afs_int32 *) 0
1478 /*Don't need pwd expiration info here */
1480 if (acode && (acode != code)) /* codes are usually the same */
1481 afs_com_err(whoami, code,
1482 "getting Authentication token for %s",
1483 PrintedName(name, instance, cell));
1485 memset(&key, 0, sizeof(key));
1489 pToken = ((token.ticketLen == 0) ? 0 : &token);
1490 code = ka_AuthServerConn(cell, KA_MAINTENANCE_SERVICE, pToken, &conn);
1491 if (code && pToken) {
1492 afs_com_err(whoami, code,
1493 "connecting to AuthServer: now trying w/o authentication");
1494 code = ka_AuthServerConn(cell, KA_MAINTENANCE_SERVICE, 0, &conn);
1496 afs_com_err(whoami, code,
1497 "making unauthenticated connection to AuthServer");
1500 afs_com_err(whoami, code,
1501 "Couldn't establish connection to Authentication Server");
1505 /* now default unspecified password by prompting from terminal */
1506 if (as->nParms >= 12)
1507 for (i = 0; i < 12; i++)
1508 if (as->parms[i].name && (as->parms[i].items == 0)) {
1509 char *p = as->parms[i].name; /* parameter name */
1510 int l = strlen(p); /* length of name */
1511 /* does parameter end in "password" */
1512 if (strcmp(p + (l - 8), "password") == 0) {
1514 char password[BUFSIZ];
1515 struct cmd_item *ip;
1519 code = read_pw_string(password, sizeof(password), msg, 1);
1522 else if (strlen(password) == 0)
1523 code = KANULLPASSWORD;
1525 afs_com_err(whoami, code, "prompting for %s", p + 1);
1528 ip = (struct cmd_item *)malloc(sizeof(struct cmd_item));
1529 ip->data = (char *)malloc(strlen(password) + 1);
1531 strcpy(ip->data, password);
1532 as->parms[i].items = ip;
1535 if (!conn) { /* if all else fails... */
1536 code = NoAuth(0, 0); /* get unauthenticated conn */
1543 /* These are some helpful command that deal with the cache managers tokens. */
1546 ForgetTicket(struct cmd_syndesc *as, void *arock)
1551 struct ktc_principal server;
1553 if (as->parms[0].items) {
1554 char *name = as->parms[0].items->data;
1556 ka_ParseLoginName(name, server.name, server.instance,
1559 afs_com_err(whoami, code, "couldn't interpret name '%s'", name);
1562 if (server.cell[0] == 0) {
1563 if (code = DefaultCell())
1565 strcpy(server.cell, cell);
1567 code = ka_ExpandCell(server.cell, server.cell, 0 /*local */ );
1569 afs_com_err(whoami, code, "Can't expand cell name");
1573 code = ktc_ForgetToken(&server);
1575 afs_com_err(whoami, code, "couldn't remove tokens for %s",
1576 PrintedPrincipal(&server));
1580 if (!as->parms[1].items) {
1581 fprintf(stderr, "Must specify server name or -all\n");
1584 code = ktc_ForgetAllTokens();
1586 afs_com_err(whoami, code, "couldn't delete all tokens");
1591 code = ktc_ForgetAllTokens();
1593 afs_com_err(whoami, code, "couldn't delete all tokens");
1600 ListTickets(struct cmd_syndesc *as, void *arock)
1603 int index, newIndex;
1604 struct ktc_principal server;
1607 if (as->parms[1].items)
1609 if (as->parms[0].items) {
1610 char *name = as->parms[0].items->data;
1612 ka_ParseLoginName(name, server.name, server.instance,
1615 afs_com_err(whoami, code, "couldn't interpret name '%s'", name);
1618 if (server.cell[0] == 0) {
1619 if ((code = DefaultCell()))
1621 strcpy(server.cell, cell);
1623 code = ka_ExpandCell(server.cell, server.cell, 0 /*local */ );
1625 afs_com_err(whoami, code, "Can't expand cell name");
1629 code = ListTicket(&server, verbose);
1631 for (index = 0;; index = newIndex) {
1632 code = ktc_ListTokens(index, &newIndex, &server);
1634 if (code == KTC_NOENT)
1635 code = 0; /* end of list */
1638 code = ListTicket(&server, verbose);
1644 add_std_args(register struct cmd_syndesc *ts)
1647 /* 12 */ cmd_AddParm(ts, "-admin_username", CMD_SINGLE, CMD_OPTIONAL,
1648 "admin principal to use for authentication");
1649 /* 13 */ cmd_AddParm(ts, "-password_for_admin", CMD_SINGLE, CMD_OPTIONAL,
1651 /* 14 */ cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
1652 /* 15 */ cmd_AddParm(ts, "-servers", CMD_LIST, CMD_OPTIONAL,
1653 "explicit list of authentication servers");
1654 /* 16 */ cmd_AddParm(ts, "-noauth", CMD_FLAG, CMD_OPTIONAL,
1655 "don't authenticate");
1659 ka_AdminInteractive(int cmd_argc, char *cmd_argv[])
1662 register struct cmd_syndesc *ts;
1668 strncpy(myName, *cmd_argv, 509);
1670 cmd_SetBeforeProc(MyBeforeProc, NULL);
1671 cmd_SetAfterProc(MyAfterProc, NULL);
1673 ts = cmd_CreateSyntax("interactive", Interactive, NULL,
1674 "enter interactive mode");
1677 ts = cmd_CreateSyntax("noauthentication", NoAuth, NULL,
1678 "connect to AuthServer w/o using token");
1680 ts = cmd_CreateSyntax("list", ListUsers, NULL,
1681 "list all users in database");
1682 cmd_AddParm(ts, "-long", CMD_FLAG, CMD_OPTIONAL,
1683 "show detailed info about each user");
1684 cmd_AddParm(ts, "-showadmin", CMD_FLAG, CMD_OPTIONAL,
1685 "show all cell administrators");
1686 cmd_AddParm(ts, "-showkey", CMD_FLAG, CMD_OPTIONAL,
1687 "show the user's actual key rather than the checksum");
1689 cmd_CreateAlias(ts, "ls");
1691 ts = cmd_CreateSyntax("examine", ExamineUser, NULL,
1692 "examine the entry for a user");
1693 cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1694 cmd_AddParm(ts, "-showkey", CMD_FLAG, CMD_OPTIONAL,
1695 "show the user's actual key rather than the checksum");
1698 ts = cmd_CreateSyntax("create", CreateUser, NULL,
1699 "create an entry for a user");
1700 cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1701 cmd_AddParm(ts, "-initial_password", CMD_SINGLE, CMD_OPTIONAL,
1702 "initial password");
1705 ts = cmd_CreateSyntax("delete", DeleteUser, NULL, "delete a user");
1706 cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1708 cmd_CreateAlias(ts, "rm");
1710 ts = cmd_CreateSyntax("setfields", SetFields, NULL,
1711 "set various fields in a user's entry");
1712 cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1713 cmd_AddParm(ts, "-flags", CMD_SINGLE, CMD_OPTIONAL,
1714 "hex flag value or flag name expression");
1715 cmd_AddParm(ts, "-expiration", CMD_SINGLE, CMD_OPTIONAL,
1716 "date of account expiration");
1717 cmd_AddParm(ts, "-lifetime", CMD_SINGLE, CMD_OPTIONAL,
1718 "maximum ticket lifetime");
1719 cmd_AddParm(ts, "-pwexpires", CMD_SINGLE, CMD_OPTIONAL,
1720 "number days password is valid ([0..254])");
1721 cmd_AddParm(ts, "-reuse", CMD_SINGLE, CMD_OPTIONAL,
1722 "permit password reuse (yes/no)");
1723 cmd_AddParm(ts, "-attempts", CMD_SINGLE, CMD_OPTIONAL,
1724 "maximum successive failed login tries ([0..254])");
1725 cmd_AddParm(ts, "-locktime", CMD_SINGLE, CMD_OPTIONAL,
1726 "failure penalty [hh:mm or minutes]");
1728 cmd_AddParm(ts, "-associates", CMD_SINGLE, CMD_OPTIONAL,
1729 "maximum associate instances");
1732 cmd_CreateAlias(ts, "sf");
1735 ts = cmd_CreateSyntax("unlock", Unlock, NULL,
1736 "Enable authentication ID after max failed attempts exceeded");
1737 cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "authentication ID");
1741 ts = cmd_CreateSyntax("stringtokey", StringToKey, NULL,
1742 "convert a string to a key");
1743 cmd_AddParm(ts, "-string", CMD_SINGLE, 0, "password string");
1744 cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
1746 ts = cmd_CreateSyntax("setpassword", SetPassword, NULL,
1747 "set a user's password");
1748 cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1749 cmd_AddParm(ts, "-new_password", CMD_SINGLE, CMD_OPTIONAL,
1752 cmd_AddParm(ts, "-kvno", CMD_SINGLE, CMD_OPTIONAL, "key version number");
1754 cmd_CreateAlias(ts, "sp");
1755 #ifdef CMD_PARSER_AMBIG_FIX
1756 cmd_CreateAlias(ts, "setpasswd");
1759 /* set a user's key */
1760 ts = cmd_CreateSyntax("setkey", SetPassword, NULL, (char *)CMD_HIDDEN);
1761 cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1763 cmd_AddParm(ts, "-new_key", CMD_SINGLE, 0, "eight byte new key");
1765 cmd_AddParm(ts, "-kvno", CMD_SINGLE, CMD_OPTIONAL, "key version number");
1768 /* get a user's password */
1769 ts = cmd_CreateSyntax("getpassword", GetPassword, NULL, (char *)CMD_HIDDEN);
1770 cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of user");
1771 /* don't take standard args */
1772 /* add_std_args (ts); */
1773 #ifdef CMD_PARSER_AMBIG_FIX
1774 cmd_CreateAlias(ts, "getpasswd");
1777 /* get a random key */
1778 ts = cmd_CreateSyntax("getrandomkey", GetRandomKey, NULL,
1779 (char *)CMD_HIDDEN);
1782 /* get a ticket for a specific server */
1783 ts = cmd_CreateSyntax("getticket", GetTicket, NULL, (char *)CMD_HIDDEN);
1784 cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name of server");
1785 cmd_AddParm(ts, "-lifetime", CMD_SINGLE, CMD_OPTIONAL, "ticket lifetime");
1788 ts = cmd_CreateSyntax("statistics", Statistics, NULL,
1789 "show statistics for AuthServer");
1792 /* show debugging info from AuthServer */
1793 ts = cmd_CreateSyntax("debuginfo", DebugInfo, NULL, (char *)CMD_HIDDEN);
1794 cmd_AddParm(ts, "-hostname", CMD_SINGLE, CMD_OPTIONAL,
1795 "authentication server host name");
1798 ts = cmd_CreateSyntax("forgetticket", ForgetTicket, NULL,
1799 "delete user's tickets");
1801 cmd_AddParm(ts, "-name", CMD_SINGLE, (CMD_OPTIONAL | CMD_HIDE),
1804 cmd_AddParm(ts, "-all", CMD_FLAG, CMD_OPTIONAL, "delete all tickets");
1806 ts = cmd_CreateSyntax("listtickets", ListTickets, NULL,
1807 "show all cache manager tickets");
1808 cmd_AddParm(ts, "-name", CMD_SINGLE, CMD_OPTIONAL, "name of server");
1809 cmd_AddParm(ts, "-long", CMD_FLAG, CMD_OPTIONAL,
1810 "show session key and ticket");
1812 ts = cmd_CreateSyntax("quit", Quit, NULL, "exit program");
1815 conn = 0; /* no connection yet */
1816 zero_argc = cmd_argc;
1817 zero_argv = cmd_argv;
1819 strcpy(whoami, "kas");
1821 if ((code = cmd_Dispatch(cmd_argc, cmd_argv))) {
1830 s = fgets(line, sizeof(line), stdin);
1832 return 0; /* EOF on input */
1833 for (i = strlen(line) - 1; i >= 0 && isspace(line[i]); i--)
1836 continue; /* blank line */
1839 cmd_ParseLine(line, argv, &argc, sizeof(argv) / sizeof(argv[0]));
1841 afs_com_err(whoami, code, "parsing line: '%s'", line);
1844 code = cmd_Dispatch(argc, argv);