3 Using the Library

Your application's use of the library can be roughly modeled into the
following steps: initialize the library, optionally specify the
callback, perform the authentication, and finally clean up. The
following image illustrates this.

The third step may look complex, but for a simple client it will
actually not involve any code. If your application needs to handle
several concurrent clients, or if it is a server that needs to serve
many clients simultaneous, things do get a bit more complicated.

For illustration, we will write a simple client. Writing a server
would be similar, the only difference is that, later on, instead of
supplying a username and password, you need to decide whether someone
should be allowed to log in or not. The code for what we have
discussed so far make up the main function in our client
(see Example 1):

Here, the call to the function client correspond to the third
step in the image above.

For a more complicated application, having several clients running
simultaneous, instead of a simple call to client, it may have
created new threads for each session, and call client within
each thread. The library is thread safe.

An actual authentication session is more complicated than what we have
seen so far. These are the steps: decide which mechanism to use,
start the session, optionally specify the callback, optionally set any
properties, perform the authentication loop, and clean up. Naturally,
your application will start to talk its own protocol (e.g., SMTP or
IMAP) after these steps have concluded.

The authentication loop is based on sending tokens (typically short
messages encoded in base 64) back and forth between the client and
server. It continues until authentication succeeds or an error
occurs. The format of the data to be transferred, the number of
iterations in the loop, and other details are specified by each
mechanism. The goal of the library is to isolate your application
from the details of all different mechanisms.

Note that the library does not send data to the server itself, but
returns it in an buffer. You must send it to the server, following an
application protocol profile. For example, the SASL application
protocol profile for SMTP is described in RFC 2554.

The following image illustrates the steps we have been talking about.

We will now show the implementation of the client function used
before.

This function is responsible for deciding which mechanism to use. In
this case, the ‘PLAIN’ mechanism is hard coded, but you will see
later how this can be made more flexible. The function creates a new
session, then it stores the username and password in the session
handle, then it calls another function client_authenticate to
handle the authentication loop, and finally it cleans up up. Let's
continue with the implementation of client_authenticate.

This last function needs to be discussed in some detail. First, you
should be aware that there are two versions of this function, that
differ in a subtle way. The version above (see Example 2) is used
for application profiles where the server sends data first. For some
mechanisms, this may waste a roundtrip, because the server needs input
from the client to proceed. Therefor, today the recommended approach
is to permit client to send data first (see Example 1). Which
version you should use depends on which application protocol you are
implementing.

Further, you should realize that it is bad programming style to use a
fixed size buffer. On GNU systems, you may use the getline
functions instead of fgets. However, in practice, there are
few mechanisms that use very large tokens. In typical configurations,
the mechanism with the largest tokens (GSSAPI) can use at least 500
bytes. A fixed buffer size of 8192 bytes may thus be sufficient for
now. But don't say I didn't warn you, when a future mechanism doesn't
work in your application, because of a fixed size buffer.

The function gsasl_step64 (and of course also gasl_step)
returns two non-error return codes. GSASL_OK is used for
success, indicating that the library considers the authentication
finished. That may include a successful server authentication,
depending on the mechanism. You must not let the client continue to
the application protocol part unless you receive GSASL_OK from
these functions. In particular, don't be fooled into believing
authentication were successful if the server replies “OK” but these
functions have failed with an error. The server may have been hacked,
and could be tricking you into sending confidential data, without
having successfully authenticated the server.

The non-error return code GSASL_NEEDS_MORE is used to signal to
your application that you should send the output token to the peer,
and wait for a new token, and do another iteration. If the server
concludes the authentication process, with no data, you should call
gsasl_step64 (or gsasl_step) specifying a zero-length
token.

If the functions (gsasl_step and gsasl_step64) return
any non-error code, the content of the output buffer is undefined.
Otherwise, it is the callers responsibility to deallocate the buffer,
by calling free. Note that in some situations, where the
buffer is empty, NULL is returned as the buffer value. You
should treat this as an empty buffer.

3.1 Choosing a mechanism

Our earlier code was hard coded to use a specific mechanism. This is
rarely a good idea. Instead, it is recommended to select the best
mechanism available from the list of mechanisms supported by the
server. Note that without TLS or similar, the list may have been
maliciously altered, by an attacker. This means that you should abort
if you cannot find any mechanism that exceeds your minimum security
level. There is a function gsasl_client_suggest_mechanism
(see Global Functions) that will try to pick the “best”
available mechanism from a list of mechanisms. Our simple interactive
example client (see Example 3) includes the following function to
decide which mechanism to use. Note that the code doesn't blindly use
what is returned from gsasl_client_suggest_mechanism, rather it
lets some logic (in this case the user, through an interactive query)
decide which mechanism is acceptable.

3.2 Using a callback

This may work for simple mechanisms, that need only a username and a
password. But some mechanism requires more information, such as an
authorization identity, a special PIN or passcode, a realm, a
hostname, a service name, or an anonymous identifier. Querying the
user for all that information, without knowing exactly which of it is
really needed will result in a poor user interface. The user should
not have to input private information, if it isn't required.

The approach is a bad idea for another reason. What if the server
aborts the authentication process? Then your application has already
queried the user for a username and password. It would be better if
you only asked the user for this information, annoying to input, when
it is known to be needed.

A better approach to this problem is to use a callback. Then the
mechanism may query your application whenever it needs some
information, like the username and password. It will only do this at
the precise step in the authentication when the information is
actually needed. Further, if the user aborts, e.g., a password
prompt, the mechanism is directly informed of this (because it invoked
the callback), and could recover somehow.

Which properties you should handle is up to you. If you don't know how
to respond to a certain property, simply return
GSASL_NO_CALLBACK. The basic properties to support are
authentication identity (GSASL_AUTHID), authorization identity
(GSASL_AUTHZID), and password (GSASL_PASSWORD).
See Properties, for the list of all properties, and what your callback
should (ideally) do for them, and which properties each mechanism
require in order to work.