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>
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>
42 #include <hcrypto/des.h>
43 #include <hcrypto/ui.h>
45 #include "kauth_internal.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_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_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_KAM_CreateUser(conn, 0, name, instance,
345 *ktc_to_EncryptionKey(&key));
348 ka_PrintUserID("Creating user ", name, instance, " ");
349 code = handle_errors(code, OKlist, &persist);
355 DeleteUser(struct cmd_syndesc *as, void *arock)
358 char name[MAXKTCNAMELEN];
359 char instance[MAXKTCNAMELEN];
362 struct OKerrors OKlist[2];
364 code = ka_ParseLoginName(as->parms[0].items->data, name, instance, 0);
366 afs_com_err(whoami, code, "parsing user's name '%s'",
367 as->parms[0].items->data);
372 code = ubik_KAM_DeleteUser(conn, 0, name, instance);
375 ka_PrintUserID("Deleting user ", name, instance, " ");
376 code = handle_errors(code, OKlist, &persist);
382 read_time_interval(char *str, afs_int32 * seconds)
388 str = strncpy(buf, str, sizeof(buf));
389 s = strchr(str, ':');
393 *s++ = '\0'; /* separate hours and minutes */
394 sec = atoi(str) * 3600 + atoi(s) * 60;
401 parse_flags(char *name, char *inst, char *str, afs_int32 * flags)
403 struct kaentryinfo tentry;
409 int addop; /* 1=add bit; 0=remove bit */
413 str = lcstring(bitspec, str, sizeof(bitspec));
415 if (strncmp(str, "0x", 2) == 0) /* 0x => hex */
416 sscanf(str, "0x%lx", (long unsigned int *) &f);
417 else if (*str == '0') /* assume octal */
418 sscanf(str, "%lo", (long unsigned int *) &f);
419 else /* just assume hex */
420 sscanf(str, "%lx", (long unsigned int *) &f);
427 if (strchr("+-", *str))
428 addop = (*str++ == '+');
429 else if (*str == '_') {
435 ubik_KAM_GetEntry(conn, 0, name, inst, KAMAJORVERSION,
438 afs_com_err(whoami, code,
439 "could get current flag value for %s.%s", name, inst);
456 if (strcmp(bit, "admin") == 0)
458 else if (strcmp(bit, "noadmin") == 0)
459 flag = KAFADMIN, addop = !addop;
460 else if (strcmp(bit, "notgs") == 0)
462 else if (strcmp(bit, "tgs") == 0)
463 flag = KAFNOTGS, addop = !addop;
464 else if (strcmp(bit, "noseal") == 0)
466 else if (strcmp(bit, "seal") == 0)
467 flag = KAFNOSEAL, addop = !addop;
468 else if (strcmp(bit, "nocpw") == 0)
470 else if (strcmp(bit, "cpw") == 0)
471 flag = KAFNOCPW, addop = !addop;
472 else if (strcmp(bit, "newassoc") == 0)
474 else if (strcmp(bit, "nonewassoc") == 0)
475 flag = KAFNEWASSOC, addop = !addop;
478 ("Illegal bit name: %s; choices are: [no]admin, [no]tgs, [no]seal, [no]cpw\n",
491 addop = 1; /* get next op */
492 else if ((*str == '-') || (*str == '_'))
495 printf("Illegal combination operator: %c\n", *str);
501 *flags = (f & KAF_SETTABLE_FLAGS) | KAFNORMAL;
505 #define seriouserror(code) ((code <0) || ((code != UNOSERVERS) && (code != UNOQUORUM) && code != UNOTSYNC))
507 /* return MAXLONG if locked forever */
509 ka_islocked(char *name, char *instance, afs_uint32 * when)
519 ubik_CallIter(KAM_LockStatus, conn, UPUBIKONLY, &count, (long) name,
520 (long) instance, (long) &tempwhen, 0, 0, 0,
521 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
523 if (seriouserror(code))
524 afs_com_err(whoami, code, NULL);
525 } else if (tempwhen) { /* user is locked */
526 if (!*when || tempwhen < *when) {
530 } else /* ! tempwhen ==> user is not locked */
533 } while (code != UNOSERVERS);
539 Unlock(struct cmd_syndesc *as, void *arock)
541 afs_int32 code, rcode = 0;
544 char name[MAXKTCNAMELEN];
545 char instance[MAXKTCNAMELEN];
547 code = ka_ParseLoginName(as->parms[0].items->data, name, instance, 0);
549 afs_com_err(whoami, code, "parsing user's name '%s'",
550 as->parms[0].items->data);
556 code = ubik_CallIter(KAM_Unlock, conn, 0, &count, (long) name, (long) instance,
557 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
558 if (code && (code != UNOSERVERS)) {
560 if (conn && conn->conns[count - 1]
561 && conn->conns[count - 1]->peer) {
562 server = conn->conns[count - 1]->peer->host;
564 afs_com_err(whoami, code,
565 "so %s.%s may still be locked (on server %d.%d.%d.%d)",
566 name, instance, ((server >> 24) & 0xFF),
567 ((server >> 16) & 0xFF), ((server >> 8) & 0xFF),
574 } while (code != UNOSERVERS);
580 SetFields(struct cmd_syndesc *as, void *arock)
583 char name[MAXKTCNAMELEN];
584 char instance[MAXKTCNAMELEN];
587 afs_int32 lifetime = 0;
588 afs_int32 maxAssociates = -1;
589 afs_int32 pwexpiry = 0;
590 afs_int32 was_spare = 0;
591 char misc_auth_bytes[4];
594 code = ka_ParseLoginName(as->parms[0].items->data, name, instance, 0);
596 afs_com_err(whoami, code, "parsing user's name '%s'",
597 as->parms[0].items->data);
601 if (as->parms[1].items) {
602 code = parse_flags(name, instance, as->parms[1].items->data, &flags);
605 ("Illegal flag specification: %s, should be of the form <'='|'+'|'-'|'_'>bitname{<'+'|'-'>bitname}*\n",
606 as->parms[1].items->data);
610 if (as->parms[2].items) {
612 char *s = strncpy(buf, as->parms[2].items->data, sizeof(buf));
613 code = ktime_DateToInt32(s, &expiration);
615 printf("Illegal time format %s: %s\n", as->parms[2].items->data,
616 ktime_GetDateUsage());
619 if (expiration == 0) {
620 fprintf(stderr, "Expiration time must be after (about) 1970.\n");
623 if (expiration < time(0)) {
625 "Warning: expiration being set into the past, account will be disabled.\n");
631 if (as->parms[3].items) {
632 code = read_time_interval(as->parms[3].items->data, &lifetime);
637 /* no point in doing this any sooner than necessary */
638 for (i = 0; i < 4; misc_auth_bytes[i++] = 0);
640 if (as->parms[4].items) {
641 if (util_isint(as->parms[4].items->data))
642 pwexpiry = atoi(as->parms[4].items->data);
645 "Password lifetime specified must be a non-negative decimal integer.\n");
648 if (pwexpiry < 0 || pwexpiry > 254) {
650 "Password lifetime range must be [0..254] days.\n");
651 fprintf(stderr, "Zero represents an unlimited lifetime.\n");
654 misc_auth_bytes[0] = pwexpiry + 1;
658 if (as->parms[5].items) {
660 reuse = (as->parms[5].items->data);
662 if (!strcmp(reuse, "yes")) {
663 misc_auth_bytes[1] = KA_REUSEPW;
664 } else if (strcmp(reuse, "no")) {
666 "must specify \"yes\" or \"no\": \"yes\" assumed\n");
667 misc_auth_bytes[1] = KA_REUSEPW;
669 misc_auth_bytes[1] = KA_NOREUSEPW;
673 if (as->parms[6].items) {
677 if (util_isint(as->parms[6].items->data)
678 && ((nfailures = atoi(as->parms[6].items->data)) < 255)) {
679 misc_auth_bytes[2] = nfailures + 1;
681 fprintf(stderr, "Failure limit must be in [0..254].\n");
682 fprintf(stderr, "Zero represents unlimited login attempts.\n");
687 if (as->parms[7].items) {
688 int locktime, hrs, mins;
692 s = as->parms[7].items->data;
694 sscanf(s, "%d:%d", &hrs, &mins);
696 sscanf(s, "%d", &mins);
698 locktime = hrs * 60 + mins;
699 if (hrs < 0 || hrs > 36 || mins < 0) {
701 "Lockout times must be either minutes or hh:mm.\n");
702 fprintf(stderr, "Lockout times must be less than 36 hours.\n");
704 } else if (locktime > 36 * 60) {
706 "Lockout times must be either minutes or hh:mm.\n");
707 fprintf(stderr, "Lockout times must be less than 36 hours.\n");
709 "Continuing with lock time of exactly 36 hours...\n");
712 locktime = (locktime * 60 + 511) >> 9; /* ceil(l*60/512) */
713 misc_auth_bytes[3] = locktime + 1; /* will be 1 if user said 0 */
716 if (as->parms[8].items) {
717 maxAssociates = atoi(as->parms[6].items->data);
718 if (maxAssociates < 0) {
719 printf("Illegal maximum number of associates\n");
724 was_spare = pack_long(misc_auth_bytes);
726 if (was_spare || flags || expiration || lifetime || (maxAssociates >= 0))
728 ubik_KAM_SetFields(conn, 0, name, instance, flags,
729 expiration, lifetime, maxAssociates, was_spare,
732 printf("Must specify one of the optional parameters\n");
736 afs_com_err(whoami, code, "calling KAM_SetFields for %s.%s", name,
742 StringToKey(struct cmd_syndesc *as, void *arock)
745 char realm[MAXKTCREALMLEN];
746 struct ktc_encryptionKey key;
748 if (as->parms[1].items) {
749 code = ka_ExpandCell(as->parms[1].items->data, realm, 0 /*local */ );
751 afs_com_err(whoami, code,
752 "expanding %s as cell name, attempting to continue",
753 as->parms[1].items->data);
755 ucstring(realm, realm, sizeof(realm));
757 if ((code = DefaultCell()))
759 ucstring(realm, cell, sizeof(realm));
761 ka_StringToKey(as->parms[0].items->data, realm, &key);
763 printf("Converting %s in realm '%s' yields key='",
764 as->parms[0].items->data, realm);
765 ka_PrintBytes((char *)&key, sizeof(key));
768 DES_string_to_key(as->parms[0].items->data, ktc_to_cblockptr(&key));
770 printf("Converting %s with the DES string to key yields key='",
771 as->parms[0].items->data);
772 ka_PrintBytes((char *)&key, sizeof(key));
779 SetPassword(struct cmd_syndesc *as, void *arock)
782 char name[MAXKTCNAMELEN];
783 char instance[MAXKTCNAMELEN];
784 char realm[MAXKTCREALMLEN];
785 struct ktc_encryptionKey key;
788 code = ka_ParseLoginName(as->parms[0].items->data, name, instance, realm);
790 afs_com_err(whoami, code, "parsing user's name '%s'",
791 as->parms[0].items->data);
795 if (strlen(realm) == 0)
796 ucstring(realm, cell, sizeof(realm));
798 if (as->parms[1].items && as->parms[2].items) {
799 printf("Can't specify both a password and a key\n");
801 } else if (as->parms[1].items) {
802 (void)init_child(myName);
803 (void)give_to_child(passwd); /* old password */
804 code = password_bad(as->parms[1].items->data);
805 (void)terminate_child();
808 ka_StringToKey(as->parms[1].items->data, realm, &key);
809 } else if (as->parms[2].items) {
810 if (ka_ReadBytes(as->parms[2].items->data, (char *)&key, sizeof(key))
812 printf("Key must be 8 bytes: '%s' was too long\n",
813 as->parms[2].items->data);
817 printf("Must specify new password or key\n");
822 if (as->parms[3].items)
823 sscanf(as->parms[3].items->data, "%d", &kvno);
825 code = ubik_KAM_SetPassword(conn, 0, name, instance, kvno,
826 *ktc_to_EncryptionKey(&key));
828 afs_com_err(whoami, code, "so can't set password for %s.%s", name,
833 #define PrintPrincipal(p,n,l) \
834 PrintName((p)->name, (p)->instance, (p)->cell, l, n)
837 PrintName(char *name, char *inst, char *acell, int buflen, char *buf)
840 int left; /* if ConvertBytes stops early */
849 left = ka_ConvertBytes(buf, buflen, name, strlen(name));
853 afs_com_err(whoami, code, "PrintName: principal name was '%s'.'%s'@'%s'",
860 if (nlen + len + 1 >= buflen)
863 left = ka_ConvertBytes(buf + nlen, buflen - nlen, inst, len);
871 char *lcell = ka_LocalCell();
874 if (strcmp(acell, lcell) != 0) {
875 /* only append cell if not the local cell */
876 if (nlen + len + 1 >= buflen)
879 left = ka_ConvertBytes(buf + nlen, buflen - nlen, acell, len);
888 #define PrintedPrincipal(p) PrintedName ((p)->name, (p)->instance, (p)->cell)
890 /* PrintedName - returned a pointer to a static string in which the formated
891 * name has been stored. */
894 PrintedName(char *name, char *inst, char *cell)
896 static char printedName[128];
898 code = PrintName(name, inst, cell, sizeof(printedName), printedName);
902 strncpy(printedName, name, sizeof(printedName));
903 printedName[sizeof(printedName) - 8] = 0;
904 strcat(printedName, "<error>");
910 ListTicket(struct ktc_principal *server, int verbose)
913 struct ktc_token token; /* the token we're printing */
914 struct ktc_principal client;
915 char UserName[sizeof(struct ktc_principal)];
916 char ServerName[sizeof(struct ktc_principal)];
917 afs_int32 now = time(0);
918 char bob[KA_TIMESTR_LEN];
920 /* get the ticket info itself */
921 code = ktc_GetToken(server, &token, sizeof(token), &client);
923 afs_com_err(whoami, code, "failed to get token info for server %s",
924 PrintedPrincipal(server));
927 code = PrintPrincipal(&client, UserName, sizeof(UserName));
930 /* spaces are printed as "\040" */
931 if (UserName[0] == 0)
933 else if (strncmp(UserName, "AFS\\040ID\\040", 13) == 0) {
934 printf("User's (AFS ID %s) tokens", UserName + 13);
935 } else if (strncmp(UserName, "Unix\\040UID\\040", 15) == 0) {
938 printf("User %s's tokens", UserName);
940 code = PrintPrincipal(server, ServerName, sizeof(ServerName));
943 printf(" for %s ", ServerName);
945 if (token.startTime > now) {
946 ka_timestr(token.startTime, bob, KA_TIMESTR_LEN);
947 printf("[>> POSTDATED 'till %s <<]", bob);
950 if (token.endTime <= now)
951 printf("[>> Expired <<]\n");
953 ka_timestr(token.endTime, bob, KA_TIMESTR_LEN);
954 printf("[Expires %s]\n", bob);
957 printf("SessionKey: ");
958 ka_PrintBytes((char *)&token.sessionKey, sizeof(token.sessionKey));
959 printf("\nTicket (kvno = %d, len = %d): ", token.kvno,
961 ka_PrintBytes((char *)token.ticket, token.ticketLen);
968 GetTicket(struct cmd_syndesc *as, void *arock)
971 struct ktc_principal server;
972 struct ktc_token token;
973 afs_int32 life = KA_SIXHOURS;
975 if (as->parms[1].items) {
976 code = read_time_interval(as->parms[1].items->data, &life);
981 ka_ParseLoginName(as->parms[0].items->data, server.name,
982 server.instance, server.cell);
984 afs_com_err(whoami, code, "parsing user's name '%s'",
985 as->parms[0].items->data);
988 if (server.cell[0] == 0) {
989 if ((code = DefaultCell()))
991 strcpy(server.cell, cell);
993 code = ka_ExpandCell(server.cell, server.cell, 0 /*local */ );
995 afs_com_err(whoami, code, "Can't expand cell name");
1000 token.ticketLen = 0; /* in case there are no tokens */
1002 ka_GetServerToken(server.name, server.instance, server.cell, life,
1003 &token, /*new */ 1, /*dosetpag */ 0);
1005 afs_com_err(whoami, code, "getting ticket for %s",
1006 PrintedPrincipal(&server));
1008 code = ListTicket(&server, /*verbose */ 1);
1014 GetPassword(struct cmd_syndesc *as, void *arock)
1017 char name[MAXKTCNAMELEN];
1018 struct ktc_encryptionKey key;
1019 static struct ubik_client *lpbkConn = 0;
1021 /* no instance allowed */
1022 code = ka_ParseLoginName(as->parms[0].items->data, name, 0, 0);
1025 afs_com_err(whoami, code,
1026 "getting %s's password via loopback connection to GetPassword",
1028 /* if we got a timeout, print a clarification, too */
1031 "%s: please note that this command must be run locally on a database server machine.\n",
1036 if (lpbkConn == 0) {
1037 struct rx_connection *conns[2];
1038 struct rx_securityClass *sc;
1039 int si; /* security class index */
1044 sc = rxnull_NewClientSecurityObject();
1045 si = RX_SCINDEX_NULL;
1047 rx_NewConnection(htonl(INADDR_LOOPBACK), htons(AFSCONF_KAUTHPORT),
1048 KA_MAINTENANCE_SERVICE, sc, si);
1050 code = ubik_ClientInit(conns, &lpbkConn);
1054 code = ubik_KAM_GetPassword(lpbkConn, 0, name,
1055 ktc_to_EncryptionKey(&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_KAM_GetRandomKey(conn, 0, ktc_to_EncryptionKey(&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("%.2x", ((char *)&key)[i] & 0xff);
1093 Statistics(struct cmd_syndesc *as, void *arock)
1099 char bob[KA_TIMESTR_LEN];
1102 ubik_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_printable_uint32_lu(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_KAM_Debug(iConn, 0, KAMAJORVERSION, 0, &info);
1178 ubik_ClientDestroy(iConn);
1180 code = ubik_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_printable_uint32_lu(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_printable_uint32_lu(info.cheader_lock),
1224 afs_printable_uint32_lu(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_uint32 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, client;
1293 struct ktc_token auth_token;
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 = UI_UTIL_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 = UI_UTIL_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(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 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);