NAME
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
LIBRARY
Simple Authentication and Security Layer client library
(libsaslc, -lsaslc)
SYNOPSIS
#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);
DESCRIPTION
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).
FUNCTIONS
The following functions are available in the library.
-
-
- saslc_alloc()
- The saslc_alloc() function allocates and
returns a new saslc context. The context is uninitialized: see
saslc_init(). Returns
NULL
on
error.
-
-
- saslc_end(ctx)
- The 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)
- The 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)
- The 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
- “noanonymous”
- reject anonymous mechanisms
- “noplaintext”
- reject plaintext mechanisms
- “nodictionary”
- reject mechanisms prone to dictionary attack
- “noactive”
- reject mechanisms prone to active non-dictionary
attacks
- “mutual”
- require mutual authentication mechanisms
Unknown security options are ignored. Returns a session handle or
NULL
on error or no match.
-
-
- saslc_sess_end(sess)
- The 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)
- The 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)
- The 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)
- The 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)
- The 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)
- As described above, 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)
- The saslc_sess_getmech() function returns
the name of the mechanism used in the session sess.
The function does not fail.
-
-
- saslc_sess_strerror(sess)
- The saslc_sess_strerror() returns the
error message associated with the session sess.
-
-
- saslc_strerror(ctx)
- The 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
.
CONFIGURATION
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
-
-
- ANONYMOUS
- See RFC 2245 and RFC 4505.
-
-
- CRAM-MD5
- See RFC 2195.
-
-
- DIGEST-MD5
- See RFC 2831.
-
-
- EXTERNAL
- See RFC 2222 section 7.4 and RFC 4422 appendix A.
-
-
- GSSAPI
- See RFC 2222 section 7.2 and RFC 4752. This requires GSS,
Heimdal, or MIT Kerberos.
-
-
- LOGIN
- Non-standard, but common.
-
-
- PLAIN
- See RFC 2595 and RFC 4616.
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.
PROPERTIES
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:
-
-
- SASLC_PROP_AUTHCID
(“AUTHCID”)
- The authentication name (or username) to authenticate with.
Used by all mechanisms except EXTERNAL.
-
-
- SASLC_PROP_AUTHZID
(“AUTHZID”)
- The authorization string to use. By default, this string is
empty. Used by the DIGEST-MD5, EXTERNAL, and PLAIN mechanisms.
-
-
- SASLC_PROP_BASE64IO
(“BASE64IO”)
- If true ("true", "yes", or nonzero),
then input and output strings are base64 encoded. Any other value is false
and the input and output strings are not base64 encoded. By default, this
is assumed true. Used by all mechanisms.
-
-
- SASLC_PROP_CIPHERMASK
(“CIPHERMASK”)
- The mask of ciphers to use with the DIGEST-MD5 mechanism
when using the “auth-conf” QOP. By default all supported
ciphers are used, but they may be limited by a comma delimited list of
cipher names. The recognized cipher names for DIGEST-MD5 are:
3des
- Triple-DES Cipher in CBC "two keys" mode with
112 bit key
aes
- AES Cipher in CBC mode with 128 bit key
des
- DES Cipher in CBC mode with 56 bit key
rc4
- RC4 Cipher with 128 bit key
rc4-40
- RC4 Cipher with 40 bit key
rc4-56
- RC4 Cipher with 56 bit key
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_PROP_DEBUG
(“DEBUG”)
- If true, then enable debug messages. This is implemented as
a global variable so it will affect all sessions. If set via
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.)
-
-
- SASLC_PROP_HOSTNAME
(“HOSTNAME”)
- The fully qualified domain name of the server host. Used by
the DIGEST-MD5 and GSSAPI mechanisms.
-
-
- SASLC_PROP_MAXBUF
(“MAXBUF”)
- The size of the decode buffer. This info is sent to the
server so that it doesn't send packets that won't fit in the decode buffer
when decoded. Used by the DIGEST-MD5 and GSSAPI mechanisms.
-
-
- SASLC_PROP_PASSWD
(“PASSWD”)
- The password to authenticate with. Used by the CRAM-MD5,
DIGEST-MD5, LOGIN, and PLAIN mechanisms.
-
-
- SASLC_PROP_QOPMASK
(“QOPMASK”)
- The mask of QOP (quality of protection) to use with the
DIGEST-MD5 and GSSAPI mechanisms. By default all supported QOP values are
allowed, but they may be limited by a comma delimited list of QOP values.
The recognized QOP values are:
auth
- authentication only
auth-int
- authentication with integrity
auth-conf
- authentication with confidentiality
so the default value of the mask is “auth,auth-int,auth-conf”.
Used by the DIGEST-MD5 and GSSAPI mechanisms.
-
-
- SASLC_PROP_REALM
(“REALM”)
- A comma delimited list of possible realms to use for
authentication. The format of each element in the list is
“[⟨hostname⟩:]⟨realm⟩”.
The user specified realm is the first realm in the list with a matching
hostname or, if none is found, the first realm in the list with no
hostname. If the server provides a list of realms, the one matching the
user specified realm is selected. If no match is found or if the user
didn't provide a realm, the first realm provided by the server is
selected. If the server doesn't provide any realms, use the user specified
realm if there is one, or the hostname if not. This is useful when the
server provides multiple realms or no realm. Used by the DIGEST-MD5
mechanism.
-
-
- SASLC_PROP_SECURITY
(“SECURITY”)
- A comma delimited list of extra security option flags that
will be “or”-ed together with those passed to
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.)
-
-
- SASLC_PROP_SERVICE
(“SERVICE”)
- The service being used, e.g., smtp, imap, etc. Used by the
DIGEST-MD5 and GSSAPI mechanisms.
-
-
- SASLC_PROP_SERVNAME
(“SERVNAME”)
- A comma delimited list of possible service names with
elements of the form
“[⟨hostname⟩:]⟨serv-name⟩”
and with the same rules as for the SASLC_PROP_REALM list. This should only
be used if the client uses a DNS name for the service that is different
from the FQDN of the server. For example, the service name
example.com might resolve (via SRV or MX records) into a
set of other DNS names, one of which, mail3.example.com,
is the FQDN of the server. (See RFC 2831 section 2.1.2
“serv-name”.) Used by the DIGEST-MD5 mechanism.
The defines in
saslc.h should be used in code, but their
values need to be used in the config files.
ENVIRONMENT
The following environment variables (defined in
saslc.h)
affect the behavior of the library:
-
-
SASLC_ENV_CONFIG
(“SASLC_CONFIG”)
- If the environment variable
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”)
- If set, turn on debugging messages. This turns on debugging
as early as possible and is a global setting.
GSSAPI AND KERBEROS
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
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
to obtain a ticket for the postfix user with the postfix credential and you
should be good to go!
FILES
-
-
- /etc/saslc.d
-
EXAMPLES
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;
}
COMPATIBILITY
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/).
STANDARDS
RFC 2195, RFC 2222, RFC 2245, RFC 2595, RFC 2831, RFC 4422, RFC 4505, RFC 4616,
RFC 4752.
HISTORY
The
libsaslc library appeared in
NetBSD
6.0.
CAVEATS
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.