xref: /minix3/external/bsd/dhcp/dist/dhcpctl/dhcpctl.c (revision 83ee113ee0d94f3844d44065af2311604e9a30ad)
1 /*	$NetBSD: dhcpctl.c,v 1.1.1.2 2014/07/12 11:57:52 spz Exp $	*/
2 /* dhcpctl.c
3 
4    Subroutines providing general support for objects. */
5 
6 /*
7  * Copyright (c) 2009,2013,2014 by Internet Systems Consortium, Inc. ("ISC")
8  * Copyright (c) 2004,2007 by Internet Systems Consortium, Inc. ("ISC")
9  * Copyright (c) 1999-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: dhcpctl.c,v 1.1.1.2 2014/07/12 11:57:52 spz Exp $");
33 
34 #include "dhcpd.h"
35 #include <omapip/omapip_p.h>
36 #include "dhcpctl.h"
37 
38 omapi_object_type_t *dhcpctl_callback_type;
39 omapi_object_type_t *dhcpctl_remote_type;
40 
41 /* dhcpctl_initialize ()
42 
43    Must be called before any other dhcpctl function. */
44 
dhcpctl_initialize()45 dhcpctl_status dhcpctl_initialize ()
46 {
47 	isc_result_t status;
48 
49 	/* Set up the isc and dns library managers */
50 	status = dhcp_context_create(DHCP_CONTEXT_PRE_DB | DHCP_CONTEXT_POST_DB,
51 				     NULL, NULL);
52 	if (status != ISC_R_SUCCESS)
53 		return status;
54 
55 	status = omapi_init();
56 	if (status != ISC_R_SUCCESS)
57 		return status;
58 
59 	status = omapi_object_type_register (&dhcpctl_callback_type,
60 					     "dhcpctl-callback",
61 					     dhcpctl_callback_set_value,
62 					     dhcpctl_callback_get_value,
63 					     dhcpctl_callback_destroy,
64 					     dhcpctl_callback_signal_handler,
65 					     dhcpctl_callback_stuff_values,
66 					     0, 0, 0, 0, 0, 0,
67 					     sizeof
68 					     (dhcpctl_callback_object_t), 0,
69 					     RC_MISC);
70 	if (status != ISC_R_SUCCESS)
71 		return status;
72 
73 	status = omapi_object_type_register (&dhcpctl_remote_type,
74 					     "dhcpctl-remote",
75 					     dhcpctl_remote_set_value,
76 					     dhcpctl_remote_get_value,
77 					     dhcpctl_remote_destroy,
78 					     dhcpctl_remote_signal_handler,
79 					     dhcpctl_remote_stuff_values,
80 					     0, 0, 0, 0, 0, 0,
81 					     sizeof (dhcpctl_remote_object_t),
82 					     0, RC_MISC);
83 	if (status != ISC_R_SUCCESS)
84 		return status;
85 
86 	return ISC_R_SUCCESS;
87 }
88 
89 /* dhcpctl_connect
90 
91    synchronous
92    returns nonzero status code if it didn't connect, zero otherwise
93    stores connection handle through connection, which can be used
94    for subsequent access to the specified server.
95    server_name is the name of the server, and port is the TCP
96    port on which it is listening.
97    authinfo is the handle to an object containing authentication
98    information. */
99 
dhcpctl_connect(dhcpctl_handle * connection,const char * server_name,int port,dhcpctl_handle authinfo)100 dhcpctl_status dhcpctl_connect (dhcpctl_handle *connection,
101 				const char *server_name, int port,
102 				dhcpctl_handle authinfo)
103 {
104 	isc_result_t status;
105 
106 	status = omapi_generic_new (connection, MDL);
107 	if (status != ISC_R_SUCCESS) {
108 		return status;
109 	}
110 
111 	status = omapi_protocol_connect (*connection, server_name,
112 					 (unsigned)port, authinfo);
113 	if (status == ISC_R_SUCCESS)
114 		return status;
115 	if (status != DHCP_R_INCOMPLETE) {
116 		omapi_object_dereference (connection, MDL);
117 		return status;
118 	}
119 
120 	status = omapi_wait_for_completion (*connection, 0);
121 	if (status != ISC_R_SUCCESS) {
122 		omapi_object_dereference (connection, MDL);
123 		return status;
124 	}
125 
126 	return status;
127 }
128 
129 /* dhcpctl_wait_for_completion
130 
131    synchronous
132    returns zero if the callback completes, a nonzero status if
133    there was some problem relating to the wait operation.   The
134    status of the queued request will be stored through s, and
135    will also be either zero for success or nonzero for some kind
136    of failure.    Never returns until completion or until the
137    connection to the server is lost.   This performs the same
138    function as dhcpctl_set_callback and the subsequent callback,
139    for programs that want to do inline execution instead of using
140    callbacks. */
141 
dhcpctl_wait_for_completion(dhcpctl_handle h,dhcpctl_status * s)142 dhcpctl_status dhcpctl_wait_for_completion (dhcpctl_handle h,
143 					    dhcpctl_status *s)
144 {
145 	isc_result_t status;
146 	status = omapi_wait_for_completion (h, 0);
147 	if (status != ISC_R_SUCCESS)
148 		return status;
149 	if (h -> type == dhcpctl_remote_type)
150 		*s = ((dhcpctl_remote_object_t *)h) -> waitstatus;
151 	return ISC_R_SUCCESS;
152 }
153 
154 /* dhcpctl_get_value
155 
156    synchronous
157    returns zero if the call succeeded, a nonzero status code if
158    it didn't.
159    result is the address of an empty data string (initialized
160    with bzero or cleared with data_string_forget).   On
161    successful completion, the addressed data string will contain
162    the value that was fetched.
163    dhcpctl_handle refers to some dhcpctl item
164    value_name refers to some value related to that item - e.g.,
165    for a handle associated with a completed host lookup, value
166    could be one of "hardware-address", "dhcp-client-identifier",
167    "known" or "client-hostname". */
168 
dhcpctl_get_value(dhcpctl_data_string * result,dhcpctl_handle h,const char * value_name)169 dhcpctl_status dhcpctl_get_value (dhcpctl_data_string *result,
170 				  dhcpctl_handle h, const char *value_name)
171 {
172 	isc_result_t status;
173 	omapi_value_t *tv = (omapi_value_t *)0;
174 	unsigned len;
175 	int ip;
176 
177 	status = omapi_get_value_str (h, (omapi_object_t *)0, value_name, &tv);
178 	if (status != ISC_R_SUCCESS)
179 		return status;
180 
181 	switch (tv -> value -> type) {
182 	      case omapi_datatype_int:
183 		len = sizeof (int);
184 		break;
185 
186 	      case omapi_datatype_string:
187 	      case omapi_datatype_data:
188 		len = tv -> value -> u.buffer.len;
189 		break;
190 
191 	      case omapi_datatype_object:
192 		len = sizeof (omapi_handle_t);
193 		break;
194 
195 	      default:
196 		omapi_typed_data_dereference (&tv -> value, MDL);
197 		return ISC_R_UNEXPECTED;
198 	}
199 
200 	status = omapi_data_string_new (result, len, MDL);
201 	if (status != ISC_R_SUCCESS) {
202 		omapi_typed_data_dereference (&tv -> value, MDL);
203 		return status;
204 	}
205 
206 	switch (tv -> value -> type) {
207 	      case omapi_datatype_int:
208 		ip = htonl (tv -> value -> u.integer);
209 		memcpy ((*result) -> value, &ip, sizeof ip);
210 		break;
211 
212 	      case omapi_datatype_string:
213 	      case omapi_datatype_data:
214 		memcpy ((*result) -> value,
215 			tv -> value -> u.buffer.value,
216 			tv -> value -> u.buffer.len);
217 		break;
218 
219 	      case omapi_datatype_object:
220 		ip = htonl (tv -> value -> u.object -> handle);
221 		memcpy ((*result) -> value, &ip, sizeof ip);
222 		break;
223 	}
224 
225 	omapi_value_dereference (&tv, MDL);
226 	return ISC_R_SUCCESS;
227 }
228 
229 /* dhcpctl_get_boolean
230 
231    like dhcpctl_get_value, but more convenient for boolean
232    values, since no data_string needs to be dealt with. */
233 
dhcpctl_get_boolean(int * result,dhcpctl_handle h,const char * value_name)234 dhcpctl_status dhcpctl_get_boolean (int *result,
235 				    dhcpctl_handle h, const char *value_name)
236 {
237 	isc_result_t status;
238 	dhcpctl_data_string data = (dhcpctl_data_string)0;
239 	int rv;
240 
241 	status = dhcpctl_get_value (&data, h, value_name);
242 	if (status != ISC_R_SUCCESS)
243 		return status;
244 	if (data -> len != sizeof rv) {
245 		omapi_data_string_dereference (&data, MDL);
246 		return ISC_R_UNEXPECTED;
247 	}
248 	memcpy (&rv, data -> value, sizeof rv);
249 	*result = ntohl (rv);
250 	return ISC_R_SUCCESS;
251 }
252 
253 /* dhcpctl_set_value
254 
255    Sets a value on an object referred to by a dhcpctl_handle.
256    The opposite of dhcpctl_get_value.   Does not update the
257    server - just sets the value on the handle. */
258 
dhcpctl_set_value(dhcpctl_handle h,dhcpctl_data_string value,const char * value_name)259 dhcpctl_status dhcpctl_set_value (dhcpctl_handle h, dhcpctl_data_string value,
260 				  const char *value_name)
261 {
262 	isc_result_t status;
263 	omapi_typed_data_t *tv = (omapi_typed_data_t *)0;
264 	omapi_data_string_t *name = (omapi_data_string_t *)0;
265 
266 	status = omapi_data_string_new (&name, strlen (value_name), MDL);
267 	if (status != ISC_R_SUCCESS)
268 		return status;
269 	memcpy (name -> value, value_name, strlen (value_name));
270 
271 	status = omapi_typed_data_new (MDL, &tv, omapi_datatype_data,
272 				       value -> len);
273 	if (status != ISC_R_SUCCESS) {
274 		omapi_data_string_dereference (&name, MDL);
275 		return status;
276 	}
277 	memcpy (tv -> u.buffer.value, value -> value, value -> len);
278 
279 	status = omapi_set_value (h, (omapi_object_t *)0, name, tv);
280 	omapi_data_string_dereference (&name, MDL);
281 	omapi_typed_data_dereference (&tv, MDL);
282 	return status;
283 }
284 
285 /* dhcpctl_set_string_value
286 
287    Sets a NUL-terminated ASCII value on an object referred to by
288    a dhcpctl_handle.   like dhcpctl_set_value, but saves the
289    trouble of creating a data_string for a NUL-terminated string.
290    Does not update the server - just sets the value on the handle. */
291 
dhcpctl_set_string_value(dhcpctl_handle h,const char * value,const char * value_name)292 dhcpctl_status dhcpctl_set_string_value (dhcpctl_handle h, const char *value,
293 					 const char *value_name)
294 {
295 	isc_result_t status;
296 	omapi_typed_data_t *tv = (omapi_typed_data_t *)0;
297 	omapi_data_string_t *name = (omapi_data_string_t *)0;
298 
299 	status = omapi_data_string_new (&name, strlen (value_name), MDL);
300 	if (status != ISC_R_SUCCESS)
301 		return status;
302 	memcpy (name -> value, value_name, strlen (value_name));
303 
304 	status = omapi_typed_data_new (MDL, &tv, omapi_datatype_string, value);
305 	if (status != ISC_R_SUCCESS) {
306 		omapi_data_string_dereference (&name, MDL);
307 		return status;
308 	}
309 
310 	status = omapi_set_value (h, (omapi_object_t *)0, name, tv);
311 	omapi_data_string_dereference (&name, MDL);
312 	omapi_typed_data_dereference (&tv, MDL);
313 	return status;
314 }
315 
316 /* dhcpctl_set_buffer_value
317 
318    Sets a value on an object referred to by a dhcpctl_handle.  like
319    dhcpctl_set_value, but saves the trouble of creating a data_string
320    for string for which we have a buffer and length.  Does not update
321    the server - just sets the value on the handle. */
322 
dhcpctl_set_data_value(dhcpctl_handle h,const char * value,unsigned len,const char * value_name)323 dhcpctl_status dhcpctl_set_data_value (dhcpctl_handle h,
324 				       const char *value, unsigned len,
325 				       const char *value_name)
326 {
327 	isc_result_t status;
328 	omapi_typed_data_t *tv = (omapi_typed_data_t *)0;
329 	omapi_data_string_t *name = (omapi_data_string_t *)0;
330 	unsigned ll;
331 
332 	ll = strlen (value_name);
333 	status = omapi_data_string_new (&name, ll, MDL);
334 	if (status != ISC_R_SUCCESS)
335 		return status;
336 	memcpy (name -> value, value_name, ll);
337 
338 	status = omapi_typed_data_new (MDL, &tv,
339 				       omapi_datatype_data, len, value);
340 	if (status != ISC_R_SUCCESS) {
341 		omapi_data_string_dereference (&name, MDL);
342 		return status;
343 	}
344 	memcpy (tv -> u.buffer.value, value, len);
345 
346 	status = omapi_set_value (h, (omapi_object_t *)0, name, tv);
347 	omapi_data_string_dereference (&name, MDL);
348 	omapi_typed_data_dereference (&tv, MDL);
349 	return status;
350 }
351 
352 /* dhcpctl_set_null_value
353 
354    Sets a null value on an object referred to by a dhcpctl_handle. */
355 
dhcpctl_set_null_value(dhcpctl_handle h,const char * value_name)356 dhcpctl_status dhcpctl_set_null_value (dhcpctl_handle h,
357 				       const char *value_name)
358 {
359 	isc_result_t status;
360 	omapi_data_string_t *name = (omapi_data_string_t *)0;
361 	unsigned ll;
362 
363 	ll = strlen (value_name);
364 	status = omapi_data_string_new (&name, ll, MDL);
365 	if (status != ISC_R_SUCCESS)
366 		return status;
367 	memcpy (name -> value, value_name, ll);
368 
369 	status = omapi_set_value (h, (omapi_object_t *)0, name,
370 				  (omapi_typed_data_t *)0);
371 	omapi_data_string_dereference (&name, MDL);
372 	return status;
373 }
374 
375 /* dhcpctl_set_boolean_value
376 
377    Sets a boolean value on an object - like dhcpctl_set_value,
378    only more convenient for booleans. */
379 
dhcpctl_set_boolean_value(dhcpctl_handle h,int value,const char * value_name)380 dhcpctl_status dhcpctl_set_boolean_value (dhcpctl_handle h, int value,
381 					  const char *value_name)
382 {
383 	isc_result_t status;
384 	omapi_typed_data_t *tv = (omapi_typed_data_t *)0;
385 	omapi_data_string_t *name = (omapi_data_string_t *)0;
386 
387 	status = omapi_data_string_new (&name, strlen (value_name), MDL);
388 	if (status != ISC_R_SUCCESS)
389 		return status;
390 	memcpy (name -> value, value_name, strlen (value_name));
391 
392 	status = omapi_typed_data_new (MDL, &tv, omapi_datatype_int, value);
393 	if (status != ISC_R_SUCCESS) {
394 		omapi_data_string_dereference (&name, MDL);
395 		return status;
396 	}
397 
398 	status = omapi_set_value (h, (omapi_object_t *)0, name, tv);
399 	omapi_data_string_dereference (&name, MDL);
400 	omapi_typed_data_dereference (&tv, MDL);
401 	return status;
402 }
403 
404 /* dhcpctl_set_int_value
405 
406    Sets a boolean value on an object - like dhcpctl_set_value,
407    only more convenient for booleans. */
408 
dhcpctl_set_int_value(dhcpctl_handle h,int value,const char * value_name)409 dhcpctl_status dhcpctl_set_int_value (dhcpctl_handle h, int value,
410 				      const char *value_name)
411 {
412 	isc_result_t status;
413 	omapi_typed_data_t *tv = (omapi_typed_data_t *)0;
414 	omapi_data_string_t *name = (omapi_data_string_t *)0;
415 
416 	status = omapi_data_string_new (&name, strlen (value_name), MDL);
417 	if (status != ISC_R_SUCCESS)
418 		return status;
419 	memcpy (name -> value, value_name, strlen (value_name));
420 
421 	status = omapi_typed_data_new (MDL, &tv, omapi_datatype_int, value);
422 	if (status != ISC_R_SUCCESS) {
423 		omapi_data_string_dereference (&name, MDL);
424 		return status;
425 	}
426 
427 	status = omapi_set_value (h, (omapi_object_t *)0, name, tv);
428 	omapi_data_string_dereference (&name, MDL);
429 	omapi_typed_data_dereference (&tv, MDL);
430 	return status;
431 }
432 
433 /* dhcpctl_object_update
434 
435    Queues an update on the object referenced by the handle (there
436    can't be any other work in progress on the handle).   An
437    update means local parameters will be sent to the server. */
438 
dhcpctl_object_update(dhcpctl_handle connection,dhcpctl_handle h)439 dhcpctl_status dhcpctl_object_update (dhcpctl_handle connection,
440 				      dhcpctl_handle h)
441 {
442 	isc_result_t status;
443 	omapi_object_t *message = (omapi_object_t *)0;
444 	dhcpctl_remote_object_t *ro;
445 
446 	if (h -> type != dhcpctl_remote_type)
447 		return DHCP_R_INVALIDARG;
448 	ro = (dhcpctl_remote_object_t *)h;
449 
450 	status = omapi_message_new (&message, MDL);
451 	if (status != ISC_R_SUCCESS) {
452 		omapi_object_dereference (&message, MDL);
453 		return status;
454 	}
455 	status = omapi_set_int_value (message, (omapi_object_t *)0,
456 				      "op", OMAPI_OP_UPDATE);
457 	if (status != ISC_R_SUCCESS) {
458 		omapi_object_dereference (&message, MDL);
459 		return status;
460 	}
461 
462 	status = omapi_set_object_value (message, (omapi_object_t *)0,
463 					 "object", h);
464 	if (status != ISC_R_SUCCESS) {
465 		omapi_object_dereference (&message, MDL);
466 		return status;
467 	}
468 
469 	status = omapi_set_int_value (message, (omapi_object_t *)0, "handle",
470 				      (int)(ro -> remote_handle));
471 	if (status != ISC_R_SUCCESS) {
472 		omapi_object_dereference (&message, MDL);
473 		return status;
474 	}
475 
476 	omapi_message_register (message);
477 	status = omapi_protocol_send_message (connection -> outer,
478 					      (omapi_object_t *)0,
479 					      message, (omapi_object_t *)0);
480 	omapi_object_dereference (&message, MDL);
481 	return status;
482 }
483 
484 /* Requests a refresh on the object referenced by the handle (there
485    can't be any other work in progress on the handle).   A
486    refresh means local parameters are updated from the server. */
487 
dhcpctl_object_refresh(dhcpctl_handle connection,dhcpctl_handle h)488 dhcpctl_status dhcpctl_object_refresh (dhcpctl_handle connection,
489 				       dhcpctl_handle h)
490 {
491 	isc_result_t status;
492 	omapi_object_t *message = (omapi_object_t *)0;
493 	dhcpctl_remote_object_t *ro;
494 
495 	if (h -> type != dhcpctl_remote_type)
496 		return DHCP_R_INVALIDARG;
497 	ro = (dhcpctl_remote_object_t *)h;
498 
499 	status = omapi_message_new (&message, MDL);
500 	if (status != ISC_R_SUCCESS) {
501 		omapi_object_dereference (&message, MDL);
502 		return status;
503 	}
504 	status = omapi_set_int_value (message, (omapi_object_t *)0,
505 				      "op", OMAPI_OP_REFRESH);
506 	if (status != ISC_R_SUCCESS) {
507 		omapi_object_dereference (&message, MDL);
508 		return status;
509 	}
510 	status = omapi_set_int_value (message, (omapi_object_t *)0,
511 				      "handle", (int)(ro -> remote_handle));
512 	if (status != ISC_R_SUCCESS) {
513 		omapi_object_dereference (&message, MDL);
514 		return status;
515 	}
516 
517 	omapi_message_register (message);
518 	status = omapi_protocol_send_message (connection -> outer,
519 					      (omapi_object_t *)0,
520 					      message, (omapi_object_t *)0);
521 
522 	/* We don't want to send the contents of the object down the
523 	   wire, but we do need to reference it so that we know what
524 	   to do with the update. */
525 	status = omapi_set_object_value (message, (omapi_object_t *)0,
526 					 "object", h);
527 	if (status != ISC_R_SUCCESS) {
528 		omapi_object_dereference (&message, MDL);
529 		return status;
530 	}
531 
532 	omapi_object_dereference (&message, MDL);
533 	return status;
534 }
535 
536 /* Requests the removal of the object referenced by the handle (there
537    can't be any other work in progress on the handle).   A
538    removal means that all searchable references to the object on the
539    server are deleted. */
540 
dhcpctl_object_remove(dhcpctl_handle connection,dhcpctl_handle h)541 dhcpctl_status dhcpctl_object_remove (dhcpctl_handle connection,
542 				      dhcpctl_handle h)
543 {
544 	isc_result_t status;
545 	omapi_object_t *message = (omapi_object_t *)0;
546 	dhcpctl_remote_object_t *ro;
547 
548 	if (h -> type != dhcpctl_remote_type)
549 		return DHCP_R_INVALIDARG;
550 	ro = (dhcpctl_remote_object_t *)h;
551 
552 	status = omapi_message_new (&message, MDL);
553 	if (status != ISC_R_SUCCESS) {
554 		omapi_object_dereference (&message, MDL);
555 		return status;
556 	}
557 	status = omapi_set_int_value (message, (omapi_object_t *)0,
558 				      "op", OMAPI_OP_DELETE);
559 	if (status != ISC_R_SUCCESS) {
560 		omapi_object_dereference (&message, MDL);
561 		return status;
562 	}
563 
564 	status = omapi_set_int_value (message, (omapi_object_t *)0, "handle",
565 				      (int)(ro -> remote_handle));
566 	if (status != ISC_R_SUCCESS) {
567 		omapi_object_dereference (&message, MDL);
568 		return status;
569 	}
570 
571 	status = omapi_set_object_value (message, (omapi_object_t *)0,
572 					 "notify-object", h);
573 	if (status != ISC_R_SUCCESS) {
574 		omapi_object_dereference (&message, MDL);
575 		return status;
576 	}
577 
578 	omapi_message_register (message);
579 	status = omapi_protocol_send_message (connection -> outer,
580 					      (omapi_object_t *)0,
581 					      message, (omapi_object_t *)0);
582 	omapi_object_dereference (&message, MDL);
583 	return status;
584 }
585 
dhcpctl_data_string_dereference(dhcpctl_data_string * vp,const char * file,int line)586 isc_result_t dhcpctl_data_string_dereference (dhcpctl_data_string *vp,
587 					      const char *file, int line)
588 {
589 	return omapi_data_string_dereference (vp, file, line);
590 }
591