]> git.ipfire.org Git - thirdparty/dhcp.git/blob - dhcpctl/omshell.c
Finished rebased
[thirdparty/dhcp.git] / dhcpctl / omshell.c
1 /* omshell.c
2
3 Examine and modify omapi objects. */
4
5 /*
6 * Copyright (c) 2009-2011,2013-2015 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC")
8 * Copyright (c) 2001-2003 by Internet Software Consortium
9 *
10 * Permission to use, copy, modify, and distribute this software for any
11 * purpose with or without fee is hereby granted, provided that the above
12 * copyright notice and this permission notice appear in all copies.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
15 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
17 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
20 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 *
22 * Internet Systems Consortium, Inc.
23 * 950 Charter Street
24 * Redwood City, CA 94063
25 * <info@isc.org>
26 * https://www.isc.org/
27 *
28 */
29
30 #include "config.h"
31
32 #include <time.h>
33 #include <sys/time.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <stdarg.h>
37 #include <string.h>
38 //#include "result.h"
39 #include <syslog.h>
40 #include "dhcpctl.h"
41 #include "dhcpd.h"
42 #include <isc/file.h>
43
44 /* Fixups */
45 isc_result_t find_class (struct class **c, const char *n, const char *f, int l)
46 {
47 return 0;
48 }
49 int parse_allow_deny (struct option_cache **oc, struct parse *cfile, int flag)
50 {
51 return 0;
52 }
53 void dhcp (struct packet *packet) { }
54 void bootp (struct packet *packet) { }
55
56 #ifdef DHCPv6
57 /* XXX: should we warn or something here? */
58 void dhcpv6(struct packet *packet) { }
59 #endif /* DHCPv6 */
60
61 int check_collection (struct packet *p, struct lease *l, struct collection *c)
62 {
63 return 0;
64 }
65 void classify (struct packet *packet, struct class *class) { }
66
67 static void usage (const char *s) {
68 fprintf (stderr, "Usage: %s\n", s);
69 exit (1);
70 }
71
72 static void check (isc_result_t status, const char *func) {
73 if (status != ISC_R_SUCCESS) {
74 fprintf (stderr, "%s: %s\n", func, isc_result_totext (status));
75 exit (1);
76 }
77 }
78
79 int
80 main(int argc, char **argv) {
81 isc_result_t status, waitstatus;
82 dhcpctl_handle connection;
83 dhcpctl_handle authenticator;
84 dhcpctl_handle oh;
85 struct data_string secret;
86 const char *name = 0, *algorithm = "hmac-md5";
87 int i;
88 int port = 7911;
89 const char *server = "127.0.0.1";
90 struct parse *cfile;
91 enum dhcp_token token;
92 const char *val;
93 char *s;
94 char buf[1024];
95 char s1[1024];
96 int connected = 0;
97 char hex_buf[1025];
98 char *progname;
99
100 #ifdef OLD_LOG_NAME
101 progname = "omshell";
102 #else
103 progname = argv[0];
104 #endif
105
106 for (i = 1; i < argc; i++) {
107 usage(isc_file_basename(progname));
108 }
109
110 /* Initially, log errors to stderr as well as to syslogd. */
111 openlog (isc_file_basename(progname),
112 DHCP_LOG_OPTIONS, DHCPD_LOG_FACILITY);
113 status = dhcpctl_initialize ();
114 if (status != ISC_R_SUCCESS) {
115 fprintf (stderr, "dhcpctl_initialize: %s\n",
116 isc_result_totext (status));
117 exit (1);
118 }
119
120 memset (&oh, 0, sizeof oh);
121
122 do {
123 if (!connected) {
124 } else if (oh == NULL) {
125 printf ("obj: <null>\n");
126 } else {
127 dhcpctl_remote_object_t *r = (dhcpctl_remote_object_t *)oh;
128 omapi_generic_object_t *g =
129 (omapi_generic_object_t *)(r -> inner);
130
131 printf ("obj: ");
132
133 if (r -> rtype -> type != omapi_datatype_string) {
134 printf ("?\n");
135 } else {
136 printf ("%.*s\n",
137 (int)(r -> rtype -> u . buffer . len),
138 r -> rtype -> u . buffer . value);
139 }
140
141 for (i = 0; i < g -> nvalues; i++) {
142 omapi_value_t *v = g -> values [i];
143
144 if (!g -> values [i])
145 continue;
146
147 printf ("%.*s = ", (int)v -> name -> len,
148 v -> name -> value);
149
150 if (!v -> value) {
151 printf ("<null>\n");
152 continue;
153 }
154 switch (v -> value -> type) {
155 case omapi_datatype_int:
156 printf ("%d\n",
157 v -> value -> u . integer);
158 break;
159
160 case omapi_datatype_string:
161 printf ("\"%.*s\"\n",
162 (int) v -> value -> u.buffer.len,
163 v -> value -> u.buffer.value);
164 break;
165
166 case omapi_datatype_data:
167 print_hex_or_string(v->value->u.buffer.len,
168 v->value->u.buffer.value,
169 sizeof(hex_buf), hex_buf);
170 printf("%s\n", hex_buf);
171 break;
172
173 case omapi_datatype_object:
174 printf ("<obj>\n");
175 break;
176 }
177 }
178 }
179
180 fputs ("> ", stdout);
181 fflush (stdout);
182 if (fgets (buf, sizeof(buf), stdin) == NULL)
183 break;
184
185 status = new_parse (&cfile, -1, buf, strlen(buf), "<STDIN>", 1);
186 check(status, "new_parse()");
187
188 token = next_token (&val, (unsigned *)0, cfile);
189 switch (token) {
190 default:
191 parse_warn (cfile, "unknown token: %s", val);
192 skip_to_semi (cfile);
193 break;
194
195 case END_OF_FILE:
196 case ENDOFLINE: /* EOL: */
197 break;
198
199 case TOKEN_HELP:
200 case QUESTIONMARK: /* '?': */
201 printf ("Commands:\n");
202 printf (" port <server omapi port>\n");
203 printf (" server <server address>\n");
204 printf (" key <key name> <key value>\n");
205 printf (" connect\n");
206 printf (" new <object-type>\n");
207 printf (" set <name> = <value>\n");
208 printf (" create\n");
209 printf (" open\n");
210 printf (" update\n");
211 printf (" unset <name>\n");
212 printf (" refresh\n");
213 printf (" remove\n");
214 skip_to_semi (cfile);
215 break;
216
217 case PORT:
218 token = next_token (&val, (unsigned *)0, cfile);
219 if (is_identifier (token)) {
220 struct servent *se;
221 se = getservbyname (val, "tcp");
222 if (se)
223 port = ntohs (se -> s_port);
224 else {
225 printf ("unknown service name: %s\n", val);
226 break;
227 }
228 } else if (token == NUMBER) {
229 port = atoi (val);
230 } else {
231 skip_to_semi (cfile);
232 printf ("usage: port <port>\n");
233 break;
234 }
235 token = next_token (&val, (unsigned *)0, cfile);
236 if (token != END_OF_FILE && token != EOL) {
237 printf ("usage: port <server>\n");
238 skip_to_semi (cfile);
239 break;
240 }
241 break;
242
243 case TOKEN_SERVER:
244 token = next_token (&val, (unsigned *)0, cfile);
245 if (token == NUMBER) {
246 int alen = (sizeof buf) - 1;
247 int len;
248
249 s = &buf [0];
250 len = strlen (val);
251 if (len + 1 > alen) {
252 baddq:
253 printf ("usage: server <server>\n");
254 skip_to_semi (cfile);
255 break;
256 } strcpy (buf, val);
257 s += len;
258 token = next_token (&val, (unsigned *)0, cfile);
259 if (token != DOT)
260 goto baddq;
261 *s++ = '.';
262 token = next_token (&val, (unsigned *)0, cfile);
263 if (token != NUMBER)
264 goto baddq;
265 len = strlen (val);
266 if (len + 1 > alen)
267 goto baddq;
268 strcpy (s, val);
269 s += len;
270 token = next_token (&val, (unsigned *)0, cfile);
271 if (token != DOT)
272 goto baddq;
273 *s++ = '.';
274 token = next_token (&val, (unsigned *)0, cfile);
275 if (token != NUMBER)
276 goto baddq;
277 len = strlen (val);
278 if (len + 1 > alen)
279 goto baddq;
280 strcpy (s, val);
281 s += len;
282 token = next_token (&val, (unsigned *)0, cfile);
283 if (token != DOT)
284 goto baddq;
285 *s++ = '.';
286 token = next_token (&val, (unsigned *)0, cfile);
287 if (token != NUMBER)
288 goto baddq;
289 len = strlen (val);
290 if (len + 1 > alen)
291 goto baddq;
292 strcpy (s, val);
293 val = &buf [0];
294 } else if (is_identifier (token)) {
295 /* Use val directly. */
296 } else {
297 printf ("usage: server <server>\n");
298 skip_to_semi (cfile);
299 break;
300 }
301
302 s = dmalloc (strlen (val) + 1, MDL);
303 if (!server) {
304 printf ("no memory to store server name.\n");
305 skip_to_semi (cfile);
306 break;
307 }
308 strcpy (s, val);
309 server = s;
310
311 token = next_token (&val, (unsigned *)0, cfile);
312 if (token != END_OF_FILE && token != EOL) {
313 printf ("usage: server <server>\n");
314 skip_to_semi (cfile);
315 break;
316 }
317 break;
318
319 case KEY:
320 token = peek_token(&val, (unsigned *)0, cfile);
321 if (token == STRING) {
322 token = next_token (&val, (unsigned *)0, cfile);
323 if (!is_identifier (token)) {
324 printf ("usage: key <name> <value>\n");
325 skip_to_semi (cfile);
326 break;
327 }
328 s = dmalloc (strlen (val) + 1, MDL);
329 if (!s) {
330 printf ("no memory for key name.\n");
331 skip_to_semi (cfile);
332 break;
333 }
334 strcpy (s, val);
335 } else {
336 s = parse_host_name(cfile);
337 if (s == NULL) {
338 printf ("usage: key <name> <value>\n");
339 skip_to_semi(cfile);
340 break;
341 }
342 }
343 name = s;
344
345 memset (&secret, 0, sizeof secret);
346 if (!parse_base64 (&secret, cfile)) {
347 skip_to_semi (cfile);
348 break;
349 }
350 token = next_token (&val, (unsigned *)0, cfile);
351 if (token != END_OF_FILE && token != EOL) {
352 printf ("usage: key <name> <secret>\n");
353 skip_to_semi (cfile);
354 break;
355 }
356 break;
357
358 case CONNECT:
359 token = next_token (&val, (unsigned *)0, cfile);
360 if (token != END_OF_FILE && token != EOL) {
361 printf ("usage: connect\n");
362 skip_to_semi (cfile);
363 break;
364 }
365
366 authenticator = dhcpctl_null_handle;
367
368 if (name) {
369 status = dhcpctl_new_authenticator (&authenticator,
370 name, algorithm,
371 secret.data,
372 secret.len);
373
374 if (status != ISC_R_SUCCESS) {
375 fprintf (stderr,
376 "Cannot create authenticator: %s\n",
377 isc_result_totext (status));
378 break;
379 }
380 }
381
382 memset (&connection, 0, sizeof connection);
383 status = dhcpctl_connect (&connection,
384 server, port, authenticator);
385 if (status != ISC_R_SUCCESS) {
386 fprintf (stderr, "dhcpctl_connect: %s\n",
387 isc_result_totext (status));
388 break;
389 }
390 connected = 1;
391 break;
392
393 case TOKEN_NEW:
394 token = next_token (&val, (unsigned *)0, cfile);
395 if ((!is_identifier (token) && token != STRING)) {
396 printf ("usage: new <object-type>\n");
397 break;
398 }
399
400 if (oh) {
401 printf ("an object is already open.\n");
402 skip_to_semi (cfile);
403 break;
404 }
405
406 if (!connected) {
407 printf ("not connected.\n");
408 skip_to_semi (cfile);
409 break;
410 }
411
412 status = dhcpctl_new_object (&oh, connection, val);
413 if (status != ISC_R_SUCCESS) {
414 printf ("can't create object: %s\n",
415 isc_result_totext (status));
416 break;
417 }
418
419 token = next_token (&val, (unsigned *)0, cfile);
420 if (token != END_OF_FILE && token != EOL) {
421 printf ("usage: new <object-type>\n");
422 skip_to_semi (cfile);
423 break;
424 }
425 break;
426
427 case TOKEN_CLOSE:
428 token = next_token (&val, (unsigned *)0, cfile);
429 if (token != END_OF_FILE && token != EOL) {
430 printf ("usage: close\n");
431 skip_to_semi (cfile);
432 break;
433 }
434
435 if (!connected) {
436 printf ("not connected.\n");
437 skip_to_semi (cfile);
438 break;
439 }
440
441 if (!oh) {
442 printf ("not open.\n");
443 skip_to_semi (cfile);
444 break;
445 }
446 omapi_object_dereference (&oh, MDL);
447
448 break;
449
450 case TOKEN_SET:
451 token = next_token (&val, (unsigned *)0, cfile);
452
453 if ((!is_identifier (token) && token != STRING)) {
454 set_usage:
455 printf ("usage: set <name> = <value>\n");
456 skip_to_semi (cfile);
457 break;
458 }
459
460 if (oh == NULL) {
461 printf ("no open object.\n");
462 skip_to_semi (cfile);
463 break;
464 }
465
466 if (!connected) {
467 printf ("not connected.\n");
468 skip_to_semi (cfile);
469 break;
470 }
471
472 #ifdef HAVE_STRLCPY
473 strlcpy (s1, val, sizeof(s1));
474 #else
475 s1[0] = 0;
476 strncat (s1, val, sizeof(s1)-strlen(s1)-1);
477 #endif
478
479 token = next_token (&val, (unsigned *)0, cfile);
480 if (token != EQUAL)
481 goto set_usage;
482
483 token = next_token (&val, (unsigned *)0, cfile);
484 switch (token) {
485 case STRING:
486 dhcpctl_set_string_value (oh, val, s1);
487 token = next_token (&val, (unsigned *)0, cfile);
488 break;
489
490 case NUMBER:
491 strcpy (buf, val);
492 token = peek_token (&val, (unsigned *)0, cfile);
493 /* Colon-separated hex list? */
494 if (token == COLON)
495 goto cshl;
496 else if (token == DOT) {
497 s = buf;
498 val = buf;
499 do {
500 int intval = atoi (val);
501 if (intval > 255) {
502 parse_warn (cfile,
503 "dotted octet > 255: %s",
504 val);
505 skip_to_semi (cfile);
506 goto badnum;
507 }
508 *s++ = intval;
509 token = next_token (&val,
510 (unsigned *)0, cfile);
511 if (token != DOT)
512 break;
513 /* DOT is zero. */
514 while ((token = next_token (&val,
515 (unsigned *)0, cfile)) == DOT)
516 *s++ = 0;
517 } while (token == NUMBER);
518 dhcpctl_set_data_value (oh, buf,
519 (unsigned)(s - buf),
520 s1);
521 break;
522 }
523 dhcpctl_set_int_value (oh, atoi (buf), s1);
524 token = next_token (&val, (unsigned *)0, cfile);
525 badnum:
526 break;
527
528 case NUMBER_OR_NAME:
529 strcpy (buf, val);
530 cshl:
531 s = buf;
532 val = buf;
533 do {
534 convert_num (cfile, (unsigned char *)s,
535 val, 16, 8);
536 ++s;
537 token = next_token (&val,
538 (unsigned *)0, cfile);
539 if (token != COLON)
540 break;
541 token = next_token (&val,
542 (unsigned *)0, cfile);
543 } while (token == NUMBER ||
544 token == NUMBER_OR_NAME);
545 dhcpctl_set_data_value (oh, buf,
546 (unsigned)(s - buf), s1);
547 break;
548
549 default:
550 printf ("invalid value.\n");
551 skip_to_semi (cfile);
552 }
553
554 if (token != END_OF_FILE && token != EOL)
555 goto set_usage;
556 break;
557
558 case UNSET:
559 token = next_token (&val, (unsigned *)0, cfile);
560
561 if ((!is_identifier (token) && token != STRING)) {
562 unset_usage:
563 printf ("usage: unset <name>\n");
564 skip_to_semi (cfile);
565 break;
566 }
567
568 if (!oh) {
569 printf ("no open object.\n");
570 skip_to_semi (cfile);
571 break;
572 }
573
574 if (!connected) {
575 printf ("not connected.\n");
576 skip_to_semi (cfile);
577 break;
578 }
579
580 #if HAVE_STRLCPY
581 strlcpy (s1, val, sizeof(s1));
582 #else
583 s1[0] = 0;
584 strncat (s1, val, sizeof(s1)-strlen(s1)-1);
585 #endif
586
587 token = next_token (&val, (unsigned *)0, cfile);
588 if (token != END_OF_FILE && token != EOL)
589 goto unset_usage;
590
591 dhcpctl_set_null_value (oh, s1);
592 break;
593
594
595 case TOKEN_CREATE:
596 case TOKEN_OPEN:
597 i = token;
598 token = next_token (&val, (unsigned *)0, cfile);
599 if (token != END_OF_FILE && token != EOL) {
600 printf ("usage: %s\n", val);
601 skip_to_semi (cfile);
602 break;
603 }
604
605 if (!connected) {
606 printf ("not connected.\n");
607 skip_to_semi (cfile);
608 break;
609 }
610
611 if (!oh) {
612 printf ("you must make a new object first!\n");
613 skip_to_semi (cfile);
614 break;
615 }
616
617 if (i == TOKEN_CREATE)
618 i = DHCPCTL_CREATE | DHCPCTL_EXCL;
619 else
620 i = 0;
621
622 status = dhcpctl_open_object (oh, connection, i);
623 if (status == ISC_R_SUCCESS)
624 status = dhcpctl_wait_for_completion
625 (oh, &waitstatus);
626 if (status == ISC_R_SUCCESS)
627 status = waitstatus;
628 if (status != ISC_R_SUCCESS) {
629 printf ("can't open object: %s\n",
630 isc_result_totext (status));
631 break;
632 }
633
634 break;
635
636 case UPDATE:
637 token = next_token (&val, (unsigned *)0, cfile);
638 if (token != END_OF_FILE && token != EOL) {
639 printf ("usage: %s\n", val);
640 skip_to_semi (cfile);
641 break;
642 }
643
644 if (!connected) {
645 printf ("not connected.\n");
646 skip_to_semi (cfile);
647 break;
648 }
649
650 if (!oh) {
651 printf ("you haven't opened an object yet!\n");
652 skip_to_semi (cfile);
653 break;
654 }
655
656 status = dhcpctl_object_update(connection, oh);
657 if (status == ISC_R_SUCCESS)
658 status = dhcpctl_wait_for_completion
659 (oh, &waitstatus);
660 if (status == ISC_R_SUCCESS)
661 status = waitstatus;
662 if (status != ISC_R_SUCCESS) {
663 printf ("can't update object: %s\n",
664 isc_result_totext (status));
665 break;
666 }
667
668 break;
669
670 case REMOVE:
671 token = next_token (&val, (unsigned *)0, cfile);
672 if (token != END_OF_FILE && token != EOL) {
673 printf ("usage: remove\n");
674 skip_to_semi (cfile);
675 break;
676 }
677
678 if (!connected) {
679 printf ("not connected.\n");
680 break;
681 }
682
683 if (!oh) {
684 printf ("no object.\n");
685 break;
686 }
687
688 status = dhcpctl_object_remove(connection, oh);
689 if (status == ISC_R_SUCCESS)
690 status = dhcpctl_wait_for_completion
691 (oh, &waitstatus);
692 if (status == ISC_R_SUCCESS)
693 status = waitstatus;
694 if (status != ISC_R_SUCCESS) {
695 printf ("can't destroy object: %s\n",
696 isc_result_totext (status));
697 break;
698 }
699 omapi_object_dereference (&oh, MDL);
700 break;
701
702 case REFRESH:
703 token = next_token (&val, (unsigned *)0, cfile);
704 if (token != END_OF_FILE && token != EOL) {
705 printf ("usage: refresh\n");
706 skip_to_semi (cfile);
707 break;
708 }
709
710 if (!connected) {
711 printf ("not connected.\n");
712 break;
713 }
714
715 if (!oh) {
716 printf ("no object.\n");
717 break;
718 }
719
720 status = dhcpctl_object_refresh(connection, oh);
721 if (status == ISC_R_SUCCESS)
722 status = dhcpctl_wait_for_completion
723 (oh, &waitstatus);
724 if (status == ISC_R_SUCCESS)
725 status = waitstatus;
726 if (status != ISC_R_SUCCESS) {
727 printf ("can't refresh object: %s\n",
728 isc_result_totext (status));
729 break;
730 }
731
732 break;
733 }
734 end_parse (&cfile);
735 } while (1);
736
737 exit (0);
738 }
739
740 /* Sigh */
741 isc_result_t dhcp_set_control_state (control_object_state_t oldstate,
742 control_object_state_t newstate)
743 {
744 if (newstate != server_shutdown)
745 return ISC_R_SUCCESS;
746 exit (0);
747 }