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