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