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