60 #include <sys/socket.h>
81 #if defined(USE_SASL_AUTH) && defined(USE_CYRUS_SASL)
89 #define STR(s) vstring_str(s)
111 #if SASL_VERSION_MAJOR < 2
113 #define SASL_SERVER_NEW(srv, fqdn, rlm, lport, rport, cb, secflags, pconn) \
114 sasl_server_new(srv, fqdn, rlm, cb, secflags, pconn)
115 #define SASL_SERVER_START(conn, mech, clin, clinlen, srvout, srvoutlen, err) \
116 sasl_server_start(conn, mech, clin, clinlen, srvout, srvoutlen, err)
117 #define SASL_SERVER_STEP(conn, clin, clinlen, srvout, srvoutlen, err) \
118 sasl_server_step(conn, clin, clinlen, srvout, srvoutlen, err)
119 #define SASL_DECODE64(in, inlen, out, outmaxlen, outlen) \
120 sasl_decode64(in, inlen, out, outlen)
121 typedef char *MECHANISM_TYPE;
122 typedef unsigned MECHANISM_COUNT_TYPE;
123 typedef char *SERVEROUT_TYPE;
124 typedef void *VOID_SERVEROUT_TYPE;
128 #if SASL_VERSION_MAJOR >= 2
130 #define SASL_SERVER_NEW(srv, fqdn, rlm, lport, rport, cb, secflags, pconn) \
131 sasl_server_new(srv, fqdn, rlm, lport, rport, cb, secflags, pconn)
132 #define SASL_SERVER_START(conn, mech, clin, clinlen, srvout, srvoutlen, err) \
133 sasl_server_start(conn, mech, clin, clinlen, srvout, srvoutlen)
134 #define SASL_SERVER_STEP(conn, clin, clinlen, srvout, srvoutlen, err) \
135 sasl_server_step(conn, clin, clinlen, srvout, srvoutlen)
136 #define SASL_DECODE64(in, inlen, out, outmaxlen, outlen) \
137 sasl_decode64(in, inlen, out, outmaxlen, outlen)
138 typedef const char *MECHANISM_TYPE;
139 typedef int MECHANISM_COUNT_TYPE;
140 typedef const char *SERVEROUT_TYPE;
141 typedef const void *VOID_SERVEROUT_TYPE;
145 #ifndef NO_IP_CYRUS_SASL_AUTH
146 #define USE_IP_CYRUS_SASL_AUTH
156 sasl_conn_t *sasl_conn;
159 char *mechanism_list;
160 } XSASL_CYRUS_SERVER;
169 static int xsasl_cyrus_server_first(
XSASL_SERVER *,
const char *,
172 static int xsasl_cyrus_server_set_security(
XSASL_SERVER *,
const char *);
173 static const char *xsasl_cyrus_server_get_mechanism_list(
XSASL_SERVER *);
174 static const char *xsasl_cyrus_server_get_username(
XSASL_SERVER *);
180 #define NO_CALLBACK_CONTEXT 0
182 static sasl_callback_t callbacks[] = {
183 {SASL_CB_LOG, (XSASL_CYRUS_CB) &xsasl_cyrus_log, NO_CALLBACK_CONTEXT},
184 {SASL_CB_LIST_END, 0, 0}
190 const char *path_info)
192 const char *myname =
"xsasl_cyrus_server_init";
196 #if SASL_VERSION_MAJOR >= 2 && (SASL_VERSION_MINOR >= 2 \
197 || (SASL_VERSION_MINOR == 1 && SASL_VERSION_STEP >= 19))
205 sasl_version_info((
const char **) 0, (
const char **) 0,
206 &sasl_major, &sasl_minor,
207 &sasl_step, (
int *) 0);
208 if (sasl_major != SASL_VERSION_MAJOR
210 || sasl_minor != SASL_VERSION_MINOR
211 || sasl_step != SASL_VERSION_STEP
214 msg_warn(
"incorrect SASL library version. "
215 "Postfix was built with include files from version %d.%d.%d, "
216 "but the run-time library version is %d.%d.%d",
217 SASL_VERSION_MAJOR, SASL_VERSION_MINOR, SASL_VERSION_STEP,
218 sasl_major, sasl_minor, sasl_step);
224 #ifdef SASL_PATH_TYPE_CONFIG
225 if (sasl_set_path(SASL_PATH_TYPE_CONFIG,
227 msg_warn(
"failed to set Cyrus SASL configuration path: \"%s\"",
230 msg_warn(
"%s is not empty, but setting the Cyrus SASL configuration "
231 "path is not supported with SASL library version %d.%d.%d",
233 SASL_VERSION_MINOR, SASL_VERSION_STEP);
241 msg_info(
"%s: SASL config file is %s.conf", myname, path_info);
242 if ((sasl_status = sasl_server_init(callbacks, path_info)) != SASL_OK) {
243 msg_warn(
"SASL per-process initialization failed: %s",
244 xsasl_cyrus_strerror(sasl_status));
253 xp->
create = xsasl_cyrus_server_create;
254 xp->
done = xsasl_cyrus_server_done;
271 const char *myname =
"xsasl_cyrus_server_create";
272 char *server_addr_port = 0;
273 char *client_addr_port = 0;
274 sasl_conn_t *sasl_conn = 0;
275 XSASL_CYRUS_SERVER *server = 0;
279 msg_info(
"%s: SASL service=%s, realm=%s",
286 #define XSASL_CYRUS_SERVER_CREATE_ERROR_RETURN(x) \
289 xsasl_cyrus_server_free(&server->xsasl); \
292 sasl_dispose(&sasl_conn); \
294 XSASL_CYRUS_SERVER_CREATE_RETURN(x); \
297 #define XSASL_CYRUS_SERVER_CREATE_RETURN(x) \
299 if (server_addr_port) \
300 myfree(server_addr_port); \
301 if (client_addr_port) \
302 myfree(client_addr_port); \
309 #define NO_SECURITY_LAYERS (0)
310 #define NO_SESSION_CALLBACKS ((sasl_callback_t *) 0)
311 #define NO_AUTH_REALM ((char *) 0)
313 #if SASL_VERSION_MAJOR >= 2 && defined(USE_IP_CYRUS_SASL_AUTH)
337 server_addr_port, client_addr_port,
338 NO_SESSION_CALLBACKS, NO_SECURITY_LAYERS,
339 &sasl_conn)) != SASL_OK) {
340 msg_warn(
"SASL per-connection server initialization: %s",
341 xsasl_cyrus_strerror(sasl_status));
342 XSASL_CYRUS_SERVER_CREATE_ERROR_RETURN(0);
350 server = (XSASL_CYRUS_SERVER *)
mymalloc(
sizeof(*server));
351 server->xsasl.free = xsasl_cyrus_server_free;
352 server->xsasl.first = xsasl_cyrus_server_first;
353 server->xsasl.next = xsasl_cyrus_server_next;
354 server->xsasl.get_mechanism_list = xsasl_cyrus_server_get_mechanism_list;
355 server->xsasl.get_username = xsasl_cyrus_server_get_username;
356 server->stream = args->
stream;
357 server->sasl_conn = sasl_conn;
359 server->username = 0;
360 server->mechanism_list = 0;
364 XSASL_CYRUS_SERVER_CREATE_ERROR_RETURN(0);
366 XSASL_CYRUS_SERVER_CREATE_RETURN(&server->xsasl);
371 static int xsasl_cyrus_server_set_security(
XSASL_SERVER *xp,
372 const char *sasl_opts_val)
374 XSASL_CYRUS_SERVER *server = (XSASL_CYRUS_SERVER *) xp;
375 sasl_security_properties_t sec_props;
382 memset(&sec_props, 0,
sizeof(sec_props));
383 sec_props.min_ssf = 0;
384 sec_props.max_ssf = 0;
386 if (*sasl_opts_val == 0) {
387 sec_props.security_flags = 0;
389 sec_props.security_flags =
390 xsasl_cyrus_security_parse_opts(sasl_opts_val);
391 if (sec_props.security_flags == 0) {
392 msg_warn(
"bad per-session SASL security properties");
396 sec_props.maxbufsize = 0;
397 sec_props.property_names = 0;
398 sec_props.property_values = 0;
400 if ((sasl_status = sasl_setprop(server->sasl_conn, SASL_SEC_PROPS,
401 &sec_props)) != SASL_OK) {
402 msg_warn(
"SASL per-connection security setup; %s",
403 xsasl_cyrus_strerror(sasl_status));
411 static const char *xsasl_cyrus_server_get_mechanism_list(
XSASL_SERVER *xp)
413 const char *myname =
"xsasl_cyrus_server_get_mechanism_list";
414 XSASL_CYRUS_SERVER *server = (XSASL_CYRUS_SERVER *) xp;
415 MECHANISM_TYPE mechanism_list;
416 MECHANISM_COUNT_TYPE mechanism_count;
422 #define UNSUPPORTED_USER ((char *) 0)
423 #define IGNORE_MECHANISM_LEN ((unsigned *) 0)
425 if ((sasl_status = sasl_listmech(server->sasl_conn, UNSUPPORTED_USER,
428 IGNORE_MECHANISM_LEN,
429 &mechanism_count)) != SASL_OK) {
430 msg_warn(
"%s: %s", myname, xsasl_cyrus_strerror(sasl_status));
433 if (mechanism_count <= 0) {
434 msg_warn(
"%s: no applicable SASL mechanisms", myname);
437 server->mechanism_list =
mystrdup(mechanism_list);
438 #if SASL_VERSION_MAJOR < 2
440 free(mechanism_list);
442 return (server->mechanism_list);
449 XSASL_CYRUS_SERVER *server = (XSASL_CYRUS_SERVER *) xp;
451 sasl_dispose(&server->sasl_conn);
453 if (server->username)
455 if (server->mechanism_list)
456 myfree(server->mechanism_list);
462 static int xsasl_cyrus_server_auth_response(
int sasl_status,
463 SERVEROUT_TYPE serverout,
464 unsigned serveroutlen,
467 const char *myname =
"xsasl_cyrus_server_auth_response";
469 unsigned enc_length_out;
480 if (sasl_status == SASL_OK) {
483 }
else if (sasl_status == SASL_CONTINUE) {
485 msg_info(
"%s: uncoded server challenge: %.*s",
486 myname, (
int) serveroutlen, serverout);
487 enc_length = ((serveroutlen + 2) / 3) * 4 + 1;
490 if ((sasl_status = sasl_encode64(serverout, serveroutlen,
492 &enc_length_out)) != SASL_OK)
494 myname, xsasl_cyrus_strerror(sasl_status));
497 if (sasl_status == SASL_NOUSER)
498 sasl_status = SASL_BADAUTH;
500 switch (sasl_status) {
514 int xsasl_cyrus_server_first(
XSASL_SERVER *xp,
const char *sasl_method,
515 const char *init_response,
VSTRING *reply)
517 const char *myname =
"xsasl_cyrus_server_first";
518 XSASL_CYRUS_SERVER *server = (XSASL_CYRUS_SERVER *) xp;
522 unsigned serveroutlen;
524 SERVEROUT_TYPE serverout = 0;
527 #if SASL_VERSION_MAJOR < 2
528 const char *errstr = 0;
532 #define IFELSE(e1,e2,e3) ((e1) ? (e2) : (e3))
535 msg_info(
"%s: sasl_method %s%s%s", myname, sasl_method,
536 IFELSE(init_response,
", init_response ",
""),
537 IFELSE(init_response, init_response,
""));
544 reply_len = strlen(init_response);
547 if ((sasl_status = SASL_DECODE64(init_response, reply_len,
548 dec_buffer =
STR(server->decoded),
550 &dec_length)) != SASL_OK) {
555 msg_info(
"%s: decoded initial response %s", myname, dec_buffer);
560 sasl_status = SASL_SERVER_START(server->sasl_conn, sasl_method, dec_buffer,
561 dec_length, &serverout,
562 &serveroutlen, &errstr);
563 xsasl_status = xsasl_cyrus_server_auth_response(sasl_status, serverout,
564 serveroutlen, reply);
565 #if SASL_VERSION_MAJOR < 2
569 return (xsasl_status);
574 static int xsasl_cyrus_server_next(
XSASL_SERVER *xp,
const char *request,
577 const char *myname =
"xsasl_cyrus_server_next";
578 XSASL_CYRUS_SERVER *server = (XSASL_CYRUS_SERVER *) xp;
580 unsigned request_len;
581 unsigned serveroutlen;
583 SERVEROUT_TYPE serverout = 0;
586 #if SASL_VERSION_MAJOR < 2
587 const char *errstr = 0;
591 request_len = strlen(request);
594 if ((sasl_status = SASL_DECODE64(request, request_len,
595 STR(server->decoded),
597 &dec_length)) != SASL_OK) {
602 msg_info(
"%s: decoded response: %.*s",
603 myname, (
int) dec_length,
STR(server->decoded));
604 sasl_status = SASL_SERVER_STEP(server->sasl_conn,
STR(server->decoded),
605 dec_length, &serverout,
606 &serveroutlen, &errstr);
607 xsasl_status = xsasl_cyrus_server_auth_response(sasl_status, serverout,
608 serveroutlen, reply);
609 #if SASL_VERSION_MAJOR < 2
613 return (xsasl_status);
618 static const char *xsasl_cyrus_server_get_username(
XSASL_SERVER *xp)
620 const char *myname =
"xsasl_cyrus_server_get_username";
621 XSASL_CYRUS_SERVER *server = (XSASL_CYRUS_SERVER *) xp;
622 VOID_SERVEROUT_TYPE serverout = 0;
628 sasl_status = sasl_getprop(server->sasl_conn, SASL_USERNAME, &serverout);
629 if (sasl_status != SASL_OK || serverout == 0) {
630 msg_warn(
"%s: sasl_getprop SASL_USERNAME botch: %s",
631 myname, xsasl_cyrus_strerror(sasl_status));
634 if (server->username)
636 server->username =
mystrdup(serverout);
638 return (server->username);
char * mystrdup(const char *str)
#define VAR_CYRUS_CONF_PATH
NORETURN msg_panic(const char *fmt,...)
void(* done)(struct XSASL_SERVER_IMPL *)
VSTRING * vstring_strcpy(VSTRING *vp, const char *src)
char * var_cyrus_conf_path
#define VSTRING_RESET(vp)
void msg_warn(const char *fmt,...)
VSTRING * vstring_alloc(ssize_t len)
const char * username(void)
#define vstring_avail(vp)
XSASL_SERVER *(* create)(struct XSASL_SERVER_IMPL *, XSASL_SERVER_CREATE_ARGS *)
char * concatenate(const char *arg0,...)
const char * security_options
#define VSTRING_SPACE(vp, len)
VSTRING * vstring_free(VSTRING *vp)
char * printable(char *string, int replacement)
void * mymalloc(ssize_t len)
void msg_info(const char *fmt,...)