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