Commit | Line | Data |
---|---|---|
805e021f CE |
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 | } |