Table of Contents
This is a document of the API for defining and utilizing multiple security and transport mechanisms for the Amanda network protocol.
The goal of this API is to allow several different forms of communication and authentication to exist between the Amanda server and its clients.
There exist many potential ways that a user might wish to grant access to the Amanda daemon. The two currently supported are BSD (reserved port) and Kerberos IV security. The current implementation of these two methods is not very general, and adding additional methods requires a large amount of code to be modified.
Additionally, the current methods require the protocol and dump transport to be transmitted across the network using a pre-defined method. The Amanda protocol currently must be sent using udp datagrams to a well-known port, and the dumps are transported using tcp connections between ports negotiated via the protocol.
The security API was designed to be a layer in between the core logic of Amanda and the transport and authentication of the protocol and dumps.
The component server and client programs now deal with abstract concepts instead of concrete udp and tcp handles.
The prefix "security_" is reserved for use as the namespace of this API.
These functions exist for transmitting pkt_t's between the client and server.
These functions operate on security_handle_t objects. These objects are described later.
const security_driver_t *security_getdriver(const char *drivername);
Given a security type ("KRB4", "BSD", "SSH", etc), returns a pointer to that type's security_driver_t (section 4.1), or NULL if no driver exists.
void security_connect(const security_driver_t *h, const char *hostname, char *(*conf_fn)(char *arg, void *arg), void (*fn)(void *arg, security_handle_t *h, security_status_t s), void *arg);
Given a security driver, and a hostname, calls back with a security_handle_t (section 4.2) that can be used to communicate with that host. The status arg to the callback is reflects the success of the request. Error messages can be had via security_geterror().
This is expected to be the Amanda server's interface for setting up connections to clients.
conf_fn is used to determine configuration information. If NULL, no configuration information is available.
void security_accept(const security_driver_t *h, int in, int out, void (*callback)(security_handle_t *, pkt_t *));
Given a security driver, an input file descriptor, and an output file descriptor, and a callback, when new connections are detected on the given file descriptors, the function is called with a newly created security handle and the initial packet received.
This is expected to be the Amanda daemon's interface for setting up incoming connections from the Amanda server. The file descriptors are typically 0 and 1 (stdin/stdout).
This function uses the event interface, and only works properly when event_loop() is called later in the program.
void security_close(security_handle_t *h);
Closes a connection created by a security_connect() or security_accept().
int security_sendpkt(security_handle_t *h, const pkt_t *pkt);
Transmits a pkt_t over a security handle. Returns 0 on success, or negative on error. A descriptive error message can be obtained via security_geterror().
int security_recvpkt(security_handle_t *h, void (*callback)(void *arg, pkt_t *pkt, security_status_t), void *arg, int timeout);
Requests that when incoming packets arrive for this handle, the given function is called with the given argument, the received packet, and the status of the reception.
If a packet does not arrive within the number of seconds specified in the 'timeout' argument, RECV_TIMEOUT is passed in the status argument of the timeout.
On receive error, the callback's status argument will be set to RECV_ERROR. An error message can be retrieved via security_geterror().
On successful reception, RECV_OK will be passed in the status argument, and the pkt argument will point to a valid packet.
This function uses the event interface. Callbacks will only be generated when event_loop() is called.
int security_recvpkt_cancel(security_handle_t *h);
Cancels a previous recvpkt request for this handle.
const char *security_geterror(security_handle_t *h);
Returns a descriptive error message for the last error condition on this handle.
void security_seterror(security_handle_t *h, const char *msg, ...);
Sets the string that security_geterror() returns.
These functions exist for transmitting random data over a stream-like connection.
These functions operate on security_stream_t objects, which are described later.
security_stream_t *security_stream_server(security_handle_t *h);
Creates the server end of a security stream, and will receive a connection from the host on the other end of the security handle passed.
Returns a security_stream_t on success, and NULL on error. Error messages can be obtained by calling security_geterror() on the security handle associated with this stream.
int security_stream_accept(security_stream_t *);
Given a security stream created by security_stream_server, blocks until a connection is made from the remote end.
Returns 0 on success, and -1 on error. Error messages can be obtained by calling security_stream_geterror().
security_stream_t *security_stream_client(security_handle_t *h, int id);
Creates the client end of a security stream, and connects it to the machine on the other end of the security handle. The 'id' argument identifies which stream on the other end to connect to.
Returns a security_stream_t on success, and NULL on error. Error messages can be obtained by calling security_geterror() on the security handle associated with this stream.
void security_stream_close(security_stream_t *s);
Closes a security stream and frees up resources associated with it.
int security_stream_auth(security_stream_t *s);
Authenticate a connected security stream.
Returns 0 on success, and -1 on error. Error messages can be obtained by calling security_stream_geterror().
int security_stream_id(security_stream_t *s);
Returns an identifier which can be used to connect to this security stream with security_stream_client().
Typical usage would be for one end of a connection to create a stream with security_stream_server(), and then transmit the id for that stream to the other side. The other side will then connect to that id with security_stream_client().
int security_stream_write(security_stream_t *s, const void *buf, size_t bufsize);
Writes a chunk of data to the security stream. Returns 0 on success, or negative on error. Error messages can be obtained by calling security_stream_geterror().
void security_stream_read(security_stream_t *s, void (*callback)(void *arg, void *buf, int bufsize), void *arg);
Requests that when data is ready to be read on this stream, the given function is called with the given arg, a buffer full of data, and the size of that buffer.
On error, the bufsize will be negative. An error message can be retrieved by calling security_stream_geterror().
This function uses the event interface. Callbacks will only be generated while in event_loop().
void security_stream_read_cancel(security_stream_t *s);
Cancels a previous read request.
const char *security_stream_geterror(security_stream_t *h);
Returns a descriptive error message for the last error condition on this stream.
All visible data types are meant to be opaque to the caller. At no time should a caller have to access a member of any data type directly. The API should always be used instead.
This is a static object containing function vectors that implement the API for a particular security type.
This is an object that describes a protocol connection to a remote server. There is one security_handle_t per request, and there can be many to the same remote host.
This is an object that describes a data connection to a remote host. It is always associated and derived from a security_handle_t. Arbitrary data can be passed over a security stream.
This is an enumerated type that is passed to the callback of security_recvpkt and security_connect. The possible values it can have are:
S_OK - the pkt_t was received fine S_TIMEOUT - no pkt_t was received within the time specified in the timeout argument to security_recvpkt(). S_ERROR - an error occurred during reception. Call security_geterror() for more information.
Each security type is defined by a struct of function vectors. These methods implement the details of this security type.
This section will document each element of security_driver_t.
const char *name;
This is the name of the driver. This is used by security_getdriver() to associate a name with a driver type.
void (*connect)(const char *hostname, void (*fn)(void *, security_handle_t *, security_status_t), void *);
This is the implementation of security_connect(). It actually sets up the connection, and then returns a structure describing the connection. The first element of this structure MUST be a security_handle_t, because it will be cast to that after it is passed up to the caller.
The first argument is the host to connect to. The second argument is a function to call when a connection is made. The third argument is passed to the callback.
The callback takes three arguments. The first is the caller supplied void pointer. The second is a newly allocated security handle. The third is a security_status_t flag indicating the success or failure of the operation.
void (*accept)(int in, int out, void (*callback)(security_handle_t *handle, pkt_t *pkt));
This is the implementation of security_accept(). It is passed the input and output file descriptors and a callback. The callback takes a security handle argument and also an initial packet received for that handle.
int (*sendpkt)(void *handle, pkt_t *pkt);
The implementation of security_sendpkt(). Security information is usually added by the driver before transmission.
void (*recvpkt)(void *handle, void (*callback)(void *arg, pkt_t *pkt, security_status_t), void *arg);
The implementation of security_recvpkt(). It will typically be layered onto the event interface somehow. It can assume that a caller will eventually call event_loop().
void (*recvpkt_cancel)(void *handle);
The implementation of security_recvpkt_cancel(). Drivers should allow this to be run even if no recvpkt was scheduled, or if one was previously cancelled.
void *(*stream_server)(void *handle);
Implementation of security_stream_server(). This function returns a object describing the stream. The first member of this object MUST be a security_stream_t, because it will be cast to that.
int (*stream_accept)(void *stream);
After calling stream_server, stream_accept must be called on the stream before it is fully connected.
void *(*stream_client)(void *handle, int id);
Implementation of security_stream_client(). The id argument is something returned by security_stream_id(). Again, the handle is referenced counted.
This function returns a object describing the stream. The first member of this object MUST be a security_stream_t, because it will be cast to that.
int (*stream_id)(void *stream);
Return a unique id for this stream. This is to be used by stream_client() to connect to this stream.
int (*stream_write)(void *stream, const void *buf, size_t bufsize);
Implementation of security_stream_write.
void (*stream_read)(void *stream, void (*callback)(void *arg, void *buf, int bufsize), void *arg);
Implementation of security_stream_read.