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>
31 #include <rx/rxkad_convert.h>
33 #define UBIK_LEGACY_CALLITER 1
36 #include <afs/cellconfig.h>
38 #include <afs/com_err.h>
39 #include <afs/afsutil.h>
42 #include "kauth_internal.h"
47 #define CMD_PARSER_AMBIG_FIX 1 /* allow ambiguous aliases */
49 #define KA_SIXHOURS (6*3600)
51 static struct ubik_client *conn;
52 static char cell[MAXKTCREALMLEN] = "";
53 static char whoami[32];
54 static char passwd[BUFSIZ];
55 static char myName[510]; /* almost like whoami save with path and without : */
59 static char **zero_argv;
60 afs_uint32 ka_islocked(char *, char *, afs_uint32 *);
69 code = ka_ExpandCell(0, cell, 0 /*local */ );
71 afs_com_err(whoami, code, "Can't expand cell name");
76 /* These are the command operation procedures. */
79 DumpUser(char *user, char *arock, int showadmin, int showkey, char *inst)
81 char name[MAXKTCNAMELEN];
82 char instance[MAXKTCNAMELEN];
85 char bob[KA_TIMESTR_LEN];
87 struct kaentryinfo tentry;
89 code = ka_ParseLoginName(user, name, instance, 0);
91 afs_com_err(whoami, code, "parsing user's name '%s'", user);
98 ubik_KAM_GetEntry(conn, 0, name, inst, KAMAJORVERSION, &tentry);
100 afs_com_err(whoami, code, "getting information for %s.%s", name, inst);
103 if (tentry.minor_version != KAMINORVERSION)
104 printf("Minor version number mismatch: got %d, expected %d\n",
105 tentry.minor_version, KAMINORVERSION);
106 if (showadmin && !(tentry.flags & KAFADMIN))
108 ka_PrintUserID("\nUser data for ", name, inst, "");
111 #define NEWPREFIX "+"
112 if (tentry.flags & KAFADMIN) {
113 printf("%sADMIN", prefix);
116 if (tentry.flags & KAFNOTGS) {
117 printf("%sNOTGS", prefix);
120 if (tentry.flags & KAFNOCPW) {
121 printf("%sNOCPW", prefix);
124 if (tentry.flags & KAFNOSEAL) {
125 printf("%sNOSEAL", prefix);
128 if (tentry.flags & KAFNEWASSOC) {
129 printf("%sNEWASSOC", prefix);
132 if (tentry.flags & KAFASSOCROOT) {
133 printf("%sASSOCROOT", prefix);
136 if (tentry.flags & KAFASSOC) {
137 printf("%sASSOC", prefix);
140 if (tentry.user_expiration <= now) {
141 printf("%sexpired", prefix);
144 if (strcmp(prefix, NEWPREFIX) == 0)
149 if ((!ka_KeyIsZero((char *)&tentry.key, sizeof(tentry.key))) && (showkey)) {
150 printf(" key (%d):", tentry.key_version);
151 ka_PrintBytes((char *)&tentry.key, sizeof(tentry.key));
153 if (tentry.keyCheckSum == 0)
154 printf(" key version is %d", tentry.key_version);
156 printf(" key (%d) cksum is %u", tentry.key_version,
159 ka_timestr(tentry.change_password_time, bob, KA_TIMESTR_LEN);
160 printf(", last cpw: %s\n", bob);
161 if (!tentry.misc_auth_bytes) {
162 printf(" password will never expire.\n");
164 (" An unlimited number of unsuccessful authentications is permitted.\n");
166 unsigned char misc_stuff[4];
169 temp = tentry.misc_auth_bytes;
171 temp = ntohl(tentry.misc_auth_bytes);
173 unpack_long(temp, misc_stuff);
175 if (!misc_stuff[0]) {
176 printf(" password will never expire.\n");
178 ka_timestr((tentry.change_password_time +
179 misc_stuff[0] * 24 * 60 * 60), bob, KA_TIMESTR_LEN);
180 printf(" password will expire: %s\n", bob);
185 (" An unlimited number of unsuccessful authentications is permitted.\n");
188 (" %d consecutive unsuccessful authentications are permitted.\n",
192 printf(" The lock time for this user is not limited.\n");
194 printf(" The lock time for this user is %4.1f minutes.\n",
195 (float)((unsigned int)misc_stuff[3] << 9) / 60.0);
197 if (!(misc_stuff[1] & KA_ISLOCKED)
198 || !ka_islocked(name, instance, &temp))
199 printf(" User is not locked.\n");
200 else if (temp == (afs_uint32) (-1L))
201 printf(" User is locked forever.\n");
203 ka_timestr(temp, bob, KA_TIMESTR_LEN);
204 printf(" User is locked until %s\n", bob);
210 char exp[KA_TIMESTR_LEN];
211 ka_timestr(tentry.user_expiration, exp, KA_TIMESTR_LEN);
212 if (tentry.user_expiration < now)
213 printf(" DISABLED entry at %s.", exp);
214 else if (tentry.user_expiration == NEVERDATE)
215 printf(" entry never expires.");
217 printf(" entry expires on %s.", exp);
219 printf(" Max ticket lifetime %.2f hours.\n",
220 tentry.max_ticket_lifetime / 3600.0);
221 ka_timestr(tentry.modification_time, bob, KA_TIMESTR_LEN);
222 printf(" last mod on %s by ", bob);
223 ka_PrintUserID("", tentry.modification_user.name,
224 tentry.modification_user.instance, "\n");
225 if ((tentry.reserved3 & 0xffff0000) == 0x12340000) {
226 int short reused = (short)tentry.reserved3;
228 printf(" permit password reuse\n");
230 printf(" don't permit password reuse\n");
237 ListUsers(struct cmd_syndesc *as, void *arock)
242 afs_int32 next_index;
243 int code, all = 0, showa = 0;
244 int showkey = (as->parms[2].items != NULL);
246 if (as->parms[0].items)
248 if (as->parms[1].items) {
252 for (index = 0; 1; index = next_index) {
254 ubik_KAM_ListEntry(conn, 0, index, &next_index, &count,
257 afs_com_err(whoami, code, "calling KAM_ListEntry");
263 printf("next_index (%d) is negative: ", next_index);
264 if (strlen(name.name) == 0)
265 printf("name is zero length: ");
267 DumpUser(name.name, NULL, showa, showkey, name.instance);
269 ka_PrintUserID("", name.name, name.instance, "\n");
276 ExamineUser(struct cmd_syndesc *as, void *arock)
278 int showkey = (as->parms[1].items != NULL);
279 return DumpUser(as->parms[0].items->data, arock, 0, showkey, NULL);
289 handle_errors(int code, /* error code to handle */
290 struct OKerrors OKlist[], /* list of errors & messages that should be ignored */
292 { /* set this if we should retry, clear otherwise */
295 for (i = 0; OKlist[i].code; i++) {
296 if (OKlist[i].code == code) {
297 printf("%s\n", OKlist[i].msg);
298 *persist = 0; /* we're done */
303 printf(" : [%s] %s", afs_error_table_name(code), afs_error_message(code));
306 printf(", wait one second\n");
310 case RX_CALL_TIMEOUT:
311 printf(" (retrying)\n");
316 *persist = 0; /* don't retry these errors */
321 CreateUser(struct cmd_syndesc *as, void *arock)
324 char name[MAXKTCNAMELEN];
325 char instance[MAXKTCNAMELEN];
326 struct ktc_encryptionKey key;
329 struct OKerrors OKlist[2];
332 code = ka_ParseLoginName(as->parms[0].items->data, name, instance, 0);
334 afs_com_err(whoami, code, "parsing user's name '%s'",
335 as->parms[0].items->data);
338 ka_StringToKey(as->parms[1].items->data, cell, &key);
341 code = ubik_KAM_CreateUser(conn, 0, name, instance,
342 *ktc_to_EncryptionKey(&key));
345 ka_PrintUserID("Creating user ", name, instance, " ");
346 code = handle_errors(code, OKlist, &persist);
352 DeleteUser(struct cmd_syndesc *as, void *arock)
355 char name[MAXKTCNAMELEN];
356 char instance[MAXKTCNAMELEN];
359 struct OKerrors OKlist[2];
361 code = ka_ParseLoginName(as->parms[0].items->data, name, instance, 0);
363 afs_com_err(whoami, code, "parsing user's name '%s'",
364 as->parms[0].items->data);
369 code = ubik_KAM_DeleteUser(conn, 0, name, instance);
372 ka_PrintUserID("Deleting user ", name, instance, " ");
373 code = handle_errors(code, OKlist, &persist);
379 read_time_interval(char *str, afs_int32 * seconds)
385 str = strncpy(buf, str, sizeof(buf));
386 s = strchr(str, ':');
390 *s++ = '\0'; /* separate hours and minutes */
391 sec = atoi(str) * 3600 + atoi(s) * 60;
398 parse_flags(char *name, char *inst, char *str, afs_int32 * flags)
400 struct kaentryinfo tentry;
406 int addop; /* 1=add bit; 0=remove bit */
410 str = lcstring(bitspec, str, sizeof(bitspec));
412 if (strncmp(str, "0x", 2) == 0) /* 0x => hex */
413 sscanf(str, "0x%lx", (long unsigned int *) &f);
414 else if (*str == '0') /* assume octal */
415 sscanf(str, "%lo", (long unsigned int *) &f);
416 else /* just assume hex */
417 sscanf(str, "%lx", (long unsigned int *) &f);
424 if (strchr("+-", *str))
425 addop = (*str++ == '+');
426 else if (*str == '_') {
432 ubik_KAM_GetEntry(conn, 0, name, inst, KAMAJORVERSION,
435 afs_com_err(whoami, code,
436 "could get current flag value for %s.%s", name, inst);
453 if (strcmp(bit, "admin") == 0)
455 else if (strcmp(bit, "noadmin") == 0)
456 flag = KAFADMIN, addop = !addop;
457 else if (strcmp(bit, "notgs") == 0)
459 else if (strcmp(bit, "tgs") == 0)
460 flag = KAFNOTGS, addop = !addop;
461 else if (strcmp(bit, "noseal") == 0)
463 else if (strcmp(bit, "seal") == 0)
464 flag = KAFNOSEAL, addop = !addop;
465 else if (strcmp(bit, "nocpw") == 0)
467 else if (strcmp(bit, "cpw") == 0)
468 flag = KAFNOCPW, addop = !addop;
469 else if (strcmp(bit, "newassoc") == 0)
471 else if (strcmp(bit, "nonewassoc") == 0)
472 flag = KAFNEWASSOC, addop = !addop;
475 ("Illegal bit name: %s; choices are: [no]admin, [no]tgs, [no]seal, [no]cpw\n",
488 addop = 1; /* get next op */
489 else if ((*str == '-') || (*str == '_'))
492 printf("Illegal combination operator: %c\n", *str);
498 *flags = (f & KAF_SETTABLE_FLAGS) | KAFNORMAL;
502 #define seriouserror(code) ((code <0) || ((code != UNOSERVERS) && (code != UNOQUORUM) && code != UNOTSYNC))
504 /* return MAXLONG if locked forever */
506 ka_islocked(char *name, char *instance, afs_uint32 * when)
516 ubik_CallIter(KAM_LockStatus, conn, UPUBIKONLY, &count, (long) name,
517 (long) instance, (long) &tempwhen, 0, 0, 0,
518 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
520 if (seriouserror(code))
521 afs_com_err(whoami, code, NULL);
522 } else if (tempwhen) { /* user is locked */
523 if (!*when || tempwhen < *when) {
527 } else /* ! tempwhen ==> user is not locked */
530 } while (code != UNOSERVERS);
536 Unlock(struct cmd_syndesc *as, void *arock)
538 afs_int32 code, rcode = 0;
541 char name[MAXKTCNAMELEN];
542 char instance[MAXKTCNAMELEN];
544 code = ka_ParseLoginName(as->parms[0].items->data, name, instance, 0);
546 afs_com_err(whoami, code, "parsing user's name '%s'",
547 as->parms[0].items->data);
553 code = ubik_CallIter(KAM_Unlock, conn, 0, &count, (long) name, (long) instance,
554 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
555 if (code && (code != UNOSERVERS)) {
557 if (conn && conn->conns[count - 1]
558 && rx_PeerOf(conn->conns[count - 1])) {
559 server = rx_HostOf(rx_PeerOf(conn->conns[count - 1]));
561 afs_com_err(whoami, code,
562 "so %s.%s may still be locked (on server %d.%d.%d.%d)",
563 name, instance, ((server >> 24) & 0xFF),
564 ((server >> 16) & 0xFF), ((server >> 8) & 0xFF),
571 } while (code != UNOSERVERS);
577 SetFields(struct cmd_syndesc *as, void *arock)
580 char name[MAXKTCNAMELEN];
581 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 pwexpiry = strtol(as->parms[4].items->data, &end, 10);
642 "Password lifetime specified must be a non-negative decimal integer.\n");
645 if (pwexpiry < 0 || pwexpiry > 254) {
647 "Password lifetime range must be [0..254] days.\n");
648 fprintf(stderr, "Zero represents an unlimited lifetime.\n");
652 misc_auth_bytes[0] = pwexpiry + 1;
655 if (as->parms[5].items) {
657 reuse = (as->parms[5].items->data);
659 if (!strcmp(reuse, "yes")) {
660 misc_auth_bytes[1] = KA_REUSEPW;
661 } else if (strcmp(reuse, "no")) {
663 "must specify \"yes\" or \"no\": \"yes\" assumed\n");
664 misc_auth_bytes[1] = KA_REUSEPW;
666 misc_auth_bytes[1] = KA_NOREUSEPW;
670 if (as->parms[6].items) {
673 nfailures = strtol(as->parms[6].items->data, &end, 10);
675 if (*end != '\0' || nfailures < 0 || nfailures > 254) {
676 fprintf(stderr, "Failure limit must be in [0..254].\n");
677 fprintf(stderr, "Zero represents unlimited login attempts.\n");
680 misc_auth_bytes[2] = nfailures + 1;
683 if (as->parms[7].items) {
684 int locktime, hrs, mins;
688 s = as->parms[7].items->data;
690 sscanf(s, "%d:%d", &hrs, &mins);
692 sscanf(s, "%d", &mins);
694 locktime = hrs * 60 + mins;
695 if (hrs < 0 || hrs > 36 || mins < 0) {
697 "Lockout times must be either minutes or hh:mm.\n");
698 fprintf(stderr, "Lockout times must be less than 36 hours.\n");
700 } else if (locktime > 36 * 60) {
702 "Lockout times must be either minutes or hh:mm.\n");
703 fprintf(stderr, "Lockout times must be less than 36 hours.\n");
705 "Continuing with lock time of exactly 36 hours...\n");
708 locktime = (locktime * 60 + 511) >> 9; /* ceil(l*60/512) */
709 misc_auth_bytes[3] = locktime + 1; /* will be 1 if user said 0 */
712 if (as->parms[8].items) {
713 maxAssociates = atoi(as->parms[6].items->data);
714 if (maxAssociates < 0) {
715 printf("Illegal maximum number of associates\n");
720 was_spare = pack_long(misc_auth_bytes);
722 if (was_spare || flags || expiration || lifetime || (maxAssociates >= 0))
724 ubik_KAM_SetFields(conn, 0, name, instance, flags,
725 expiration, lifetime, maxAssociates, was_spare,
728 printf("Must specify one of the optional parameters\n");
732 afs_com_err(whoami, code, "calling KAM_SetFields for %s.%s", name,
738 StringToKey(struct cmd_syndesc *as, void *arock)
741 char realm[MAXKTCREALMLEN];
742 struct ktc_encryptionKey key;
744 if (as->parms[1].items) {
745 code = ka_ExpandCell(as->parms[1].items->data, realm, 0 /*local */ );
747 afs_com_err(whoami, code,
748 "expanding %s as cell name, attempting to continue",
749 as->parms[1].items->data);
751 ucstring(realm, realm, sizeof(realm));
753 if ((code = DefaultCell()))
755 ucstring(realm, cell, sizeof(realm));
757 ka_StringToKey(as->parms[0].items->data, realm, &key);
759 printf("Converting %s in realm '%s' yields key='",
760 as->parms[0].items->data, realm);
761 ka_PrintBytes((char *)&key, sizeof(key));
764 DES_string_to_key(as->parms[0].items->data, ktc_to_cblockptr(&key));
766 printf("Converting %s with the DES string to key yields key='",
767 as->parms[0].items->data);
768 ka_PrintBytes((char *)&key, sizeof(key));
775 SetPassword(struct cmd_syndesc *as, void *arock)
778 char name[MAXKTCNAMELEN];
779 char instance[MAXKTCNAMELEN];
780 char realm[MAXKTCREALMLEN];
781 struct ktc_encryptionKey key;
784 code = ka_ParseLoginName(as->parms[0].items->data, name, instance, realm);
786 afs_com_err(whoami, code, "parsing user's name '%s'",
787 as->parms[0].items->data);
791 if (strlen(realm) == 0)
792 ucstring(realm, cell, sizeof(realm));
794 if (as->parms[1].items && as->parms[2].items) {
795 printf("Can't specify both a password and a key\n");
797 } else if (as->parms[1].items) {
798 (void)init_child(myName);
799 (void)give_to_child(passwd); /* old password */
800 code = password_bad(as->parms[1].items->data);
801 (void)terminate_child();
804 ka_StringToKey(as->parms[1].items->data, realm, &key);
805 } else if (as->parms[2].items) {
806 if (ka_ReadBytes(as->parms[2].items->data, (char *)&key, sizeof(key))
808 printf("Key must be 8 bytes: '%s' was too long\n",
809 as->parms[2].items->data);
813 printf("Must specify new password or key\n");
818 if (as->parms[3].items)
819 sscanf(as->parms[3].items->data, "%d", &kvno);
821 code = ubik_KAM_SetPassword(conn, 0, name, instance, kvno,
822 *ktc_to_EncryptionKey(&key));
824 afs_com_err(whoami, code, "so can't set password for %s.%s", name,
829 #define PrintPrincipal(p,n,l) \
830 PrintName((p)->name, (p)->instance, (p)->cell, l, n)
833 PrintName(char *name, char *inst, char *acell, int buflen, char *buf)
836 int left; /* if ConvertBytes stops early */
845 left = ka_ConvertBytes(buf, buflen, name, strlen(name));
849 afs_com_err(whoami, code, "PrintName: principal name was '%s'.'%s'@'%s'",
856 if (nlen + len + 1 >= buflen)
859 left = ka_ConvertBytes(buf + nlen, buflen - nlen, inst, len);
867 char *lcell = ka_LocalCell();
870 if (strcmp(acell, lcell) != 0) {
871 /* only append cell if not the local cell */
872 if (nlen + len + 1 >= buflen)
875 left = ka_ConvertBytes(buf + nlen, buflen - nlen, acell, len);
884 #define PrintedPrincipal(p) PrintedName ((p)->name, (p)->instance, (p)->cell)
886 /* PrintedName - returned a pointer to a static string in which the formated
887 * name has been stored. */
890 PrintedName(char *name, char *inst, char *cell)
892 static char printedName[128];
894 code = PrintName(name, inst, cell, sizeof(printedName), printedName);
898 strncpy(printedName, name, sizeof(printedName));
899 printedName[sizeof(printedName) - 8] = 0;
900 strcat(printedName, "<error>");
906 ListTicket(struct ktc_principal *server, int verbose)
909 struct ktc_token token; /* the token we're printing */
910 struct ktc_principal client;
911 char UserName[sizeof(struct ktc_principal)];
912 char ServerName[sizeof(struct ktc_principal)];
913 afs_int32 now = time(0);
914 char bob[KA_TIMESTR_LEN];
916 /* get the ticket info itself */
917 code = ktc_GetToken(server, &token, sizeof(token), &client);
919 afs_com_err(whoami, code, "failed to get token info for server %s",
920 PrintedPrincipal(server));
923 code = PrintPrincipal(&client, UserName, sizeof(UserName));
926 /* spaces are printed as "\040" */
927 if (UserName[0] == 0)
929 else if (strncmp(UserName, "AFS\\040ID\\040", 13) == 0) {
930 printf("User's (AFS ID %s) tokens", UserName + 13);
931 } else if (strncmp(UserName, "Unix\\040UID\\040", 15) == 0) {
934 printf("User %s's tokens", UserName);
936 code = PrintPrincipal(server, ServerName, sizeof(ServerName));
939 printf(" for %s ", ServerName);
941 if (token.startTime > now) {
942 ka_timestr(token.startTime, bob, KA_TIMESTR_LEN);
943 printf("[>> POSTDATED 'till %s <<]", bob);
946 if (token.endTime <= now)
947 printf("[>> Expired <<]\n");
949 ka_timestr(token.endTime, bob, KA_TIMESTR_LEN);
950 printf("[Expires %s]\n", bob);
953 printf("SessionKey: ");
954 ka_PrintBytes((char *)&token.sessionKey, sizeof(token.sessionKey));
955 printf("\nTicket (kvno = %d, len = %d): ", token.kvno,
957 ka_PrintBytes((char *)token.ticket, token.ticketLen);
964 GetTicket(struct cmd_syndesc *as, void *arock)
967 struct ktc_principal server;
968 struct ktc_token token;
969 afs_int32 life = KA_SIXHOURS;
971 if (as->parms[1].items) {
972 code = read_time_interval(as->parms[1].items->data, &life);
977 ka_ParseLoginName(as->parms[0].items->data, server.name,
978 server.instance, server.cell);
980 afs_com_err(whoami, code, "parsing user's name '%s'",
981 as->parms[0].items->data);
984 if (server.cell[0] == 0) {
985 if ((code = DefaultCell()))
987 strcpy(server.cell, cell);
989 code = ka_ExpandCell(server.cell, server.cell, 0 /*local */ );
991 afs_com_err(whoami, code, "Can't expand cell name");
996 token.ticketLen = 0; /* in case there are no tokens */
998 ka_GetServerToken(server.name, server.instance, server.cell, life,
999 &token, /*new */ 1, /*dosetpag */ 0);
1001 afs_com_err(whoami, code, "getting ticket for %s",
1002 PrintedPrincipal(&server));
1004 code = ListTicket(&server, /*verbose */ 1);
1010 GetPassword(struct cmd_syndesc *as, void *arock)
1013 char name[MAXKTCNAMELEN];
1014 struct ktc_encryptionKey key;
1015 static struct ubik_client *lpbkConn = 0;
1017 /* no instance allowed */
1018 code = ka_ParseLoginName(as->parms[0].items->data, name, 0, 0);
1021 afs_com_err(whoami, code,
1022 "getting %s's password via loopback connection to GetPassword",
1024 /* if we got a timeout, print a clarification, too */
1027 "%s: please note that this command must be run locally on a database server machine.\n",
1032 if (lpbkConn == 0) {
1033 struct rx_connection *conns[2];
1034 struct rx_securityClass *sc;
1035 int si; /* security class index */
1040 sc = rxnull_NewClientSecurityObject();
1041 si = RX_SCINDEX_NULL;
1043 rx_NewConnection(htonl(INADDR_LOOPBACK), htons(AFSCONF_KAUTHPORT),
1044 KA_MAINTENANCE_SERVICE, sc, si);
1046 code = ubik_ClientInit(conns, &lpbkConn);
1050 code = ubik_KAM_GetPassword(lpbkConn, 0, name,
1051 ktc_to_EncryptionKey(&key));
1052 /* Lets close down the ubik_Client connection now */
1053 ubik_ClientDestroy(lpbkConn);
1057 ka_PrintBytes((char *)&key, sizeof(key));
1063 GetRandomKey(struct cmd_syndesc *as, void *arock)
1066 struct ktc_encryptionKey key;
1068 code = ubik_KAM_GetRandomKey(conn, 0, ktc_to_EncryptionKey(&key));
1070 afs_com_err(whoami, code, "so can't get random key");
1074 ka_PrintBytes((char *)&key, sizeof(key));
1076 for (i = 0; i < sizeof(key); i++) {
1077 printf("%.2x", ((char *)&key)[i] & 0xff);
1089 Statistics(struct cmd_syndesc *as, void *arock)
1095 char bob[KA_TIMESTR_LEN];
1098 ubik_KAM_GetStats(conn, 0, KAMAJORVERSION, &admins, &statics,
1101 printf("call to GetStats failed: %s\n", ka_ErrorString(code));
1104 if (statics.minor_version != KAMINORVERSION)
1105 printf("Minor version number mismatch: got %d, expected %d\n",
1106 statics.minor_version, KAMINORVERSION);
1107 printf("%d allocs, %d frees, %d password changes\n", statics.allocs,
1108 statics.frees, statics.cpws);
1109 printf("Hash table utilization = %f%%\n",
1110 (double)dynamics.hashTableUtilization / 100.0);
1111 ka_timestr(dynamics.start_time, bob, KA_TIMESTR_LEN);
1112 printf("From host %lx started at %s:\n",
1113 afs_printable_uint32_lu(dynamics.host), bob);
1115 #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)
1116 print_stat(Authenticate);
1117 print_stat(ChangePassword);
1118 print_stat(GetTicket);
1119 print_stat(CreateUser);
1120 print_stat(SetPassword);
1121 print_stat(SetFields);
1122 print_stat(DeleteUser);
1123 print_stat(GetEntry);
1124 print_stat(ListEntry);
1125 print_stat(GetStats);
1126 print_stat(GetPassword);
1127 print_stat(GetRandomKey);
1129 print_stat(UAuthenticate);
1130 print_stat(UGetTicket);
1132 #if (KAMAJORVERSION>5)
1133 print cpu stats printf("%d string checks\n", dynamics.string_checks);
1135 printf("Used %.3f seconds of CPU time.\n",
1136 dynamics.string_checks / 1000.0);
1138 printf("%d admin accounts\n", admins);
1143 DebugInfo(struct cmd_syndesc *as, void *arock)
1146 struct ka_debugInfo info;
1150 char bob[KA_TIMESTR_LEN];
1153 if (as->parms[0].items) {
1154 struct ubik_client *iConn;
1156 ka_SingleServerConn(cell, as->parms[0].items->data,
1157 KA_MAINTENANCE_SERVICE, 0, &iConn);
1159 struct afsconf_cell cellinfo;
1161 afs_com_err(whoami, code, "couldn't find host %s in cell %s",
1162 as->parms[0].items->data, cell);
1163 code = ka_GetServers(cell, &cellinfo);
1165 afs_com_err(whoami, code, "getting servers in cell %s", cell);
1167 printf("Servers in cell %s, are:\n", cell);
1168 for (i = 0; i < cellinfo.numServers; i++)
1169 printf(" %s\n", cellinfo.hostName[i]);
1173 code = ubik_KAM_Debug(iConn, 0, KAMAJORVERSION, 0, &info);
1174 ubik_ClientDestroy(iConn);
1176 code = ubik_KAM_Debug(conn, 0, KAMAJORVERSION, 0, &info);
1179 afs_com_err(whoami, code, "call to Debug failed");
1184 if (info.minorVersion != KAMINORVERSION)
1185 printf("Minor version number mismatch: got %d, expected %d\n",
1186 info.minorVersion, KAMINORVERSION);
1189 #if (KAMAJORVERSION>5)
1196 timeOffset = -timeOffset;
1197 if (timeOffset > 60) {
1199 ("WARNING: Large server client clock skew: %d seconds. Call itself took %d seconds.\n",
1200 timeOffset, now - start);
1202 ka_timestr(info.startTime, bob, KA_TIMESTR_LEN);
1203 printf("From host %lx started %sat %s:\n",
1204 afs_printable_uint32_lu(info.host),
1205 (info.noAuth ? "w/o authorization " : ""), bob);
1206 ka_timestr(info.lastTrans, bob, KA_TIMESTR_LEN);
1207 printf("Last trans was %s at %s\n", info.lastOperation, bob);
1208 ka_timestr(info.dbHeaderRead, bob, KA_TIMESTR_LEN);
1209 printf("Header last read %s.\n", bob);
1210 printf("db version=%d, keyVersion=%d, key cache version=%d\n",
1211 info.dbVersion, info.dbSpecialKeysVersion, info.kcVersion);
1212 printf("db ptrs: free %d, eof %d, kvno %d.\n", info.dbFreePtr,
1213 info.dbEofPtr, info.dbKvnoPtr);
1214 ka_timestr(info.nextAutoCPW, bob, KA_TIMESTR_LEN);
1215 printf("Next autoCPW at %s or in %d updates.\n", bob,
1216 info.updatesRemaining);
1217 if (info.cheader_lock || info.keycache_lock)
1218 printf("locks: cheader %08lx, keycache %08lx\n",
1219 afs_printable_uint32_lu(info.cheader_lock),
1220 afs_printable_uint32_lu(info.keycache_lock));
1221 printf("Last authentication for %s, last admin user was %s\n",
1222 info.lastAuth, info.lastAdmin);
1223 printf("Last TGS op was a %s ticket was for %s\n", info.lastTGSServer,
1225 printf("Last UDP TGS was a %s ticket for %s. UDP Authenticate for %s\n",
1226 info.lastUTGSServer, info.lastUTGS, info.lastUAuth);
1227 printf("key cache size %d, used %d.\n", info.kcSize, info.kcUsed);
1228 if (info.kcUsed > KADEBUGKCINFOSIZE) {
1229 printf("insufficient room to return all key cache entries!\n");
1230 info.kcUsed = KADEBUGKCINFOSIZE;
1232 for (i = 0; i < info.kcUsed; i++)
1233 ka_timestr(info.kcInfo[i].used, bob, KA_TIMESTR_LEN);
1234 printf("%32s %c %2x(%2x) used %s\n", info.kcInfo[i].principal,
1235 (info.kcInfo[i].primary ? '*' : ' '), info.kcInfo[i].kvno,
1236 info.kcInfo[i].keycksum, bob);
1241 Interactive(struct cmd_syndesc *as, void *arock)
1248 Quit(struct cmd_syndesc *as, void *arock)
1255 MyAfterProc(struct cmd_syndesc *as, void *arock)
1257 if (!strcmp(as->name, "help"))
1260 /* Determine if we need to destory the ubik connection.
1261 * Closing it avoids resends of packets.
1264 ubik_ClientDestroy(conn);
1271 int init = 0, noauth;
1272 char name[MAXKTCNAMELEN];
1273 char instance[MAXKTCNAMELEN];
1274 char newCell[MAXKTCREALMLEN];
1275 afs_uint32 serverList[MAXSERVERS];
1278 NoAuth(struct cmd_syndesc *as, void *arock)
1285 MyBeforeProc(struct cmd_syndesc *as, void *arock)
1287 struct ktc_encryptionKey key;
1288 struct ktc_principal auth_server, client;
1289 struct ktc_token auth_token;
1290 char realm[MAXKTCREALMLEN];
1292 struct ktc_token token, *pToken;
1293 int i, acode, code = 0;
1296 char *ws = strrchr(as->a0name, '/');
1298 ws++; /* skip everything before the "/" */
1301 if (strlen(ws) > 0) {
1302 strncpy(whoami, ws, sizeof(whoami));
1303 if (strlen(whoami) + 1 >= sizeof(whoami))
1304 strcpy(whoami, "kas:");
1306 strcat(whoami, ":");
1309 /* append sub-command name */
1310 strncat(whoami, as->name, sizeof(whoami) - strlen(whoami) - 1);
1313 if (as->parms[12].name == 0)
1316 assert(as->parms[13].name && as->parms[14].name && as->parms[15].name
1317 && as->parms[16].name);
1319 /* MyAfterProc() destroys the conn, but just to be sure */
1321 code = ubik_ClientDestroy(conn);
1325 if (!init || as->parms[12].items || as->parms[13].items
1326 || as->parms[14].items || as->parms[15].items
1327 || as->parms[16].items) {
1328 strcpy(instance, "");
1329 strcpy(newCell, "");
1331 if (as->parms[12].items) { /* -admin_username */
1333 ka_ParseLoginName(as->parms[12].items->data, name, instance,
1336 afs_com_err(whoami, code, "parsing user's name '%s'",
1337 as->parms[12].items->data);
1342 DWORD len = MAXKTCNAMELEN;
1343 if (!GetUserName((LPTSTR) name, &len)) {
1344 printf("Can't get user name \n");
1348 /* No explicit name provided: use Unix uid. */
1349 struct passwd *pw = getpwuid(getuid());
1351 printf("Can't figure out your name from your user id.\n");
1354 strncpy(name, pw->pw_name, sizeof(name));
1358 if (as->parms[14].items) { /* -cell */
1359 if (strlen(newCell) > 0) {
1360 printf("Duplicate cell specification not allowed\n");
1362 strncpy(newCell, as->parms[14].items->data, sizeof(newCell));
1365 code = ka_ExpandCell(newCell, newCell, 0 /*local */ );
1367 afs_com_err(whoami, code, "Can't expand cell name");
1370 strcpy(cell, newCell);
1372 if (as->parms[15].items) { /* -servers */
1373 struct cmd_item *ip;
1374 char *ap[MAXSERVERS + 2];
1378 for (ip = as->parms[15].items, i = 2; ip; ip = ip->next, i++)
1380 code = ubik_ParseClientList(i, ap, serverList);
1382 afs_com_err(whoami, code, "could not parse server list");
1385 ka_ExplicitCell(cell, serverList);
1388 noauth = (as->parms[16].items ? 1 : 0); /* -noauth */
1393 token.ticketLen = 0; /* in case there are no tokens */
1394 if (!noauth) { /* Will prompt for a password */
1395 /* first see if there's already an admin ticket */
1397 ka_GetAdminToken(0, 0, cell, 0, KA_SIXHOURS, &token,
1399 if (code) { /* if not then get key and try again */
1400 if (as->parms[13].items) { /* if password specified */
1401 strncpy(passwd, as->parms[13].items->data, sizeof(passwd));
1402 memset(as->parms[13].items->data, 0,
1403 strlen(as->parms[13].items->data));
1405 char msg[MAXKTCNAMELEN + 50];
1406 if (as->parms[12].items)
1407 sprintf(msg, "Administrator's (%s) Password: ", name);
1409 sprintf(msg, "Password for %s: ", name);
1410 code = UI_UTIL_read_pw_string(passwd, sizeof(passwd), msg, 0);
1413 else if (strlen(passwd) == 0)
1414 code = KANULLPASSWORD;
1416 afs_com_err(whoami, code, "reading password");
1420 ka_StringToKey(passwd, cell, &key);
1422 ka_GetAdminToken(name, instance, cell, &key, KA_SIXHOURS,
1423 &token, 0 /* !new */ );
1424 if (code == KABADREQUEST) {
1425 DES_string_to_key(passwd, ktc_to_cblockptr(&key));
1427 ka_GetAdminToken(name, instance, cell, &key, KA_SIXHOURS,
1428 &token, 0 /* !new */ );
1430 if ((code == KABADREQUEST) && (strlen(passwd) > 8)) {
1431 /* try with only the first 8 characters incase they set
1432 * their password with an old style passwd program. */
1434 ka_StringToKey(passwd, cell, &key);
1436 ka_GetAdminToken(name, instance, cell, &key, KA_SIXHOURS,
1437 &token, 0 /* !new */ );
1440 "Warning: you have typed a password longer than 8 characters, but only the\n");
1442 "first 8 characters were actually significant. If you change your password\n");
1444 "again this warning message will go away.\n");
1451 reason = "password was incorrect";
1454 reason = "Authentication Server was unavailable";
1457 reason = (char *)afs_error_message(code);
1460 "%s: Auth. as %s to AuthServer failed: %s\nProceeding w/o authentication\n",
1461 whoami, PrintedName(name, instance, cell), reason);
1463 /* get an Authentication token while were at it. */
1464 if (ka_CellToRealm(cell, realm, 0) != 0)
1466 strcpy(auth_server.name, KA_TGS_NAME);
1467 strcpy(auth_server.instance, realm);
1468 strcpy(auth_server.cell, cell);
1470 (&auth_server, &auth_token, sizeof(struct ktc_token),
1473 ka_GetAuthToken(name, instance, cell, &key,
1474 MAXKTCTICKETLIFETIME, (afs_int32 *) 0
1475 /*Don't need pwd expiration info here */
1477 if (acode && (acode != code)) /* codes are usually the same */
1478 afs_com_err(whoami, code,
1479 "getting Authentication token for %s",
1480 PrintedName(name, instance, cell));
1482 memset(&key, 0, sizeof(key));
1486 pToken = ((token.ticketLen == 0) ? 0 : &token);
1487 code = ka_AuthServerConn(cell, KA_MAINTENANCE_SERVICE, pToken, &conn);
1488 if (code && pToken) {
1489 afs_com_err(whoami, code,
1490 "connecting to AuthServer: now trying w/o authentication");
1491 code = ka_AuthServerConn(cell, KA_MAINTENANCE_SERVICE, 0, &conn);
1493 afs_com_err(whoami, code,
1494 "making unauthenticated connection to AuthServer");
1497 afs_com_err(whoami, code,
1498 "Couldn't establish connection to Authentication Server");
1502 /* now default unspecified password by prompting from terminal */
1503 if (as->nParms >= 12)
1504 for (i = 0; i < 12; i++)
1505 if (as->parms[i].name && (as->parms[i].items == 0)) {
1506 char *p = as->parms[i].name; /* parameter name */
1507 int l = strlen(p); /* length of name */
1508 /* does parameter end in "password" */
1509 if (strcmp(p + (l - 8), "password") == 0) {
1511 char password[BUFSIZ];
1512 struct cmd_item *ip;
1516 code = UI_UTIL_read_pw_string(password, sizeof(password), msg, 1);
1519 else if (strlen(password) == 0)
1520 code = KANULLPASSWORD;
1522 afs_com_err(whoami, code, "prompting for %s", p + 1);
1525 ip = malloc(sizeof(struct cmd_item));
1526 ip->data = strdup(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);