Chapter 26. Amanda Security API

Mike Grupenhoff

Original text
AMANDA Core Team

Stefan G. Weichinger

XML-conversion;Updates
AMANDA Core Team

Table of Contents

Introduction
The Problem
The API
protocol packet transmission functions
stream functions
Data Types
security_driver_t
security_handle_t
security_stream_t
security_status_t
SECURITY DRIVERS
name
connect
accept
close
sendpkt
recvpkt
recvpkt_cancel
stream_server
stream_accept
stream_client
stream_close
stream_auth
stream_id
stream_write
stream_read
stream_read_cancel

Introduction

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.

The Problem

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 API

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.

protocol packet transmission functions

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.

security_getdriver

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.

security_connect

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.

security_accept

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.

security_close

void security_close(security_handle_t *h);

Closes a connection created by a security_connect() or security_accept().

security_sendpkt

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().

security_recvpkt

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.

security_recvpkt_cancel

int security_recvpkt_cancel(security_handle_t *h);

Cancels a previous recvpkt request for this handle.

security_geterror

const char *security_geterror(security_handle_t *h);

Returns a descriptive error message for the last error condition on this handle.

security_seterror

void security_seterror(security_handle_t *h, const char *msg, ...);

Sets the string that security_geterror() returns.

security_handleinit

void security_handleinit(security_handle_t *, const security_driver_t *);

Initializes a security_handle_t. This is meant to be called only by security drivers to initialize the common part of a newly allocated security_handle_t.

stream functions

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_server

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.

security_stream_accept

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_client

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.

security_stream_close

void security_stream_close(security_stream_t *s);

Closes a security stream and frees up resources associated with it.

security_stream_auth

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().

security_stream_id

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().

security_stream_write

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().

security_stream_read

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().

security_stream_read_cancel

void security_stream_read_cancel(security_stream_t *s);

Cancels a previous read request.

security_stream_geterror

const char *security_stream_geterror(security_stream_t *h);

Returns a descriptive error message for the last error condition on this stream.

security_stream_seterror

void security_stream_seterror(security_stream_t *h, const char *msg, ...);

Sets the string that security_stream_geterror() returns.

Data Types

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.

security_driver_t

This is a static object containing function vectors that implement the API for a particular security type.

security_handle_t

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.

security_stream_t

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.

security_status_t

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.

SECURITY DRIVERS

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.

name

const char *name;

This is the name of the driver. This is used by security_getdriver() to associate a name with a driver type.

connect

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.

accept

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.

close

void (*close)(void *handle);

The implementation of security_close().

sendpkt

int (*sendpkt)(void *handle, pkt_t *pkt);

The implementation of security_sendpkt(). Security information is usually added by the driver before transmission.

recvpkt

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().

recvpkt_cancel

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.

stream_server

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.

stream_accept

int (*stream_accept)(void *stream);

After calling stream_server, stream_accept must be called on the stream before it is fully connected.

stream_client

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.

stream_close

void (*stream_close)(void *stream);

Close and free up resources for an open stream.

stream_auth

int (*stream_auth)(void *stream);

Authenticate a connected stream.

stream_id

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.

stream_write

int (*stream_write)(void *stream, const void *buf, size_t bufsize);

Implementation of security_stream_write.

stream_read

void (*stream_read)(void *stream, void (*callback)(void *arg, void *buf, int bufsize), void *arg);

Implementation of security_stream_read.

stream_read_cancel

void (*stream_read_cancel)(void *stream);

Implementation of security_stream_read_cancel.

Note

Refer to http://www.amanda.org/docs/security-api.html for the current version of this document.