]> andersk Git - moira.git/blame - clients/mrtest/mrtest.c
Don't crash if given more than MAXARGS arguments.
[moira.git] / clients / mrtest / mrtest.c
CommitLineData
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 46RCSID("$Header$");
47
71da1922 48int recursion = 0, quote_output = 0, interactive;
5eaef520 49int count, quit = 0, cancel = 0;
1a5c774c 50char *whoami;
533bacb3 51
74c84b52 52sigjmp_buf jb;
1a5c774c 53
54#define MAXARGS 20
6e6374cb 55
533bacb3 56void discard_input(int sig);
7ac48069 57char *mr_gets(char *prompt, char *buf, size_t len);
58void execute_line(char *cmdbuf);
59int parse(char *buf, char *argv[MAXARGS]);
8c9b31a9 60int print_reply(int argc, char **argv, void *help);
7ac48069 61void test_noop(void);
62void test_connect(int argc, char **argv);
63void test_disconnect(void);
64void test_host(void);
7ac48069 65void test_motd(void);
66void test_query(int argc, char **argv);
67void test_auth(void);
e7138c1c 68void test_proxy(int argc, char **argv);
7ac48069 69void test_access(int argc, char **argv);
70void test_dcm(void);
71void test_script(int argc, char **argv);
72void test_list_requests(void);
acde26f0 73void test_version(int argc, char **argv);
991417e4 74void test_krb5_auth(void);
533bacb3 75void set_signal_handler(int, void (*handler)(int));
76void set_signal_blocking(int, int);
f281aa29 77
5eaef520 78int 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 121void 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 133char *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 162void 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 208int 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 277void test_noop(void)
6e6374cb 278{
5eaef520 279 int status = mr_noop();
280 if (status)
281 com_err("moira (noop)", status, "");
6e6374cb 282}
283
7ac48069 284void 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 297void test_disconnect(void)
6e6374cb 298{
5eaef520 299 int status = mr_disconnect();
300 if (status)
301 com_err("moira (disconnect)", status, "");
6e6374cb 302}
303
7ac48069 304void 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 317void 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 326void 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 335void 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 349void 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 441int 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 468void 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 490void 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 503void 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 511void 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 524void 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
544void 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
560void 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
570void 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
580void set_signal_handler(int sig, void (*handler)(int))
581{
582 signal(sig, handler);
583}
584
585#ifdef _WIN32
586BOOL WINAPI blocking_handler(DWORD dwCtrlType)
587{
588 return(TRUE);
589}
590
591void 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 */
This page took 0.202572 seconds and 5 git commands to generate.