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>
22 #include <afs/debug.h>
26 /* These two needed for rxgen output to work */
27 #include <sys/types.h>
33 #define UBIK_LEGACY_CALLITER 1
39 #include <afs/cellconfig.h>
41 #include <afs/com_err.h>
42 #include <afs/afsutil.h>
48 #define CMD_PARSER_AMBIG_FIX 1 /* allow ambiguous aliases */
50 #define KA_SIXHOURS (6*3600)
52 static struct ubik_client *conn;
53 static char cell[MAXKTCREALMLEN] = "";
54 static char whoami[32];
55 static char passwd[BUFSIZ];
56 static char myName[510]; /* almost like whoami save with path and without : */
60 static char **zero_argv;
61 afs_uint32 ka_islocked();
70 code = ka_ExpandCell(0, cell, 0 /*local */ );
72 afs_com_err(whoami, code, "Can't expand cell name");
77 /* These are the command operation procedures. */
80 DumpUser(char *user, char *arock, int showadmin, int showkey, char *inst)
82 char name[MAXKTCNAMELEN];
83 char instance[MAXKTCNAMELEN];
86 char bob[KA_TIMESTR_LEN];
88 struct kaentryinfo tentry;
90 code = ka_ParseLoginName(user, name, instance, 0);
92 afs_com_err(whoami, code, "parsing user's name '%s'", user);
99 ubik_Call(KAM_GetEntry, conn, 0, name, inst, KAMAJORVERSION, &tentry);
101 afs_com_err(whoami, code, "getting information for %s.%s", name, inst);
104 if (tentry.minor_version != KAMINORVERSION)
105 printf("Minor version number mismatch: got %d, expected %d\n",
106 tentry.minor_version, KAMINORVERSION);
107 if (showadmin && !(tentry.flags & KAFADMIN))
109 ka_PrintUserID("\nUser data for ", name, inst, "");
112 #define NEWPREFIX "+"
113 if (tentry.flags & KAFADMIN) {
114 printf("%sADMIN", prefix);
117 if (tentry.flags & KAFNOTGS) {
118 printf("%sNOTGS", prefix);
121 if (tentry.flags & KAFNOCPW) {
122 printf("%sNOCPW", prefix);
125 if (tentry.flags & KAFNOSEAL) {
126 printf("%sNOSEAL", prefix);
129 if (tentry.flags & KAFNEWASSOC) {
130 printf("%sNEWASSOC", prefix);
133 if (tentry.flags & KAFASSOCROOT) {
134 printf("%sASSOCROOT", prefix);
137 if (tentry.flags & KAFASSOC) {
138 printf("%sASSOC", prefix);
141 if (tentry.user_expiration <= now) {
142 printf("%sexpired", prefix);
145 if (strcmp(prefix, NEWPREFIX) == 0)
150 if ((!ka_KeyIsZero((char *)&tentry.key, sizeof(tentry.key))) && (showkey)) {
151 printf(" key (%d):", tentry.key_version);
152 ka_PrintBytes((char *)&tentry.key, sizeof(tentry.key));
154 if (tentry.keyCheckSum == 0)
155 printf(" key version is %d", tentry.key_version);
157 printf(" key (%d) cksum is %u", tentry.key_version,
160 ka_timestr(tentry.change_password_time, bob, KA_TIMESTR_LEN);
161 printf(", last cpw: %s\n", bob);
162 if (!tentry.misc_auth_bytes) {
163 printf(" password will never expire.\n");
165 (" An unlimited number of unsuccessful authentications is permitted.\n");
167 unsigned char misc_stuff[4];
170 temp = tentry.misc_auth_bytes;
172 temp = ntohl(tentry.misc_auth_bytes);
174 unpack_long(temp, misc_stuff);
176 if (!misc_stuff[0]) {
177 printf(" password will never expire.\n");
179 ka_timestr((tentry.change_password_time +
180 misc_stuff[0] * 24 * 60 * 60), bob, KA_TIMESTR_LEN);
181 printf(" password will expire: %s\n", bob);
186 (" An unlimited number of unsuccessful authentications is permitted.\n");
189 (" %d consecutive unsuccessful authentications are permitted.\n",
193 printf(" The lock time for this user is not limited.\n");
195 printf(" The lock time for this user is %4.1f minutes.\n",
196 (float)((unsigned int)misc_stuff[3] << 9) / 60.0);
198 if (!(misc_stuff[1] & KA_ISLOCKED)
199 || !ka_islocked(name, instance, &temp))
200 printf(" User is not locked.\n");
201 else if (temp == (afs_uint32) (-1L))
202 printf(" User is locked forever.\n");
204 ka_timestr(temp, bob, KA_TIMESTR_LEN);
205 printf(" User is locked until %s\n", bob);
211 char exp[KA_TIMESTR_LEN];
212 ka_timestr(tentry.user_expiration, exp, KA_TIMESTR_LEN);
213 if (tentry.user_expiration < now)
214 printf(" DISABLED entry at %s.", exp);
215 else if (tentry.user_expiration == NEVERDATE)
216 printf(" entry never expires.");
218 printf(" entry expires on %s.", exp);
220 printf(" Max ticket lifetime %.2f hours.\n",
221 tentry.max_ticket_lifetime / 3600.0);
222 ka_timestr(tentry.modification_time, bob, KA_TIMESTR_LEN);
223 printf(" last mod on %s by ", bob);
224 ka_PrintUserID("", tentry.modification_user.name,
225 tentry.modification_user.instance, "\n");
226 if ((tentry.reserved3 & 0xffff0000) == 0x12340000) {
227 int short reused = (short)tentry.reserved3;
229 printf(" permit password reuse\n");
231 printf(" don't permit password reuse\n");
238 ListUsers(struct cmd_syndesc *as, void *arock)
243 afs_int32 next_index;
244 int code, all = 0, showa = 0;
245 int showkey = (as->parms[2].items != NULL);
247 if (as->parms[0].items)
249 if (as->parms[1].items) {
253 for (index = 0; 1; index = next_index) {
255 ubik_Call(KAM_ListEntry, conn, 0, index, &next_index, &count,
258 afs_com_err(whoami, code, "calling KAM_ListEntry");
264 printf("next_index (%d) is negative: ", next_index);
265 if (strlen(name.name) == 0)
266 printf("name is zero length: ");
268 DumpUser(name.name, NULL, showa, showkey, name.instance);
270 ka_PrintUserID("", name.name, name.instance, "\n");
277 ExamineUser(struct cmd_syndesc *as, void *arock)
279 int showkey = (as->parms[1].items != NULL);
280 return DumpUser(as->parms[0].items->data, arock, 0, showkey, NULL);
290 handle_errors(int code, /* error code to handle */
291 struct OKerrors OKlist[], /* list of errors & messages that should be ignored */
293 { /* set this if we should retry, clear otherwise */
296 for (i = 0; OKlist[i].code; i++) {
297 if (OKlist[i].code == code) {
298 printf("%s\n", OKlist[i].msg);
299 *persist = 0; /* we're done */
304 printf(" : [%s] %s", afs_error_table_name(code), afs_error_message(code));
307 printf(", wait one second\n");
311 case RX_CALL_TIMEOUT:
312 printf(" (retrying)\n");
317 *persist = 0; /* don't retry these errors */
322 CreateUser(struct cmd_syndesc *as, void *arock)
325 char name[MAXKTCNAMELEN];
326 char instance[MAXKTCNAMELEN];
327 struct ktc_encryptionKey key;
330 struct OKerrors OKlist[2];
333 code = ka_ParseLoginName(as->parms[0].items->data, name, instance, 0);
335 afs_com_err(whoami, code, "parsing user's name '%s'",
336 as->parms[0].items->data);
339 ka_StringToKey(as->parms[1].items->data, cell, &key);
342 code = ubik_Call(KAM_CreateUser, conn, 0, name, instance, 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_Call(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", &f);
414 else if (*str == '0') /* assume octal */
415 sscanf(str, "%lo", &f);
416 else /* just assume hex */
417 sscanf(str, "%lx", &f);
424 if (strchr("+-", *str))
425 addop = (*str++ == '+');
426 else if (*str == '_') {
432 ubik_Call(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, "");
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 && conn->conns[count - 1]->peer) {
559 server = conn->conns[count - 1]->peer->host;
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];
584 afs_int32 lifetime = 0;
585 afs_int32 maxAssociates = -1;
586 afs_int32 pwexpiry = 0;
587 afs_int32 was_spare = 0;
588 char misc_auth_bytes[4];
591 code = ka_ParseLoginName(as->parms[0].items->data, name, instance, 0);
593 afs_com_err(whoami, code, "parsing user's name '%s'",
594 as->parms[0].items->data);
598 if (as->parms[1].items) {
599 code = parse_flags(name, instance, as->parms[1].items->data, &flags);
602 ("Illegal flag specification: %s, should be of the form <'='|'+'|'-'|'_'>bitname{<'+'|'-'>bitname}*\n",
603 as->parms[1].items->data);
607 if (as->parms[2].items) {
609 char *s = strncpy(buf, as->parms[2].items->data, sizeof(buf));
610 code = ktime_DateToInt32(s, &expiration);
612 printf("Illegal time format %s: %s\n", as->parms[2].items->data,
613 ktime_GetDateUsage());
616 if (expiration == 0) {
617 fprintf(stderr, "Expiration time must be after (about) 1970.\n");
620 if (expiration < time(0)) {
622 "Warning: expiration being set into the past, account will be disabled.\n");
628 if (as->parms[3].items) {
629 code = read_time_interval(as->parms[3].items->data, &lifetime);
634 /* no point in doing this any sooner than necessary */
635 for (i = 0; i < 4; misc_auth_bytes[i++] = 0);
637 if (as->parms[4].items) {
638 if (util_isint(as->parms[4].items->data))
639 pwexpiry = atoi(as->parms[4].items->data);
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");
651 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) {
674 if (util_isint(as->parms[6].items->data)
675 && ((nfailures = atoi(as->parms[6].items->data)) < 255)) {
676 misc_auth_bytes[2] = nfailures + 1;
678 fprintf(stderr, "Failure limit must be in [0..254].\n");
679 fprintf(stderr, "Zero represents unlimited login attempts.\n");
684 if (as->parms[7].items) {
685 int locktime, hrs, mins;
689 s = as->parms[7].items->data;
691 sscanf(s, "%d:%d", &hrs, &mins);
693 sscanf(s, "%d", &mins);
695 locktime = hrs * 60 + mins;
696 if (hrs < 0 || hrs > 36 || mins < 0) {
698 "Lockout times must be either minutes or hh:mm.\n");
699 fprintf(stderr, "Lockout times must be less than 36 hours.\n");
701 } else if (locktime > 36 * 60) {
703 "Lockout times must be either minutes or hh:mm.\n");
704 fprintf(stderr, "Lockout times must be less than 36 hours.\n");
706 "Continuing with lock time of exactly 36 hours...\n");
709 locktime = (locktime * 60 + 511) >> 9; /* ceil(l*60/512) */
710 misc_auth_bytes[3] = locktime + 1; /* will be 1 if user said 0 */
713 if (as->parms[8].items) {
714 maxAssociates = atoi(as->parms[6].items->data);
715 if (maxAssociates < 0) {
716 printf("Illegal maximum number of associates\n");
721 was_spare = pack_long(misc_auth_bytes);
723 if (was_spare || flags || expiration || lifetime || (maxAssociates >= 0))
725 ubik_Call(KAM_SetFields, conn, 0, name, instance, flags,
726 expiration, lifetime, maxAssociates, was_spare,
729 printf("Must specify one of the optional parameters\n");
733 afs_com_err(whoami, code, "calling KAM_SetFields for %s.%s", name,
739 StringToKey(struct cmd_syndesc *as, void *arock)
742 char realm[MAXKTCREALMLEN];
743 struct ktc_encryptionKey key;
745 if (as->parms[1].items) {
746 code = ka_ExpandCell(as->parms[1].items->data, realm, 0 /*local */ );
748 afs_com_err(whoami, code,
749 "expanding %s as cell name, attempting to continue",
750 as->parms[1].items->data);
752 ucstring(realm, realm, sizeof(realm));
754 if (code = DefaultCell())
756 ucstring(realm, cell, sizeof(realm));
758 ka_StringToKey(as->parms[0].items->data, realm, &key);
760 printf("Converting %s in realm '%s' yields key='",
761 as->parms[0].items->data, realm);
762 ka_PrintBytes((char *)&key, sizeof(key));
765 des_string_to_key(as->parms[0].items->data, &key);
767 printf("Converting %s with the DES string to key yields key='",
768 as->parms[0].items->data);
769 ka_PrintBytes((char *)&key, sizeof(key));
776 SetPassword(struct cmd_syndesc *as, void *arock)
779 char name[MAXKTCNAMELEN];
780 char instance[MAXKTCNAMELEN];
781 char realm[MAXKTCREALMLEN];
782 struct ktc_encryptionKey key;
785 code = ka_ParseLoginName(as->parms[0].items->data, name, instance, realm);
787 afs_com_err(whoami, code, "parsing user's name '%s'",
788 as->parms[0].items->data);
792 if (strlen(realm) == 0)
793 ucstring(realm, cell, sizeof(realm));
795 if (as->parms[1].items && as->parms[2].items) {
796 printf("Can't specify both a password and a key\n");
798 } else if (as->parms[1].items) {
799 (void)init_child(myName);
800 (void)give_to_child(passwd); /* old password */
801 code = password_bad(as->parms[1].items->data);
802 (void)terminate_child();
805 ka_StringToKey(as->parms[1].items->data, realm, &key);
806 } else if (as->parms[2].items) {
807 if (ka_ReadBytes(as->parms[2].items->data, (char *)&key, sizeof(key))
809 printf("Key must be 8 bytes: '%s' was too long\n",
810 as->parms[2].items->data);
814 printf("Must specify new password or key\n");
819 if (as->parms[3].items)
820 sscanf(as->parms[3].items->data, "%d", &kvno);
822 #if defined(AFS_S390_LINUX20_ENV) && !defined(AFS_S390X_LINUX20_ENV)
823 code = ubik_Call(KAM_SetPassword, conn, 0, name, instance, kvno, 0, key);
825 code = ubik_Call(KAM_SetPassword, conn, 0, name, instance, kvno, 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_Call(KAM_GetPassword, lpbkConn, 0, name, &key);
1055 /* Lets close down the ubik_Client connection now */
1056 ubik_ClientDestroy(lpbkConn);
1060 ka_PrintBytes((char *)&key, sizeof(key));
1066 GetRandomKey(struct cmd_syndesc *as, void *arock)
1069 struct ktc_encryptionKey key;
1071 code = ubik_Call(KAM_GetRandomKey, conn, 0, &key);
1073 afs_com_err(whoami, code, "so can't get random key");
1077 ka_PrintBytes((char *)&key, sizeof(key));
1079 for (i = 0; i < sizeof(key); i++) {
1080 printf("%0.2x", ((char *)&key)[i] & 0xff);
1092 Statistics(struct cmd_syndesc *as, void *arock)
1098 char bob[KA_TIMESTR_LEN];
1101 ubik_Call(KAM_GetStats, conn, 0, KAMAJORVERSION, &admins, &statics,
1104 printf("call to GetStats failed: %s\n", ka_ErrorString(code));
1107 if (statics.minor_version != KAMINORVERSION)
1108 printf("Minor version number mismatch: got %d, expected %d\n",
1109 statics.minor_version, KAMINORVERSION);
1110 printf("%d allocs, %d frees, %d password changes\n", statics.allocs,
1111 statics.frees, statics.cpws);
1112 printf("Hash table utilization = %f%%\n",
1113 (double)dynamics.hashTableUtilization / 100.0);
1114 ka_timestr(dynamics.start_time, bob, KA_TIMESTR_LEN);
1115 printf("From host %lx started at %s:\n",
1116 afs_cast_uint32(dynamics.host), bob);
1118 #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)
1119 print_stat(Authenticate);
1120 print_stat(ChangePassword);
1121 print_stat(GetTicket);
1122 print_stat(CreateUser);
1123 print_stat(SetPassword);
1124 print_stat(SetFields);
1125 print_stat(DeleteUser);
1126 print_stat(GetEntry);
1127 print_stat(ListEntry);
1128 print_stat(GetStats);
1129 print_stat(GetPassword);
1130 print_stat(GetRandomKey);
1132 print_stat(UAuthenticate);
1133 print_stat(UGetTicket);
1135 #if (KAMAJORVERSION>5)
1136 print cpu stats printf("%d string checks\n", dynamics.string_checks);
1138 printf("Used %.3f seconds of CPU time.\n",
1139 dynamics.string_checks / 1000.0);
1141 printf("%d admin accounts\n", admins);
1146 DebugInfo(struct cmd_syndesc *as, void *arock)
1149 struct ka_debugInfo info;
1153 char bob[KA_TIMESTR_LEN];
1156 if (as->parms[0].items) {
1157 struct ubik_client *iConn;
1159 ka_SingleServerConn(cell, as->parms[0].items->data,
1160 KA_MAINTENANCE_SERVICE, 0, &iConn);
1162 struct afsconf_cell cellinfo;
1164 afs_com_err(whoami, code, "couldn't find host %s in cell %s",
1165 as->parms[0].items->data, cell);
1166 code = ka_GetServers(cell, &cellinfo);
1168 afs_com_err(whoami, code, "getting servers in cell %s", cell);
1170 printf("Servers in cell %s, are:\n", cell);
1171 for (i = 0; i < cellinfo.numServers; i++)
1172 printf(" %s\n", cellinfo.hostName[i]);
1176 code = ubik_Call(KAM_Debug, iConn, 0, KAMAJORVERSION, 0, &info);
1177 ubik_ClientDestroy(iConn);
1179 code = ubik_Call(KAM_Debug, conn, 0, KAMAJORVERSION, 0, &info);
1182 afs_com_err(whoami, code, "call to Debug failed");
1187 if (info.minorVersion != KAMINORVERSION)
1188 printf("Minor version number mismatch: got %d, expected %d\n",
1189 info.minorVersion, KAMINORVERSION);
1192 #if (KAMAJORVERSION>5)
1199 timeOffset = -timeOffset;
1200 if (timeOffset > 60) {
1202 ("WARNING: Large server client clock skew: %d seconds. Call itself took %d seconds.\n",
1203 timeOffset, now - start);
1205 ka_timestr(info.startTime, bob, KA_TIMESTR_LEN);
1206 printf("From host %lx started %sat %s:\n",
1207 afs_cast_uint32(info.host),
1208 (info.noAuth ? "w/o authorization " : ""), bob);
1209 ka_timestr(info.lastTrans, bob, KA_TIMESTR_LEN);
1210 printf("Last trans was %s at %s\n", info.lastOperation, bob);
1211 ka_timestr(info.dbHeaderRead, bob, KA_TIMESTR_LEN);
1212 printf("Header last read %s.\n", bob);
1213 printf("db version=%d, keyVersion=%d, key cache version=%d\n",
1214 info.dbVersion, info.dbSpecialKeysVersion, info.kcVersion);
1215 printf("db ptrs: free %d, eof %d, kvno %d.\n", info.dbFreePtr,
1216 info.dbEofPtr, info.dbKvnoPtr);
1217 ka_timestr(info.nextAutoCPW, bob, KA_TIMESTR_LEN);
1218 printf("Next autoCPW at %s or in %d updates.\n", bob,
1219 info.updatesRemaining);
1220 if (info.cheader_lock || info.keycache_lock)
1221 printf("locks: cheader %08lx, keycache %08lx\n",
1222 afs_cast_uint32(info.cheader_lock),
1223 afs_cast_uint32(info.keycache_lock));
1224 printf("Last authentication for %s, last admin user was %s\n",
1225 info.lastAuth, info.lastAdmin);
1226 printf("Last TGS op was a %s ticket was for %s\n", info.lastTGSServer,
1228 printf("Last UDP TGS was a %s ticket for %s. UDP Authenticate for %s\n",
1229 info.lastUTGSServer, info.lastUTGS, info.lastUAuth);
1230 printf("key cache size %d, used %d.\n", info.kcSize, info.kcUsed);
1231 if (info.kcUsed > KADEBUGKCINFOSIZE) {
1232 printf("insufficient room to return all key cache entries!\n");
1233 info.kcUsed = KADEBUGKCINFOSIZE;
1235 for (i = 0; i < info.kcUsed; i++)
1236 ka_timestr(info.kcInfo[i].used, bob, KA_TIMESTR_LEN);
1237 printf("%32s %c %2x(%2x) used %s\n", info.kcInfo[i].principal,
1238 (info.kcInfo[i].primary ? '*' : ' '), info.kcInfo[i].kvno,
1239 info.kcInfo[i].keycksum, bob);
1244 Interactive(struct cmd_syndesc *as, void *arock)
1251 Quit(struct cmd_syndesc *as, void *arock)
1258 MyAfterProc(struct cmd_syndesc *as, void *arock)
1260 if (!strcmp(as->name, "help"))
1263 /* Determine if we need to destory the ubik connection.
1264 * Closing it avoids resends of packets.
1267 ubik_ClientDestroy(conn);
1274 int init = 0, noauth;
1275 char name[MAXKTCNAMELEN];
1276 char instance[MAXKTCNAMELEN];
1277 char newCell[MAXKTCREALMLEN];
1278 afs_int32 serverList[MAXSERVERS];
1281 NoAuth(struct cmd_syndesc *as, void *arock)
1288 MyBeforeProc(struct cmd_syndesc *as, void *arock)
1290 extern struct passwd *getpwuid();
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);