| LIBSASLC(3) | Library Functions Manual | LIBSASLC(3) |
libsaslc, saslc.d,
saslc_alloc, saslc_end,
saslc_init, saslc_sess_init,
saslc_sess_end,
saslc_sess_getprop,
saslc_sess_setprop,
saslc_sess_cont,
saslc_sess_decode,
saslc_sess_encode,
saslc_sess_getmech,
saslc_sess_strerror,
saslc_strerror — Simple
Authentication and Security Layer client library
Simple Authentication and Security Layer client library (libsaslc, -lsaslc)
#include
<saslc.h>
saslc_t *
saslc_alloc(void);
int
saslc_end(saslc_t
*ctx);
int
saslc_init(saslc_t
*ctx, const char
*appname, const char
*cfgpath);
saslc_sess_t *
saslc_sess_init(saslc_t
*ctx, const char
*mechs, const char
*secopts);
void
saslc_sess_end(saslc_sess_t
*sess);
const char *
saslc_sess_getprop(saslc_sess_t
*sess, const char
*key);
int
saslc_sess_setprop(saslc_sess_t
*sess, const char
*key, const char
*value);
int
saslc_sess_cont(saslc_sess_t
*sess, const void
*in, size_t inlen,
void* *out,
size_t *outlen);
ssize_t
saslc_sess_decode(saslc_sess_t
*sess, const void
*in, size_t inlen,
void* *out,
size_t *outlen);
ssize_t
saslc_sess_encode(saslc_sess_t
*sess, const void
*in, size_t inlen,
void* *out,
size_t *outlen);
const char *
saslc_sess_getmech(saslc_sess_t
*sess);
const char *
saslc_sess_strerror(saslc_sess_t
*sess);
const char *
saslc_strerror(saslc_t
*ctx);
The libsaslc library offers a client
interface for the Simple Authentication and Security Layer (SASL). The
library is heavily influenced by its use with
postfix(1).
The following functions are available in the library.
saslc_alloc()saslc_alloc() function allocates and returns a
new saslc context. The context is uninitialized: see
saslc_init(). Returns NULL
on error.saslc_end(ctx)saslc_end() function destroys and deallocate
resources used by the context ctx. The context
shouldn't have any sessions assigned to it. Returns 0 on success and -1 if
the context has active sessions and cannot be deallocated.saslc_init(ctx,
appname, cfgpath)saslc_init() function initializes the saslc
context ctx. Based on the application name
appname, it also parses the configuration files as
indicated by cfgpath, sets up the context and
mechanism dictionaries, and creates mechanism list for the context. If
cfgpath is NULL, it checks
the environment variable SASLC_CONFIG for a
location and if that is not found it uses the default path
/etc/saslc.d. Returns 0 on success and -1 on
failure.saslc_sess_init(ctx,
mechs, secopts)saslc_sess_init() function creates new session
assigned to the ctx context. The function chooses
the mechanism to use for authentication from the
mechs list taking into account the requirements from
the secopts list. Both lists may be space or comma
delimited. The first matching mechanism from the
mechs list is used. See
CONFIGURATION below for the
supported mechanisms. The valid security options are
Unknown security options are ignored. Returns a session handle
or NULL on error or no match.
saslc_sess_end(sess)saslc_sess_end() function ends the sasl
session sess. It destroys and deallocates all
internal resources. This does not fail.saslc_sess_getprop(sess,
key)saslc_sess_getprop() function gets the
property indicated by the key from the saslc
dictionaries. Dictionaries are searched in following order: session
sess dictionary, context dictionary (global
configuration), and mechanism dictionary. Returns the property value or
NULL if the property is not found.saslc_sess_setprop(sess,
key, value)saslc_sess_setprop() function sets the
property indexed by key to the value
value in the session sess
dictionary. If the property already exists in the session dictionary, then
the previous value is replaced by the new value. If
value is NULL, then any
previous value in the session dictionary is removed. Returns 0 on success
or -1 on failure.saslc_sess_cont(sess,
in, inlen,
out, outlen)saslc_sess_cont() function performs one step
of the sasl authentication. It reads inlen bytes of
input data (from the server) from the in buffer and
stores outlen bytes of output data in
out (for the server). The user is responsible for
freeing memory allocated for out. It returns 0 if
the authentication process is completed, 1 if another step is required,
and -1 on error. Note that the completion of authentication process does
not mean the client is authenticated; that is determined by the
server.saslc_sess_decode(sess,
in, inlen,
out, outlen)saslc_sess_encode() and
saslc_sess_decode() functions are used to provide
the integrity ("auth-int") and confidentiality
("auth-conf") layers for mechanisms that provide them. They
encode and, respectively, decode inlen bytes of data
from the in buffer using the method negotiated
during authentication. On error they return -1. Otherwise, they return the
number of bytes consumed from in and output
outlen bytes of data in the
out buffer. The user is responsible for freeing
memory allocated for out. If
outlen is 0, more data is needed before anything can
be output. Unused input data is stored internally for use in subsequent
calls.
When decoding, the internal buffers can
only be flushed by providing the missing packet data and it is an error
to call
ssalc_sess_decode()
with inlen = 0. The first call of
saslc_sess_decode()
in a session must begin at the start of a packet. Subsequent calls need
not be aligned on packet boundaries.
saslc_sess_encode(sess,
in, inlen,
out, outlen)saslc_sess_encode() encodes
inlen bytes of data from the
in buffer. Note that unlike when decoding, the
internal buffer may be flushed through the encoder by calling
saslc_sess_encode() with
inlen = 0. In this case,
saslc_sess_encode() returns the number of bytes
that were flushed from the internal buffer.saslc_sess_getmech(sess)saslc_sess_getmech() function returns the name
of the mechanism used in the session sess. The
function does not fail.saslc_sess_strerror(sess)saslc_sess_strerror() returns the error
message associated with the session sess.saslc_strerror(ctx)saslc_strerror() function operates as
saslc_sess_strerror(), but instead returns the
error message string for the last error in the context
ctx. Neither function will ever return
NULL.The library uses three types of dictionaries: context (or global),
session, and mechanism, and they are searched in that order by
saslc_getprop()
and the first matching entry is taken. The context and mechanism
dictionaries are loaded from configuration files, while the session
dictionary is loaded by the caller via
saslc_setprop().
The configuration file
<cfgpath>/<appname>/saslc.conf is used
for the context configuration. The
<cfgpath>/<appname>/mech/<mechanism>.conf
file is used for the mechanism configuration. The
<cfgpath> is
/etc/saslc.d by default, but this may be overridden
by the environment variable SASLC_CONFIG, which in
turn may be overridden by
saslc_init().
The <appname> is saslc
by default, but may also be overridden by
saslc_init(). Finally, the
<mechanism> is the mechanism in use by the
session as returned by
saslc_sess_getmech().
Note that this name is case sensitive. The currently supported mechanisms
are
If any of the mechanism files are missing they are silently ignored, unless debugging is enabled.
The configuration files consists of lines of the form:
# comment line ⟨key⟩ ⟨value⟩ [# comment]
The ⟨key⟩ is a string beginning with an alpha character (isalpha(3)) followed by any number of alpha numeric (isalnum(3)) or underscore ‘_’ characters; this is case sensitive. The ⟨value⟩ is a number or a quoted string. More than one ⟨key⟩ and ⟨value⟩ pair may occur on a single line, but they may not be broken across lines. A ‘#’ character (outside a quoted string) indicates that the rest of the line is a comment.
NOTE: Currently, no escaping is supported in strings, so they may
not contain quotes. Numbers must be between 0 and
LLONG_MAX, inclusive. Any base supported by
strtoll(3) is allowed.
Most of the control of the library behavior is done via setting
various properties in the context or mechanism dictionaries via the
configuration files or in the session dictionary with
saslc_setprop().
The following properties are currently used, as defined in
saslc.h:
The default value is "des,3des,rc4,rc4_40,rc4_56,aes". (Note that "aes" is not part of the official standard.) Used by the DIGEST-MD5 mechanism.
saslc_sess_setprop(),
it should be set before the first call to
saslc_sess_cont().
(Also see the environment variable SASLC_ENV_DEBUG
in the ENVIRONMENT section
below.)so the default value of the mask is "auth,auth-int,auth-conf". Used by the DIGEST-MD5 and GSSAPI mechanisms.
saslc_sess_init().
Since these flags are used to choose the session mechanism, they are only
effective if they are in the context configuration file. (See the
CONFIGURATION section and the
saslc_sess_init() function.)The defines in saslc.h should be used in code, but their values need to be used in the config files.
The following environment variables (defined in saslc.h) affect the behavior of the library:
SASLC_ENV_CONFIG
("SASLC_CONFIG")SASLC_CONFIG is set it
overrides the default configuration file location of
/etc/saslc.d. This may be overridden by
saslc_init().SASLC_ENV_DEBUG
("SASLC_DEBUG")The following is a minimal (Heimdal) Kerberos 5 setup for use with an smtp server that has been configured to support SASL with the GSSAPI mechanism. It assumes that Kerberos and the smtp server will both run on server.my.domain and that the client is on client.my.domain. It also assumes that the smtp server runs as user postfix and group mail, and that it is not chrooted.
On server.my.domain run the following script as root and then start the Kerberos server kdc(8). You will be prompted for a master password for Kerberos and a password for the postfix principal.
#/bin/sh
cat <<- EOF >> /etc/krb5.conf
[libdefaults]
default_realm = MY.DOMAIN
[realms]
MY.DOMAIN = {
kdc = server.my.domain
admin_servers = server.my.domain
}
[domain_realm]
.my.domain = MY.DOMAIN
EOF
mkdir /var/heimdal
chown root:wheel /var/heimdal
chmod 755 /var/heimdal
kstash
kadmin -l init --realm-max-ticket-life=unlimited \
--realm-max-renewable-life=unlimited \
MY.DOMAIN
kadmin -l add --max-ticket-life="1 day" \
--max-renewable-life="1 week" \
--expiration-time=never \
--pw-expiration-time=never \
--attributes="" \
postfix
kadmin -l add --random-key \
--max-ticket-life="1 day" \
--max-renewable-life="1 week" \
--expiration-time=never \
--pw-expiration-time=never \
--attributes="" \
smtp/server.my.domain
kadmin -l ext -k /etc/krb5.keytab smtp/server.my.domain
chown root:mail /etc/krb5.keytab
chmod 640 /etc/krb5.keytab
Note that the keytab
/etc/krb5.keytab must be readable by the smtp server
or authentication will fail. The location of this keytab file may be changed
with the environment variable KRB5_KTNAME. If
postfix is the smtp server, note the
import_environment
parameter (see
postconf(5)).
On client.my.domain copy the keytab file from server.my.domain:/etc/krb5.keytab to /etc/krb5.keytab. Setup the /etc/saslc.d configuration directory (see CONFIGURATION above). Add the line
AUTHCID "postfix"
to the file /etc/saslc.d/postfix/mech/GSSAPI.conf so that the postfix principal will be used for authentication. Enable SASL in the smtp client. Assuming the smtp client is postfix, you will need to add the following to the /etc/postfix/main.cf file to do this:
smtp_sasl_auth_enable = yes smtp_sasl_type = saslc smtp_sasl_mechanism_filter = GSSAPI relayhost = [server.my.domain]:submission
Here we have assumed the submission port is the port the server is listening to. Finally, as root, run the command
su -m postfix -c kinit
to obtain a ticket for the postfix user with the postfix credential and you should be good to go!
The following code fragments illustrate the possible use of the functions described above.
int
decode_stream(saslc_sess_t *sess, int fdin, int fdout)
{
uint8_t buf[BUFSIZE];
uint8_t *in;
void *out;
size_t inlen, outlen;
ssize_t n, rval;
for (;;) {
if ((rval = read(fdin, buf, sizeof(buf))) == -1)
return -1;
if (rval == 0)
break;
in = buf;
inlen = rval;
while (inlen > 0) {
rval = saslc_sess_decode(sess, in, inlen, &out,
&outlen);
if (rval == -1)
return -1;
if (outlen > 0) {
n = write(fdout, out, outlen);
free(out);
if (n == -1)
return -1;
}
in += rval;
inlen -= rval;
}
}
return 0;
}
int
encode_stream(saslc_sess_t *sess, int fdin, int fdout)
{
uint8_t buf[BUFSIZE];
uint8_t *in;
void *out;
size_t inlen, outlen;
ssize_t n, rval;
for (;;) {
if ((rval = read(fdin, buf, sizeof(buf))) == -1)
return -1;
if (rval == 0)
break;
in = buf;
inlen = rval;
while (inlen > 0) {
rval = saslc_sess_encode(sess, in, inlen, &out,
&outlen);
if (rval == -1)
return -1;
if (outlen > 0) {
n = write(fdout, out, outlen);
free(out);
if (n == -1)
return -1;
}
in += rval;
inlen -= rval;
}
}
/* flush internal encoder buffer */
if (saslc_sess_encode(sess, NULL, 0, &out, &outlen) == -1)
return -1;
if (outlen > 0)
if (write(fdout, out, outlen) == -1)
return -1;
return 0;
}
There exist other SASL client library implementations including Cyrus SASL (http://asg.web.cmu.edu/sasl/sasl-library.html) and GNU SASL (http://www.gnu.org/software/gsasl/).
RFC 2195, RFC 2222, RFC 2245, RFC 2595, RFC 2831, RFC 4422, RFC 4505, RFC 4616, RFC 4752.
The libsaslc library appeared in
NetBSD 6.0.
The API was heavily influenced by its use with postfix(1).
Currently the ANONYMOUS, LOGIN, PLAIN, CRAM-MD5, DIGEST-MD5, and
GSSAPI mechanisms have been tested and shown to work for authentication with
a postfix(1) SMTP server
using the cyrus-sasl library. LOGIN, PLAIN, CRAM-MD5, and DIGEST-MD5 have
also been tested and shown to work with a
postfix(1) SMTP server using
a dovecot backend for authentication. The DIGEST-MD5 and GSSAPI specs also
provide for integrity and confidentiality layers via the
saslc_sess_encode() and
saslc_sess_decode() routines, but these have not yet
been tested against any servers.
| May 3, 2015 | NetBSD 11.0 |