     [file version.texi not included]

This file documents the use and the internals of Assuan.

This is Edition EDITION, last updated UPDATED, of The `Developing with Assuan' Manual, for Version VERSION.

Published by the Free Software Foundation

51 Franklin Street, Fifth Floor

Boston, MA 02110-1301 USA

Copyright © 2002, 2003, 2006 Free Software Foundation, Inc.

Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version. The text of the license can be found in the
section entitled ``Copying''.

Introduction
************

This manual documents how to exploit the Assuan library, a simple interprocess communcation library.

Introduction to Assuan
**********************

In an ideal world, Assuan is irrelevant.  Assuan's primary use is to allow a client to interact with a non-persistent server.  Using Assuan, this is accomplished by forking a subprocess and communicating with it via, for example, a pipe or unix domain socket.  This method is neither elegant nor efficient especially when there is a lot of data spread across several transactions: not only is there a penalty for an increased number of context switches, but also a significant amount of data is MEMCPYed from the client to a file descriptor and from the file descriptor to the server.  Despite these and other disadvantages, this type of client/server communication can be useful: the client is completely separate from the server; they are in different address spaces.  This is especially important in situations where the server must have a known degree of reliability and data must be protected: as the Assuan protocol is well defined and clients cannot corrupt the servers' address space, auditing become much easier.

Assuan was developed for use by the GNU Privacy Guard, GnuPG, to prevent potentially buggy clients from unwittingly corrupting sensitive transactions or compromising data such as a secret key. Assuan permits the servers, which do the actual work, e.g. encryption and decryption of data using a secret key, to be developed independently of the user interfaces, e.g. mail clients and other encryption front ends.  Like a shared library, the interface is well defined and any number of front ends can use it; however, unlike a shared library, the client cannot see or touch the server's data.  As with any modular system, Assuan helps keep the servers small and understandable help to make code more understandable and less error prone.

Assuan is not, however, limited to use with GnuPG servers and clients: it was design to be flexible enough to meet the demands of almost any transaction based environment with non-persistent servers.

Description of the Assuan protocol.
***********************************

The architecture of the modular GnuPG system is based on several highly specialized modules which compose a network of client/server communication.  A common framework for intermodule communication is therefore needed and should be implemented in a library.

Goals:

  * Common framework for module communication

  * Easy debugging

  * Easy module testing

  * Extendible

  * Optional authentication and encryption facility

  * Usable to access external hardware

Design criteria:

  * Client server with back channel

  * Use a mainly text based protocol

  * Escape certain control characters

  * Allow indefinite data length

  * Request confidentiality for parts of the communication

  * Dummy module to allow direct linking of client and server

  * Inline data or descriptor passing for bulk data

  * No protection against DoS needed

  * Subliminal channels are not an issue

Implementation
**************

The implementation is line based with a maximum line size of 1000 octects.  The default IPC mechanism are Unix Domain Sockets.

On a connect request the server responds either with an okay or an error status.  For authentication check the server may send an Inquiry Response prior to the first Okay, it may also issue Status messages. The server must check that the client is allowed to connect, this is done by requesting the credentials for the peer and comparing them to those of the server.  This avoids attacks based on wrong socket permissions.

It may choose to delay the first response in case of an error.  The server never closes the connection - however the lower protocol may do so after some time of inactivity or when the connection is in an error state.

All textual messages are assumed to be in UTF-8 unless otherwise noted.

Server responses
================

OK  [<arbitary debugging information>]
     Request was successful.

ERR ERRORCODE [<human readable error description>]
     Request could not be fulfilled.  The error codes are mostly application specific except for a few common ones.

S KEYWORD <status information depending on keyword>
     Informational output by the server, still processing the request.

# <string>
     Comment line issued only for debugging purposes.  Totally ignored.

D <raw data>
     Raw data returned to client. There must be exactly one space after the 'D'.  The values for '%', CR and LF must be percent escaped; this is encoded as %25, %0D and %0A.  Only uppercase letters should be used in the hexadecimal representation.  Other characters may be percent escaped for easier debugging.  All these Data lines are considered one data stream up to the OK or ERR response.  Status and Inquiry Responses may be mixed with the Data lines.

INQUIRE KEYWORD> <parameters>
     Server needs further information from the client.  The client should answer with a command which is allowed after an inquiry.  Note that the server does not confirm that client command but either continues processing or ends processing with an error status.  Not all commands are allowed.

A client should only check the first letter of each line and then skip over to the next token (except for data lines where the raw data starts exactly after 2 bytes).  Lines larger than 1000 bytes should be treated as a communication error. (The rationale for having a line length limit is to allow for easier multiplexing of several channels).

Client requests
===============

The server waits for client requests after he sent an Okay or Error. The client should not issue a request in other cases.

     COMMAND <parameters>

COMMAND is a one word string without preceding white space. Parameters are command specific, CR, LF and the percent signs should be percent escaped as described above.  To send a backslash as the last character it should also be percent escaped.  Percent escaping is allowed anywhere in the parameters but not in the command.  The line ends with a CR, LF or just a LF.

Not yet implemented feature: If there is a need for a parameter list longer than the line length limit (1000 characters including command and CR, LF), the last character of the line (right before the CR/LF or LF) must be a non-escape encoded backslash. The following line is then expected to be a continuation of the line with the backslash replaced by a blank and the line ending removed.

     D <raw data>

Raw data to the server. There must be exactly one space after the 'D'. The values for '%', CR and LF must be percent escaped; this is encoded as %25, %0D and %0A.  Only uppercase letters should be used in the hexadecimal representation.  Other characters may be percent escaped for easier debugging.  All these Data lines are considered one data stream up to the OKAY or ERROR response.  Status and Inquiry Responses may be mixed with the Data lines.

     END

Lines beginning with a # or empty lines are ignored.  This is useful to comment test scripts.

Although the commands are application specific, some of them are used by all protocols and partly directly supported by the Assuan library:

CANCEL
     This command is used for future extenxions.  It may today be used to cancel outstanding requests in an asynchronous protocol.

BYE
     Close the connect, the server will reply with an OK.

AUTH
     Not yet specified as we don't implement it in the first phase.  See my mail to gpa-dev on 2001-10-25 about the rationale for measurements against local attacks.

RESET
     Reset the connection but not any existing authentication.  The server should release all resources associated with the connection.

END
     Used by a client to mark the end of raw data.  The server may send END to indicate a partial end of data.

HELP
     Reserved for future extensions.

QUIT
     Reserved for future extensions.

Error codes
===========

Here we keep a list of error codes used in any Assuan based protocol.  The format is the string ERR, white space, the error number, white space, a textual description of the error.

General error codes pertaining to the actual Assuan operations:

0  Success

1  General error

2  Out of core

3  Invalid value

4  Timeout

5  Read error

6  Write error

7  Problem starting server

8  Not a server

9  Not a client

10 Nested commands

11 Invalid response

12 No data callback

13 No inquire callback

14 Connect failed

15 Accept failed

Error codes used as status codes in the Assuan protocol:

100 Not implemented

101 Server fault (catch all error code)

102 Invalid command

103 Unknown command

104 Syntax error

105 Parameter error

106 Parameter conflict

107 Line too long

108 Line not terminated

109 No input

110 No output

111 Canceled

112 Unsupported algorithm

113 Server resource problem

114 Server I/O error

115 Server bug

116 No data available

117 Invalid data

118 Unexpected command

119 Too much data

120 Inquire unknown

121 Inquire error

122 Invalid option

123 Invalid index

124 Unexpected status

125 Unexpected data

126 Invalid status

128 Not confirmed

For historical reasons a few more error codes are defined in assuan.h; they should not be used by new applications.

Errror codes in the range ASSUAN_USER_ERROR_FIRST to ASSUAN_USER_ERROR_LAST may be used at the applications own discretion. Error codes greater than 65535 are not defined by Assuan and may also be used by applications --- note that the GnuPG system maps libgpg-error codes into this range.

Preparation
***********

To use `LIBASSUAN', you have to perform some changes to your sources and the build system.  The necessary changes are small and explained in the following sections.

Header
======

All interfaces (data types and functions) of LIBASSUAN are defined in the header file assuan.h.  You must include this in all source files using the library, either directly or through some other header file, like this:

     #include <assuan.h>

The name space of `ASSUAN' is assuan_* for function and type names and ASSUAN* for other symbols.  In addition the same name prefixes with one prepended underscore are reserved for internal use and should never be used by an application.

Building sources
================

If you want to compile a source file including the assuan.h header file, you must make sure that the compiler can find it in the directory hierarchy.  This is accomplished by adding the path to the directory in which the header file is located to the compilers include file search path (via the -I option).

However, the path to the include file is determined at the time the source is configured.  To solve this problem, LIBGCRYPT ships with a small helper program libassuan-config that knows the path to the include file and other configuration options.  The options that need to be added to the compiler invocation at compile time are output by the --cflags option to libassuan-config.  The following example shows how it can be used at the command line:

     gcc -c foo.c $(libassuan-config --cflags)

Adding the output of libassuan-config --cflags to the compiler's command line will ensure that the compiler can find the assuan.h header file.

A similar problem occurs when linking the program with the library. Again, the compiler/linker has to find the library files.  For this to work, the path to the library files has to be added to the library search path (via the -L option).  For this, the option --libs to libassuan-config can be used.  For convenience, this option also outputs all other options that are required to link the program with the LIBASSUAN libraries (in particular, the -lassuan option).  The example shows how to link foo.o with the LIBASSUAN library to a program foo.

     gcc -o foo foo.o $(libassuan-config --libs)

Of course you can also combine both examples to a single command by specifying both options to libassuan-config:

     gcc -o foo foo.c $(libassuan-config --cflags --libs)

Building sources using Automake
===============================

It is much easier if you use GNU Automake instead of writing your own Makefiles.  If you do that you do not have to worry about finding and invoking the libassuan-config script at all.  LIBASSUAN provides an Automake macro that does all the work for you.

 -- Macro: AM_PATH_LIBASSUAN ([minimum-version], [action-if-found], [action-if-not-found])
     Check whether LIBASSUAN (at least version MINIMUM-VERSION, if given) exists on the host system.  If it is found, execute ACTION-IF-FOUND, otherwise do ACTION-IF-NOT-FOUND, if given.

     Additionally, the function defines LIBASSUAN_CFLAGS to the flags needed for compilation of the program to find the assuan.h header file, and LIBASSUAN_LIBS to the linker flags needed to link the program to the LIBASSUAN library.

You can use the defined Autoconf variables like this in your Makefile.am:

     AM_CPPFLAGS = $(LIBASSUAN_CFLAGS)
     LDADD = $(LIBASSUAN_LIBS)

Multi Threading
===============

The LIBGCRYPT library is thread-safe if you adhere to the following requirements:

  * Run the initialization functions before you actually start to use threads.

  * Only one thread at a time may access an LIBASSUAN context.

  * Use assuan_set_assuan_log_stream to setup a default log stream.

Generalities
************

Data Types used by the library
==============================

LIBASSUAN uses a context approach to keep state.  The following data type is used all over the place:

 -- Data type: assuan_context_t
     The assuan_context_t type is a pointer to an object mainted internally by the library.  Certain Assuan functions allocate such a context and return it to the caller using this data type. Other functions take this data type to access the state created by these functions.

For compatibility with older versions of LIBASSUAN a data type for error return values exists:

 -- Data type: assuan_error_t
     This has orginally been an enum but applications should either view it as an int or if possible use the gpg_error_t data type as defined by the LIBGPG-ERROR package.

Initializing the library
========================

In general the library requires no initialization.  There are however some initialization hooks provided which aren often useful.  These should be called as early as possible and in a multi-threaded application before a second thread is created.

If your application uses its own memory allocation functions or wrappers it is good idea to tell LIBASSUAN about it so it can make use of the same functions or wrappers.  You do this with

 -- Function: void assuan_set_malloc_hooks (void *(*MALLOC_FUNC)(size_t), void *(*REALLOC_FUNC)(void *, size_t), void (*FREE_FUNC)(void*))
     You need to provide all three functions.  Those functions need to behave exactly as their standard counterparts (malloc, realloc and free).  If you write your own functions please take care to set errno whenever an error has occured.

To integrate assuan logging and diagnostics into your own logging system, you may use the following two functions:

 -- Function: void assuan_set_assuan_log_stream (FILE *FP)
     This sets the stream to which LIBASSUAN should log messages not associated with a specific context to FP.  The default is to log to stderr.  This default value is also changed by using assuan_set_log_stream (to set a logging stream for a specific context) unless this function has been used.  Obviously this is not thread-asfe and thus it is highly recommended to use this function to setup a proper default.

 -- Function: void assuan_set_assuan_log_prefix (const char *TEXT)
     Set the prefix to be used at the start of a line emitted by assuan on the log stream to TEXT.  The default is the empty string.

If you intend to use LIBASSUAN along with the package LIBGPG-ERROR it is recommended to switch LIBASSUAN into a mode which directly makes use of error codes provided by LIBGPG-ERROR. Because the Assuan error codes and those of gpg-error overlap, it is required to explictly request this.  You do this by calling the function

 -- Function: void assuan_set_assuan_err_source (int ERRSOURCE)
     Enable gpg-error style error codes.  ERRSOURCE is one of the gpg-error sources.  Switching back to the old style mode is not possible.  The usual way to call this function is

          assuan_set_assuan_err_source (GPG_ERR_SOURCE_DEFAULT);

How to communicate with the peer
================================

What would be a IPC library without the ability to read and write data? Not very useful.  Libassuan has high level functions to take care of of the more boring stuff but eventully actually data needs to be written.

The basic read and write functions are:

 -- Function: assuan_error_t assuan_read_line (assuan_context_t CTX, char **LINE, size_t *LINELEN)

     Read the next line from the client or server and store a pointer to the buffer holding that line at the address LINE.  The valid length of the lines is stored at the address of LINELEN. This buffer is valid until the next read operation on the same context CTX.  You may modify the contet of this buffer.  The buffer is invalid (i.e. must not be used) if an error is returned.  This function returns 0 on success or an error code.

 -- Function: assuan_error_t assuan_write_line (assuan_context_t CTX, const char *LINE)

     Write the string LINE to the other end.  This string needs to be a proper formatted Assuan protocol line and should not include a linefeed. Sending linefeed or Nul characters is not possible and not alowed by the assuan protocol.  This fucntion shall not be used for sendind data (D) lines.  This function returns 0 on success or an error code.

To actually send bulk data lines a specialized function is available:

 -- Function: assuan_error_t assuan_send_data (assuan_context_t CTX, const void *BUFFER, size_t LENGTH)

     This function is used by a server or a client to send LENGTH bytes of bulk data in BUFFER to the other end. The data will be escaped as required by the Assuan protocol and may get buffered until a line is full.  To force sending the data out BUFFER may be passed as NULL and LENGTH be 0.

     When used by a client this flush operation does also send the terminating END command to terminate the response on an ``INQUIRE'' response.  Note, that the fucntion assuan_transact takes care of sending this END itself.

     This function returns 0 on success or an error code.

How to develop an Assuan client
*******************************

assuan_error_t assuan_pipe_connect (assuan_context_t *ctx, const char *name, const char *const argv[], int *fd_child_list); assuan_error_t assuan_pipe_connect2 (assuan_context_t *ctx, const char *name, const char *const argv[], int *fd_child_list, void (*atfork) (void*, int), void *atforkvalue); assuan_error_t assuan_pipe_connect_ext (assuan_context_t *ctx, const char *name, const char *const argv[], int *fd_child_list, void (*atfork) (void *, int), void *atforkvalue, unsigned int flags);

assuan_error_t assuan_socket_connect (assuan_context_t *ctx, const char *name, pid_t server_pid); assuan_error_t assuan_socket_connect_ext (assuan_context_t *ctx, const char *name, pid_t server_pid, unsigned int flags);

void assuan_disconnect (assuan_context_t ctx);

assuan_error_t assuan_transact (assuan_context_t ctx, const char *command, int (*data_cb)(void *, const void *, size_t), void *data_cb_arg, int (*inquire_cb)(void*, const char *), void *inquire_cb_arg, int (*status_cb)(void*, const char *), void *status_cb_arg);

/* The file descriptor must be pending before assuan_receivefd is called.  This means that assuan_sendfd should be called *before* the trigger is sent (normally via assuan_write_line ("INPUT FD")).  */ assuan_error_t assuan_sendfd (assuan_context_t ctx, int fd); assuan_error_t assuan_receivefd (assuan_context_t ctx, int *fd);

How to develop an Assuan server
*******************************

bar int assuan_register_command (assuan_context_t ctx, const char *cmd_string, int (*handler)(assuan_context_t, char *)); int assuan_register_bye_notify (assuan_context_t ctx, void (*fnc)(assuan_context_t)); int assuan_register_reset_notify (assuan_context_t ctx, void (*fnc)(assuan_context_t)); int assuan_register_cancel_notify (assuan_context_t ctx, void (*fnc)(assuan_context_t)); int assuan_register_input_notify (assuan_context_t ctx, void (*fnc)(assuan_context_t, const char *)); int assuan_register_output_notify (assuan_context_t ctx, void (*fnc)(assuan_context_t, const char *));

int assuan_register_option_handler (assuan_context_t ctx, int (*fnc)(assuan_context_t, const char*, const char*));

int assuan_process (assuan_context_t ctx); int assuan_process_next (assuan_context_t ctx);

FILE *assuan_get_data_fp (assuan_context_t ctx); assuan_error_t assuan_set_okay_line (assuan_context_t ctx, const char *line); assuan_error_t assuan_write_status (assuan_context_t ctx, const char *keyword, const char *text);

/* Negotiate a file descriptor.  If LINE contains "FD=N", returns N assuming a local file descriptor.  If LINE contains "FD" reads a file descriptor via CTX and stores it in *RDF (the CTX must be capable of passing file descriptors).  */ assuan_error_t assuan_command_parse_fd (assuan_context_t ctx, char *line, int *rfd);

assuan_error_t assuan_set_hello_line (assuan_context_t ctx, const char *line); assuan_error_t assuan_accept (assuan_context_t ctx); int assuan_get_input_fd (assuan_context_t ctx); int assuan_get_output_fd (assuan_context_t ctx); assuan_error_t assuan_close_input_fd (assuan_context_t ctx); assuan_error_t assuan_close_output_fd (assuan_context_t ctx);

int assuan_init_pipe_server (assuan_context_t *r_ctx, int filedes[2]); void assuan_deinit_server (assuan_context_t ctx);

int assuan_init_socket_server (assuan_context_t *r_ctx, int listen_fd); int assuan_init_connected_socket_server (assuan_context_t *r_ctx, int fd); int assuan_init_socket_server_ext (assuan_context_t *r_ctx, int fd, unsigned int flags);

assuan_error_t assuan_inquire (assuan_context_t ctx, const char *keyword, unsigned char **r_buffer, size_t *r_length, size_t maxlen);

Utility functions
*****************

void assuan_set_log_stream (assuan_context_t ctx, FILE *fp); int assuan_set_error (assuan_context_t ctx, int err, const char *text); void assuan_set_pointer (assuan_context_t ctx, void *pointer); void *assuan_get_pointer (assuan_context_t ctx);

void assuan_begin_confidential (assuan_context_t ctx); void assuan_end_confidential (assuan_context_t ctx);

/* For context CTX, set the flag FLAG to VALUE.  Values for flags are usually 1 or 0 but certain flags might allow for other values; see the description of the type assuan_flag_t for details. */ void assuan_set_flag (assuan_context_t ctx, assuan_flag_t flag, int value);

typedef enum /* When using a pipe server, by default Assuan will wait for the forked process to die in assuan_disconnect.  In certain cases this is not desirable.  By setting this flag, the waitpid will be skipped and the caller is responsible to cleanup a forked process. */ ASSUAN_NO_WAITPID = 1 assuan_flag_t;

/* Return the VALUE of FLAG in context CTX. */ int  assuan_get_flag (assuan_context_t ctx, assuan_flag_t flag);

const char *assuan_strerror (assuan_error_t err);

 -- Function: pid_t assuan_get_pid (assuan_context_t CTX)

     This function returns the pid of the connected connected peer.  If that pid is not known -1 is returned.  Note that it is not always possible to learn the pid of the other process. For a pipe based server the client knows it instantly and a mechnism is in palce to let the server learn it.  For socket based servers the pid is only available on systems providing the ``SO_PEERCRED'' socket option  (to our knowledge only the Linux kernel has this feature).

 -- Function: assuan_error_t assuan_get_peercred (assuan_context_t CTX, pid_t *PID, uid_t *UID, gid_t *PID)

     Return user credentials of the peer. This will work only on certain systems and only when connected over a socket.  If you are not interested in some of the values, pass NULL instead of the address of an appropriate variable.  PID, UID and GID are only set if the function succeeds and returns with 0.

     As of now only the server is able to retrieve this information.  Note, that for getting the pid of the peer assuan_get_pid is usually better suited.

int assuan_get_active_fds (assuan_context_t ctx, int what, int *fdarray, int fdarraysize);

int assuan_pending_line (assuan_context_t ctx);

/* Return the stream which is currently being using for global logging.  */ FILE *assuan_get_assuan_log_stream (void);

/* Return a prefix to be used at the start of a line emitted by assuan on the log stream.  The default implementation returns the empty string, i.e. ""  */ const char *assuan_get_assuan_log_prefix (void);

     [file lgpl.texi not included]
     [file gpl.texi not included]