| 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 —
#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);
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).
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.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.
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.
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”)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!
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;
}
libsaslc library appeared in NetBSD
  6.0.
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 9.3 |