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