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