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