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