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