/*++
/* NAME
/* xsasl_dovecot_server 3
/* SUMMARY
/* Dovecot SASL server-side plug-in
/* SYNOPSIS
/* XSASL_SERVER_IMPL *xsasl_dovecot_server_init(server_type, appl_name)
/* const char *server_type;
/* const char *appl_name;
/* DESCRIPTION
/* This module implements the Dovecot SASL server-side authentication
/* plug-in.
/*
/* .IP server_type
/* The plug-in type that was specified to xsasl_server_init().
/* The argument is ignored, because the Dovecot plug-in
/* implements only one plug-in type.
/* .IP path_info
/* The location of the Dovecot authentication server's UNIX-domain
/* socket. Note: the Dovecot plug-in uses late binding, therefore
/* all connect operations are done with Postfix privileges.
/* DIAGNOSTICS
/* Fatal: out of memory.
/*
/* Panic: interface violation.
/*
/* Other: the routines log a warning and return an error result
/* as specified in xsasl_server(3).
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/* Initial implementation by:
/* Timo Sirainen
/* Procontrol
/* Finland
/*
/* Adopted by:
/* 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
/*--*/
/* System library. */
#include <sys_defs.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef STRCASECMP_IN_STRINGS_H
#include <strings.h>
#endif
/* Utility library. */
#include <msg.h>
#include <mymalloc.h>
#include <connect.h>
#include <split_at.h>
#include <stringops.h>
#include <vstream.h>
#include <vstring_vstream.h>
#include <name_mask.h>
#include <argv.h>
#include <myaddrinfo.h>
/* Global library. */
#include <mail_params.h>
/* Application-specific. */
#include <xsasl.h>
#include <xsasl_dovecot.h>
#ifdef USE_SASL_AUTH
/* Major version changes are not backwards compatible,
minor version numbers can be ignored. */
#define AUTH_PROTOCOL_MAJOR_VERSION 1
#define AUTH_PROTOCOL_MINOR_VERSION 0
/*
* Enforce read / write time limits , so that we can produce accurate
* diagnostics instead of getting killed by the watchdog timer .
*/
#define AUTH_TIMEOUT 10
/*
* Security property bitmasks .
*/
#define SEC_PROPS_NOPLAINTEXT (1 << 0 )
#define SEC_PROPS_NOACTIVE (1 << 1 )
#define SEC_PROPS_NODICTIONARY (1 << 2 )
#define SEC_PROPS_NOANONYMOUS (1 << 3 )
#define SEC_PROPS_FWD_SECRECY (1 << 4 )
#define SEC_PROPS_MUTUAL_AUTH (1 << 5 )
#define SEC_PROPS_PRIVATE (1 << 6 )
#define SEC_PROPS_POS_MASK (SEC_PROPS_MUTUAL_AUTH | SEC_PROPS_FWD_SECRECY)
#define SEC_PROPS_NEG_MASK (SEC_PROPS_NOPLAINTEXT | SEC_PROPS_NOACTIVE | \
SEC_PROPS_NODICTIONARY | SEC_PROPS_NOANONYMOUS)
/*
* Security properties as specified in the Postfix main . cf file .
*/
static const NAME_MASK xsasl_dovecot_conf_sec_props[] = {
"noplaintext" , SEC_PROPS_NOPLAINTEXT,
"noactive" , SEC_PROPS_NOACTIVE,
"nodictionary" , SEC_PROPS_NODICTIONARY,
"noanonymous" , SEC_PROPS_NOANONYMOUS,
"forward_secrecy" , SEC_PROPS_FWD_SECRECY,
"mutual_auth" , SEC_PROPS_MUTUAL_AUTH,
0 , 0 ,
};
/*
* Security properties as specified in the Dovecot protocol . See
* https : //doc.dovecot.org/2.3/developer_manual/design/auth_protocol/
*/
static const NAME_MASK xsasl_dovecot_serv_sec_props[] = {
"plaintext" , SEC_PROPS_NOPLAINTEXT,
"active" , SEC_PROPS_NOACTIVE,
"dictionary" , SEC_PROPS_NODICTIONARY,
"anonymous" , SEC_PROPS_NOANONYMOUS,
"forward-secrecy" , SEC_PROPS_FWD_SECRECY,
"mutual-auth" , SEC_PROPS_MUTUAL_AUTH,
"private" , SEC_PROPS_PRIVATE,
0 , 0 ,
};
/*
* Class variables .
*/
typedef struct XSASL_DCSRV_MECH {
char *mech_name; /* mechanism name */
int sec_props; /* mechanism properties */
struct XSASL_DCSRV_MECH *next;
} XSASL_DCSRV_MECH;
typedef struct {
XSASL_SERVER_IMPL xsasl;
VSTREAM *sasl_stream;
char *socket_path;
XSASL_DCSRV_MECH *mechanism_list; /* unfiltered mechanism list */
unsigned int request_id_counter;
} XSASL_DOVECOT_SERVER_IMPL;
/*
* The XSASL_DOVECOT_SERVER object is derived from the generic XSASL_SERVER
* object .
*/
typedef struct {
XSASL_SERVER xsasl; /* generic members, must be first */
XSASL_DOVECOT_SERVER_IMPL *impl;
unsigned int last_request_id;
char *service;
char *username; /* authenticated user */
VSTRING *sasl_line;
unsigned int sec_props; /* Postfix mechanism filter */
int tls_flag; /* TLS enabled in this session */
char *mechanism_list; /* filtered mechanism list */
ARGV *mechanism_argv; /* ditto */
char *client_addr; /* remote IP address */
char *server_addr; /* remote IP address */
} XSASL_DOVECOT_SERVER;
/*
* Forward declarations .
*/
static void xsasl_dovecot_server_done(XSASL_SERVER_IMPL *);
static XSASL_SERVER *xsasl_dovecot_server_create(XSASL_SERVER_IMPL *,
XSASL_SERVER_CREATE_ARGS *);
static void xsasl_dovecot_server_free(XSASL_SERVER *);
static int xsasl_dovecot_server_first(XSASL_SERVER *, const char *,
const char *, VSTRING *);
static int xsasl_dovecot_server_next(XSASL_SERVER *, const char *, VSTRING *);
static const char *xsasl_dovecot_server_get_mechanism_list(XSASL_SERVER *);
static const char *xsasl_dovecot_server_get_username(XSASL_SERVER *);
/* xsasl_dovecot_server_mech_append - append server mechanism entry */
static void xsasl_dovecot_server_mech_append(XSASL_DCSRV_MECH **mech_list,
const char *mech_name, int sec_props)
{
XSASL_DCSRV_MECH **mpp;
XSASL_DCSRV_MECH *mp;
for (mpp = mech_list; *mpp != 0 ; mpp = &mpp[0 ]->next)
/* void */ ;
mp = (XSASL_DCSRV_MECH *) mymalloc(sizeof (*mp));
mp->mech_name = mystrdup(mech_name);
mp->sec_props = sec_props;
mp->next = 0 ;
*mpp = mp;
}
/* xsasl_dovecot_server_mech_free - destroy server mechanism list */
static void xsasl_dovecot_server_mech_free(XSASL_DCSRV_MECH *mech_list)
{
XSASL_DCSRV_MECH *mp;
XSASL_DCSRV_MECH *next;
for (mp = mech_list; mp != 0 ; mp = next) {
myfree(mp->mech_name);
next = mp->next;
myfree((void *) mp);
}
}
/* xsasl_dovecot_server_mech_filter - filter server mechanism list */
static char *xsasl_dovecot_server_mech_filter(ARGV *mechanism_argv,
XSASL_DCSRV_MECH *mechanism_list,
unsigned int conf_props)
{
const char *myname = "xsasl_dovecot_server_mech_filter" ;
unsigned int pos_conf_props = (conf_props & SEC_PROPS_POS_MASK);
unsigned int neg_conf_props = (conf_props & SEC_PROPS_NEG_MASK);
VSTRING *mechanisms_str = vstring_alloc(10 );
XSASL_DCSRV_MECH *mp;
/*
* Match Postfix properties against Dovecot server properties .
*/
for (mp = mechanism_list; mp != 0 ; mp = mp->next) {
if ((mp->sec_props & pos_conf_props) == pos_conf_props
&& (mp->sec_props & neg_conf_props) == 0 ) {
if (VSTRING_LEN(mechanisms_str) > 0 )
VSTRING_ADDCH(mechanisms_str, ' ' );
vstring_strcat(mechanisms_str, mp->mech_name);
argv_add(mechanism_argv, mp->mech_name, (char *) 0 );
if (msg_verbose)
msg_info("%s: keep mechanism: %s" , myname, mp->mech_name);
} else {
if (msg_verbose)
msg_info("%s: skip mechanism: %s" , myname, mp->mech_name);
}
}
return (vstring_export(mechanisms_str));
}
/* xsasl_dovecot_server_connect - initial auth server handshake */
static int xsasl_dovecot_server_connect(XSASL_DOVECOT_SERVER_IMPL *xp)
{
const char *myname = "xsasl_dovecot_server_connect" ;
VSTRING *line_str;
VSTREAM *sasl_stream;
char *line, *cmd, *mech_name;
unsigned int major_version, minor_version;
int fd, success, have_mech_line;
int sec_props;
const char *path;
if (msg_verbose)
msg_info("%s: Connecting" , myname);
/*
* Not documented , but necessary for testing .
*/
path = xp->socket_path;
if (strncmp(path, "inet:" , 5 ) == 0 ) {
fd = inet_connect(path + 5 , BLOCKING, AUTH_TIMEOUT);
} else {
if (strncmp(path, "unix:" , 5 ) == 0 )
path += 5 ;
fd = unix_connect(path, BLOCKING, AUTH_TIMEOUT);
}
if (fd < 0 ) {
msg_warn("SASL: Connect to Dovecot auth socket '%s' failed: %m" ,
xp->socket_path);
return (-1 );
}
sasl_stream = vstream_fdopen(fd, O_RDWR);
vstream_control(sasl_stream,
CA_VSTREAM_CTL_PATH(xp->socket_path),
CA_VSTREAM_CTL_TIMEOUT(AUTH_TIMEOUT),
CA_VSTREAM_CTL_END);
/* XXX Encapsulate for logging. */
vstream_fprintf(sasl_stream,
"VERSION\t%u\t%u\n"
"CPID\t%u\n" ,
AUTH_PROTOCOL_MAJOR_VERSION,
AUTH_PROTOCOL_MINOR_VERSION,
(unsigned int ) getpid());
if (vstream_fflush(sasl_stream) == VSTREAM_EOF) {
msg_warn("SASL: Couldn't send handshake: %m" );
(void ) vstream_fclose(sasl_stream);
return (-1 );
}
success = 0 ;
have_mech_line = 0 ;
line_str = vstring_alloc(256 );
/* XXX Encapsulate for logging. */
while (vstring_get_nonl(line_str, sasl_stream) != VSTREAM_EOF) {
line = vstring_str(line_str);
if (msg_verbose)
msg_info("%s: auth reply: %s" , myname, line);
cmd = line;
line = split_at(line, '\t' );
if (strcmp(cmd, "VERSION" ) == 0 ) {
if (sscanf(line, "%u\t%u" , &major_version, &minor_version) != 2 ) {
msg_warn("SASL: Protocol version error" );
break ;
}
if (major_version != AUTH_PROTOCOL_MAJOR_VERSION) {
/* Major version is different from ours. */
msg_warn("SASL: Protocol version mismatch (%d vs. %d)" ,
major_version, AUTH_PROTOCOL_MAJOR_VERSION);
break ;
}
} else if (strcmp(cmd, "MECH" ) == 0 && line != NULL) {
mech_name = line;
have_mech_line = 1 ;
line = split_at(line, '\t' );
if (line != 0 ) {
sec_props =
name_mask_delim_opt(myname,
xsasl_dovecot_serv_sec_props,
line, "\t" ,
NAME_MASK_ANY_CASE | NAME_MASK_IGNORE);
if ((sec_props & SEC_PROPS_PRIVATE) != 0 )
continue ;
} else
sec_props = 0 ;
xsasl_dovecot_server_mech_append(&xp->mechanism_list, mech_name,
sec_props);
} else if (strcmp(cmd, "SPID" ) == 0 ) {
/*
* Unfortunately the auth protocol handshake wasn ' t designed well
* to differentiate between auth - client / userdb / master .
* auth - userdb and auth - master send VERSION + SPID lines only and
* nothing afterwards , while auth - client sends VERSION + MECH +
* SPID + CUID + more . The simplest way that we can determine if
* we ' ve connected to the correct socket is to see if MECH line
* exists or not ( alternatively we ' d have to have a small timeout
* after SPID to see if CUID is sent or not ) .
*/
if (!have_mech_line) {
msg_warn("SASL: Connected to wrong auth socket (auth-master instead of auth-client)" );
break ;
}
} else if (strcmp(cmd, "DONE" ) == 0 ) {
/* Handshake finished. */
success = 1 ;
break ;
} else {
/* ignore any unknown commands */
}
}
vstring_free(line_str);
if (!success) {
/* handshake failed */
(void ) vstream_fclose(sasl_stream);
return (-1 );
}
xp->sasl_stream = sasl_stream;
return (0 );
}
/* xsasl_dovecot_server_disconnect - dispose of server connection state */
static void xsasl_dovecot_server_disconnect(XSASL_DOVECOT_SERVER_IMPL *xp)
{
if (xp->sasl_stream) {
(void ) vstream_fclose(xp->sasl_stream);
xp->sasl_stream = 0 ;
}
if (xp->mechanism_list) {
xsasl_dovecot_server_mech_free(xp->mechanism_list);
xp->mechanism_list = 0 ;
}
}
/* xsasl_dovecot_server_init - create implementation handle */
XSASL_SERVER_IMPL *xsasl_dovecot_server_init(const char *server_type,
const char *path_info)
{
XSASL_DOVECOT_SERVER_IMPL *xp;
xp = (XSASL_DOVECOT_SERVER_IMPL *) mymalloc(sizeof (*xp));
xp->xsasl.create = xsasl_dovecot_server_create;
xp->xsasl.done = xsasl_dovecot_server_done;
xp->socket_path = mystrdup(path_info);
xp->sasl_stream = 0 ;
xp->mechanism_list = 0 ;
xp->request_id_counter = 0 ;
return (&xp->xsasl);
}
/* xsasl_dovecot_server_done - dispose of implementation */
static void xsasl_dovecot_server_done(XSASL_SERVER_IMPL *impl)
{
XSASL_DOVECOT_SERVER_IMPL *xp = (XSASL_DOVECOT_SERVER_IMPL *) impl;
xsasl_dovecot_server_disconnect(xp);
myfree(xp->socket_path);
myfree((void *) impl);
}
/* xsasl_dovecot_server_create - create server instance */
static XSASL_SERVER *xsasl_dovecot_server_create(XSASL_SERVER_IMPL *impl,
XSASL_SERVER_CREATE_ARGS *args)
{
const char *myname = "xsasl_dovecot_server_create" ;
XSASL_DOVECOT_SERVER *server;
struct sockaddr_storage ss;
struct sockaddr *sa = (struct sockaddr *) &ss;
SOCKADDR_SIZE salen;
MAI_HOSTADDR_STR server_addr;
if (msg_verbose)
msg_info("%s: SASL service=%s, realm=%s" ,
myname, args->service, args->user_realm ?
args->user_realm : "(null)" );
/*
* Extend the XSASL_SERVER_IMPL object with our own data . We use
* long - lived conversion buffers rather than local variables to avoid
* memory leaks in case of read / write timeout or I / O error .
*/
server = (XSASL_DOVECOT_SERVER *) mymalloc(sizeof (*server));
server->xsasl.free = xsasl_dovecot_server_free;
server->xsasl.first = xsasl_dovecot_server_first;
server->xsasl.next = xsasl_dovecot_server_next;
server->xsasl.get_mechanism_list = xsasl_dovecot_server_get_mechanism_list;
server->xsasl.get_username = xsasl_dovecot_server_get_username;
server->impl = (XSASL_DOVECOT_SERVER_IMPL *) impl;
server->sasl_line = vstring_alloc(256 );
server->username = 0 ;
server->service = mystrdup(args->service);
server->last_request_id = 0 ;
server->mechanism_list = 0 ;
server->mechanism_argv = 0 ;
server->tls_flag = args->tls_flag;
server->sec_props =
name_mask_opt(myname, xsasl_dovecot_conf_sec_props,
args->security_options,
NAME_MASK_ANY_CASE | NAME_MASK_FATAL);
server->client_addr = mystrdup(args->client_addr);
/*
* XXX Temporary code until smtpd_peer . c is updated .
*/
if (args->server_addr && *args->server_addr) {
server->server_addr = mystrdup(args->server_addr);
} else {
salen = sizeof (ss);
if (getsockname(vstream_fileno(args->stream), sa, &salen) < 0
|| sockaddr_to_hostaddr(sa, salen, &server_addr, 0 , 0 ) != 0 )
server_addr.buf[0 ] = 0 ;
server->server_addr = mystrdup(server_addr.buf);
}
return (&server->xsasl);
}
/* xsasl_dovecot_server_get_mechanism_list - get available mechanisms */
static const char *xsasl_dovecot_server_get_mechanism_list(XSASL_SERVER *xp)
{
XSASL_DOVECOT_SERVER *server = (XSASL_DOVECOT_SERVER *) xp;
if (!server->impl->sasl_stream) {
if (xsasl_dovecot_server_connect(server->impl) < 0 )
return (0 );
}
if (server->mechanism_list == 0 ) {
server->mechanism_argv = argv_alloc(2 );
server->mechanism_list =
xsasl_dovecot_server_mech_filter(server->mechanism_argv,
server->impl->mechanism_list,
server->sec_props);
}
return (server->mechanism_list[0 ] ? server->mechanism_list : 0 );
}
/* xsasl_dovecot_server_free - destroy server instance */
static void xsasl_dovecot_server_free(XSASL_SERVER *xp)
{
XSASL_DOVECOT_SERVER *server = (XSASL_DOVECOT_SERVER *) xp;
vstring_free(server->sasl_line);
if (server->username)
myfree(server->username);
if (server->mechanism_list) {
myfree(server->mechanism_list);
argv_free(server->mechanism_argv);
}
myfree(server->service);
myfree(server->server_addr);
myfree(server->client_addr);
myfree((void *) server);
}
/* xsasl_dovecot_server_auth_response - encode server first/next response */
static int xsasl_dovecot_parse_reply(XSASL_DOVECOT_SERVER *server, char **line)
{
char *id;
if (*line == NULL) {
msg_warn("SASL: Protocol error" );
return -1 ;
}
id = *line;
*line = split_at(*line, '\t' );
if (strtoul(id, NULL, 0 ) != server->last_request_id) {
/* reply to another request, shouldn't really happen.. */
return -1 ;
}
return 0 ;
}
static void xsasl_dovecot_parse_reply_args(XSASL_DOVECOT_SERVER *server,
char *line, VSTRING *reply,
int success)
{
char *next;
if (server->username) {
myfree(server->username);
server->username = 0 ;
}
VSTRING_RESET(reply);
VSTRING_TERMINATE(reply);
/*
* Note : TAB is part of the Dovecot protocol and must not appear in
* legitimate Dovecot usernames , otherwise the protocol would break .
*/
for (; line != NULL; line = next) {
next = split_at(line, '\t' );
if (strncmp(line, "user=" , 5 ) == 0 ) {
server->username = mystrdup(line + 5 );
printable(server->username, '?' );
} else if (strncmp(line, "reason=" , 7 ) == 0 ) {
if (!success) {
printable(line + 7 , '?' );
vstring_strcpy(reply, line + 7 );
}
}
}
}
/* xsasl_dovecot_handle_reply - receive and process auth reply */
static int xsasl_dovecot_handle_reply(XSASL_DOVECOT_SERVER *server,
VSTRING *reply)
{
const char *myname = "xsasl_dovecot_handle_reply" ;
char *line, *cmd;
/* XXX Encapsulate for logging. */
while (vstring_get_nonl(server->sasl_line,
server->impl->sasl_stream) != VSTREAM_EOF) {
line = vstring_str(server->sasl_line);
if (msg_verbose)
msg_info("%s: auth reply: %s" , myname, line);
cmd = line;
line = split_at(line, '\t' );
if (strcmp(cmd, "OK" ) == 0 ) {
if (xsasl_dovecot_parse_reply(server, &line) == 0 ) {
/* authentication successful */
xsasl_dovecot_parse_reply_args(server, line, reply, 1 );
if (server->username == 0 ) {
msg_warn("missing Dovecot server %s username field" , cmd);
vstring_strcpy(reply, "Authentication backend error" );
return XSASL_AUTH_FAIL;
}
return XSASL_AUTH_DONE;
}
} else if (strcmp(cmd, "CONT" ) == 0 ) {
if (xsasl_dovecot_parse_reply(server, &line) == 0 ) {
if (line == 0 ) {
msg_warn("missing Dovecot server %s reply field" , cmd);
vstring_strcpy(reply, "Authentication backend error" );
return XSASL_AUTH_FAIL;
}
vstring_strcpy(reply, line);
return XSASL_AUTH_MORE;
}
} else if (strcmp(cmd, "FAIL" ) == 0 ) {
if (xsasl_dovecot_parse_reply(server, &line) == 0 ) {
/* authentication failure */
xsasl_dovecot_parse_reply_args(server, line, reply, 0 );
return XSASL_AUTH_FAIL;
}
} else {
/* ignore */
}
}
vstring_strcpy(reply, "Connection lost to authentication server" );
xsasl_dovecot_server_disconnect(server->impl);
return XSASL_AUTH_TEMP;
}
/* is_valid_base64 - input sanitized */
static int is_valid_base64(const char *data)
{
/*
* XXX Maybe use ISALNUM ( ) ( isascii & & isalnum , i . e . locale independent ) .
*/
for (; *data != '\0' ; data++) {
if (!((*data >= '0' && *data <= '9' ) ||
(*data >= 'a' && *data <= 'z' ) ||
(*data >= 'A' && *data <= 'Z' ) ||
*data == '+' || *data == '/' || *data == '=' ))
return 0 ;
}
return 1 ;
}
/* xsasl_dovecot_server_first - per-session authentication */
int xsasl_dovecot_server_first(XSASL_SERVER *xp, const char *sasl_method,
const char *init_response, VSTRING *reply)
{
const char *myname = "xsasl_dovecot_server_first" ;
XSASL_DOVECOT_SERVER *server = (XSASL_DOVECOT_SERVER *) xp;
int i;
char **cpp;
#define IFELSE(e1,e2,e3) ((e1) ? (e2) : (e3))
if (msg_verbose)
msg_info("%s: sasl_method %s%s%s" , myname, sasl_method,
IFELSE(init_response, ", init_response " , "" ),
IFELSE(init_response, init_response, "" ));
if (server->mechanism_argv == 0 )
msg_panic("%s: no mechanism list" , myname);
for (cpp = server->mechanism_argv->argv; /* see below */ ; cpp++) {
if (*cpp == 0 ) {
vstring_sprintf(reply, "Invalid authentication mechanism: '%s'" ,
sasl_method);
printable(vstring_str(reply), '?' );
return XSASL_AUTH_FAIL;
}
if (strcasecmp(sasl_method, *cpp) == 0 )
break ;
}
if (init_response)
if (!is_valid_base64(init_response)) {
vstring_strcpy(reply, "Invalid base64 data in initial response" );
return XSASL_AUTH_FAIL;
}
for (i = 0 ; i < 2 ; i++) {
if (!server->impl->sasl_stream) {
if (xsasl_dovecot_server_connect(server->impl) < 0 )
return XSASL_AUTH_TEMP;
}
/* send the request */
server->last_request_id = ++server->impl->request_id_counter;
/* XXX Encapsulate for logging. */
vstream_fprintf(server->impl->sasl_stream,
"AUTH\t%u\t%s\tservice=%s\tnologin\tlip=%s\trip=%s" ,
server->last_request_id, sasl_method,
server->service, server->server_addr,
server->client_addr);
if (server->tls_flag)
/* XXX Encapsulate for logging. */
vstream_fputs("\tsecured" , server->impl->sasl_stream);
if (init_response) {
/*
* initial response is already base64 encoded , so we can send it
* directly .
*/
/* XXX Encapsulate for logging. */
vstream_fprintf(server->impl->sasl_stream,
"\tresp=%s" , init_response);
}
/* XXX Encapsulate for logging. */
VSTREAM_PUTC('\n' , server->impl->sasl_stream);
if (vstream_fflush(server->impl->sasl_stream) != VSTREAM_EOF)
break ;
if (i == 1 ) {
vstring_strcpy(reply, "Can't connect to authentication server" );
xsasl_dovecot_server_disconnect(server->impl);
return XSASL_AUTH_TEMP;
}
/*
* Reconnect and try again .
*/
xsasl_dovecot_server_disconnect(server->impl);
}
return xsasl_dovecot_handle_reply(server, reply);
}
/* xsasl_dovecot_server_next - continue authentication */
static int xsasl_dovecot_server_next(XSASL_SERVER *xp, const char *request,
VSTRING *reply)
{
XSASL_DOVECOT_SERVER *server = (XSASL_DOVECOT_SERVER *) xp;
if (!is_valid_base64(request)) {
vstring_strcpy(reply, "Invalid base64 data in continued response" );
return XSASL_AUTH_FAIL;
}
/* XXX Encapsulate for logging. */
vstream_fprintf(server->impl->sasl_stream,
"CONT\t%u\t%s\n" , server->last_request_id, request);
if (vstream_fflush(server->impl->sasl_stream) == VSTREAM_EOF) {
vstring_strcpy(reply, "Connection lost to authentication server" );
xsasl_dovecot_server_disconnect(server->impl);
return XSASL_AUTH_TEMP;
}
return xsasl_dovecot_handle_reply(server, reply);
}
/* xsasl_dovecot_server_get_username - get authenticated username */
static const char *xsasl_dovecot_server_get_username(XSASL_SERVER *xp)
{
XSASL_DOVECOT_SERVER *server = (XSASL_DOVECOT_SERVER *) xp;
return (server->username);
}
#endif
Messung V0.5 in Prozent C=79 H=92 G=85
¤ Dauer der Verarbeitung: 0.38 Sekunden
(vorverarbeitet am 2026-08-08)
¤
*© Formatika GbR, Deutschland