58 #ifdef STRCASECMP_IN_STRINGS_H
88 #define AUTH_PROTOCOL_MAJOR_VERSION 1
89 #define AUTH_PROTOCOL_MINOR_VERSION 0
95 #define AUTH_TIMEOUT 10
100 #define SEC_PROPS_NOPLAINTEXT (1 << 0)
101 #define SEC_PROPS_NOACTIVE (1 << 1)
102 #define SEC_PROPS_NODICTIONARY (1 << 2)
103 #define SEC_PROPS_NOANONYMOUS (1 << 3)
104 #define SEC_PROPS_FWD_SECRECY (1 << 4)
105 #define SEC_PROPS_MUTUAL_AUTH (1 << 5)
106 #define SEC_PROPS_PRIVATE (1 << 6)
108 #define SEC_PROPS_POS_MASK (SEC_PROPS_MUTUAL_AUTH | SEC_PROPS_FWD_SECRECY)
109 #define SEC_PROPS_NEG_MASK (SEC_PROPS_NOPLAINTEXT | SEC_PROPS_NOACTIVE | \
110 SEC_PROPS_NODICTIONARY | SEC_PROPS_NOANONYMOUS)
115 static const NAME_MASK xsasl_dovecot_conf_sec_props[] = {
116 "noplaintext", SEC_PROPS_NOPLAINTEXT,
117 "noactive", SEC_PROPS_NOACTIVE,
118 "nodictionary", SEC_PROPS_NODICTIONARY,
119 "noanonymous", SEC_PROPS_NOANONYMOUS,
120 "forward_secrecy", SEC_PROPS_FWD_SECRECY,
121 "mutual_auth", SEC_PROPS_MUTUAL_AUTH,
129 static const NAME_MASK xsasl_dovecot_serv_sec_props[] = {
130 "plaintext", SEC_PROPS_NOPLAINTEXT,
131 "active", SEC_PROPS_NOACTIVE,
132 "dictionary", SEC_PROPS_NODICTIONARY,
133 "anonymous", SEC_PROPS_NOANONYMOUS,
134 "forward-secrecy", SEC_PROPS_FWD_SECRECY,
135 "mutual-auth", SEC_PROPS_MUTUAL_AUTH,
136 "private", SEC_PROPS_PRIVATE,
143 typedef struct XSASL_DCSRV_MECH {
146 struct XSASL_DCSRV_MECH *next;
153 XSASL_DCSRV_MECH *mechanism_list;
154 unsigned int request_id_counter;
155 } XSASL_DOVECOT_SERVER_IMPL;
163 XSASL_DOVECOT_SERVER_IMPL *impl;
164 unsigned int last_request_id;
168 unsigned int sec_props;
170 char *mechanism_list;
171 ARGV *mechanism_argv;
174 } XSASL_DOVECOT_SERVER;
183 static int xsasl_dovecot_server_first(
XSASL_SERVER *,
const char *,
186 static const char *xsasl_dovecot_server_get_mechanism_list(
XSASL_SERVER *);
187 static const char *xsasl_dovecot_server_get_username(
XSASL_SERVER *);
191 static void xsasl_dovecot_server_mech_append(XSASL_DCSRV_MECH **mech_list,
192 const char *mech_name,
int sec_props)
194 XSASL_DCSRV_MECH **mpp;
195 XSASL_DCSRV_MECH *mp;
197 for (mpp = mech_list; *mpp != 0; mpp = &mpp[0]->next)
200 mp = (XSASL_DCSRV_MECH *)
mymalloc(
sizeof(*mp));
201 mp->mech_name =
mystrdup(mech_name);
202 mp->sec_props = sec_props;
209 static void xsasl_dovecot_server_mech_free(XSASL_DCSRV_MECH *mech_list)
211 XSASL_DCSRV_MECH *mp;
212 XSASL_DCSRV_MECH *next;
214 for (mp = mech_list; mp != 0; mp = next) {
223 static char *xsasl_dovecot_server_mech_filter(
ARGV *mechanism_argv,
224 XSASL_DCSRV_MECH *mechanism_list,
225 unsigned int conf_props)
227 const char *myname =
"xsasl_dovecot_server_mech_filter";
228 unsigned int pos_conf_props = (conf_props & SEC_PROPS_POS_MASK);
229 unsigned int neg_conf_props = (conf_props & SEC_PROPS_NEG_MASK);
231 XSASL_DCSRV_MECH *mp;
236 for (mp = mechanism_list; mp != 0; mp = mp->next) {
237 if ((mp->sec_props & pos_conf_props) == pos_conf_props
238 && (mp->sec_props & neg_conf_props) == 0) {
242 argv_add(mechanism_argv, mp->mech_name, (
char *) 0);
244 msg_info(
"%s: keep mechanism: %s", myname, mp->mech_name);
247 msg_info(
"%s: skip mechanism: %s", myname, mp->mech_name);
255 static int xsasl_dovecot_server_connect(XSASL_DOVECOT_SERVER_IMPL *xp)
257 const char *myname =
"xsasl_dovecot_server_connect";
260 char *line, *cmd, *mech_name;
261 unsigned int major_version, minor_version;
262 int fd, success, have_mech_line;
272 path = xp->socket_path;
273 if (strncmp(path,
"inet:", 5) == 0) {
276 if (strncmp(path,
"unix:", 5) == 0)
281 msg_warn(
"SASL: Connect to %s failed: %m", xp->socket_path);
294 AUTH_PROTOCOL_MAJOR_VERSION,
295 AUTH_PROTOCOL_MINOR_VERSION,
296 (
unsigned int) getpid());
298 msg_warn(
"SASL: Couldn't send handshake: %m");
309 msg_info(
"%s: auth reply: %s", myname, line);
314 if (strcmp(cmd,
"VERSION") == 0) {
315 if (sscanf(line,
"%u\t%u", &major_version, &minor_version) != 2) {
316 msg_warn(
"SASL: Protocol version error");
319 if (major_version != AUTH_PROTOCOL_MAJOR_VERSION) {
321 msg_warn(
"SASL: Protocol version mismatch (%d vs. %d)",
322 major_version, AUTH_PROTOCOL_MAJOR_VERSION);
325 }
else if (strcmp(cmd,
"MECH") == 0 && line != NULL) {
332 xsasl_dovecot_serv_sec_props,
335 if ((sec_props & SEC_PROPS_PRIVATE) != 0)
339 xsasl_dovecot_server_mech_append(&xp->mechanism_list, mech_name,
341 }
else if (strcmp(cmd,
"SPID") == 0) {
353 if (!have_mech_line) {
354 msg_warn(
"SASL: Connected to wrong auth socket (auth-master instead of auth-client)");
357 }
else if (strcmp(cmd,
"DONE") == 0) {
372 xp->sasl_stream = sasl_stream;
378 static void xsasl_dovecot_server_disconnect(XSASL_DOVECOT_SERVER_IMPL *xp)
380 if (xp->sasl_stream) {
384 if (xp->mechanism_list) {
385 xsasl_dovecot_server_mech_free(xp->mechanism_list);
386 xp->mechanism_list = 0;
393 const char *path_info)
395 XSASL_DOVECOT_SERVER_IMPL *xp;
397 xp = (XSASL_DOVECOT_SERVER_IMPL *)
mymalloc(
sizeof(*xp));
398 xp->xsasl.create = xsasl_dovecot_server_create;
399 xp->xsasl.done = xsasl_dovecot_server_done;
400 xp->socket_path =
mystrdup(path_info);
402 xp->mechanism_list = 0;
403 xp->request_id_counter = 0;
411 XSASL_DOVECOT_SERVER_IMPL *xp = (XSASL_DOVECOT_SERVER_IMPL *) impl;
413 xsasl_dovecot_server_disconnect(xp);
423 const char *myname =
"xsasl_dovecot_server_create";
424 XSASL_DOVECOT_SERVER *server;
425 struct sockaddr_storage ss;
426 struct sockaddr *sa = (
struct sockaddr *) &ss;
431 msg_info(
"%s: SASL service=%s, realm=%s",
440 server = (XSASL_DOVECOT_SERVER *)
mymalloc(
sizeof(*server));
441 server->xsasl.free = xsasl_dovecot_server_free;
442 server->xsasl.first = xsasl_dovecot_server_first;
443 server->xsasl.next = xsasl_dovecot_server_next;
444 server->xsasl.get_mechanism_list = xsasl_dovecot_server_get_mechanism_list;
445 server->xsasl.get_username = xsasl_dovecot_server_get_username;
446 server->impl = (XSASL_DOVECOT_SERVER_IMPL *) impl;
448 server->username = 0;
450 server->last_request_id = 0;
451 server->mechanism_list = 0;
452 server->mechanism_argv = 0;
469 server_addr.
buf[0] = 0;
473 return (&server->xsasl);
478 static const char *xsasl_dovecot_server_get_mechanism_list(
XSASL_SERVER *xp)
480 XSASL_DOVECOT_SERVER *server = (XSASL_DOVECOT_SERVER *) xp;
482 if (!server->impl->sasl_stream) {
483 if (xsasl_dovecot_server_connect(server->impl) < 0)
486 if (server->mechanism_list == 0) {
488 server->mechanism_list =
489 xsasl_dovecot_server_mech_filter(server->mechanism_argv,
490 server->impl->mechanism_list,
493 return (server->mechanism_list[0] ? server->mechanism_list : 0);
500 XSASL_DOVECOT_SERVER *server = (XSASL_DOVECOT_SERVER *) xp;
503 if (server->username)
505 if (server->mechanism_list) {
506 myfree(server->mechanism_list);
510 myfree(server->server_addr);
511 myfree(server->client_addr);
517 static int xsasl_dovecot_parse_reply(XSASL_DOVECOT_SERVER *server,
char **line)
528 if (strtoul(
id, NULL, 0) != server->last_request_id) {
535 static void xsasl_dovecot_parse_reply_args(XSASL_DOVECOT_SERVER *server,
541 if (server->username) {
543 server->username = 0;
550 for (; line != NULL; line = next) {
552 if (strncmp(line,
"user=", 5) == 0) {
553 server->username =
mystrdup(line + 5);
555 }
else if (strncmp(line,
"reason=", 7) == 0) {
566 static int xsasl_dovecot_handle_reply(XSASL_DOVECOT_SERVER *server,
569 const char *myname =
"xsasl_dovecot_handle_reply";
578 msg_info(
"%s: auth reply: %s", myname, line);
583 if (strcmp(cmd,
"OK") == 0) {
584 if (xsasl_dovecot_parse_reply(server, &line) == 0) {
586 xsasl_dovecot_parse_reply_args(server, line, reply, 1);
589 }
else if (strcmp(cmd,
"CONT") == 0) {
590 if (xsasl_dovecot_parse_reply(server, &line) == 0) {
594 }
else if (strcmp(cmd,
"FAIL") == 0) {
595 if (xsasl_dovecot_parse_reply(server, &line) == 0) {
597 xsasl_dovecot_parse_reply_args(server, line, reply, 0);
605 vstring_strcpy(reply,
"Connection lost to authentication server");
611 static int is_valid_base64(
const char *data)
617 for (; *data !=
'\0'; data++) {
618 if (!((*data >=
'0' && *data <=
'9') ||
619 (*data >=
'a' && *data <=
'z') ||
620 (*data >=
'A' && *data <=
'Z') ||
621 *data ==
'+' || *data ==
'/' || *data ==
'='))
629 int xsasl_dovecot_server_first(
XSASL_SERVER *xp,
const char *sasl_method,
630 const char *init_response,
VSTRING *reply)
632 const char *myname =
"xsasl_dovecot_server_first";
633 XSASL_DOVECOT_SERVER *server = (XSASL_DOVECOT_SERVER *) xp;
637 #define IFELSE(e1,e2,e3) ((e1) ? (e2) : (e3))
640 msg_info(
"%s: sasl_method %s%s%s", myname, sasl_method,
641 IFELSE(init_response,
", init_response ",
""),
642 IFELSE(init_response, init_response,
""));
644 if (server->mechanism_argv == 0)
645 msg_panic(
"%s: no mechanism list", myname);
647 for (cpp = server->mechanism_argv->argv; ; cpp++) {
656 if (!is_valid_base64(init_response)) {
660 for (i = 0; i < 2; i++) {
661 if (!server->impl->sasl_stream) {
662 if (xsasl_dovecot_server_connect(server->impl) < 0)
666 server->last_request_id = ++server->impl->request_id_counter;
669 "AUTH\t%u\t%s\tservice=%s\tnologin\tlip=%s\trip=%s",
670 server->last_request_id, sasl_method,
671 server->service, server->server_addr,
672 server->client_addr);
673 if (server->tls_flag)
684 "\tresp=%s", init_response);
700 xsasl_dovecot_server_disconnect(server->impl);
703 return xsasl_dovecot_handle_reply(server, reply);
708 static int xsasl_dovecot_server_next(
XSASL_SERVER *xp,
const char *request,
711 XSASL_DOVECOT_SERVER *server = (XSASL_DOVECOT_SERVER *) xp;
713 if (!is_valid_base64(request)) {
714 vstring_strcpy(reply,
"Invalid base64 data in continued response");
719 "CONT\t%u\t%s\n", server->last_request_id, request);
721 vstring_strcpy(reply,
"Connection lost to authentication server");
724 return xsasl_dovecot_handle_reply(server, reply);
729 static const char *xsasl_dovecot_server_get_username(
XSASL_SERVER *xp)
731 XSASL_DOVECOT_SERVER *server = (XSASL_DOVECOT_SERVER *) xp;
733 return (server->username);
#define CA_VSTREAM_CTL_TIMEOUT(v)
char * mystrdup(const char *str)
int vstring_get_nonl(VSTRING *vp, VSTREAM *fp)
ARGV * argv_free(ARGV *argvp)
NORETURN msg_panic(const char *fmt,...)
void argv_add(ARGV *argvp,...)
ARGV * argv_alloc(ssize_t len)
VSTRING * vstring_strcpy(VSTRING *vp, const char *src)
int sockaddr_to_hostaddr(const struct sockaddr *sa, SOCKADDR_SIZE salen, MAI_HOSTADDR_STR *hostaddr, MAI_SERVPORT_STR *portnum, int unused_socktype)
#define VSTRING_ADDCH(vp, ch)
char buf[MAI_HOSTADDR_STRSIZE]
VSTREAM * vstream_fprintf(VSTREAM *stream, const char *fmt,...)
int inet_connect(const char *, int, int)
int vstream_fclose(VSTREAM *stream)
int unix_connect(const char *, int, int)
void msg_warn(const char *fmt,...)
int name_mask_delim_opt(const char *context, const NAME_MASK *table, const char *names, const char *delim, int flags)
VSTRING * vstring_alloc(ssize_t len)
const char * username(void)
int vstream_fflush(VSTREAM *stream)
const char * security_options
int strcasecmp(const char *s1, const char *s2)
VSTRING * vstring_free(VSTRING *vp)
char * split_at(char *string, int delimiter)
#define vstream_fileno(vp)
#define NAME_MASK_ANY_CASE
#define CA_VSTREAM_CTL_END
#define CA_VSTREAM_CTL_PATH(v)
#define VSTREAM_PUTC(ch, vp)
char * printable(char *string, int replacement)
void vstream_control(VSTREAM *stream, int name,...)
#define name_mask_opt(tag, table, str, flags)
VSTRING * vstring_strcat(VSTRING *vp, const char *src)
char * vstring_export(VSTRING *vp)
VSTREAM * vstream_fdopen(int fd, int flags)
void * mymalloc(ssize_t len)
int vstream_fputs(const char *str, VSTREAM *stream)
void msg_info(const char *fmt,...)