diff options
author | Ted Lemon <source@isc.org> | 1999-09-09 21:12:44 +0000 |
---|---|---|
committer | Ted Lemon <source@isc.org> | 1999-09-09 21:12:44 +0000 |
commit | 36c6e2b61b1500fb72f5b9bb9cc1239d0e0096a4 (patch) | |
tree | 7c145605352f0bc130b533c9c01cd7fe2ea85ec9 /doc | |
parent | 808db3d367cb9b8dd778974aa34cddd9f4a36de4 (diff) | |
download | isc-dhcp-36c6e2b61b1500fb72f5b9bb9cc1239d0e0096a4.tar.gz |
OMAPI specification.
Diffstat (limited to 'doc')
-rw-r--r-- | doc/api+protocol | 428 |
1 files changed, 428 insertions, 0 deletions
diff --git a/doc/api+protocol b/doc/api+protocol new file mode 100644 index 00000000..9423b225 --- /dev/null +++ b/doc/api+protocol @@ -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. |