]>
Commit | Line | Data |
---|---|---|
c441a31a | 1 | /* $Id$ |
6e6374cb | 2 | * |
7ac48069 | 3 | * Bare-bones Moira client |
6e6374cb | 4 | * |
7ac48069 | 5 | * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology |
6 | * For copying and distribution information, please see the file | |
7 | * <mit-copyright.h>. | |
6e6374cb | 8 | */ |
9 | ||
c801de4c | 10 | #include <mit-copyright.h> |
8defc06b | 11 | #include <moira.h> |
7ac48069 | 12 | |
13 | #include <errno.h> | |
14 | #include <fcntl.h> | |
f281aa29 | 15 | #include <setjmp.h> |
16 | #include <signal.h> | |
7ac48069 | 17 | #include <stdio.h> |
18 | #include <stdlib.h> | |
19 | #include <string.h> | |
533bacb3 | 20 | #ifdef HAVE_UNISTD_H |
7ac48069 | 21 | #include <unistd.h> |
533bacb3 | 22 | #endif |
23 | ||
24 | #ifdef HAVE_GETOPT_H | |
25 | #include <getopt.h> | |
26 | #endif | |
27 | ||
28 | #ifdef _WIN32 | |
29 | #include <windows.h> | |
30 | #include <io.h> | |
31 | #define dup _dup | |
32 | #define dup2 _dup2 | |
33 | #define isatty _isatty | |
34 | #define close _close | |
35 | #define open _open | |
36 | #define sigjmp_buf jmp_buf | |
37 | #define siglongjmp longjmp | |
38 | #define sigsetjmp(env, save) setjmp(env) | |
39 | #endif /* _WIN32 */ | |
f281aa29 | 40 | |
ea0caf4a | 41 | #ifdef HAVE_READLINE |
c5c5a18d | 42 | #include "readline/readline.h" |
43 | #include "readline/history.h" | |
f281aa29 | 44 | #endif |
6e6374cb | 45 | |
7ac48069 | 46 | RCSID("$Header$"); |
47 | ||
71da1922 | 48 | int recursion = 0, quote_output = 0, interactive; |
5eaef520 | 49 | int count, quit = 0, cancel = 0; |
1a5c774c | 50 | char *whoami; |
533bacb3 | 51 | |
74c84b52 | 52 | sigjmp_buf jb; |
1a5c774c | 53 | |
54 | #define MAXARGS 20 | |
6e6374cb | 55 | |
533bacb3 | 56 | void discard_input(int sig); |
7ac48069 | 57 | char *mr_gets(char *prompt, char *buf, size_t len); |
58 | void execute_line(char *cmdbuf); | |
59 | int parse(char *buf, char *argv[MAXARGS]); | |
8c9b31a9 | 60 | int print_reply(int argc, char **argv, void *help); |
7ac48069 | 61 | void test_noop(void); |
62 | void test_connect(int argc, char **argv); | |
63 | void test_disconnect(void); | |
64 | void test_host(void); | |
7ac48069 | 65 | void test_motd(void); |
66 | void test_query(int argc, char **argv); | |
67 | void test_auth(void); | |
e7138c1c | 68 | void test_proxy(int argc, char **argv); |
7ac48069 | 69 | void test_access(int argc, char **argv); |
70 | void test_dcm(void); | |
71 | void test_script(int argc, char **argv); | |
72 | void test_list_requests(void); | |
acde26f0 | 73 | void test_version(int argc, char **argv); |
991417e4 | 74 | void test_krb5_auth(void); |
533bacb3 | 75 | void set_signal_handler(int, void (*handler)(int)); |
76 | void set_signal_blocking(int, int); | |
f281aa29 | 77 | |
5eaef520 | 78 | int main(int argc, char **argv) |
79 | { | |
80 | char cmdbuf[BUFSIZ]; | |
71da1922 | 81 | int c; |
6e6374cb | 82 | |
5eaef520 | 83 | whoami = argv[0]; |
84 | interactive = (isatty(0) && isatty(1)); | |
3442308f | 85 | |
71da1922 | 86 | while ((c = getopt(argc, argv, "q")) != -1) |
87 | { | |
88 | switch (c) | |
89 | { | |
90 | case 'q': | |
91 | quote_output = 1; | |
92 | break; | |
93 | ||
94 | default: | |
95 | fprintf(stderr, "Usage: mrtest [-q]\n"); | |
96 | exit (1); | |
97 | } | |
98 | } | |
99 | ||
5eaef520 | 100 | initialize_sms_error_table(); |
101 | initialize_krb_error_table(); | |
102 | ||
ea0caf4a | 103 | #ifdef HAVE_READLINE |
5eaef520 | 104 | /* we don't want filename completion */ |
105 | rl_bind_key('\t', rl_insert); | |
74c84b52 | 106 | #endif |
f281aa29 | 107 | |
533bacb3 | 108 | set_signal_handler(SIGINT, discard_input); |
5eaef520 | 109 | sigsetjmp(jb, 1); |
110 | ||
111 | while (!quit) | |
112 | { | |
113 | if (!mr_gets("moira: ", cmdbuf, BUFSIZ)) | |
114 | break; | |
115 | execute_line(cmdbuf); | |
116 | } | |
117 | mr_disconnect(); | |
118 | exit(0); | |
1a5c774c | 119 | } |
120 | ||
533bacb3 | 121 | void discard_input(int sig) |
f281aa29 | 122 | { |
123 | putc('\n', stdout); | |
fcb0b7fa | 124 | |
125 | /* if we're inside a script, we have to clean up file descriptors, | |
126 | so don't jump out yet */ | |
5eaef520 | 127 | if (recursion) |
128 | cancel = 1; | |
129 | else | |
fcb0b7fa | 130 | siglongjmp(jb, 1); |
f281aa29 | 131 | } |
132 | ||
5eaef520 | 133 | char *mr_gets(char *prompt, char *buf, size_t len) |
f281aa29 | 134 | { |
135 | char *in; | |
ea0caf4a | 136 | #ifdef HAVE_READLINE |
5eaef520 | 137 | if (interactive) |
138 | { | |
139 | in = readline(prompt); | |
140 | ||
141 | if (!in) | |
142 | return NULL; | |
143 | if (*in) | |
144 | add_history(in); | |
145 | strncpy(buf, in, len - 1); | |
146 | buf[len] = 0; | |
147 | free(in); | |
148 | ||
149 | return buf; | |
f281aa29 | 150 | } |
f281aa29 | 151 | #endif |
152 | printf("%s", prompt); | |
153 | fflush(stdout); | |
5eaef520 | 154 | in = fgets(buf, len, stdin); |
155 | if (!in) | |
156 | return in; | |
157 | if (strchr(buf, '\n')) | |
158 | *(strchr(buf, '\n')) = '\0'; | |
f281aa29 | 159 | return buf; |
160 | } | |
161 | ||
7ac48069 | 162 | void execute_line(char *cmdbuf) |
1a5c774c | 163 | { |
164 | int argc; | |
165 | char *argv[MAXARGS]; | |
166 | ||
5eaef520 | 167 | argc = parse(cmdbuf, argv); |
168 | if (argc == 0) | |
169 | return; | |
170 | if (!strcmp(argv[0], "noop")) | |
1a5c774c | 171 | test_noop(); |
5eaef520 | 172 | else if (!strcmp(argv[0], "connect") || !strcmp(argv[0], "c")) |
1a5c774c | 173 | test_connect(argc, argv); |
5eaef520 | 174 | else if (!strcmp(argv[0], "disconnect") || !strcmp(argv[0], "d")) |
1a5c774c | 175 | test_disconnect(); |
5eaef520 | 176 | else if (!strcmp(argv[0], "host")) |
1a5c774c | 177 | test_host(); |
059d3dc2 | 178 | else if (!strcmp(argv[0], "motd") || !strcmp(argv[0], "m")) |
1a5c774c | 179 | test_motd(); |
5eaef520 | 180 | else if (!strcmp(argv[0], "query") || !strcmp(argv[0], "qy")) |
1a5c774c | 181 | test_query(argc, argv); |
5eaef520 | 182 | else if (!strcmp(argv[0], "auth") || !strcmp(argv[0], "a")) |
991417e4 | 183 | test_krb5_auth(); |
e7138c1c | 184 | else if (!strcmp(argv[0], "proxy") || !strcmp(argv[0], "p")) |
185 | test_proxy(argc, argv); | |
5eaef520 | 186 | else if (!strcmp(argv[0], "access")) |
1a5c774c | 187 | test_access(argc, argv); |
5eaef520 | 188 | else if (!strcmp(argv[0], "dcm")) |
1a5c774c | 189 | test_dcm(); |
5eaef520 | 190 | else if (!strcmp(argv[0], "script") || !strcmp(argv[0], "s")) |
1a5c774c | 191 | test_script(argc, argv); |
5eaef520 | 192 | else if (!strcmp(argv[0], "list_requests") || |
193 | !strcmp(argv[0], "lr") || !strcmp(argv[0], "?")) | |
1a5c774c | 194 | test_list_requests(); |
5eaef520 | 195 | else if (!strcmp(argv[0], "quit") || !strcmp(argv[0], "Q")) |
196 | quit = 1; | |
acde26f0 | 197 | else if (!strcmp(argv[0], "version") || !strcmp(argv[0], "v")) |
198 | test_version(argc, argv); | |
991417e4 | 199 | else if (!strcmp(argv[0], "krb4_auth") || !strcmp(argv[0], "4")) |
200 | test_auth(); | |
5eaef520 | 201 | else |
202 | { | |
203 | fprintf(stderr, "moira: Unknown request \"%s\". " | |
204 | "Type \"?\" for a request list.\n", argv[0]); | |
205 | } | |
1a5c774c | 206 | } |
207 | ||
5eaef520 | 208 | int parse(char *buf, char *argv[MAXARGS]) |
1a5c774c | 209 | { |
210 | char *p; | |
211 | int argc, num; | |
5eaef520 | 212 | |
213 | if (!*buf) | |
214 | return 0; | |
215 | ||
216 | for (p = buf, argc = 0, argv[0] = buf; *p && *p != '\n'; p++) | |
217 | { | |
218 | if (*p == '"') | |
219 | { | |
220 | char *d = p++; | |
221 | /* skip to close-quote, copying back over open-quote */ | |
222 | while (*p != '"') | |
223 | { | |
224 | if (!*p || *p == '\n') | |
225 | { | |
226 | fprintf(stderr, | |
227 | "moira: Unbalanced quotes in command line\n"); | |
228 | return 0; | |
229 | } | |
230 | /* deal with \### or \\ */ | |
231 | if (*p == '\\') | |
232 | { | |
233 | if (*++p != '"' && (*p < '0' || *p > '9') && (*p != '\\')) | |
234 | { | |
235 | fprintf(stderr, "moira: Bad use of \\\n"); | |
236 | return 0; | |
237 | } | |
238 | else if (*p >= '0' && *p <= '9') | |
239 | { | |
240 | num = (*p - '0') * 64 + (*++p - '0') * 8 + (*++p - '0'); | |
241 | *p = num; | |
242 | } | |
243 | } | |
244 | *d++ = *p++; | |
245 | } | |
246 | if (p == d + 1) | |
247 | { | |
248 | *d = '\0'; | |
249 | p++; | |
250 | } | |
251 | else | |
252 | { | |
253 | while (p >= d) | |
254 | *p-- = ' '; | |
255 | } | |
2c031a2a | 256 | } |
5eaef520 | 257 | if (*p == ' ' || *p == '\t') |
258 | { | |
259 | /* skip whitespace */ | |
260 | for (*p++ = '\0'; *p == ' ' || *p == '\t'; p++) | |
261 | ; | |
2d84b01c | 262 | if (*p && *p != '\n') { |
263 | if (++argc >= MAXARGS) { | |
264 | fprintf(stderr, | |
265 | "moira: Too many command line arguments\n"); | |
266 | return 0; | |
267 | } | |
268 | argv[argc] = p--; | |
269 | } | |
6e6374cb | 270 | } |
1a5c774c | 271 | } |
5eaef520 | 272 | if (*p == '\n') |
273 | *p = '\0'; | |
274 | return argc + 1; | |
6e6374cb | 275 | } |
276 | ||
7ac48069 | 277 | void test_noop(void) |
6e6374cb | 278 | { |
5eaef520 | 279 | int status = mr_noop(); |
280 | if (status) | |
281 | com_err("moira (noop)", status, ""); | |
6e6374cb | 282 | } |
283 | ||
7ac48069 | 284 | void test_connect(int argc, char *argv[]) |
6e6374cb | 285 | { |
5eaef520 | 286 | char *server = ""; |
287 | int status; | |
288 | ||
289 | if (argc > 1) | |
290 | server = argv[1]; | |
291 | status = mr_connect(server); | |
292 | if (status) | |
293 | com_err("moira (connect)", status, ""); | |
acde26f0 | 294 | mr_version(-1); |
6e6374cb | 295 | } |
296 | ||
7ac48069 | 297 | void test_disconnect(void) |
6e6374cb | 298 | { |
5eaef520 | 299 | int status = mr_disconnect(); |
300 | if (status) | |
301 | com_err("moira (disconnect)", status, ""); | |
6e6374cb | 302 | } |
303 | ||
7ac48069 | 304 | void test_host(void) |
66848930 | 305 | { |
5eaef520 | 306 | char host[BUFSIZ]; |
307 | int status; | |
66848930 | 308 | |
5eaef520 | 309 | memset(host, 0, sizeof(host)); |
66848930 | 310 | |
5eaef520 | 311 | if ((status = mr_host(host, sizeof(host) - 1))) |
312 | com_err("moira (host)", status, ""); | |
313 | else | |
314 | printf("You are connected to host %s\n", host); | |
66848930 | 315 | } |
316 | ||
7ac48069 | 317 | void test_auth(void) |
6e6374cb | 318 | { |
5eaef520 | 319 | int status; |
59af7b90 | 320 | |
5eaef520 | 321 | status = mr_auth("mrtest"); |
322 | if (status) | |
323 | com_err("moira (auth)", status, ""); | |
6e6374cb | 324 | } |
325 | ||
991417e4 | 326 | void test_krb5_auth(void) |
327 | { | |
328 | int status; | |
329 | ||
330 | status = mr_krb5_auth("mrtest"); | |
331 | if (status) | |
332 | com_err("moira (krb5_auth)", status, ""); | |
333 | } | |
334 | ||
e7138c1c | 335 | void test_proxy(int argc, char *argv[]) |
336 | { | |
337 | int status; | |
338 | ||
339 | if (argc != 3) | |
340 | { | |
341 | com_err("moira (proxy)", 0, "Usage: proxy principal authtype"); | |
342 | return; | |
343 | } | |
344 | status = mr_proxy(argv[1], argv[2]); | |
345 | if (status) | |
346 | com_err("moira (proxy)", status, ""); | |
347 | } | |
348 | ||
7ac48069 | 349 | void test_script(int argc, char *argv[]) |
58b825a4 | 350 | { |
5eaef520 | 351 | FILE *inp; |
352 | char input[BUFSIZ], *cp; | |
353 | int status, oldstdout, oldstderr; | |
354 | ||
355 | if (recursion > 8) | |
356 | { | |
357 | com_err("moira (script)", 0, "too many levels deep in script files\n"); | |
358 | return; | |
58b825a4 | 359 | } |
360 | ||
5eaef520 | 361 | if (argc < 2) |
362 | { | |
363 | com_err("moira (script)", 0, "Usage: script input_file [ output_file ]"); | |
364 | return; | |
58b825a4 | 365 | } |
366 | ||
5eaef520 | 367 | inp = fopen(argv[1], "r"); |
368 | if (!inp) | |
369 | { | |
370 | sprintf(input, "Cannot open input file %s", argv[1]); | |
371 | com_err("moira (script)", 0, input); | |
372 | return; | |
58b825a4 | 373 | } |
374 | ||
5eaef520 | 375 | if (argc == 3) |
376 | { | |
377 | printf("Redirecting output to %s\n", argv[2]); | |
378 | fflush(stdout); | |
379 | oldstdout = dup(1); | |
380 | close(1); | |
381 | status = open(argv[2], O_CREAT|O_WRONLY|O_APPEND, 0664); | |
382 | if (status != 1) | |
383 | { | |
384 | close(status); | |
385 | dup2(oldstdout, 1); | |
386 | argc = 2; | |
387 | sprintf(input, "Unable to redirect output to %s\n", argv[2]); | |
388 | com_err("moira (script)", errno, input); | |
389 | } | |
390 | else | |
391 | { | |
392 | fflush(stderr); | |
393 | oldstderr = dup(2); | |
394 | close(2); | |
395 | dup2(1, 2); | |
58b825a4 | 396 | } |
397 | } | |
398 | ||
5eaef520 | 399 | recursion++; |
400 | ||
401 | while (!cancel) | |
402 | { | |
403 | if (!fgets(input, BUFSIZ, inp)) | |
404 | break; | |
405 | if ((cp = strchr(input, '\n'))) | |
406 | *cp = '\0'; | |
407 | if (input[0] == 0) | |
408 | { | |
409 | printf("\n"); | |
410 | continue; | |
6a592314 | 411 | } |
5eaef520 | 412 | if (input[0] == '%') |
413 | { | |
414 | for (cp = &input[1]; *cp && isspace(*cp); cp++) | |
415 | ; | |
416 | printf("Comment: %s\n", cp); | |
417 | continue; | |
58b825a4 | 418 | } |
5eaef520 | 419 | printf("Executing: %s\n", input); |
420 | execute_line(input); | |
58b825a4 | 421 | } |
422 | ||
5eaef520 | 423 | recursion--; |
424 | if (!recursion) | |
425 | cancel = 0; | |
426 | ||
427 | fclose(inp); | |
428 | if (argc == 3) | |
429 | { | |
430 | fflush(stdout); | |
431 | close(1); | |
432 | dup2(oldstdout, 1); | |
433 | close(oldstdout); | |
434 | fflush(stderr); | |
435 | close(2); | |
436 | dup2(oldstderr, 2); | |
437 | close(oldstderr); | |
58b825a4 | 438 | } |
439 | } | |
440 | ||
8c9b31a9 | 441 | int print_reply(int argc, char **argv, void *help) |
6e6374cb | 442 | { |
5eaef520 | 443 | int i; |
444 | for (i = 0; i < argc; i++) | |
445 | { | |
446 | if (i != 0) | |
447 | printf(", "); | |
8c9b31a9 | 448 | if (quote_output && !*(int *)help) |
71da1922 | 449 | { |
450 | unsigned char *p; | |
451 | ||
452 | for (p = (unsigned char *)argv[i]; *p; p++) | |
453 | { | |
454 | if (isprint(*p) && *p != '\\' && *p != ',') | |
455 | putc(*p, stdout); | |
456 | else | |
457 | printf("\\%03o", *p); | |
458 | } | |
459 | } | |
460 | else | |
461 | printf("%s", argv[i]); | |
5eaef520 | 462 | } |
463 | printf("\n"); | |
464 | count++; | |
465 | return MR_CONT; | |
6e6374cb | 466 | } |
467 | ||
7ac48069 | 468 | void test_query(int argc, char **argv) |
6e6374cb | 469 | { |
6fedb0a4 | 470 | int status, help; |
fcb0b7fa | 471 | |
5eaef520 | 472 | if (argc < 2) |
473 | { | |
474 | com_err("moira (query)", 0, "Usage: query handle [ args ... ]"); | |
475 | return; | |
476 | } | |
6fedb0a4 | 477 | help = !strcmp(argv[1], "_help"); |
59af7b90 | 478 | |
5eaef520 | 479 | count = 0; |
480 | /* Don't allow ^C during the query: it will confuse libmoira's | |
481 | internal state. (Yay static variables) */ | |
533bacb3 | 482 | set_signal_blocking(SIGINT, 1); |
8c9b31a9 | 483 | status = mr_query(argv[1], argc - 2, argv + 2, print_reply, &help); |
533bacb3 | 484 | set_signal_blocking(SIGINT, 0); |
5eaef520 | 485 | printf("%d tuple%s\n", count, ((count == 1) ? "" : "s")); |
486 | if (status) | |
487 | com_err("moira (query)", status, ""); | |
6e6374cb | 488 | } |
489 | ||
7ac48069 | 490 | void test_access(int argc, char **argv) |
6e6374cb | 491 | { |
5eaef520 | 492 | int status; |
493 | if (argc < 2) | |
494 | { | |
495 | com_err("moira (access)", 0, "Usage: access handle [ args ... ]"); | |
496 | return; | |
497 | } | |
498 | status = mr_access(argv[1], argc - 2, argv + 2); | |
499 | if (status) | |
500 | com_err("moira (access)", status, ""); | |
6e6374cb | 501 | } |
fc3ac28e | 502 | |
7ac48069 | 503 | void test_dcm() |
fc3ac28e | 504 | { |
5eaef520 | 505 | int status; |
fc3ac28e | 506 | |
5eaef520 | 507 | if ((status = mr_do_update())) |
508 | com_err("moira (dcm)", status, " while triggering dcm"); | |
fc3ac28e | 509 | } |
093b57b1 | 510 | |
7ac48069 | 511 | void test_motd() |
093b57b1 | 512 | { |
5eaef520 | 513 | int status; |
514 | char *motd; | |
515 | ||
516 | if ((status = mr_motd(&motd))) | |
517 | com_err("moira (motd)", status, " while getting motd"); | |
518 | if (motd) | |
519 | printf("%s\n", motd); | |
520 | else | |
521 | printf("No message of the day.\n"); | |
093b57b1 | 522 | } |
1a5c774c | 523 | |
7ac48069 | 524 | void test_list_requests(void) |
1a5c774c | 525 | { |
5eaef520 | 526 | printf("Available moira requests:\n"); |
527 | printf("\n"); | |
528 | printf("noop\t\t\tAsk Moira to do nothing\n"); | |
529 | printf("connect, c\t\tConnect to Moira server\n"); | |
530 | printf("disconnect, d\t\tDisconnect from server\n"); | |
531 | printf("host\t\t\tIdentify the server host\n"); | |
5eaef520 | 532 | printf("motd, m\t\t\tGet the Message of the Day\n"); |
533 | printf("query, qy\t\tMake a query.\n"); | |
bb38293f | 534 | printf("auth, a\t\t\tAuthenticate to Moira via krb5.\n"); |
535 | printf("krb4_auth, 4\t\tAuthenticate to Moira via krb4.\n"); | |
e7138c1c | 536 | printf("proxy, p\t\tProxy authenticate to Moira.\n"); |
5eaef520 | 537 | printf("access\t\t\tCheck access to a Moira query.\n"); |
538 | printf("dcm\t\t\tTrigger the DCM\n"); | |
539 | printf("script, s\t\tRead commands from a script.\n"); | |
540 | printf("list_requests, lr, ?\tList available commands.\n"); | |
541 | printf("quit, Q\t\t\tLeave the subsystem.\n"); | |
1a5c774c | 542 | } |
acde26f0 | 543 | |
544 | void test_version(int argc, char **argv) | |
545 | { | |
546 | int status; | |
547 | ||
548 | if (argc != 2) | |
549 | { | |
550 | com_err("moira (version)", 0, "Usage: version versionnumber"); | |
551 | return; | |
552 | } | |
553 | status = mr_version(atoi(argv[1])); | |
554 | if (status) | |
555 | com_err("moira (version)", status, ""); | |
556 | } | |
533bacb3 | 557 | |
558 | #ifdef HAVE_POSIX_SIGNALS | |
559 | ||
560 | void set_signal_handler(int sig, void (*handler)(int)) | |
561 | { | |
562 | struct sigaction action; | |
563 | ||
564 | sigemptyset(&action.sa_mask); | |
565 | action.sa_flags = 0; | |
566 | action.sa_handler = handler; | |
567 | sigaction(sig, &action, NULL); | |
568 | } | |
569 | ||
570 | void set_signal_blocking(int sig, int block) | |
571 | { | |
572 | sigset_t sigs; | |
573 | sigemptyset(&sigs); | |
574 | sigaddset(&sigs, sig); | |
575 | sigprocmask(block ? SIG_BLOCK : SIG_UNBLOCK, &sigs, NULL); | |
576 | } | |
577 | ||
578 | #else | |
579 | ||
580 | void set_signal_handler(int sig, void (*handler)(int)) | |
581 | { | |
582 | signal(sig, handler); | |
583 | } | |
584 | ||
585 | #ifdef _WIN32 | |
586 | BOOL WINAPI blocking_handler(DWORD dwCtrlType) | |
587 | { | |
588 | return(TRUE); | |
589 | } | |
590 | ||
591 | void set_signal_blocking(int sig, int block) | |
592 | { | |
593 | SetConsoleCtrlHandler(blocking_handler, block ? TRUE : FALSE); | |
594 | } | |
595 | #endif /* _WIN32 */ | |
596 | ||
597 | #endif /* HAVE_POSIX_SIGNALS */ |