Bug Summary

File:kauth/admin_tools.c
Location:line 1806, column 5
Description:Value stored to 'ts' is never read

Annotated Source Code

1/*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
4 *
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
8 */
9
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. */
14
15#include <afsconfig.h>
16#include <afs/param.h>
17#include <afs/stds.h>
18
19#include <roken.h>
20
21#include <ctype.h>
22
23#include <hcrypto/des.h>
24#include <hcrypto/ui.h>
25
26#include <rx/xdr.h>
27#include <rx/rx.h>
28#include <rx/rxkad.h>
29#include <lock.h>
30#define UBIK_LEGACY_CALLITER1 1
31#include <ubik.h>
32#include <afs/auth.h>
33#include <afs/cellconfig.h>
34#include <afs/cmd.h>
35#include <afs/com_err.h>
36#include <afs/afsutil.h>
37
38#include "kauth.h"
39#include "kauth_internal.h"
40#include "kautils.h"
41#include "kaport.h"
42#include "kkids.h"
43
44#define CMD_PARSER_AMBIG_FIX1 1 /* allow ambiguous aliases */
45
46#define KA_SIXHOURS(6*3600) (6*3600)
47
48static struct ubik_client *conn;
49static char cell[MAXKTCREALMLEN64] = "";
50static char whoami[32];
51static char passwd[BUFSIZ1024];
52static char myName[510]; /* almost like whoami save with path and without : */
53
54static int finished;
55static int zero_argc;
56static char **zero_argv;
57afs_uint32 ka_islocked(char *, char *, afs_uint32 *);
58
59afs_int32
60DefaultCell(void)
61{
62 afs_int32 code;
63
64 if (cell[0] != 0)
65 return 0;
66 code = ka_ExpandCell(0, cell, 0 /*local */ );
67 if (code) {
68 afs_com_err(whoami, code, "Can't expand cell name");
69 }
70 return code;
71}
72
73/* These are the command operation procedures. */
74
75int
76DumpUser(char *user, char *arock, int showadmin, int showkey, char *inst)
77{
78 char name[MAXKTCNAMELEN64];
79 char instance[MAXKTCNAMELEN64];
80 Dateafs_uint32 now = time(0);
81 int code;
82 char bob[KA_TIMESTR_LEN30];
83
84 struct kaentryinfo tentry;
85
86 code = ka_ParseLoginName(user, name, instance, 0);
87 if (code) {
88 afs_com_err(whoami, code, "parsing user's name '%s'", user);
89 return KABADCMD(180493L);
90 }
91
92 if (!inst)
93 inst = instance;
94 code =
95 ubik_KAM_GetEntry(conn, 0, name, inst, KAMAJORVERSION5, &tentry);
96 if (code) {
97 afs_com_err(whoami, code, "getting information for %s.%s", name, inst);
98 return code;
99 }
100 if (tentry.minor_version != KAMINORVERSION2)
101 printf("Minor version number mismatch: got %d, expected %d\n",
102 tentry.minor_version, KAMINORVERSION2);
103 if (showadmin && !(tentry.flags & KAFADMIN0x004))
104 return 0;
105 ka_PrintUserID("\nUser data for ", name, inst, "");
106 {
107 char *prefix = " (";
108#define NEWPREFIX"+" "+"
109 if (tentry.flags & KAFADMIN0x004) {
110 printf("%sADMIN", prefix);
111 prefix = NEWPREFIX"+";
112 }
113 if (tentry.flags & KAFNOTGS0x008) {
114 printf("%sNOTGS", prefix);
115 prefix = NEWPREFIX"+";
116 }
117 if (tentry.flags & KAFNOCPW0x040) {
118 printf("%sNOCPW", prefix);
119 prefix = NEWPREFIX"+";
120 }
121 if (tentry.flags & KAFNOSEAL0x020) {
122 printf("%sNOSEAL", prefix);
123 prefix = NEWPREFIX"+";
124 }
125 if (tentry.flags & KAFNEWASSOC0x080) {
126 printf("%sNEWASSOC", prefix);
127 prefix = NEWPREFIX"+";
128 }
129 if (tentry.flags & KAFASSOCROOT0x200) {
130 printf("%sASSOCROOT", prefix);
131 prefix = NEWPREFIX"+";
132 }
133 if (tentry.flags & KAFASSOC0x400) {
134 printf("%sASSOC", prefix);
135 prefix = NEWPREFIX"+";
136 }
137 if (tentry.user_expiration <= now) {
138 printf("%sexpired", prefix);
139 prefix = NEWPREFIX"+";
140 }
141 if (strcmp(prefix, NEWPREFIX"+") == 0)
142 printf(")\n");
143 else
144 printf("\n");
145 }
146 if ((!ka_KeyIsZero((char *)&tentry.key, sizeof(tentry.key))) && (showkey)) {
147 printf(" key (%d):", tentry.key_version);
148 ka_PrintBytes((char *)&tentry.key, sizeof(tentry.key));
149 } else {
150 if (tentry.keyCheckSum == 0)
151 printf(" key version is %d", tentry.key_version);
152 else
153 printf(" key (%d) cksum is %u", tentry.key_version,
154 tentry.keyCheckSum);
155 }
156 ka_timestr(tentry.change_password_time, bob, KA_TIMESTR_LEN30);
157 printf(", last cpw: %s\n", bob);
158 if (!tentry.misc_auth_bytes) {
159 printf(" password will never expire.\n");
160 printf
161 (" An unlimited number of unsuccessful authentications is permitted.\n");
162 } else {
163 unsigned char misc_stuff[4];
164 afs_uint32 temp;
165
166 temp = tentry.misc_auth_bytes;
167/*
168 temp = ntohl(tentry.misc_auth_bytes);
169*/
170 unpack_long(temp, misc_stuff){ misc_stuff[0] = ((unsigned char)(((afs_uint32)(temp) & 0xff000000
) >> 24) & 0xff); misc_stuff[1] = ((unsigned char)(
((afs_uint32)(temp) & 0x00ff0000) >> 16) & 0xff
); misc_stuff[2] = ((unsigned char)(((afs_uint32)(temp) &
0x0000ff00) >> 8) & 0xff); misc_stuff[3] = ((unsigned
char)(((afs_uint32)(temp) & 0x000000ff) >> 0) &
0xff); }
;
171
172 if (!misc_stuff[0]) {
173 printf(" password will never expire.\n");
174 } else {
175 ka_timestr((tentry.change_password_time +
176 misc_stuff[0] * 24 * 60 * 60), bob, KA_TIMESTR_LEN30);
177 printf(" password will expire: %s\n", bob);
178 }
179
180 if (!misc_stuff[2])
181 printf
182 (" An unlimited number of unsuccessful authentications is permitted.\n");
183 else {
184 printf
185 (" %d consecutive unsuccessful authentications are permitted.\n",
186 misc_stuff[2]);
187
188 if (!misc_stuff[3])
189 printf(" The lock time for this user is not limited.\n");
190 else
191 printf(" The lock time for this user is %4.1f minutes.\n",
192 (float)((unsigned int)misc_stuff[3] << 9) / 60.0);
193
194 if (!(misc_stuff[1] & KA_ISLOCKED4)
195 || !ka_islocked(name, instance, &temp))
196 printf(" User is not locked.\n");
197 else if (temp == (afs_uint32) (-1L))
198 printf(" User is locked forever.\n");
199 else {
200 ka_timestr(temp, bob, KA_TIMESTR_LEN30);
201 printf(" User is locked until %s\n", bob);
202 }
203 }
204
205 }
206 {
207 char exp[KA_TIMESTR_LEN30];
208 ka_timestr(tentry.user_expiration, exp, KA_TIMESTR_LEN30);
209 if (tentry.user_expiration < now)
210 printf(" DISABLED entry at %s.", exp);
211 else if (tentry.user_expiration == NEVERDATE0xffffffff)
212 printf(" entry never expires.");
213 else
214 printf(" entry expires on %s.", exp);
215 }
216 printf(" Max ticket lifetime %.2f hours.\n",
217 tentry.max_ticket_lifetime / 3600.0);
218 ka_timestr(tentry.modification_time, bob, KA_TIMESTR_LEN30);
219 printf(" last mod on %s by ", bob);
220 ka_PrintUserID("", tentry.modification_user.name,
221 tentry.modification_user.instance, "\n");
222 if ((tentry.reserved3 & 0xffff0000) == 0x12340000) {
223 int short reused = (short)tentry.reserved3;
224 if (!reused) {
225 printf(" permit password reuse\n");
226 } else {
227 printf(" don't permit password reuse\n");
228 }
229 }
230 return 0;
231}
232
233int
234ListUsers(struct cmd_syndesc *as, void *arock)
235{
236 struct kaident name;
237 afs_int32 index;
238 afs_int32 count;
239 afs_int32 next_index;
240 int code, all = 0, showa = 0;
241 int showkey = (as->parms[2].items != NULL((void *)0));
242
243 if (as->parms[0].items)
244 all = 1;
245 if (as->parms[1].items) {
246 all = 1;
247 showa = 1;
248 }
249 for (index = 0; 1; index = next_index) {
250 code =
251 ubik_KAM_ListEntry(conn, 0, index, &next_index, &count,
252 &name);
253 if (code) {
254 afs_com_err(whoami, code, "calling KAM_ListEntry");
255 break;
256 }
257 if (!next_index)
258 break;
259 if (next_index < 0)
260 printf("next_index (%d) is negative: ", next_index);
261 if (strlen(name.name) == 0)
262 printf("name is zero length: ");
263 if (all)
264 DumpUser(name.name, NULL((void *)0), showa, showkey, name.instance);
265 else
266 ka_PrintUserID("", name.name, name.instance, "\n");
267 }
268 return code;
269}
270
271
272int
273ExamineUser(struct cmd_syndesc *as, void *arock)
274{
275 int showkey = (as->parms[1].items != NULL((void *)0));
276 return DumpUser(as->parms[0].items->data, arock, 0, showkey, NULL((void *)0));
277}
278
279
280struct OKerrors {
281 int code;
282 char *msg;
283};
284
285int
286handle_errors(int code, /* error code to handle */
287 struct OKerrors OKlist[], /* list of errors & messages that should be ignored */
288 int *persist)
289{ /* set this if we should retry, clear otherwise */
290 int i;
291
292 for (i = 0; OKlist[i].code; i++) {
293 if (OKlist[i].code == code) {
294 printf("%s\n", OKlist[i].msg);
295 *persist = 0; /* we're done */
296 return 0;
297 }
298 }
299
300 printf(" : [%s] %s", afs_error_table_name(code), afs_error_message(code));
301 switch (code) {
302 case UNOQUORUM(5376L):
303 printf(", wait one second\n");
304 IOMGR_Sleep(1);
305 return 0;
306 case KAEMPTY(180485L):
307 case RX_CALL_TIMEOUT(-3):
308 printf(" (retrying)\n");
309 return 0;
310 }
311 printf("\n");
312
313 *persist = 0; /* don't retry these errors */
314 return code;
315}
316
317int
318CreateUser(struct cmd_syndesc *as, void *arock)
319{
320 int code;
321 char name[MAXKTCNAMELEN64];
322 char instance[MAXKTCNAMELEN64];
323 struct ktc_encryptionKey key;
324
325 int persist = 1;
326 struct OKerrors OKlist[2];
327 OKlist[0].code = 0;
328
329 code = ka_ParseLoginName(as->parms[0].items->data, name, instance, 0);
330 if (code) {
331 afs_com_err(whoami, code, "parsing user's name '%s'",
332 as->parms[0].items->data);
333 return KABADCMD(180493L);
334 }
335 ka_StringToKey(as->parms[1].items->data, cell, &key);
336
337 do {
338 code = ubik_KAM_CreateUser(conn, 0, name, instance,
339 *ktc_to_EncryptionKey(&key));
340 if (!code)
341 return 0;
342 ka_PrintUserID("Creating user ", name, instance, " ");
343 code = handle_errors(code, OKlist, &persist);
344 } while (persist);
345 return code;
346}
347
348int
349DeleteUser(struct cmd_syndesc *as, void *arock)
350{
351 int code;
352 char name[MAXKTCNAMELEN64];
353 char instance[MAXKTCNAMELEN64];
354
355 int persist = 1;
356 struct OKerrors OKlist[2];
357 OKlist[0].code = 0;
358 code = ka_ParseLoginName(as->parms[0].items->data, name, instance, 0);
359 if (code) {
360 afs_com_err(whoami, code, "parsing user's name '%s'",
361 as->parms[0].items->data);
362 return KABADCMD(180493L);
363 }
364
365 do {
366 code = ubik_KAM_DeleteUser(conn, 0, name, instance);
367 if (!code)
368 return 0;
369 ka_PrintUserID("Deleting user ", name, instance, " ");
370 code = handle_errors(code, OKlist, &persist);
371 } while (persist);
372 return code;
373}
374
375static int
376read_time_interval(char *str, afs_int32 * seconds)
377{
378 char *s;
379 int sec = 0;
380 char buf[32];
381
382 str = strncpy(buf, str, sizeof(buf));
383 s = strchr(str, ':');
384 if (s == 0)
385 sec = atoi(str);
386 else {
387 *s++ = '\0'; /* separate hours and minutes */
388 sec = atoi(str) * 3600 + atoi(s) * 60;
389 }
390 *seconds = sec;
391 return 0;
392}
393
394int
395parse_flags(char *name, char *inst, char *str, afs_int32 * flags)
396{
397 struct kaentryinfo tentry;
398 int code;
399 char bitspec[100];
400 afs_int32 f;
401 char bit[25];
402 char c;
403 int addop; /* 1=add bit; 0=remove bit */
404 int flag;
405 int i;
406
407 str = lcstring(bitspec, str, sizeof(bitspec));
408 if (isdigit(*str)__isctype((*str), 0x00000400L)) {
409 if (strncmp(str, "0x", 2) == 0) /* 0x => hex */
410 sscanf(str, "0x%lx", (long unsigned int *) &f);
411 else if (*str == '0') /* assume octal */
412 sscanf(str, "%lo", (long unsigned int *) &f);
413 else /* just assume hex */
414 sscanf(str, "%lx", (long unsigned int *) &f);
415 } else {
416 if (*str == '=') {
417 str++;
418 f = 0;
419 addop = 1;
420 } else {
421 if (strchr("+-", *str))
422 addop = (*str++ == '+');
423 else if (*str == '_') {
424 addop = 0;
425 str++;
426 } else
427 addop = 1;
428 code =
429 ubik_KAM_GetEntry(conn, 0, name, inst, KAMAJORVERSION5,
430 &tentry);
431 if (code) {
432 afs_com_err(whoami, code,
433 "could get current flag value for %s.%s", name, inst);
434 return -1;
435 }
436 f = tentry.flags;
437 }
438 while (*str) {
439 i = 0;
440 while (1) {
441 c = *str;
442 if (isupper(c)__sbistype((c), 0x00008000L))
443 c = tolower(c)__sbtolower(c);
444 if (!islower(c)__sbistype((c), 0x00001000L))
445 break;
446 bit[i++] = c;
447 str++;
448 }
449 bit[i] = '\0';
450 if (strcmp(bit, "admin") == 0)
451 flag = KAFADMIN0x004;
452 else if (strcmp(bit, "noadmin") == 0)
453 flag = KAFADMIN0x004, addop = !addop;
454 else if (strcmp(bit, "notgs") == 0)
455 flag = KAFNOTGS0x008;
456 else if (strcmp(bit, "tgs") == 0)
457 flag = KAFNOTGS0x008, addop = !addop;
458 else if (strcmp(bit, "noseal") == 0)
459 flag = KAFNOSEAL0x020;
460 else if (strcmp(bit, "seal") == 0)
461 flag = KAFNOSEAL0x020, addop = !addop;
462 else if (strcmp(bit, "nocpw") == 0)
463 flag = KAFNOCPW0x040;
464 else if (strcmp(bit, "cpw") == 0)
465 flag = KAFNOCPW0x040, addop = !addop;
466 else if (strcmp(bit, "newassoc") == 0)
467 flag = KAFNEWASSOC0x080;
468 else if (strcmp(bit, "nonewassoc") == 0)
469 flag = KAFNEWASSOC0x080, addop = !addop;
470 else {
471 printf
472 ("Illegal bit name: %s; choices are: [no]admin, [no]tgs, [no]seal, [no]cpw\n",
473 bit);
474 return -1;
475 }
476
477 if (addop)
478 f |= flag;
479 else
480 f &= ~flag;
481
482 if (*str == 0)
483 break;
484 if (*str == '+')
485 addop = 1; /* get next op */
486 else if ((*str == '-') || (*str == '_'))
487 addop = 0;
488 else {
489 printf("Illegal combination operator: %c\n", *str);
490 return -1;
491 }
492 str++;
493 }
494 }
495 *flags = (f & KAF_SETTABLE_FLAGS(0x004 | 0x008 | 0x020 | 0x040 | 0x080)) | KAFNORMAL0x001;
496 return 0;
497}
498
499#define seriouserror(code)((code <0) || ((code != (5389L)) && (code != (5376L
)) && code != (5377L)))
((code <0) || ((code != UNOSERVERS(5389L)) && (code != UNOQUORUM(5376L)) && code != UNOTSYNC(5377L)))
500
501/* return MAXLONG if locked forever */
502afs_uint32
503ka_islocked(char *name, char *instance, afs_uint32 * when)
504{
505 int count, code;
506 afs_uint32 tempwhen;
507
508 count = 0;
509 *when = 0;
510 do {
511 tempwhen = 0;
512 code =
513 ubik_CallIter(KAM_LockStatus, conn, UPUBIKONLY1, &count, (long) name,
514 (long) instance, (long) &tempwhen, 0, 0, 0,
515 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
516 if (code) {
517 if (seriouserror(code)((code <0) || ((code != (5389L)) && (code != (5376L
)) && code != (5377L)))
)
518 afs_com_err(whoami, code, NULL((void *)0));
519 } else if (tempwhen) { /* user is locked */
520 if (!*when || tempwhen < *when) {
521 *when = tempwhen;
522 return (*when);
523 }
524 } else /* ! tempwhen ==> user is not locked */
525 return 0;
526
527 } while (code != UNOSERVERS(5389L));
528
529 return (*when);
530}
531
532int
533Unlock(struct cmd_syndesc *as, void *arock)
534{
535 afs_int32 code, rcode = 0;
536 afs_int32 count;
537 afs_int32 server;
538 char name[MAXKTCNAMELEN64];
539 char instance[MAXKTCNAMELEN64];
540
541 code = ka_ParseLoginName(as->parms[0].items->data, name, instance, 0);
542 if (code) {
543 afs_com_err(whoami, code, "parsing user's name '%s'",
544 as->parms[0].items->data);
545 return KABADCMD(180493L);
546 }
547
548 count = 0;
549 do {
550 code = ubik_CallIter(KAM_Unlock, conn, 0, &count, (long) name, (long) instance,
551 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
552 if (code && (code != UNOSERVERS(5389L))) {
553 server = 0;
554 if (conn && conn->conns[count - 1]
555 && conn->conns[count - 1]->peer) {
556 server = conn->conns[count - 1]->peer->host;
557 }
558 afs_com_err(whoami, code,
559 "so %s.%s may still be locked (on server %d.%d.%d.%d)",
560 name, instance, ((server >> 24) & 0xFF),
561 ((server >> 16) & 0xFF), ((server >> 8) & 0xFF),
562 (server & 0xFF));
563
564 if (!rcode) {
565 rcode = code;
566 }
567 }
568 } while (code != UNOSERVERS(5389L));
569
570 return rcode;
571}
572
573int
574SetFields(struct cmd_syndesc *as, void *arock)
575{
576 int code;
577 char name[MAXKTCNAMELEN64];
578 char instance[MAXKTCNAMELEN64];
579 char *end;
580 afs_int32 flags = 0;
581 Dateafs_uint32 expiration = 0;
582 afs_int32 lifetime = 0;
583 afs_int32 maxAssociates = -1;
584 afs_int32 pwexpiry = 0;
585 afs_int32 was_spare = 0;
586 char misc_auth_bytes[4];
587 int i;
588
589 code = ka_ParseLoginName(as->parms[0].items->data, name, instance, 0);
590 if (code) {
591 afs_com_err(whoami, code, "parsing user's name '%s'",
592 as->parms[0].items->data);
593 return KABADCMD(180493L);
594 }
595
596 if (as->parms[1].items) {
597 code = parse_flags(name, instance, as->parms[1].items->data, &flags);
598 if (code) {
599 printf
600 ("Illegal flag specification: %s, should be of the form <'='|'+'|'-'|'_'>bitname{<'+'|'-'>bitname}*\n",
601 as->parms[1].items->data);
602 return KABADCMD(180493L);
603 }
604 }
605 if (as->parms[2].items) {
606 char buf[32];
607 char *s = strncpy(buf, as->parms[2].items->data, sizeof(buf));
608 code = ktime_DateToInt32(s, &expiration);
609 if (code) {
610 printf("Illegal time format %s: %s\n", as->parms[2].items->data,
611 ktime_GetDateUsage());
612 return KABADCMD(180493L);
613 }
614 if (expiration == 0) {
615 fprintf(stderr__stderrp, "Expiration time must be after (about) 1970.\n");
616 return KABADCMD(180493L);
617 }
618 if (expiration < time(0)) {
619 fprintf(stderr__stderrp,
620 "Warning: expiration being set into the past, account will be disabled.\n");
621 }
622 }
623 /*
624 * TICKET lifetime...
625 */
626 if (as->parms[3].items) {
627 code = read_time_interval(as->parms[3].items->data, &lifetime);
628 if (code)
629 return KABADCMD(180493L);
630 }
631
632 /* no point in doing this any sooner than necessary */
633 for (i = 0; i < 4; misc_auth_bytes[i++] = 0);
634
635 if (as->parms[4].items) {
636 pwexpiry = strtol(as->parms[4].items->data, &end, 10);
637 if (*end != '\0') {
638 fprintf(stderr__stderrp,
639 "Password lifetime specified must be a non-negative decimal integer.\n");
640 pwexpiry = -1;
641 }
642 if (pwexpiry < 0 || pwexpiry > 254) {
643 fprintf(stderr__stderrp,
644 "Password lifetime range must be [0..254] days.\n");
645 fprintf(stderr__stderrp, "Zero represents an unlimited lifetime.\n");
646 return KABADCMD(180493L);
647 }
648
649 misc_auth_bytes[0] = pwexpiry + 1;
650 }
651
652 if (as->parms[5].items) {
653 char *reuse;
654 reuse = (as->parms[5].items->data);
655
656 if (!strcmp(reuse, "yes")) {
657 misc_auth_bytes[1] = KA_REUSEPW1;
658 } else if (strcmp(reuse, "no")) {
659 fprintf(stderr__stderrp,
660 "must specify \"yes\" or \"no\": \"yes\" assumed\n");
661 misc_auth_bytes[1] = KA_REUSEPW1;
662 } else {
663 misc_auth_bytes[1] = KA_NOREUSEPW2;
664 }
665 }
666
667 if (as->parms[6].items) {
668 int nfailures;
669
670 nfailures = strtol(as->parms[6].items->data, &end, 10);
671
672 if (*end != '\0' || nfailures < 0 || nfailures > 254) {
673 fprintf(stderr__stderrp, "Failure limit must be in [0..254].\n");
674 fprintf(stderr__stderrp, "Zero represents unlimited login attempts.\n");
675 return KABADCMD(180493L);
676 }
677 misc_auth_bytes[2] = nfailures + 1;
678 }
679
680 if (as->parms[7].items) {
681 int locktime, hrs, mins;
682 char *s;
683
684 hrs = 0;
685 s = as->parms[7].items->data;
686 if (strchr(s, ':'))
687 sscanf(s, "%d:%d", &hrs, &mins);
688 else
689 sscanf(s, "%d", &mins);
690
691 locktime = hrs * 60 + mins;
692 if (hrs < 0 || hrs > 36 || mins < 0) {
693 fprintf(stderr__stderrp,
694 "Lockout times must be either minutes or hh:mm.\n");
695 fprintf(stderr__stderrp, "Lockout times must be less than 36 hours.\n");
696 return KABADCMD(180493L);
697 } else if (locktime > 36 * 60) {
698 fprintf(stderr__stderrp,
699 "Lockout times must be either minutes or hh:mm.\n");
700 fprintf(stderr__stderrp, "Lockout times must be less than 36 hours.\n");
701 fprintf(stderr__stderrp,
702 "Continuing with lock time of exactly 36 hours...\n");
703 locktime = 36 * 60;
704 }
705 locktime = (locktime * 60 + 511) >> 9; /* ceil(l*60/512) */
706 misc_auth_bytes[3] = locktime + 1; /* will be 1 if user said 0 */
707 }
708#if ASSOCIATES
709 if (as->parms[8].items) {
710 maxAssociates = atoi(as->parms[6].items->data);
711 if (maxAssociates < 0) {
712 printf("Illegal maximum number of associates\n");
713 return KABADCMD(180493L);
714 }
715 }
716#endif
717 was_spare = pack_long(misc_auth_bytes)( (afs_uint32) ( ((afs_uint32) ((misc_auth_bytes)[0] & 0xff
) << 24) | ((afs_uint32) ((misc_auth_bytes)[1] & 0xff
) << 16) | ((afs_uint32) ((misc_auth_bytes)[2] & 0xff
) << 8) | ((afs_uint32) ((misc_auth_bytes)[3] & 0xff
) << 0) ) )
;
718
719 if (was_spare || flags || expiration || lifetime || (maxAssociates >= 0))
720 code =
721 ubik_KAM_SetFields(conn, 0, name, instance, flags,
722 expiration, lifetime, maxAssociates, was_spare,
723 /* spare */ 0);
724 else {
725 printf("Must specify one of the optional parameters\n");
726 return KABADCMD(180493L);
727 }
728 if (code)
729 afs_com_err(whoami, code, "calling KAM_SetFields for %s.%s", name,
730 instance);
731 return code;
732}
733
734int
735StringToKey(struct cmd_syndesc *as, void *arock)
736{
737 afs_int32 code;
738 char realm[MAXKTCREALMLEN64];
739 struct ktc_encryptionKey key;
740
741 if (as->parms[1].items) {
742 code = ka_ExpandCell(as->parms[1].items->data, realm, 0 /*local */ );
743 if (code) {
744 afs_com_err(whoami, code,
745 "expanding %s as cell name, attempting to continue",
746 as->parms[1].items->data);
747 }
748 ucstring(realm, realm, sizeof(realm));
749 } else {
750 if ((code = DefaultCell()))
751 return code;
752 ucstring(realm, cell, sizeof(realm));
753 }
754 ka_StringToKey(as->parms[0].items->data, realm, &key);
755
756 printf("Converting %s in realm '%s' yields key='",
757 as->parms[0].items->data, realm);
758 ka_PrintBytes((char *)&key, sizeof(key));
759 printf("'.\n");
760
761 DES_string_to_keyhc_DES_string_to_key(as->parms[0].items->data, ktc_to_cblockptr(&key));
762
763 printf("Converting %s with the DES string to key yields key='",
764 as->parms[0].items->data);
765 ka_PrintBytes((char *)&key, sizeof(key));
766 printf("'.\n");
767
768 return 0;
769}
770
771int
772SetPassword(struct cmd_syndesc *as, void *arock)
773{
774 int code;
775 char name[MAXKTCNAMELEN64];
776 char instance[MAXKTCNAMELEN64];
777 char realm[MAXKTCREALMLEN64];
778 struct ktc_encryptionKey key;
779 afs_int32 kvno = 0;
780
781 code = ka_ParseLoginName(as->parms[0].items->data, name, instance, realm);
782 if (code) {
783 afs_com_err(whoami, code, "parsing user's name '%s'",
784 as->parms[0].items->data);
785 return KABADCMD(180493L);
786 }
787
788 if (strlen(realm) == 0)
789 ucstring(realm, cell, sizeof(realm));
790
791 if (as->parms[1].items && as->parms[2].items) {
792 printf("Can't specify both a password and a key\n");
793 return KABADCMD(180493L);
794 } else if (as->parms[1].items) {
795 (void)init_child(myName);
796 (void)give_to_child(passwd); /* old password */
797 code = password_bad(as->parms[1].items->data);
798 (void)terminate_child();
799 if (code)
800 return KABADCMD(180493L);
801 ka_StringToKey(as->parms[1].items->data, realm, &key);
802 } else if (as->parms[2].items) {
803 if (ka_ReadBytes(as->parms[2].items->data, (char *)&key, sizeof(key))
804 != 8) {
805 printf("Key must be 8 bytes: '%s' was too long\n",
806 as->parms[2].items->data);
807 return KABADCMD(180493L);
808 }
809 } else {
810 printf("Must specify new password or key\n");
811 return KABADCMD(180493L);
812 }
813
814
815 if (as->parms[3].items)
816 sscanf(as->parms[3].items->data, "%d", &kvno);
817
818 code = ubik_KAM_SetPassword(conn, 0, name, instance, kvno,
819 *ktc_to_EncryptionKey(&key));
820 if (code)
821 afs_com_err(whoami, code, "so can't set password for %s.%s", name,
822 instance);
823 return code;
824}
825
826#define PrintPrincipal(p,n,l)PrintName((p)->name, (p)->instance, (p)->cell, l, n) \
827 PrintName((p)->name, (p)->instance, (p)->cell, l, n)
828
829static afs_int32
830PrintName(char *name, char *inst, char *acell, int buflen, char *buf)
831{
832 int nlen, len;
833 int left; /* if ConvertBytes stops early */
834 afs_int32 code;
835
836 if (name == 0)
837 name = "";
838 if (inst == 0)
839 inst = "";
840 if (acell == 0)
841 acell = "";
842 left = ka_ConvertBytes(buf, buflen, name, strlen(name));
843 if (left) {
844 bad_name:
845 code = KABADNAME(180486L);
846 afs_com_err(whoami, code, "PrintName: principal name was '%s'.'%s'@'%s'",
847 name, inst, acell);
848 return code;
849 }
850 nlen = strlen(buf);
851 len = strlen(inst);
852 if (len) {
853 if (nlen + len + 1 >= buflen)
854 goto bad_name;
855 buf[nlen++] = '.';
856 left = ka_ConvertBytes(buf + nlen, buflen - nlen, inst, len);
857 if (left)
858 goto bad_name;
859 nlen += len;
860 }
861
862 len = strlen(acell);
863 if (len) {
864 char *lcell = ka_LocalCell();
865 if (lcell == 0)
866 lcell = "";
867 if (strcmp(acell, lcell) != 0) {
868 /* only append cell if not the local cell */
869 if (nlen + len + 1 >= buflen)
870 goto bad_name;
871 buf[nlen++] = '@';
872 left = ka_ConvertBytes(buf + nlen, buflen - nlen, acell, len);
873 if (left)
874 goto bad_name;
875 nlen += len;
876 }
877 }
878 return 0;
879}
880
881#define PrintedPrincipal(p)PrintedName ((p)->name, (p)->instance, (p)->cell) PrintedName ((p)->name, (p)->instance, (p)->cell)
882
883/* PrintedName - returned a pointer to a static string in which the formated
884 * name has been stored. */
885
886static char *
887PrintedName(char *name, char *inst, char *cell)
888{
889 static char printedName[128];
890 afs_int32 code;
891 code = PrintName(name, inst, cell, sizeof(printedName), printedName);
892 if (code) {
893 if (name == 0)
894 name = "";
895 strncpy(printedName, name, sizeof(printedName));
896 printedName[sizeof(printedName) - 8] = 0;
897 strcat(printedName, "<error>");
898 }
899 return printedName;
900}
901
902static afs_int32
903ListTicket(struct ktc_principal *server, int verbose)
904{
905 afs_int32 code;
906 struct ktc_token token; /* the token we're printing */
907 struct ktc_principal client;
908 char UserName[sizeof(struct ktc_principal)];
909 char ServerName[sizeof(struct ktc_principal)];
910 afs_int32 now = time(0);
911 char bob[KA_TIMESTR_LEN30];
912
913 /* get the ticket info itself */
914 code = ktc_GetToken(server, &token, sizeof(token), &client);
915 if (code) {
916 afs_com_err(whoami, code, "failed to get token info for server %s",
917 PrintedPrincipal(server)PrintedName ((server)->name, (server)->instance, (server
)->cell)
);
918 return code;
919 }
920 code = PrintPrincipal(&client, UserName, sizeof(UserName))PrintName((&client)->name, (&client)->instance,
(&client)->cell, sizeof(UserName), UserName)
;
921 if (code)
922 return code;
923 /* spaces are printed as "\040" */
924 if (UserName[0] == 0)
925 printf("Tokens");
926 else if (strncmp(UserName, "AFS\\040ID\\040", 13) == 0) {
927 printf("User's (AFS ID %s) tokens", UserName + 13);
928 } else if (strncmp(UserName, "Unix\\040UID\\040", 15) == 0) {
929 printf("Tokens");
930 } else
931 printf("User %s's tokens", UserName);
932
933 code = PrintPrincipal(server, ServerName, sizeof(ServerName))PrintName((server)->name, (server)->instance, (server)->
cell, sizeof(ServerName), ServerName)
;
934 if (code)
935 return code;
936 printf(" for %s ", ServerName);
937
938 if (token.startTime > now) {
939 ka_timestr(token.startTime, bob, KA_TIMESTR_LEN30);
940 printf("[>> POSTDATED 'till %s <<]", bob);
941 }
942
943 if (token.endTime <= now)
944 printf("[>> Expired <<]\n");
945 else {
946 ka_timestr(token.endTime, bob, KA_TIMESTR_LEN30);
947 printf("[Expires %s]\n", bob);
948 }
949 if (verbose) {
950 printf("SessionKey: ");
951 ka_PrintBytes((char *)&token.sessionKey, sizeof(token.sessionKey));
952 printf("\nTicket (kvno = %d, len = %d): ", token.kvno,
953 token.ticketLen);
954 ka_PrintBytes((char *)token.ticket, token.ticketLen);
955 printf("\n");
956 }
957 return 0;
958}
959
960static int
961GetTicket(struct cmd_syndesc *as, void *arock)
962{
963 int code;
964 struct ktc_principal server;
965 struct ktc_token token;
966 afs_int32 life = KA_SIXHOURS(6*3600);
967
968 if (as->parms[1].items) {
969 code = read_time_interval(as->parms[1].items->data, &life);
970 if (code)
971 return KABADCMD(180493L);
972 }
973 code =
974 ka_ParseLoginName(as->parms[0].items->data, server.name,
975 server.instance, server.cell);
976 if (code) {
977 afs_com_err(whoami, code, "parsing user's name '%s'",
978 as->parms[0].items->data);
979 return KABADCMD(180493L);
980 }
981 if (server.cell[0] == 0) {
982 if ((code = DefaultCell()))
983 return code;
984 strcpy(server.cell, cell);
985 } else {
986 code = ka_ExpandCell(server.cell, server.cell, 0 /*local */ );
987 if (code) {
988 afs_com_err(whoami, code, "Can't expand cell name");
989 return code;
990 }
991 }
992
993 token.ticketLen = 0; /* in case there are no tokens */
994 code =
995 ka_GetServerToken(server.name, server.instance, server.cell, life,
996 &token, /*new */ 1, /*dosetpag */ 0);
997 if (code)
998 afs_com_err(whoami, code, "getting ticket for %s",
999 PrintedPrincipal(&server)PrintedName ((&server)->name, (&server)->instance
, (&server)->cell)
);
1000 else {
1001 code = ListTicket(&server, /*verbose */ 1);
1002 }
1003 return code;
1004}
1005
1006static int
1007GetPassword(struct cmd_syndesc *as, void *arock)
1008{
1009 int code;
1010 char name[MAXKTCNAMELEN64];
1011 struct ktc_encryptionKey key;
1012 static struct ubik_client *lpbkConn = 0;
1013
1014 /* no instance allowed */
1015 code = ka_ParseLoginName(as->parms[0].items->data, name, 0, 0);
1016 if (code) {
1017 abort:
1018 afs_com_err(whoami, code,
1019 "getting %s's password via loopback connection to GetPassword",
1020 name);
1021 /* if we got a timeout, print a clarification, too */
1022 if (code == -1) {
1023 fprintf(stderr__stderrp,
1024 "%s: please note that this command must be run locally on a database server machine.\n",
1025 whoami);
1026 }
1027 return code;
1028 }
1029 if (lpbkConn == 0) {
1030 struct rx_connection *conns[2];
1031 struct rx_securityClass *sc;
1032 int si; /* security class index */
1033
1034 code = rx_Init(0);
1035 if (code)
1036 goto abort;
1037 sc = rxnull_NewClientSecurityObject();
1038 si = RX_SCINDEX_NULL0;
1039 conns[0] =
1040 rx_NewConnection(htonl(INADDR_LOOPBACK)(__builtin_constant_p((u_int32_t)0x7f000001) ? ((((__uint32_t
)((u_int32_t)0x7f000001)) >> 24) | ((((__uint32_t)((u_int32_t
)0x7f000001)) & (0xff << 16)) >> 8) | ((((__uint32_t
)((u_int32_t)0x7f000001)) & (0xff << 8)) << 8
) | (((__uint32_t)((u_int32_t)0x7f000001)) << 24)) : __bswap32_var
((u_int32_t)0x7f000001))
, htons(AFSCONF_KAUTHPORT)(__builtin_constant_p(7004) ? (__uint16_t)(((__uint16_t)(7004
)) << 8 | ((__uint16_t)(7004)) >> 8) : __bswap16_var
(7004))
,
1041 KA_MAINTENANCE_SERVICE733, sc, si);
1042 conns[1] = 0;
1043 code = ubik_ClientInit(conns, &lpbkConn);
1044 if (code)
1045 goto abort;
1046 }
1047 code = ubik_KAM_GetPassword(lpbkConn, 0, name,
1048 ktc_to_EncryptionKey(&key));
1049 /* Lets close down the ubik_Client connection now */
1050 ubik_ClientDestroy(lpbkConn);
1051 if (code)
1052 goto abort;
1053 printf("Key: ");
1054 ka_PrintBytes((char *)&key, sizeof(key));
1055 printf("\n");
1056 return code;
1057}
1058
1059int
1060GetRandomKey(struct cmd_syndesc *as, void *arock)
1061{
1062 int code;
1063 struct ktc_encryptionKey key;
1064
1065 code = ubik_KAM_GetRandomKey(conn, 0, ktc_to_EncryptionKey(&key));
1066 if (code)
1067 afs_com_err(whoami, code, "so can't get random key");
1068 else {
1069 int i;
1070 printf("Key: ");
1071 ka_PrintBytes((char *)&key, sizeof(key));
1072 printf(" (");
1073 for (i = 0; i < sizeof(key); i++) {
1074 printf("%.2x", ((char *)&key)[i] & 0xff);
1075 if (i == 3)
1076 printf(" ");
1077 else if (i != 7)
1078 printf(".");
1079 }
1080 printf(")\n");
1081 }
1082 return code;
1083}
1084
1085int
1086Statistics(struct cmd_syndesc *as, void *arock)
1087{
1088 int code;
1089 kasstats statics;
1090 kadstats dynamics;
1091 afs_int32 admins;
1092 char bob[KA_TIMESTR_LEN30];
1093
1094 code =
1095 ubik_KAM_GetStats(conn, 0, KAMAJORVERSION5, &admins, &statics,
1096 &dynamics);
1097 if (code) {
1098 printf("call to GetStats failed: %s\n", ka_ErrorStringafs_error_message(code));
1099 return code;
1100 }
1101 if (statics.minor_version != KAMINORVERSION2)
1102 printf("Minor version number mismatch: got %d, expected %d\n",
1103 statics.minor_version, KAMINORVERSION2);
1104 printf("%d allocs, %d frees, %d password changes\n", statics.allocs,
1105 statics.frees, statics.cpws);
1106 printf("Hash table utilization = %f%%\n",
1107 (double)dynamics.hashTableUtilization / 100.0);
1108 ka_timestr(dynamics.start_time, bob, KA_TIMESTR_LEN30);
1109 printf("From host %lx started at %s:\n",
1110 afs_printable_uint32_lu(dynamics.host), bob);
1111
1112#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)
if (dynamics.name.requests) printf (" of %d requests for %s, %d were aborted.\n", dynamics.name.requests, # name, dynamics.name.aborts)
1113 print_stat(Authenticate)if (dynamics.Authenticate.requests) printf (" of %d requests for %s, %d were aborted.\n"
, dynamics.Authenticate.requests, "Authenticate", dynamics.Authenticate
.aborts)
;
1114 print_stat(ChangePassword)if (dynamics.ChangePassword.requests) printf (" of %d requests for %s, %d were aborted.\n"
, dynamics.ChangePassword.requests, "ChangePassword", dynamics
.ChangePassword.aborts)
;
1115 print_stat(GetTicket)if (dynamics.GetTicket.requests) printf (" of %d requests for %s, %d were aborted.\n"
, dynamics.GetTicket.requests, "GetTicket", dynamics.GetTicket
.aborts)
;
1116 print_stat(CreateUser)if (dynamics.CreateUser.requests) printf (" of %d requests for %s, %d were aborted.\n"
, dynamics.CreateUser.requests, "CreateUser", dynamics.CreateUser
.aborts)
;
1117 print_stat(SetPassword)if (dynamics.SetPassword.requests) printf (" of %d requests for %s, %d were aborted.\n"
, dynamics.SetPassword.requests, "SetPassword", dynamics.SetPassword
.aborts)
;
1118 print_stat(SetFields)if (dynamics.SetFields.requests) printf (" of %d requests for %s, %d were aborted.\n"
, dynamics.SetFields.requests, "SetFields", dynamics.SetFields
.aborts)
;
1119 print_stat(DeleteUser)if (dynamics.DeleteUser.requests) printf (" of %d requests for %s, %d were aborted.\n"
, dynamics.DeleteUser.requests, "DeleteUser", dynamics.DeleteUser
.aborts)
;
1120 print_stat(GetEntry)if (dynamics.GetEntry.requests) printf (" of %d requests for %s, %d were aborted.\n"
, dynamics.GetEntry.requests, "GetEntry", dynamics.GetEntry.aborts
)
;
1121 print_stat(ListEntry)if (dynamics.ListEntry.requests) printf (" of %d requests for %s, %d were aborted.\n"
, dynamics.ListEntry.requests, "ListEntry", dynamics.ListEntry
.aborts)
;
1122 print_stat(GetStats)if (dynamics.GetStats.requests) printf (" of %d requests for %s, %d were aborted.\n"
, dynamics.GetStats.requests, "GetStats", dynamics.GetStats.aborts
)
;
1123 print_stat(GetPassword)if (dynamics.GetPassword.requests) printf (" of %d requests for %s, %d were aborted.\n"
, dynamics.GetPassword.requests, "GetPassword", dynamics.GetPassword
.aborts)
;
1124 print_stat(GetRandomKey)if (dynamics.GetRandomKey.requests) printf (" of %d requests for %s, %d were aborted.\n"
, dynamics.GetRandomKey.requests, "GetRandomKey", dynamics.GetRandomKey
.aborts)
;
1125 print_stat(Debug)if (dynamics.Debug.requests) printf (" of %d requests for %s, %d were aborted.\n"
, dynamics.Debug.requests, "Debug", dynamics.Debug.aborts)
;
1126 print_stat(UAuthenticate)if (dynamics.UAuthenticate.requests) printf (" of %d requests for %s, %d were aborted.\n"
, dynamics.UAuthenticate.requests, "UAuthenticate", dynamics.
UAuthenticate.aborts)
;
1127 print_stat(UGetTicket)if (dynamics.UGetTicket.requests) printf (" of %d requests for %s, %d were aborted.\n"
, dynamics.UGetTicket.requests, "UGetTicket", dynamics.UGetTicket
.aborts)
;
1128
1129#if (KAMAJORVERSION5>5)
1130 print cpu stats printf("%d string checks\n", dynamics.string_checks);
1131#else
1132 printf("Used %.3f seconds of CPU time.\n",
1133 dynamics.string_checks / 1000.0);
1134#endif
1135 printf("%d admin accounts\n", admins);
1136 return 0;
1137}
1138
1139int
1140DebugInfo(struct cmd_syndesc *as, void *arock)
1141{
1142 int code;
1143 struct ka_debugInfo info;
1144 int i;
1145 Dateafs_uint32 start, now;
1146 int timeOffset;
1147 char bob[KA_TIMESTR_LEN30];
1148
1149 start = time(0);
1150 if (as->parms[0].items) {
1151 struct ubik_client *iConn;
1152 code =
1153 ka_SingleServerConn(cell, as->parms[0].items->data,
1154 KA_MAINTENANCE_SERVICE733, 0, &iConn);
1155 if (code) {
1156 struct afsconf_cell cellinfo;
1157
1158 afs_com_err(whoami, code, "couldn't find host %s in cell %s",
1159 as->parms[0].items->data, cell);
1160 code = ka_GetServers(cell, &cellinfo);
1161 if (code)
1162 afs_com_err(whoami, code, "getting servers in cell %s", cell);
1163 else {
1164 printf("Servers in cell %s, are:\n", cell);
1165 for (i = 0; i < cellinfo.numServers; i++)
1166 printf(" %s\n", cellinfo.hostName[i]);
1167 }
1168 return code;
1169 }
1170 code = ubik_KAM_Debug(iConn, 0, KAMAJORVERSION5, 0, &info);
1171 ubik_ClientDestroy(iConn);
1172 } else
1173 code = ubik_KAM_Debug(conn, 0, KAMAJORVERSION5, 0, &info);
1174
1175 if (code) {
1176 afs_com_err(whoami, code, "call to Debug failed");
1177 return code;
1178 }
1179 now = time(0);
1180
1181 if (info.minorVersion != KAMINORVERSION2)
1182 printf("Minor version number mismatch: got %d, expected %d\n",
1183 info.minorVersion, KAMINORVERSION2);
1184
1185 timeOffset = info.
1186#if (KAMAJORVERSION5>5)
1187 now
1188#else
1189 reserved1
1190#endif
1191 - now;
1192 if (timeOffset < 0)
1193 timeOffset = -timeOffset;
1194 if (timeOffset > 60) {
1195 printf
1196 ("WARNING: Large server client clock skew: %d seconds. Call itself took %d seconds.\n",
1197 timeOffset, now - start);
1198 }
1199 ka_timestr(info.startTime, bob, KA_TIMESTR_LEN30);
1200 printf("From host %lx started %sat %s:\n",
1201 afs_printable_uint32_lu(info.host),
1202 (info.noAuth ? "w/o authorization " : ""), bob);
1203 ka_timestr(info.lastTrans, bob, KA_TIMESTR_LEN30);
1204 printf("Last trans was %s at %s\n", info.lastOperation, bob);
1205 ka_timestr(info.dbHeaderRead, bob, KA_TIMESTR_LEN30);
1206 printf("Header last read %s.\n", bob);
1207 printf("db version=%d, keyVersion=%d, key cache version=%d\n",
1208 info.dbVersion, info.dbSpecialKeysVersion, info.kcVersion);
1209 printf("db ptrs: free %d, eof %d, kvno %d.\n", info.dbFreePtr,
1210 info.dbEofPtr, info.dbKvnoPtr);
1211 ka_timestr(info.nextAutoCPW, bob, KA_TIMESTR_LEN30);
1212 printf("Next autoCPW at %s or in %d updates.\n", bob,
1213 info.updatesRemaining);
1214 if (info.cheader_lock || info.keycache_lock)
1215 printf("locks: cheader %08lx, keycache %08lx\n",
1216 afs_printable_uint32_lu(info.cheader_lock),
1217 afs_printable_uint32_lu(info.keycache_lock));
1218 printf("Last authentication for %s, last admin user was %s\n",
1219 info.lastAuth, info.lastAdmin);
1220 printf("Last TGS op was a %s ticket was for %s\n", info.lastTGSServer,
1221 info.lastTGS);
1222 printf("Last UDP TGS was a %s ticket for %s. UDP Authenticate for %s\n",
1223 info.lastUTGSServer, info.lastUTGS, info.lastUAuth);
1224 printf("key cache size %d, used %d.\n", info.kcSize, info.kcUsed);
1225 if (info.kcUsed > KADEBUGKCINFOSIZE25) {
1226 printf("insufficient room to return all key cache entries!\n");
1227 info.kcUsed = KADEBUGKCINFOSIZE25;
1228 }
1229 for (i = 0; i < info.kcUsed; i++)
1230 ka_timestr(info.kcInfo[i].used, bob, KA_TIMESTR_LEN30);
1231 printf("%32s %c %2x(%2x) used %s\n", info.kcInfo[i].principal,
1232 (info.kcInfo[i].primary ? '*' : ' '), info.kcInfo[i].kvno,
1233 info.kcInfo[i].keycksum, bob);
1234 return 0;
1235}
1236
1237int
1238Interactive(struct cmd_syndesc *as, void *arock)
1239{
1240 finished = 0;
1241 return 0;
1242}
1243
1244int
1245Quit(struct cmd_syndesc *as, void *arock)
1246{
1247 finished = 1;
1248 return 0;
1249}
1250
1251int
1252MyAfterProc(struct cmd_syndesc *as, void *arock)
1253{
1254 if (!strcmp(as->name, "help"))
1255 return 0;
1256
1257 /* Determine if we need to destory the ubik connection.
1258 * Closing it avoids resends of packets.
1259 */
1260 if (conn) {
1261 ubik_ClientDestroy(conn);
1262 conn = 0;
1263 }
1264
1265 return 0;
1266}
1267
1268int init = 0, noauth;
1269char name[MAXKTCNAMELEN64];
1270char instance[MAXKTCNAMELEN64];
1271char newCell[MAXKTCREALMLEN64];
1272afs_uint32 serverList[MAXSERVERS20];
1273
1274int
1275NoAuth(struct cmd_syndesc *as, void *arock)
1276{
1277 noauth = 1;
1278 return 0;
1279}
1280
1281static int
1282MyBeforeProc(struct cmd_syndesc *as, void *arock)
1283{
1284 struct ktc_encryptionKey key;
1285 struct ktc_principal auth_server, client;
1286 struct ktc_token auth_token;
1287 char realm[MAXKTCREALMLEN64];
1288
1289 struct ktc_token token, *pToken;
1290 int i, acode, code = 0;
1291
1292 {
1293 char *ws = strrchr(as->a0name, '/');
1294 if (ws)
1295 ws++; /* skip everything before the "/" */
1296 else
1297 ws = as->a0name;
1298 if (strlen(ws) > 0) {
1299 strncpy(whoami, ws, sizeof(whoami));
1300 if (strlen(whoami) + 1 >= sizeof(whoami))
1301 strcpy(whoami, "kas:");
1302 else
1303 strcat(whoami, ":");
1304 } else
1305 whoami[0] = 0;
1306 /* append sub-command name */
1307 strncat(whoami, as->name, sizeof(whoami) - strlen(whoami) - 1);
1308 }
1309
1310 if (as->parms[12].name == 0)
1311 return 0;
1312
1313 assert(as->parms[13].name && as->parms[14].name && as->parms[15].namedo{if (!(as->parms[13].name && as->parms[14].name
&& as->parms[15].name && as->parms[16]
.name)) AssertionFailed("admin_tools.c", 1314);}while(0)
1314 && as->parms[16].name)do{if (!(as->parms[13].name && as->parms[14].name
&& as->parms[15].name && as->parms[16]
.name)) AssertionFailed("admin_tools.c", 1314);}while(0)
;
1315
1316 /* MyAfterProc() destroys the conn, but just to be sure */
1317 if (conn) {
1318 code = ubik_ClientDestroy(conn);
1319 conn = 0;
1320 }
1321
1322 if (!init || as->parms[12].items || as->parms[13].items
1323 || as->parms[14].items || as->parms[15].items
1324 || as->parms[16].items) {
1325 strcpy(instance, "");
1326 strcpy(newCell, "");
1327
1328 if (as->parms[12].items) { /* -admin_username */
1329 code =
1330 ka_ParseLoginName(as->parms[12].items->data, name, instance,
1331 newCell);
1332 if (code) {
1333 afs_com_err(whoami, code, "parsing user's name '%s'",
1334 as->parms[12].items->data);
1335 return code;
1336 }
1337 } else {
1338#ifdef AFS_NT40_ENV
1339 DWORD len = MAXKTCNAMELEN64;
1340 if (!GetUserName((LPTSTR) name, &len)) {
1341 printf("Can't get user name \n");
1342 return KABADCMD(180493L);
1343 }
1344#else
1345 /* No explicit name provided: use Unix uid. */
1346 struct passwd *pw = getpwuid(getuid());
1347 if (pw == NULL((void *)0)) {
1348 printf("Can't figure out your name from your user id.\n");
1349 return KABADCMD(180493L);
1350 }
1351 strncpy(name, pw->pw_name, sizeof(name));
1352#endif
1353 }
1354
1355 if (as->parms[14].items) { /* -cell */
1356 if (strlen(newCell) > 0) {
1357 printf("Duplicate cell specification not allowed\n");
1358 } else {
1359 strncpy(newCell, as->parms[14].items->data, sizeof(newCell));
1360 }
1361 }
1362 code = ka_ExpandCell(newCell, newCell, 0 /*local */ );
1363 if (code) {
1364 afs_com_err(whoami, code, "Can't expand cell name");
1365 return code;
1366 }
1367 strcpy(cell, newCell);
1368
1369 if (as->parms[15].items) { /* -servers */
1370 struct cmd_item *ip;
1371 char *ap[MAXSERVERS20 + 2];
1372
1373 ap[0] = "";
1374 ap[1] = "-servers";
1375 for (ip = as->parms[15].items, i = 2; ip; ip = ip->next, i++)
1376 ap[i] = ip->data;
1377 code = ubik_ParseClientList(i, ap, serverList);
1378 if (code) {
1379 afs_com_err(whoami, code, "could not parse server list");
1380 return code;
1381 }
1382 ka_ExplicitCell(cell, serverList);
1383 }
1384
1385 noauth = (as->parms[16].items ? 1 : 0); /* -noauth */
1386
1387 init = 1;
1388 }
1389
1390 token.ticketLen = 0; /* in case there are no tokens */
1391 if (!noauth) { /* Will prompt for a password */
1392 /* first see if there's already an admin ticket */
1393 code =
1394 ka_GetAdminToken(0, 0, cell, 0, KA_SIXHOURS(6*3600), &token,
1395 0 /* !new */ );
1396 if (code) { /* if not then get key and try again */
1397 if (as->parms[13].items) { /* if password specified */
1398 strncpy(passwd, as->parms[13].items->data, sizeof(passwd));
1399 memset(as->parms[13].items->data, 0,
1400 strlen(as->parms[13].items->data));
1401 } else {
1402 char msg[MAXKTCNAMELEN64 + 50];
1403 if (as->parms[12].items)
1404 sprintf(msg, "Administrator's (%s) Password: ", name);
1405 else
1406 sprintf(msg, "Password for %s: ", name);
1407 code = UI_UTIL_read_pw_stringhc_UI_UTIL_read_pw_string(passwd, sizeof(passwd), msg, 0);
1408 if (code)
1409 code = KAREADPW(180495L);
1410 else if (strlen(passwd) == 0)
1411 code = KANULLPASSWORD(180517L);
1412 if (code) {
1413 afs_com_err(whoami, code, "reading password");
1414 return code;
1415 }
1416 }
1417 ka_StringToKey(passwd, cell, &key);
1418 code =
1419 ka_GetAdminToken(name, instance, cell, &key, KA_SIXHOURS(6*3600),
1420 &token, 0 /* !new */ );
1421 if (code == KABADREQUEST(180490L)) {
1422 DES_string_to_keyhc_DES_string_to_key(passwd, ktc_to_cblockptr(&key));
1423 code =
1424 ka_GetAdminToken(name, instance, cell, &key, KA_SIXHOURS(6*3600),
1425 &token, 0 /* !new */ );
1426 }
1427 if ((code == KABADREQUEST(180490L)) && (strlen(passwd) > 8)) {
1428 /* try with only the first 8 characters incase they set
1429 * their password with an old style passwd program. */
1430 passwd[8] = 0;
1431 ka_StringToKey(passwd, cell, &key);
1432 code =
1433 ka_GetAdminToken(name, instance, cell, &key, KA_SIXHOURS(6*3600),
1434 &token, 0 /* !new */ );
1435 if (code == 0) {
1436 fprintf(stderr__stderrp,
1437 "Warning: you have typed a password longer than 8 characters, but only the\n");
1438 fprintf(stderr__stderrp,
1439 "first 8 characters were actually significant. If you change your password\n");
1440 fprintf(stderr__stderrp,
1441 "again this warning message will go away.\n");
1442 }
1443 }
1444 if (code) {
1445 char *reason;
1446 switch (code) {
1447 case KABADREQUEST(180490L):
1448 reason = "password was incorrect";
1449 break;
1450 case KAUBIKCALL(180498L):
1451 reason = "Authentication Server was unavailable";
1452 break;
1453 default:
1454 reason = (char *)afs_error_message(code);
1455 }
1456 fprintf(stderr__stderrp,
1457 "%s: Auth. as %s to AuthServer failed: %s\nProceeding w/o authentication\n",
1458 whoami, PrintedName(name, instance, cell), reason);
1459 }
1460 /* get an Authentication token while were at it. */
1461 if (ka_CellToRealm(cell, realm, 0) != 0)
1462 realm[0] = '\0';
1463 strcpy(auth_server.name, KA_TGS_NAME"krbtgt");
1464 strcpy(auth_server.instance, realm);
1465 strcpy(auth_server.cell, cell);
1466 if (ktc_GetToken
1467 (&auth_server, &auth_token, sizeof(struct ktc_token),
1468 &client) != 0) {
1469 acode =
1470 ka_GetAuthToken(name, instance, cell, &key,
1471 MAXKTCTICKETLIFETIME(30*24*3600), (afs_int32 *) 0
1472 /*Don't need pwd expiration info here */
1473 );
1474 if (acode && (acode != code)) /* codes are usually the same */
1475 afs_com_err(whoami, code,
1476 "getting Authentication token for %s",
1477 PrintedName(name, instance, cell));
1478 }
1479 memset(&key, 0, sizeof(key));
1480 }
1481 }
1482
1483 pToken = ((token.ticketLen == 0) ? 0 : &token);
1484 code = ka_AuthServerConn(cell, KA_MAINTENANCE_SERVICE733, pToken, &conn);
1485 if (code && pToken) {
1486 afs_com_err(whoami, code,
1487 "connecting to AuthServer: now trying w/o authentication");
1488 code = ka_AuthServerConn(cell, KA_MAINTENANCE_SERVICE733, 0, &conn);
1489 if (code)
1490 afs_com_err(whoami, code,
1491 "making unauthenticated connection to AuthServer");
1492 }
1493 if (code) {
1494 afs_com_err(whoami, code,
1495 "Couldn't establish connection to Authentication Server");
1496 return code;
1497 }
1498
1499 /* now default unspecified password by prompting from terminal */
1500 if (as->nParms >= 12)
1501 for (i = 0; i < 12; i++)
1502 if (as->parms[i].name && (as->parms[i].items == 0)) {
1503 char *p = as->parms[i].name; /* parameter name */
1504 int l = strlen(p); /* length of name */
1505 /* does parameter end in "password" */
1506 if (strcmp(p + (l - 8), "password") == 0) {
1507 char msg[32];
1508 char password[BUFSIZ1024];
1509 struct cmd_item *ip;
1510
1511 strcpy(msg, p + 1);
1512 strcat(msg, ": ");
1513 code = UI_UTIL_read_pw_stringhc_UI_UTIL_read_pw_string(password, sizeof(password), msg, 1);
1514 if (code)
1515 code = KAREADPW(180495L);
1516 else if (strlen(password) == 0)
1517 code = KANULLPASSWORD(180517L);
1518 if (code) {
1519 afs_com_err(whoami, code, "prompting for %s", p + 1);
1520 return code;
1521 }
1522 ip = (struct cmd_item *)malloc(sizeof(struct cmd_item));
1523 ip->data = (char *)malloc(strlen(password) + 1);
1524 ip->next = 0;
1525 strcpy(ip->data, password);
1526 as->parms[i].items = ip;
1527 }
1528 }
1529 if (!conn) { /* if all else fails... */
1530 code = NoAuth(0, 0); /* get unauthenticated conn */
1531 if (code)
1532 return code;
1533 }
1534 return 0;
1535}
1536
1537/* These are some helpful command that deal with the cache managers tokens. */
1538
1539static int
1540ForgetTicket(struct cmd_syndesc *as, void *arock)
1541{
1542 afs_int32 code;
1543
1544#ifdef notdef
1545 struct ktc_principal server;
1546
1547 if (as->parms[0].items) {
1548 char *name = as->parms[0].items->data;
1549 code =
1550 ka_ParseLoginName(name, server.name, server.instance,
1551 server.cell);
1552 if (code) {
1553 afs_com_err(whoami, code, "couldn't interpret name '%s'", name);
1554 return code;
1555 }
1556 if (server.cell[0] == 0) {
1557 if (code = DefaultCell())
1558 return code;
1559 strcpy(server.cell, cell);
1560 } else {
1561 code = ka_ExpandCell(server.cell, server.cell, 0 /*local */ );
1562 if (code) {
1563 afs_com_err(whoami, code, "Can't expand cell name");
1564 return code;
1565 }
1566 }
1567 code = ktc_ForgetToken(&server);
1568 if (code) {
1569 afs_com_err(whoami, code, "couldn't remove tokens for %s",
1570 PrintedPrincipal(&server)PrintedName ((&server)->name, (&server)->instance
, (&server)->cell)
);
1571 return code;
1572 }
1573 } else {
1574 if (!as->parms[1].items) {
1575 fprintf(stderr__stderrp, "Must specify server name or -all\n");
1576 return KABADCMD(180493L);
1577 }
1578 code = ktc_ForgetAllTokens();
1579 if (code) {
1580 afs_com_err(whoami, code, "couldn't delete all tokens");
1581 return code;
1582 }
1583 }
1584#endif
1585 code = ktc_ForgetAllTokens();
1586 if (code) {
1587 afs_com_err(whoami, code, "couldn't delete all tokens");
1588 return code;
1589 }
1590 return 0;
1591}
1592
1593static int
1594ListTickets(struct cmd_syndesc *as, void *arock)
1595{
1596 afs_int32 code = 0;
1597 int index, newIndex;
1598 struct ktc_principal server;
1599 int verbose = 0;
1600
1601 if (as->parms[1].items)
1602 verbose = 1;
1603 if (as->parms[0].items) {
1604 char *name = as->parms[0].items->data;
1605 code =
1606 ka_ParseLoginName(name, server.name, server.instance,
1607 server.cell);
1608 if (code) {
1609 afs_com_err(whoami, code, "couldn't interpret name '%s'", name);
1610 return code;
1611 }
1612 if (server.cell[0] == 0) {
1613 if ((code = DefaultCell()))
1614 return code;
1615 strcpy(server.cell, cell);
1616 } else {
1617 code = ka_ExpandCell(server.cell, server.cell, 0 /*local */ );
1618 if (code) {
1619 afs_com_err(whoami, code, "Can't expand cell name");
1620 return code;
1621 }
1622 }
1623 code = ListTicket(&server, verbose);
1624 } else
1625 for (index = 0;; index = newIndex) {
1626 code = ktc_ListTokens(index, &newIndex, &server);
1627 if (code) {
1628 if (code == KTC_NOENT(11862787L))
1629 code = 0; /* end of list */
1630 break;
1631 }
1632 code = ListTicket(&server, verbose);
1633 }
1634 return code;
1635}
1636
1637static void
1638add_std_args(struct cmd_syndesc *ts)
1639{
1640 cmd_Seek(ts, 12);
1641 /* 12 */ cmd_AddParm(ts, "-admin_username", CMD_SINGLE2, CMD_OPTIONAL1,
1642 "admin principal to use for authentication");
1643 /* 13 */ cmd_AddParm(ts, "-password_for_admin", CMD_SINGLE2, CMD_OPTIONAL1,
1644 "admin password");
1645 /* 14 */ cmd_AddParm(ts, "-cell", CMD_SINGLE2, CMD_OPTIONAL1, "cell name");
1646 /* 15 */ cmd_AddParm(ts, "-servers", CMD_LIST3, CMD_OPTIONAL1,
1647 "explicit list of authentication servers");
1648 /* 16 */ cmd_AddParm(ts, "-noauth", CMD_FLAG1, CMD_OPTIONAL1,
1649 "don't authenticate");
1650}
1651
1652afs_int32
1653ka_AdminInteractive(int cmd_argc, char *cmd_argv[])
1654{
1655 int code;
1656 struct cmd_syndesc *ts;
1657
1658 char line[BUFSIZ1024];
1659 afs_int32 argc;
1660 char *argv[32];
1661
1662 strncpy(myName, *cmd_argv, 509);
1663
1664 cmd_SetBeforeProc(MyBeforeProc, NULL((void *)0));
1665 cmd_SetAfterProc(MyAfterProc, NULL((void *)0));
1666
1667 ts = cmd_CreateSyntax("interactive", Interactive, NULL((void *)0),
1668 "enter interactive mode");
1669 add_std_args(ts);
1670
1671 ts = cmd_CreateSyntax("noauthentication", NoAuth, NULL((void *)0),
1672 "connect to AuthServer w/o using token");
1673
1674 ts = cmd_CreateSyntax("list", ListUsers, NULL((void *)0),
1675 "list all users in database");
1676 cmd_AddParm(ts, "-long", CMD_FLAG1, CMD_OPTIONAL1,
1677 "show detailed info about each user");
1678 cmd_AddParm(ts, "-showadmin", CMD_FLAG1, CMD_OPTIONAL1,
1679 "show all cell administrators");
1680 cmd_AddParm(ts, "-showkey", CMD_FLAG1, CMD_OPTIONAL1,
1681 "show the user's actual key rather than the checksum");
1682 add_std_args(ts);
1683 cmd_CreateAlias(ts, "ls");
1684
1685 ts = cmd_CreateSyntax("examine", ExamineUser, NULL((void *)0),
1686 "examine the entry for a user");
1687 cmd_AddParm(ts, "-name", CMD_SINGLE2, 0, "name of user");
1688 cmd_AddParm(ts, "-showkey", CMD_FLAG1, CMD_OPTIONAL1,
1689 "show the user's actual key rather than the checksum");
1690 add_std_args(ts);
1691
1692 ts = cmd_CreateSyntax("create", CreateUser, NULL((void *)0),
1693 "create an entry for a user");
1694 cmd_AddParm(ts, "-name", CMD_SINGLE2, 0, "name of user");
1695 cmd_AddParm(ts, "-initial_password", CMD_SINGLE2, CMD_OPTIONAL1,
1696 "initial password");
1697 add_std_args(ts);
1698
1699 ts = cmd_CreateSyntax("delete", DeleteUser, NULL((void *)0), "delete a user");
1700 cmd_AddParm(ts, "-name", CMD_SINGLE2, 0, "name of user");
1701 add_std_args(ts);
1702 cmd_CreateAlias(ts, "rm");
1703
1704 ts = cmd_CreateSyntax("setfields", SetFields, NULL((void *)0),
1705 "set various fields in a user's entry");
1706 cmd_AddParm(ts, "-name", CMD_SINGLE2, 0, "name of user");
1707 cmd_AddParm(ts, "-flags", CMD_SINGLE2, CMD_OPTIONAL1,
1708 "hex flag value or flag name expression");
1709 cmd_AddParm(ts, "-expiration", CMD_SINGLE2, CMD_OPTIONAL1,
1710 "date of account expiration");
1711 cmd_AddParm(ts, "-lifetime", CMD_SINGLE2, CMD_OPTIONAL1,
1712 "maximum ticket lifetime");
1713 cmd_AddParm(ts, "-pwexpires", CMD_SINGLE2, CMD_OPTIONAL1,
1714 "number days password is valid ([0..254])");
1715 cmd_AddParm(ts, "-reuse", CMD_SINGLE2, CMD_OPTIONAL1,
1716 "permit password reuse (yes/no)");
1717 cmd_AddParm(ts, "-attempts", CMD_SINGLE2, CMD_OPTIONAL1,
1718 "maximum successive failed login tries ([0..254])");
1719 cmd_AddParm(ts, "-locktime", CMD_SINGLE2, CMD_OPTIONAL1,
1720 "failure penalty [hh:mm or minutes]");
1721#if ASSOCIATES
1722 cmd_AddParm(ts, "-associates", CMD_SINGLE2, CMD_OPTIONAL1,
1723 "maximum associate instances");
1724#endif
1725 add_std_args(ts);
1726 cmd_CreateAlias(ts, "sf");
1727
1728
1729 ts = cmd_CreateSyntax("unlock", Unlock, NULL((void *)0),
1730 "Enable authentication ID after max failed attempts exceeded");
1731 cmd_AddParm(ts, "-name", CMD_SINGLE2, 0, "authentication ID");
1732 add_std_args(ts);
1733
1734
1735 ts = cmd_CreateSyntax("stringtokey", StringToKey, NULL((void *)0),
1736 "convert a string to a key");
1737 cmd_AddParm(ts, "-string", CMD_SINGLE2, 0, "password string");
1738 cmd_AddParm(ts, "-cell", CMD_SINGLE2, CMD_OPTIONAL1, "cell name");
1739
1740 ts = cmd_CreateSyntax("setpassword", SetPassword, NULL((void *)0),
1741 "set a user's password");
1742 cmd_AddParm(ts, "-name", CMD_SINGLE2, 0, "name of user");
1743 cmd_AddParm(ts, "-new_password", CMD_SINGLE2, CMD_OPTIONAL1,
1744 "new password");
1745 cmd_Seek(ts, 3);
1746 cmd_AddParm(ts, "-kvno", CMD_SINGLE2, CMD_OPTIONAL1, "key version number");
1747 add_std_args(ts);
1748 cmd_CreateAlias(ts, "sp");
1749#ifdef CMD_PARSER_AMBIG_FIX1
1750 cmd_CreateAlias(ts, "setpasswd");
1751#endif
1752
1753 /* set a user's key */
1754 ts = cmd_CreateSyntax("setkey", SetPassword, NULL((void *)0), (char *)CMD_HIDDEN4);
1755 cmd_AddParm(ts, "-name", CMD_SINGLE2, 0, "name of user");
1756 cmd_Seek(ts, 2);
1757 cmd_AddParm(ts, "-new_key", CMD_SINGLE2, 0, "eight byte new key");
1758 cmd_Seek(ts, 3);
1759 cmd_AddParm(ts, "-kvno", CMD_SINGLE2, CMD_OPTIONAL1, "key version number");
1760 add_std_args(ts);
1761
1762 /* get a user's password */
1763 ts = cmd_CreateSyntax("getpassword", GetPassword, NULL((void *)0), (char *)CMD_HIDDEN4);
1764 cmd_AddParm(ts, "-name", CMD_SINGLE2, 0, "name of user");
1765 /* don't take standard args */
1766 /* add_std_args (ts); */
1767#ifdef CMD_PARSER_AMBIG_FIX1
1768 cmd_CreateAlias(ts, "getpasswd");
1769#endif
1770
1771 /* get a random key */
1772 ts = cmd_CreateSyntax("getrandomkey", GetRandomKey, NULL((void *)0),
1773 (char *)CMD_HIDDEN4);
1774 add_std_args(ts);
1775
1776 /* get a ticket for a specific server */
1777 ts = cmd_CreateSyntax("getticket", GetTicket, NULL((void *)0), (char *)CMD_HIDDEN4);
1778 cmd_AddParm(ts, "-name", CMD_SINGLE2, 0, "name of server");
1779 cmd_AddParm(ts, "-lifetime", CMD_SINGLE2, CMD_OPTIONAL1, "ticket lifetime");
1780 add_std_args(ts);
1781
1782 ts = cmd_CreateSyntax("statistics", Statistics, NULL((void *)0),
1783 "show statistics for AuthServer");
1784 add_std_args(ts);
1785
1786 /* show debugging info from AuthServer */
1787 ts = cmd_CreateSyntax("debuginfo", DebugInfo, NULL((void *)0), (char *)CMD_HIDDEN4);
1788 cmd_AddParm(ts, "-hostname", CMD_SINGLE2, CMD_OPTIONAL1,
1789 "authentication server host name");
1790 add_std_args(ts);
1791
1792 ts = cmd_CreateSyntax("forgetticket", ForgetTicket, NULL((void *)0),
1793 "delete user's tickets");
1794#ifdef notdef
1795 cmd_AddParm(ts, "-name", CMD_SINGLE2, (CMD_OPTIONAL1 | CMD_HIDE4),
1796 "name of server");
1797#endif
1798 cmd_AddParm(ts, "-all", CMD_FLAG1, CMD_OPTIONAL1, "delete all tickets");
1799
1800 ts = cmd_CreateSyntax("listtickets", ListTickets, NULL((void *)0),
1801 "show all cache manager tickets");
1802 cmd_AddParm(ts, "-name", CMD_SINGLE2, CMD_OPTIONAL1, "name of server");
1803 cmd_AddParm(ts, "-long", CMD_FLAG1, CMD_OPTIONAL1,
1804 "show session key and ticket");
1805
1806 ts = cmd_CreateSyntax("quit", Quit, NULL((void *)0), "exit program");
Value stored to 'ts' is never read
1807
1808 finished = 1;
1809 conn = 0; /* no connection yet */
1810 zero_argc = cmd_argc;
1811 zero_argv = cmd_argv;
1812
1813 strcpy(whoami, "kas");
1814
1815 if ((code = cmd_Dispatch(cmd_argc, cmd_argv))) {
1816 return code;
1817 }
1818
1819 while (!finished) {
1820 char *s;
1821 int i;
1822
1823 printf("ka> ");
1824 s = fgets(line, sizeof(line), stdin__stdinp);
1825 if (s == NULL((void *)0))
1826 return 0; /* EOF on input */
1827 for (i = strlen(line) - 1; i >= 0 && isspace(line[i])__sbistype((line[i]), 0x00004000L); i--)
1828 line[i] = 0;
1829 if (i < 0)
1830 continue; /* blank line */
1831
1832 code =
1833 cmd_ParseLine(line, argv, &argc, sizeof(argv) / sizeof(argv[0]));
1834 if (code) {
1835 afs_com_err(whoami, code, "parsing line: '%s'", line);
1836 return code;
1837 }
1838 code = cmd_Dispatch(argc, argv);
1839 cmd_FreeArgv(argv);
1840 }
1841 return code;
1842}