/*++
/* NAME
/*	xsasl-server 3
/* SUMMARY
/*	Postfix SASL server plug-in interface
/* SYNOPSIS
/*	#include <xsasl.h>
/*
/*	XSASL_SERVER_IMPL *xsasl_server_init(server_type, path_info)
/*	const char *server_type;
/*	const char *path_info;
/*
/*	void	xsasl_server_done(implementation)
/*	XSASL_SERVER_IMPL *implementation;
/*
/*	ARGV	*xsasl_server_types()
/*
/* .in +4
/*	typedef struct XSASL_SERVER_CREATE_ARGS {
/*		VSTREAM *stream;
/*		const char *server_addr;
/*		const char *client_addr;
/*		const char *service;
/*		const char *user_realm;
/*		const char *security_options;
/*		int     tls_flag;
/*	} XSASL_SERVER_CREATE_ARGS;
/* .in -4
/*
/*	XSASL_SERVER *xsasl_server_create(implementation, args)
/*	XSASL_SERVER_IMPL *implementation;
/*	XSASL_SERVER_CREATE_ARGS *args;
/*
/*	XSASL_SERVER *XSASL_SERVER_CREATE(implementation, args,
/*					stream = stream_value,
/*					...,
/*					tls_flag = tls_flag_value)
/*	XSASL_SERVER_IMPL *implementation;
/*	XSASL_SERVER_CREATE_ARGS *args;
/*
/*	void xsasl_server_free(server)
/*	XSASL_SERVER *server;
/*
/*	int	xsasl_server_first(server, auth_method, init_resp, server_reply)
/*	XSASL_SERVER *server;
/*	const char *auth_method;
/*	const char *init_resp;
/*	VSTRING *server_reply;
/*
/*	int	xsasl_server_next(server, client_request, server_reply)
/*	XSASL_SERVER *server;
/*	const char *client_request;
/*	VSTRING *server_reply;
/*
/*	const char *xsasl_server_get_mechanism_list(server)
/*	XSASL_SERVER *server;
/*
/*	const char *xsasl_server_get_username(server)
/*	XSASL_SERVER *server;
/* DESCRIPTION
/*	The XSASL_SERVER abstraction implements a generic interface
/*	to one or more SASL authentication implementations.
/*
/*	xsasl_server_init() is called once during process initialization.
/*	It selects a SASL implementation by name, specifies the
/*	location of a configuration file or rendez-vous point, and
/*	returns an implementation handle that can be used to generate
/*	SASL server instances. This function is typically used to
/*	initialize the underlying implementation.
/*
/*	xsasl_server_done() disposes of an implementation handle,
/*	and allows the underlying implementation to release resources.
/*
/*	xsasl_server_types() lists the available implementation types.
/*	The result should be destroyed by the caller.
/*
/*	xsasl_server_create() is called at the start of an SMTP
/*	session. It generates a Postfix SASL plug-in server instance
/*	for the specified service and authentication realm, and
/*	with the specified security properties. Specify a null
/*	pointer when no realm should be used. The stream handle is
/*	stored so that encryption can be turned on after successful
/*	negotiations. Specify zero-length strings when a client or
/*	server address is unavailable.
/*
/*	XSASL_SERVER_CREATE() is a macro that provides an interface
/*	with named parameters.  Named parameters do not have to
/*	appear in a fixed order. The parameter names correspond to
/*	the member names of the XSASL_SERVER_CREATE_ARGS structure.
/*
/*	xsasl_server_free() is called at the end of an SMTP session.
/*	It destroys a SASL server instance, and disables further
/*	read/write operations if encryption was turned on.
/*
/*	xsasl_server_first() produces the server response for the
/*	client AUTH command. The client input are an authentication
/*	method, and an optional initial response or null pointer.
/*	The initial response and server non-error replies are BASE64
/*	encoded.  Server error replies are 7-bit ASCII text without
/*	control characters, without BASE64 encoding, and without
/*	SMTP reply code or enhanced status code.
/*
/*	The result is one of the following:
/* .IP XSASL_AUTH_MORE
/*	More client input is needed. The server reply specifies
/*	what.
/* .IP XSASL_AUTH_DONE
/*	Authentication completed successfully.
/* .IP XSASL_AUTH_FORM
/*	The client input is incorrectly formatted. The server error
/*	reply explains why.
/* .IP XSASL_AUTH_FAIL
/*	Authentication failed. The server error reply explains why.
/* .PP
/*	xsasl_server_next() supports the subsequent stages of the
/*	client-server AUTH protocol. Both the client input and
/*	server non-error responses are BASE64 encoded.  See
/*	xsasl_server_first() for other details.
/*
/*	xsasl_server_get_mechanism_list() returns the authentication
/*	mechanisms that match the security properties, as a white-space
/*	separated list. This is meant to be used in the SMTP EHLO
/*	reply.
/*
/*	xsasl_server_get_username() returns the stored username
/*	after successful authentication. The username may be null
/*	after authentication failure, depending on the kind of
/*	failure and on authentication backend implementation
/*	details. A non-null result is converted to printable text.
/*
/*	Arguments:
/* .IP addr_family
/*	The network address family: AF_INET6 or AF_INET.
/* .IP auth_method
/*	AUTH command authentication method.
/* .IP client_addr
/*	IPv4 or IPv6 address (no surrounding [] or ipv6: prefix),
/*	or zero-length string if unavailable.
/* .IP client_port
/*	TCP port or zero-length string if unavailable.
/* .IP init_resp
/*	AUTH command initial response or null pointer.
/* .IP implementation
/*	Implementation handle that was obtained with xsasl_server_init().
/* .IP path_info
/*	The value of the smtpd_sasl_path parameter or equivalent.
/*	This specifies the implementation-dependent location of a
/*	configuration file, rendez-vous point, etc., and is passed
/*	unchanged to the plug-in.
/* .IP security_options
/*	The value of the smtpd_security_options parameter or
/*	equivalent. This is passed unchanged to the plug-in.
/* .IP server
/*	SASL plug-in server handle.
/* .IP server_addr
/*	IPv4 or IPv6 address (no surrounding [] or ipv6: prefix),
/*	or zero-length string if unavailable.
/* .IP server_port
/*	TCP port or zero-length string if unavailable.
/* .IP server_reply
/*	BASE64 encoded server non-error reply (without SMTP reply
/*	code or enhanced status code), or ASCII error description.
/* .IP server_type
/*	The name of a Postfix SASL server plug_in implementation.
/* .IP server_types
/*	Null-terminated array of strings with SASL server plug-in
/*	implementation names.
/* .IP service
/*	The service that is implemented by the local server, typically
/*	"smtp" or "lmtp".
/* .IP stream
/*	The connection between client and server.  When SASL
/*	encryption is negotiated, the plug-in will transparently
/*	intercept the socket read/write operations.
/* .IP user_realm
/*	Authentication domain or null pointer.
/* SECURITY
/* .ad
/* .fi
/*	The caller does not sanitize client input. It is the
/*	responsibility of the underlying SASL server implementation
/*	to produce 7-bit ASCII without control characters as server
/*	non-error and error replies, and as the result from
/*	xsasl_server_method() and xsasl_server_username().
/* DIAGNOSTICS
/*	In case of failure, xsasl_server_init(), xsasl_server_create(),
/*	xsasl_server_get_mechanism_list() and xsasl_server_get_username()
/*	log a warning and return a null pointer.
/*
/*	Functions that normally return XSASL_AUTH_OK will log a warning
/*	and return an appropriate result value.
/*
/*	Fatal errors: out of memory.
/*
/*	Panic: interface violations.
/* SEE ALSO
/*	cyrus_security(3) Cyrus SASL security features
/* LICENSE
/* .ad
/* .fi
/*	The Secure Mailer license must be distributed with this
/*	software.
/* AUTHOR(S)
/*	Wietse Venema
/*	IBM T.J. Watson Research
/*	P.O. Box 704
/*	Yorktown Heights, NY 10598, USA
/*
/*	Wietse Venema
/*	Google, Inc.
/*	111 8th Avenue
/*	New York, NY 10011, USA
/*
/*	Wietse Venema
/*	porcupine.org
/*	Amawalk, NY 10501, USA
/*--*/

/* System library. */

#include <sys_defs.h>
#include <string.h>

/* Utility library. */

#include <msg.h>
#include <mymalloc.h>

/* SASL implementations. */

#include <xsasl.h>
#include <xsasl_cyrus.h>
#include <xsasl_dovecot.h>

 /*
  * Lookup table for available SASL server implementations.
  */
typedef struct {
    char   *server_type;
    struct XSASL_SERVER_IMPL *(*server_init) (const char *, const char *);
} XSASL_SERVER_IMPL_INFO;

static const XSASL_SERVER_IMPL_INFO server_impl_info[] = {
#ifdef XSASL_TYPE_CYRUS
    {XSASL_TYPE_CYRUS, xsasl_cyrus_server_init},
#endif
#ifdef XSASL_TYPE_DOVECOT
    {XSASL_TYPE_DOVECOT, xsasl_dovecot_server_init},
#endif
    {0, 0}
};

/* xsasl_server_init - look up server implementation by name */

XSASL_SERVER_IMPL *xsasl_server_init(const char *server_type,
				             const char *path_info)
{
    const XSASL_SERVER_IMPL_INFO *xp;

    for (xp = server_impl_info; xp->server_type; xp++)
	if (strcmp(server_type, xp->server_type) == 0)
	    return (xp->server_init(server_type, path_info));
    msg_warn("unsupported SASL server implementation: %s", server_type);
    return (0);
}

/* xsasl_server_types - report available implementation types */

ARGV   *xsasl_server_types(void)
{
    const XSASL_SERVER_IMPL_INFO *xp;
    ARGV   *argv = argv_alloc(1);

    for (xp = server_impl_info; xp->server_type; xp++)
	argv_add(argv, xp->server_type, ARGV_END);
    return (argv);
}
