80 #if defined(USE_SASL_AUTH) && defined(USE_CYRUS_SASL)
88 #define STR(s) vstring_str(s)
108 #if SASL_VERSION_MAJOR < 2
110 #define SASL_CLIENT_NEW(srv, fqdn, lport, rport, prompt, secflags, pconn) \
111 sasl_client_new(srv, fqdn, prompt, secflags, pconn)
112 #define SASL_CLIENT_START(conn, mechlst, secret, prompt, clout, cllen, mech) \
113 sasl_client_start(conn, mechlst, secret, prompt, clout, cllen, mech)
114 #define SASL_DECODE64(in, inlen, out, outmaxlen, outlen) \
115 sasl_decode64(in, inlen, out, outlen)
116 typedef char *CLIENTOUT_TYPE;
120 #if SASL_VERSION_MAJOR >= 2
122 #define SASL_CLIENT_NEW(srv, fqdn, lport, rport, prompt, secflags, pconn) \
123 sasl_client_new(srv, fqdn, lport, rport, prompt, secflags, pconn)
124 #define SASL_CLIENT_START(conn, mechlst, secret, prompt, clout, cllen, mech) \
125 sasl_client_start(conn, mechlst, prompt, clout, cllen, mech)
126 #define SASL_DECODE64(in, inlen, out, outmaxlen, outlen) \
127 sasl_decode64(in, inlen, out, outmaxlen, outlen)
128 typedef const char *CLIENTOUT_TYPE;
139 sasl_conn_t *sasl_conn;
141 sasl_callback_t *callbacks;
144 } XSASL_CYRUS_CLIENT;
152 static int xsasl_cyrus_client_set_security(
XSASL_CLIENT *,
const char *);
153 static int xsasl_cyrus_client_first(
XSASL_CLIENT *,
const char *,
const char *,
154 const char *,
const char **,
VSTRING *);
160 static int xsasl_cyrus_client_get_user(
void *context,
int unused_id,
164 const char *myname =
"xsasl_cyrus_client_get_user";
165 XSASL_CYRUS_CLIENT *client = (XSASL_CYRUS_CLIENT *) context;
168 msg_info(
"%s: %s", myname, client->username);
173 if (client->password == 0)
174 msg_panic(
"%s: no username looked up", myname);
176 *result = client->username;
178 *len = strlen(client->username);
184 static int xsasl_cyrus_client_get_passwd(sasl_conn_t *conn,
void *context,
185 int id, sasl_secret_t **psecret)
187 const char *myname =
"xsasl_cyrus_client_get_passwd";
188 XSASL_CYRUS_CLIENT *client = (XSASL_CYRUS_CLIENT *) context;
192 msg_info(
"%s: %s", myname, client->password);
197 if (!conn || !psecret ||
id != SASL_CB_PASS)
198 return (SASL_BADPARAM);
199 if (client->password == 0)
200 msg_panic(
"%s: no password looked up", myname);
205 len = strlen(client->password);
206 if ((*psecret = (sasl_secret_t *) malloc(
sizeof(sasl_secret_t) + len)) == 0)
208 (*psecret)->len = len;
209 memcpy((*psecret)->data, client->password, len + 1);
217 const char *unused_path_info)
225 static sasl_callback_t callbacks[] = {
226 {SASL_CB_LOG, (XSASL_CYRUS_CB) &xsasl_cyrus_log, 0},
227 {SASL_CB_LIST_END, 0, 0}
230 #if SASL_VERSION_MAJOR >= 2 && (SASL_VERSION_MINOR >= 2 \
231 || (SASL_VERSION_MINOR == 1 && SASL_VERSION_STEP >= 19))
239 sasl_version_info((
const char **) 0, (
const char **) 0,
240 &sasl_major, &sasl_minor,
241 &sasl_step, (
int *) 0);
242 if (sasl_major != SASL_VERSION_MAJOR
244 || sasl_minor != SASL_VERSION_MINOR
245 || sasl_step != SASL_VERSION_STEP
248 msg_warn(
"incorrect SASL library version. "
249 "Postfix was built with include files from version %d.%d.%d, "
250 "but the run-time library version is %d.%d.%d",
251 SASL_VERSION_MAJOR, SASL_VERSION_MINOR, SASL_VERSION_STEP,
252 sasl_major, sasl_minor, sasl_step);
258 #ifdef SASL_PATH_TYPE_CONFIG
259 if (sasl_set_path(SASL_PATH_TYPE_CONFIG,
261 msg_warn(
"failed to set Cyrus SASL configuration path: \"%s\"",
264 msg_warn(
"%s is not empty, but setting the Cyrus SASL configuration "
265 "path is not supported with SASL library version %d.%d.%d",
267 SASL_VERSION_MINOR, SASL_VERSION_STEP);
274 if ((sasl_status = sasl_client_init(callbacks)) != SASL_OK) {
275 msg_warn(
"SASL library initialization error: %s",
276 xsasl_cyrus_strerror(sasl_status));
285 xp->
create = xsasl_cyrus_client_create;
286 xp->
done = xsasl_cyrus_client_done;
303 XSASL_CYRUS_CLIENT *client = 0;
304 static sasl_callback_t callbacks[] = {
305 {SASL_CB_USER, (XSASL_CYRUS_CB) &xsasl_cyrus_client_get_user, 0},
306 {SASL_CB_AUTHNAME, (XSASL_CYRUS_CB) &xsasl_cyrus_client_get_user, 0},
307 {SASL_CB_PASS, (XSASL_CYRUS_CB) &xsasl_cyrus_client_get_passwd, 0},
308 {SASL_CB_LIST_END, 0, 0}
310 sasl_conn_t *sasl_conn = 0;
311 sasl_callback_t *custom_callbacks = 0;
318 #define XSASL_CYRUS_CLIENT_CREATE_ERROR_RETURN(x) \
321 xsasl_cyrus_client_free(&client->xsasl); \
323 if (custom_callbacks) \
324 myfree((void *) custom_callbacks); \
326 sasl_dispose(&sasl_conn); \
335 #define NULL_SECFLAGS 0
337 custom_callbacks = (sasl_callback_t *)
mymalloc(
sizeof(callbacks));
338 memcpy((
void *) custom_callbacks, callbacks,
sizeof(callbacks));
340 #define NULL_SERVER_ADDR ((char *) 0)
341 #define NULL_CLIENT_ADDR ((char *) 0)
344 NULL_CLIENT_ADDR, NULL_SERVER_ADDR,
346 custom_callbacks + 1, NULL_SECFLAGS,
347 &sasl_conn)) != SASL_OK) {
348 msg_warn(
"per-session SASL client initialization: %s",
349 xsasl_cyrus_strerror(sasl_status));
350 XSASL_CYRUS_CLIENT_CREATE_ERROR_RETURN(0);
362 client = (XSASL_CYRUS_CLIENT *)
mymalloc(
sizeof(*client));
363 client->xsasl.free = xsasl_cyrus_client_free;
364 client->xsasl.first = xsasl_cyrus_client_first;
365 client->xsasl.next = xsasl_cyrus_client_next;
366 client->stream = args->
stream;
367 client->sasl_conn = sasl_conn;
368 client->callbacks = custom_callbacks;
370 client->username = 0;
371 client->password = 0;
373 for (cp = custom_callbacks; cp->id != SASL_CB_LIST_END; cp++)
374 cp->context = (
void *) client;
376 if (xsasl_cyrus_client_set_security(&client->xsasl,
379 XSASL_CYRUS_CLIENT_CREATE_ERROR_RETURN(0);
381 return (&client->xsasl);
386 static int xsasl_cyrus_client_set_security(
XSASL_CLIENT *xp,
387 const char *sasl_opts_val)
389 XSASL_CYRUS_CLIENT *client = (XSASL_CYRUS_CLIENT *) xp;
390 sasl_security_properties_t sec_props;
397 memset(&sec_props, 0,
sizeof(sec_props));
398 sec_props.min_ssf = 0;
399 sec_props.max_ssf = 0;
401 if (*sasl_opts_val == 0) {
402 sec_props.security_flags = 0;
404 sec_props.security_flags =
405 xsasl_cyrus_security_parse_opts(sasl_opts_val);
406 if (sec_props.security_flags == 0) {
407 msg_warn(
"bad per-session SASL security properties");
411 sec_props.maxbufsize = 0;
412 sec_props.property_names = 0;
413 sec_props.property_values = 0;
414 if ((sasl_status = sasl_setprop(client->sasl_conn, SASL_SEC_PROPS,
415 &sec_props)) != SASL_OK) {
416 msg_warn(
"set per-session SASL security properties: %s",
417 xsasl_cyrus_strerror(sasl_status));
426 const char *mechanism_list,
428 const char *password,
429 const char **mechanism,
432 const char *myname =
"xsasl_cyrus_client_first";
433 XSASL_CYRUS_CLIENT *client = (XSASL_CYRUS_CLIENT *) xp;
435 unsigned enc_length_out;
436 CLIENTOUT_TYPE clientout;
437 unsigned clientoutlen;
440 #define NO_SASL_SECRET 0
441 #define NO_SASL_INTERACTION 0
446 if (client->username)
448 client->username =
mystrdup(username);
449 if (client->password)
451 client->password =
mystrdup(password);
456 sasl_status = SASL_CLIENT_START((sasl_conn_t *) client->sasl_conn,
458 NO_SASL_SECRET, NO_SASL_INTERACTION,
459 &clientout, &clientoutlen, mechanism);
460 if (sasl_status != SASL_OK && sasl_status != SASL_CONTINUE) {
470 #define ENCODE64_LENGTH(n) ((((n) + 2) / 3) * 4)
472 if (clientoutlen > 0) {
474 escape(client->decoded, clientout, clientoutlen);
475 msg_info(
"%s: uncoded initial reply: %s",
476 myname,
STR(client->decoded));
478 enc_length = ENCODE64_LENGTH(clientoutlen) + 1;
481 if ((sasl_status = sasl_encode64(clientout, clientoutlen,
484 &enc_length_out)) != SASL_OK)
486 myname, xsasl_cyrus_strerror(sasl_status));
488 #if SASL_VERSION_MAJOR < 2
500 static int xsasl_cyrus_client_next(
XSASL_CLIENT *xp,
const char *server_reply,
503 const char *myname =
"xsasl_cyrus_client_next";
504 XSASL_CYRUS_CLIENT *client = (XSASL_CYRUS_CLIENT *) xp;
506 unsigned enc_length_out;
507 CLIENTOUT_TYPE clientout;
508 unsigned clientoutlen;
509 unsigned serverinlen;
515 serverinlen = strlen(server_reply);
518 if ((sasl_status = SASL_DECODE64(server_reply, serverinlen,
519 STR(client->decoded),
521 &enc_length)) != SASL_OK) {
526 msg_info(
"%s: decoded challenge: %.*s",
527 myname, (
int) enc_length,
STR(client->decoded));
528 sasl_status = sasl_client_step(client->sasl_conn,
STR(client->decoded),
529 enc_length, NO_SASL_INTERACTION,
530 &clientout, &clientoutlen);
531 if (sasl_status != SASL_OK && sasl_status != SASL_CONTINUE) {
539 if (clientoutlen > 0) {
541 msg_info(
"%s: uncoded client response %.*s",
542 myname, (
int) clientoutlen, clientout);
543 enc_length = ENCODE64_LENGTH(clientoutlen) + 1;
546 if ((sasl_status = sasl_encode64(clientout, clientoutlen,
549 &enc_length_out)) != SASL_OK)
551 myname, xsasl_cyrus_strerror(sasl_status));
552 #if SASL_VERSION_MAJOR < 2
567 XSASL_CYRUS_CLIENT *client = (XSASL_CYRUS_CLIENT *) xp;
569 if (client->username)
571 if (client->password)
573 if (client->sasl_conn)
574 sasl_dispose(&client->sasl_conn);
575 myfree((
void *) client->callbacks);
char * mystrdup(const char *str)
#define VAR_CYRUS_CONF_PATH
NORETURN msg_panic(const char *fmt,...)
void(* done)(struct XSASL_CLIENT_IMPL *)
VSTRING * escape(VSTRING *, const char *, ssize_t)
VSTRING * vstring_strcpy(VSTRING *vp, const char *src)
XSASL_CLIENT *(* create)(struct XSASL_CLIENT_IMPL *, XSASL_CLIENT_CREATE_ARGS *)
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)
int var_cyrus_sasl_authzid
#define vstring_avail(vp)
const char * security_options
#define VSTRING_SPACE(vp, len)
VSTRING * vstring_free(VSTRING *vp)
#define VSTRING_AT_OFFSET(vp, offset)
void * mymalloc(ssize_t len)
void msg_info(const char *fmt,...)