]> git.ipfire.org Git - thirdparty/dhcp.git/commitdiff
OMAPI specification.
authorTed Lemon <source@isc.org>
Thu, 9 Sep 1999 21:12:44 +0000 (21:12 +0000)
committerTed Lemon <source@isc.org>
Thu, 9 Sep 1999 21:12:44 +0000 (21:12 +0000)
doc/api+protocol [new file with mode: 0644]

diff --git a/doc/api+protocol b/doc/api+protocol
new file mode 100644 (file)
index 0000000..9423b22
--- /dev/null
@@ -0,0 +1,428 @@
+This file documents the protocol that the ISC DHCP server and ISC
+Object Management clients (clients that use the ISC Object Management
+API) speak between one another.
+
+Protocol:
+
+All multi-byte numbers are represented in network byte order.
+
+On startup, each side sends a status message indicating what version
+of the protocol they are speaking.   The status message looks like
+this:
+
++---------+---------+
+| version | hlength |
++---------+---------+
+
+version - a 32-bit fixed-point number with the decimal point between
+         the third and second decimal digits from the left,
+         representing the version of the protocol.   The current
+         protocol version is 1.00.   If the field were considered as
+         a 32-bit integer, this would correspond to a value of 100
+         decimal, or 0x64.
+
+hlength - a 32-bit integer representing the length of the fixed-length
+         header in subsequent messages.   This is normally 56, but
+         can be changed to a value larger than 56 by either side
+         without upgrading the revision number.
+
+
+The startup message is not authenticated.   Either side may reject the
+other side's startup message as invalid by simply closing the
+connection.   The only fixed part of the startup message is the
+version number - future versions may delete hlength, or add further
+startup information.
+
+Following the startup message, all messages have the same format.
+Currently, the format includes a fixed-length header (the length in
+hlength, above)
+
++--------+----+--------+----+-----+---------+------------+------------+-----+
+| authid | op | handle | id | rid | authlen | msg values | obj values | sig |
++--------+----+--------+----+-----+---------+------------+------------+-----+
+
+The fixed-length header consists of:
+
+authid = a 32-bit authenticator handle.
+       For an original message (one not in response to some other
+       message), this will be chosen by the originator.   For a
+       message in response to another message, the authenticator for
+       that message is used, except if the response is an error
+       message indicating that the authenticator used was unknown,
+       in which case the null authenticator is used.   Messages that
+       are generated as the result of a notify registration use the
+       authenticator used in the original notify registration.
+       The authenticator itself is generated by having one side of
+       the connection send an object of type "authenticator" to the
+       other side with values that indicate what kind of
+       authentication mechanism to use and what key to use.   The two
+       most likely things here are a Kerberos V principal name or the
+       name of a shared secret that can be used to calculate an MD5
+       hash.   The mechanism for doing this has yet to be finalized.
+       If authid is zero, the message is not authenticated.
+
+op = 32-bit opcode, one of:
+       open = 1
+       refresh = 2
+       update = 3
+       notify = 4
+       error = 5
+handle = 32-bit object handle
+       A handle on the object being opened, created, refreshed or
+       updated.   If no handle is yet available (e.g., with open and
+       new), then the value zero is sent.
+id = 32-bit transaction id of the message - a monotonically increasing
+     number that starts with some randomly chosen number at the
+     beginning of the life of the connection.   The value should never
+     be zero.
+rid = 32-bit transaction ID of the message to which this message is a
+      response, or zero if this message is not in response to a
+      message from the other side.
+
+authlen = a 32-bit number representing the length of the authenticator
+
+msg values = a series of name+value pairs, specific to this message.
+        Each name+value pair starts with a 16-bit name length,
+        followed by that many bytes of name, followed by a 32-bit
+        value length, followed by that many bytes of value.   If the
+        length is zero, this is a value of the blank string.   If the
+        length is all ones (2^32-1), then there is no value - for an
+        update, this means the value for this name and the name
+        itself should be deleted from the object, which may or may
+        not be possible.   The list of name/value pairs ends with a
+        zero-length name, which is not followed by a value
+        length/value pair.
+
+obj values = a series of name+value pairs, as above, specific to the
+       object being created, updated or refreshed.
+
+signature = authlen bytes of data signing the message.   The signature
+           algorithm is a property of the authenticator handle.
+
+Message types:
+
+1: open
+   relevant input values:
+       object-type = the name of the type of object
+       open:create = boolean - create the object if it doesn't yet exist
+       open:exclusive = boolean - don't open the object if it does exist
+       open:update = boolean - update the object with included values
+                     if it matches.
+       the handle should always be the null handle
+
+   The input value must also contain key information for the type of
+   object being searched that uniquely identifies an object, or search
+   information that matches only one object.  Each object has a key
+   specification (a key is something that uniquely identifies an
+   object), so see the key specification for that object to see
+   what to send here.   An open message with the create flag set must
+   specify a key, and not merely matching criteria.   Some objects may
+   allow more than one key, and it may be that the union of those keys
+   is required to uniquely identify the object, or it may be that any
+   one such key will uniquely identify the object.   The documentation
+   for the type of object will specify this.
+
+   An open message will result in an immediate response message whose
+   opcode will either be "error" or "update".   The error message may
+   include an error:reason value containing a text string explaining
+   the error, and will always include an error:code value which will
+   be the numeric error code for what went wrong.   Possible error
+   codes are:
+
+       not found - no such object exists
+       already exists - object already exists, and exclusive flag was
+                        set.
+       not unique - more than one object matching the specification
+                    exists.
+       permission denied - the authenticator ID specified does not
+                           have authorization to access this object,
+                           or if the update flag was specified, to
+                           update the object.
+
+   If the response is an update message, the update message will
+   include the object handle and all of the name/value pairs
+   associated with that object.
+
+2: refresh
+
+   no input values except the handle need be specified.   The null
+   handle may not be specified.   If the handle is valid, and the
+   authenticator ID specified has permission to examine the object,
+   then an update message will be sent for that object.   Otherwise,
+   one of the following errors will be sent:
+
+       invalid handle - the handle does not refer to a known object
+       permisson denied - the handle refers to an object that the
+                          requestor does not have permission to
+                          examine. 
+
+3: update
+
+   Requests that the contents of the specified object be updated with
+   the values included.   Values that are not specified are not
+   updated.   The response will be either an error message or an
+   update-ok message.   If rid is nonzero, no response will be
+   generated, even if there was an error.   Possible errors include:
+
+       invalid handle - no such object was found
+       permission denied - the handle refers to an object that the
+                           requestor does not have permission to
+                           modify.
+       not confirmed - the update could not be committed due to some
+                       kind of resource problem, for example
+                       insufficient memory or a disk failure.
+
+4: notify
+
+   Requests that whenever the object with the specified handle is
+   modified, an update be sent.   If there is something wrong with the
+   request, an error message will be returned immediately.
+   Otherwise, whenever a change is made to the object, an update
+   message will be sent containing whatever changes were made (or
+   possibly all the values associated with the object, depending on
+   the implementation).   Possible errors:
+
+       invalid handle
+       permission denied - the handle refers to an object that the
+                           requestor does not have permission to
+                           examine.
+       not supported - the object implementation does not support
+                       notifications
+
+5: status
+
+   Sends a status code in response to a message.  Always sent in
+   response to a message sent by the other side.  There should never
+   be a response to this message.
+
+6: notify-cancel
+
+   Like notify, but requests that an existing notification be cancelled.
+
+7: notify-cancelled
+
+   Indicates that because of a local change, a notification that had
+   been registered can no longer be performed.   This could be as a
+   result of the permissions on a object changing, or an object being
+   deleted.   There should never be a response to this message.
+
+8: delete
+
+   Deletes the specified object.   Response will be either request-ok,
+   or error.   Possible errors include:
+
+       invalid handle - no such object was found
+       permission denied - the handle refers to an object that the
+                           requestor does not have permission to
+                           modify.
+       not confirmed - the deletion could not be committed due to
+                       some kind of resource problem, for example
+                       insufficient memory or a disk failure.
+
+internals:
+
+Both client and server use same protocol and infrastructure.   There
+are many object types, each of which is stored in a registry.
+Objects whose type is not recognized can either be handled by the
+generic object type, which is registered with the type "*".   If no
+generic object type is registered, then objects with unknown types are
+simply not supported.   On the client, there are probably no special
+object handlers (although this is by no means forbidden).   On the
+server, probably everything is a special object.
+
+Each object type has the following methods:
+
+
+
+
+dhcpctl_status dhcpctl_connect (dhcpctl_handle *connection,
+                               char *server_name, int port,
+                               dhcpctl_handle *authinfo)
+       synchronous
+       returns nonzero status code if it didn't connect, zero otherwise
+       stores connection handle through connection, which can be used
+       for subsequent access to the specified server. 
+       server_name is the name of the server, and port is the TCP
+       port on which it is listening.
+       authinfo is the handle to an object containing authentication
+       information.
+
+dhcpctl_status dhcpctl_open_object (dhcpctl_handle h,
+                                   dhcpctl_handle connection,
+                                   int flags)
+       asynchronous - just queues the request
+       returns nonzero status code if open couldn't be queued
+       returns zero if open was queued
+       h is a handle to an object created by dhcpctl_new_object
+       connection is a connection to a DHCP server
+       flags include:
+          DHCPCTL_CREATE - if the object doesn't exist, create it
+          DHCPCTL_UPDATE - update the object on the server using the
+                           attached parameters 
+          DHCPCTL_EXCL - error if the object exists and DHCPCTL_CREATE
+                         was also specified
+
+dhcpctl_status dhcpctl_new_object (dhcpctl_handle *h,
+                                  dhcpctl_handle connection,
+                                  char *object_type)
+       synchronous - creates a local handle for a host entry.
+       returns nonzero status code if the local host entry couldn't
+       be created
+       stores handle to host through h if successful, and returns zero.
+       object_type is a pointer to a NUL-terminated string containing
+       the ascii name of the type of object being accessed - e.g., "host"
+
+dhcpctl_status dhcpctl_set_callback (dhcpctl_handle h, void *data,
+                                    void (*callback) (dhcpctl_handle,
+                                                      dhcpctl_status, void *))
+       synchronous, with asynchronous aftereffect
+       handle is some object upon which some kind of process has been
+       started - e.g., an open, an update or a refresh.
+       data is an anonymous pointer containing some information that
+       the callback will use to figure out what event completed.
+       return value of 0 means callback was successfully set, a nonzero
+       status code is returned otherwise.
+       Upon completion of whatever task is in process, the callback
+       will be passed the handle to the object, a status code
+       indicating what happened, and the anonymous pointer passed to 
+
+dhcpctl_status dhcpctl_wait_for_completion (dhcpctl_handle h,
+                                           dhcpctl_status *s)
+       synchronous
+       returns zero if the callback completes, a nonzero status if
+       there was some problem relating to the wait operation.   The
+       status of the queued request will be stored through s, and
+       will also be either zero for success or nonzero for some kind
+       of failure.    Never returns until completion or until the
+       connection to the server is lost.   This performs the same
+       function as dhcpctl_set_callback and the subsequent callback,
+       for programs that want to do inline execution instead of using
+       callbacks.
+
+dhcpctl_status dhcpctl_get_value (data_string *result,
+                                 dhcpctl_handle h, char *value_name)
+       synchronous
+       returns zero if the call succeeded, a nonzero status code if
+       it didn't. 
+       result is the address of an empty data string (initialized
+       with bzero or cleared with data_string_forget).   On
+       successful completion, the addressed data string will contain
+       the value that was fetched.
+       dhcpctl_handle refers to some dhcpctl item
+       value_name refers to some value related to that item - e.g.,
+       for a handle associated with a completed host lookup, value
+       could be one of "hardware-address", "dhcp-client-identifier",
+       "known" or "client-hostname".
+
+dhcpctl_status dhcpctl_get_boolean (int *result,
+                                   dhcpctl_handle h, char *value_name)
+       like dhcpctl_get_value, but more convenient for boolean
+       values, since no data_string needs to be dealt with.
+
+dhcpctl_status dhcpctl_set_value (dhcpctl_handle h, data_string value,
+                                 char *value_name)
+       Sets a value on an object referred to by a dhcpctl_handle.
+       The opposite of dhcpctl_get_value.   Does not update the
+       server - just sets the value on the handle.
+
+dhcpctl_status dhcpctl_set_string_value (dhcpctl_handle h, char *value,
+                                        char *value_name)
+       Sets a NUL-terminated ASCII value on an object referred to by
+       a dhcpctl_handle.   like dhcpctl_set_value, but saves the
+       trouble of creating a data_string for a NUL-terminated string.
+       Does not update the server - just sets the value on the handle.
+
+dhcpctl_status dhcpctl_set_boolean (dhcpctl_handle h, int value,
+                                   char *value_name)
+       Sets a boolean value on an object - like dhcpctl_set_value,
+       only more convenient for booleans.
+
+dhcpctl_status dhcpctl_object_update (dhcpctl_handle h)
+       Queues an update on the object referenced by the handle (there
+       can't be any other work in progress on the handle).   An
+       update means local parameters will be sent to the server.
+
+dhcpctl_status dhcpctl_object_refresh (dhcpctl_handle h)
+       Queues an update on the object referenced by the handle (there
+       can't be any other work in progress on the handle).   An
+       update means local parameters will be sent to the server.
+
+So a sample program that would update a host declaration would look
+something like this:
+
+       /* Create a local object into which to store authentication
+          information. */
+       if ((status = dhcpctl_new_object (&auth, dhcpctl_null_handle,
+                                         "authentication-information")))
+               dhcpctl_error ("Can't create authentication information: %m");
+
+       /* Set up the authenticator with an algorithm type, user name and
+          password. */
+       if ((status = dhcpctl_set_string_value (&auth, "mellon", "username")))
+               dhcpctl_error ("Can't set username: %m", status);
+       if ((status = dhcpctl_set_string_value (&auth, "three blind mice",
+                                               "password")))
+               dhcpctl_error ("Can't set password: %m", status);
+       if ((status = dhcpctl_set_string_value (&auth, "md5-hash",
+                                               "algorithm")))
+               dhcpctl_error ("Can't set authentication algorithm: %m.",
+                              status);
+
+       /* Connect to the server. */
+       if ((status = dhcpctl_connect (&c, "dhcp.server.com", 612, &auth)))
+
+               dhcpctl_error ("Can't connect to dhcp.server.com: %m",
+                              status);
+
+       /* Create a host object. */
+       if ((status = dhcpctl_new_object (&hp, c, "host")))
+               dhcpctl_error ("Host create failed: %m", status);
+
+       /* Create a data_string to contain the host's client
+          identifier, and set it. */
+       if ((status =
+            data_string_create_from_hex (&client_id,
+                                         "1:08:00:2b:34:1a:c3")))
+               dhcpctl_error ("Can't create client identifier: %m");
+       if ((status = dhcpctl_set_value (hp, client_id,
+                                        "dhcp-client-identifier")))
+               dhcpctl_error ("Host client identifier set failed.");
+       /* Set the known flag to 1. */
+       if ((status = dhcpctl_set_boolean (hp, 1, "known")))
+               dhcpctl_error ("Host known set failed.");
+
+       /* Open an existing host object that matches the client identifier,
+          and update it from the local context, or if no host entry
+          yet exists matching the identifier, create one and
+          initialize it. */
+       if ((status = dhcpctl_open_object (&hp, c,
+                                          DHCPCTL_CREATE | DHCPCTL_UPDATE)))
+               dhcpctl_error ("Can't open host: %m", status);
+
+       /* Wait for the process to complete, check status. */
+       if ((status = dhcpctl_wait_for_completion (hp, &wait_status)))
+               dhcpctl_error ("Host create/lookup wait failed: %m", status);
+       if (waitstatus)
+               dhcpctl_error ("Host create/lookup failed: %m", status);
+
+The API is a bit complicated, for a couple of reasons.   I want to
+make it general, so that there aren't a bazillion functions to call,
+one for each data type.   I want it to be thread-safe, which is why
+each function returns a status and the error printer requires a status
+code for input.   I want it to be possible to make it asynchronous, so
+that it can work in tandem with, for example, an X toolkit.   If
+you're just writing a simple update cgi program, you probably won't
+want to bother to use the asynchronous callbacks, and indeed the above
+example doesn't.
+
+I glossed over data strings above - basically, they're objects with a
+pointer to a reference-counted buffer structure, an offset into that
+buffer, and a length.   These are used within the DHCP server, so you
+can get an idea of how they work - basically, they're a convenient and
+efficient way to store a string with a length such that substrings can
+easily be taken and such that more than one user at a time can have a
+pointer to the string.
+
+I will also probably add locking primitives, so that you can get the
+value of something and be sure that some other updator process won't
+modify it while you have the lock.