1/*++ 2/* NAME 3/* xsasl_dovecot_server 3 4/* SUMMARY 5/* Dovecot SASL server-side plug-in 6/* SYNOPSIS 7/* XSASL_SERVER_IMPL *xsasl_dovecot_server_init(server_type, appl_name) 8/* const char *server_type; 9/* const char *appl_name; 10/* DESCRIPTION 11/* This module implements the Dovecot SASL server-side authentication 12/* plug-in. 13/* 14/* .IP server_type 15/* The plug-in type that was specified to xsasl_server_init(). 16/* The argument is ignored, because the Dovecot plug-in 17/* implements only one plug-in type. 18/* .IP path_info 19/* The location of the Dovecot authentication server's UNIX-domain 20/* socket. Note: the Dovecot plug-in uses late binding, therefore 21/* all connect operations are done with Postfix privileges. 22/* DIAGNOSTICS 23/* Fatal: out of memory. 24/* 25/* Panic: interface violation. 26/* 27/* Other: the routines log a warning and return an error result 28/* as specified in xsasl_server(3). 29/* LICENSE 30/* .ad 31/* .fi 32/* The Secure Mailer license must be distributed with this software. 33/* AUTHOR(S) 34/* Initial implementation by: 35/* Timo Sirainen 36/* Procontrol 37/* Finland 38/* 39/* Adopted by: 40/* Wietse Venema 41/* IBM T.J. Watson Research 42/* P.O. Box 704 43/* Yorktown Heights, NY 10598, USA 44/*--*/ 45 46/* System library. */ 47 48#include <sys_defs.h> 49#include <stdio.h> 50#include <stdlib.h> 51#include <string.h> 52 53#ifdef STRCASECMP_IN_STRINGS_H 54#include <strings.h> 55#endif 56 57/* Utility library. */ 58 59#include <msg.h> 60#include <mymalloc.h> 61#include <connect.h> 62#include <split_at.h> 63#include <stringops.h> 64#include <vstream.h> 65#include <vstring_vstream.h> 66#include <name_mask.h> 67#include <argv.h> 68#include <myaddrinfo.h> 69 70/* Global library. */ 71 72#include <mail_params.h> 73 74/* Application-specific. */ 75 76#include <xsasl.h> 77#include <xsasl_dovecot.h> 78 79#ifdef USE_SASL_AUTH 80 81/* Major version changes are not backwards compatible, 82 minor version numbers can be ignored. */ 83#define AUTH_PROTOCOL_MAJOR_VERSION 1 84#define AUTH_PROTOCOL_MINOR_VERSION 0 85 86 /* 87 * Encorce read/write time limits, so that we can produce accurate 88 * diagnostics instead of getting killed by the watchdog timer. 89 */ 90#define AUTH_TIMEOUT 10 91 92 /* 93 * Security property bitmasks. 94 */ 95#define SEC_PROPS_NOPLAINTEXT (1 << 0) 96#define SEC_PROPS_NOACTIVE (1 << 1) 97#define SEC_PROPS_NODICTIONARY (1 << 2) 98#define SEC_PROPS_NOANONYMOUS (1 << 3) 99#define SEC_PROPS_FWD_SECRECY (1 << 4) 100#define SEC_PROPS_MUTUAL_AUTH (1 << 5) 101#define SEC_PROPS_PRIVATE (1 << 6) 102 103#define SEC_PROPS_POS_MASK (SEC_PROPS_MUTUAL_AUTH | SEC_PROPS_FWD_SECRECY) 104#define SEC_PROPS_NEG_MASK (SEC_PROPS_NOPLAINTEXT | SEC_PROPS_NOACTIVE | \ 105 SEC_PROPS_NODICTIONARY | SEC_PROPS_NOANONYMOUS) 106 107 /* 108 * Security properties as specified in the Postfix main.cf file. 109 */ 110static const NAME_MASK xsasl_dovecot_conf_sec_props[] = { 111 "noplaintext", SEC_PROPS_NOPLAINTEXT, 112 "noactive", SEC_PROPS_NOACTIVE, 113 "nodictionary", SEC_PROPS_NODICTIONARY, 114 "noanonymous", SEC_PROPS_NOANONYMOUS, 115 "forward_secrecy", SEC_PROPS_FWD_SECRECY, 116 "mutual_auth", SEC_PROPS_MUTUAL_AUTH, 117 0, 0, 118}; 119 120 /* 121 * Security properties as specified in the Dovecot protocol. See 122 * http://wiki.dovecot.org/Authentication_Protocol. 123 */ 124static const NAME_MASK xsasl_dovecot_serv_sec_props[] = { 125 "plaintext", SEC_PROPS_NOPLAINTEXT, 126 "active", SEC_PROPS_NOACTIVE, 127 "dictionary", SEC_PROPS_NODICTIONARY, 128 "anonymous", SEC_PROPS_NOANONYMOUS, 129 "forward-secrecy", SEC_PROPS_FWD_SECRECY, 130 "mutual-auth", SEC_PROPS_MUTUAL_AUTH, 131 "private", SEC_PROPS_PRIVATE, 132 0, 0, 133}; 134 135 /* 136 * Class variables. 137 */ 138typedef struct XSASL_DCSRV_MECH { 139 char *mech_name; /* mechanism name */ 140 int sec_props; /* mechanism properties */ 141 struct XSASL_DCSRV_MECH *next; 142} XSASL_DCSRV_MECH; 143 144typedef struct { 145 XSASL_SERVER_IMPL xsasl; 146 VSTREAM *sasl_stream; 147 char *socket_path; 148 XSASL_DCSRV_MECH *mechanism_list; /* unfiltered mechanism list */ 149 unsigned int request_id_counter; 150} XSASL_DOVECOT_SERVER_IMPL; 151 152 /* 153 * The XSASL_DOVECOT_SERVER object is derived from the generic XSASL_SERVER 154 * object. 155 */ 156typedef struct { 157 XSASL_SERVER xsasl; /* generic members, must be first */ 158 XSASL_DOVECOT_SERVER_IMPL *impl; 159 unsigned int last_request_id; 160 char *service; 161 char *username; /* authenticated user */ 162 VSTRING *sasl_line; 163 unsigned int sec_props; /* Postfix mechanism filter */ 164 int tls_flag; /* TLS enabled in this session */ 165 char *mechanism_list; /* filtered mechanism list */ 166 ARGV *mechanism_argv; /* ditto */ 167 char *client_addr; /* remote IP address */ 168 char *server_addr; /* remote IP address */ 169} XSASL_DOVECOT_SERVER; 170 171 /* 172 * Forward declarations. 173 */ 174static void xsasl_dovecot_server_done(XSASL_SERVER_IMPL *); 175static XSASL_SERVER *xsasl_dovecot_server_create(XSASL_SERVER_IMPL *, 176 XSASL_SERVER_CREATE_ARGS *); 177static void xsasl_dovecot_server_free(XSASL_SERVER *); 178static int xsasl_dovecot_server_first(XSASL_SERVER *, const char *, 179 const char *, VSTRING *); 180static int xsasl_dovecot_server_next(XSASL_SERVER *, const char *, VSTRING *); 181static const char *xsasl_dovecot_server_get_mechanism_list(XSASL_SERVER *); 182static const char *xsasl_dovecot_server_get_username(XSASL_SERVER *); 183 184/* xsasl_dovecot_server_mech_append - append server mechanism entry */ 185 186static void xsasl_dovecot_server_mech_append(XSASL_DCSRV_MECH **mech_list, 187 const char *mech_name, int sec_props) 188{ 189 XSASL_DCSRV_MECH **mpp; 190 XSASL_DCSRV_MECH *mp; 191 192 for (mpp = mech_list; *mpp != 0; mpp = &mpp[0]->next) 193 /* void */ ; 194 195 mp = (XSASL_DCSRV_MECH *) mymalloc(sizeof(*mp)); 196 mp->mech_name = mystrdup(mech_name); 197 mp->sec_props = sec_props; 198 mp->next = 0; 199 *mpp = mp; 200} 201 202/* xsasl_dovecot_server_mech_free - destroy server mechanism list */ 203 204static void xsasl_dovecot_server_mech_free(XSASL_DCSRV_MECH *mech_list) 205{ 206 XSASL_DCSRV_MECH *mp; 207 XSASL_DCSRV_MECH *next; 208 209 for (mp = mech_list; mp != 0; mp = next) { 210 myfree(mp->mech_name); 211 next = mp->next; 212 myfree((char *) mp); 213 } 214} 215 216/* xsasl_dovecot_server_mech_filter - filter server mechanism list */ 217 218static char *xsasl_dovecot_server_mech_filter(ARGV *mechanism_argv, 219 XSASL_DCSRV_MECH *mechanism_list, 220 unsigned int conf_props) 221{ 222 const char *myname = "xsasl_dovecot_server_mech_filter"; 223 unsigned int pos_conf_props = (conf_props & SEC_PROPS_POS_MASK); 224 unsigned int neg_conf_props = (conf_props & SEC_PROPS_NEG_MASK); 225 VSTRING *mechanisms_str = vstring_alloc(10); 226 XSASL_DCSRV_MECH *mp; 227 228 /* 229 * Match Postfix properties against Dovecot server properties. 230 */ 231 for (mp = mechanism_list; mp != 0; mp = mp->next) { 232 if ((mp->sec_props & pos_conf_props) == pos_conf_props 233 && (mp->sec_props & neg_conf_props) == 0) { 234 if (VSTRING_LEN(mechanisms_str) > 0) 235 VSTRING_ADDCH(mechanisms_str, ' '); 236 vstring_strcat(mechanisms_str, mp->mech_name); 237 argv_add(mechanism_argv, mp->mech_name, (char *) 0); 238 if (msg_verbose) 239 msg_info("%s: keep mechanism: %s", myname, mp->mech_name); 240 } else { 241 if (msg_verbose) 242 msg_info("%s: skip mechanism: %s", myname, mp->mech_name); 243 } 244 } 245 return (vstring_export(mechanisms_str)); 246} 247 248/* xsasl_dovecot_server_connect - initial auth server handshake */ 249 250static int xsasl_dovecot_server_connect(XSASL_DOVECOT_SERVER_IMPL *xp) 251{ 252 const char *myname = "xsasl_dovecot_server_connect"; 253 VSTRING *line_str; 254 VSTREAM *sasl_stream; 255 char *line, *cmd, *mech_name; 256 unsigned int major_version, minor_version; 257 int fd, success; 258 int sec_props; 259 const char *path; 260 261 if (msg_verbose) 262 msg_info("%s: Connecting", myname); 263 264 /* 265 * Not documented, but necessary for testing. 266 */ 267 path = xp->socket_path; 268 if (strncmp(path, "inet:", 5) == 0) { 269 fd = inet_connect(path + 5, BLOCKING, AUTH_TIMEOUT); 270 } else { 271 if (strncmp(path, "unix:", 5) == 0) 272 path += 5; 273 fd = unix_connect(path, BLOCKING, AUTH_TIMEOUT); 274 } 275 if (fd < 0) { 276 msg_warn("SASL: Connect to %s failed: %m", xp->socket_path); 277 return (-1); 278 } 279 sasl_stream = vstream_fdopen(fd, O_RDWR); 280 vstream_control(sasl_stream, 281 VSTREAM_CTL_PATH, xp->socket_path, 282 VSTREAM_CTL_TIMEOUT, AUTH_TIMEOUT, 283 VSTREAM_CTL_END); 284 285 /* XXX Encapsulate for logging. */ 286 vstream_fprintf(sasl_stream, 287 "VERSION\t%u\t%u\n" 288 "CPID\t%u\n", 289 AUTH_PROTOCOL_MAJOR_VERSION, 290 AUTH_PROTOCOL_MINOR_VERSION, 291 (unsigned int) getpid()); 292 if (vstream_fflush(sasl_stream) == VSTREAM_EOF) { 293 msg_warn("SASL: Couldn't send handshake: %m"); 294 return (-1); 295 } 296 success = 0; 297 line_str = vstring_alloc(256); 298 /* XXX Encapsulate for logging. */ 299 while (vstring_get_nonl(line_str, sasl_stream) != VSTREAM_EOF) { 300 line = vstring_str(line_str); 301 302 if (msg_verbose) 303 msg_info("%s: auth reply: %s", myname, line); 304 305 cmd = line; 306 line = split_at(line, '\t'); 307 308 if (strcmp(cmd, "VERSION") == 0) { 309 if (sscanf(line, "%u\t%u", &major_version, &minor_version) != 2) { 310 msg_warn("SASL: Protocol version error"); 311 break; 312 } 313 if (major_version != AUTH_PROTOCOL_MAJOR_VERSION) { 314 /* Major version is different from ours. */ 315 msg_warn("SASL: Protocol version mismatch (%d vs. %d)", 316 major_version, AUTH_PROTOCOL_MAJOR_VERSION); 317 break; 318 } 319 } else if (strcmp(cmd, "MECH") == 0 && line != NULL) { 320 mech_name = line; 321 line = split_at(line, '\t'); 322 if (line != 0) { 323 sec_props = 324 name_mask_delim_opt(myname, 325 xsasl_dovecot_serv_sec_props, 326 line, "\t", 327 NAME_MASK_ANY_CASE | NAME_MASK_IGNORE); 328 if ((sec_props & SEC_PROPS_PRIVATE) != 0) 329 continue; 330 } else 331 sec_props = 0; 332 xsasl_dovecot_server_mech_append(&xp->mechanism_list, mech_name, 333 sec_props); 334 } else if (strcmp(cmd, "DONE") == 0) { 335 /* Handshake finished. */ 336 success = 1; 337 break; 338 } else { 339 /* ignore any unknown commands */ 340 } 341 } 342 vstring_free(line_str); 343 344 if (!success) { 345 /* handshake failed */ 346 (void) vstream_fclose(sasl_stream); 347 return (-1); 348 } 349 xp->sasl_stream = sasl_stream; 350 return (0); 351} 352 353/* xsasl_dovecot_server_disconnect - dispose of server connection state */ 354 355static void xsasl_dovecot_server_disconnect(XSASL_DOVECOT_SERVER_IMPL *xp) 356{ 357 if (xp->sasl_stream) { 358 (void) vstream_fclose(xp->sasl_stream); 359 xp->sasl_stream = 0; 360 } 361 if (xp->mechanism_list) { 362 xsasl_dovecot_server_mech_free(xp->mechanism_list); 363 xp->mechanism_list = 0; 364 } 365} 366 367/* xsasl_dovecot_server_init - create implementation handle */ 368 369XSASL_SERVER_IMPL *xsasl_dovecot_server_init(const char *server_type, 370 const char *path_info) 371{ 372 XSASL_DOVECOT_SERVER_IMPL *xp; 373 374 xp = (XSASL_DOVECOT_SERVER_IMPL *) mymalloc(sizeof(*xp)); 375 xp->xsasl.create = xsasl_dovecot_server_create; 376 xp->xsasl.done = xsasl_dovecot_server_done; 377 xp->socket_path = mystrdup(path_info); 378 xp->sasl_stream = 0; 379 xp->mechanism_list = 0; 380 xp->request_id_counter = 0; 381 return (&xp->xsasl); 382} 383 384/* xsasl_dovecot_server_done - dispose of implementation */ 385 386static void xsasl_dovecot_server_done(XSASL_SERVER_IMPL *impl) 387{ 388 XSASL_DOVECOT_SERVER_IMPL *xp = (XSASL_DOVECOT_SERVER_IMPL *) impl; 389 390 xsasl_dovecot_server_disconnect(xp); 391 myfree(xp->socket_path); 392 myfree((char *) impl); 393} 394 395/* xsasl_dovecot_server_create - create server instance */ 396 397static XSASL_SERVER *xsasl_dovecot_server_create(XSASL_SERVER_IMPL *impl, 398 XSASL_SERVER_CREATE_ARGS *args) 399{ 400 const char *myname = "xsasl_dovecot_server_create"; 401 XSASL_DOVECOT_SERVER *server; 402 struct sockaddr_storage ss; 403 struct sockaddr *sa = (struct sockaddr *) & ss; 404 SOCKADDR_SIZE salen; 405 MAI_HOSTADDR_STR server_addr; 406 407 if (msg_verbose) 408 msg_info("%s: SASL service=%s, realm=%s", 409 myname, args->service, args->user_realm ? 410 args->user_realm : "(null)"); 411 412 /* 413 * Extend the XSASL_SERVER_IMPL object with our own data. We use 414 * long-lived conversion buffers rather than local variables to avoid 415 * memory leaks in case of read/write timeout or I/O error. 416 */ 417 server = (XSASL_DOVECOT_SERVER *) mymalloc(sizeof(*server)); 418 server->xsasl.free = xsasl_dovecot_server_free; 419 server->xsasl.first = xsasl_dovecot_server_first; 420 server->xsasl.next = xsasl_dovecot_server_next; 421 server->xsasl.get_mechanism_list = xsasl_dovecot_server_get_mechanism_list; 422 server->xsasl.get_username = xsasl_dovecot_server_get_username; 423 server->impl = (XSASL_DOVECOT_SERVER_IMPL *) impl; 424 server->sasl_line = vstring_alloc(256); 425 server->username = 0; 426 server->service = mystrdup(args->service); 427 server->last_request_id = 0; 428 server->mechanism_list = 0; 429 server->mechanism_argv = 0; 430 server->tls_flag = args->tls_flag; 431 server->sec_props = 432 name_mask_opt(myname, xsasl_dovecot_conf_sec_props, 433 args->security_options, 434 NAME_MASK_ANY_CASE | NAME_MASK_FATAL); 435 server->client_addr = mystrdup(args->client_addr); 436 437 /* 438 * XXX Temporary code until smtpd_peer.c is updated. 439 */ 440 if (args->server_addr && *args->server_addr) { 441 server->server_addr = mystrdup(args->server_addr); 442 } else { 443 salen = sizeof(ss); 444 if (getsockname(vstream_fileno(args->stream), sa, &salen) < 0 445 || sockaddr_to_hostaddr(sa, salen, &server_addr, 0, 0) != 0) 446 server_addr.buf[0] = 0; 447 server->server_addr = mystrdup(server_addr.buf); 448 } 449 450 return (&server->xsasl); 451} 452 453/* xsasl_dovecot_server_get_mechanism_list - get available mechanisms */ 454 455static const char *xsasl_dovecot_server_get_mechanism_list(XSASL_SERVER *xp) 456{ 457 XSASL_DOVECOT_SERVER *server = (XSASL_DOVECOT_SERVER *) xp; 458 459 if (!server->impl->sasl_stream) { 460 if (xsasl_dovecot_server_connect(server->impl) < 0) 461 return (0); 462 } 463 if (server->mechanism_list == 0) { 464 server->mechanism_argv = argv_alloc(2); 465 server->mechanism_list = 466 xsasl_dovecot_server_mech_filter(server->mechanism_argv, 467 server->impl->mechanism_list, 468 server->sec_props); 469 } 470 return (server->mechanism_list[0] ? server->mechanism_list : 0); 471} 472 473/* xsasl_dovecot_server_free - destroy server instance */ 474 475static void xsasl_dovecot_server_free(XSASL_SERVER *xp) 476{ 477 XSASL_DOVECOT_SERVER *server = (XSASL_DOVECOT_SERVER *) xp; 478 479 vstring_free(server->sasl_line); 480 if (server->username) 481 myfree(server->username); 482 if (server->mechanism_list) { 483 myfree(server->mechanism_list); 484 argv_free(server->mechanism_argv); 485 } 486 myfree(server->service); 487 myfree(server->server_addr); 488 myfree(server->client_addr); 489 myfree((char *) server); 490} 491 492/* xsasl_dovecot_server_auth_response - encode server first/next response */ 493 494static int xsasl_dovecot_parse_reply(XSASL_DOVECOT_SERVER *server, char **line) 495{ 496 char *id; 497 498 if (*line == NULL) { 499 msg_warn("SASL: Protocol error"); 500 return -1; 501 } 502 id = *line; 503 *line = split_at(*line, '\t'); 504 505 if (strtoul(id, NULL, 0) != server->last_request_id) { 506 /* reply to another request, shouldn't really happen.. */ 507 return -1; 508 } 509 return 0; 510} 511 512static void xsasl_dovecot_parse_reply_args(XSASL_DOVECOT_SERVER *server, 513 char *line, VSTRING *reply, 514 int success) 515{ 516 char *next; 517 518 if (server->username) { 519 myfree(server->username); 520 server->username = 0; 521 } 522 523 /* 524 * Note: TAB is part of the Dovecot protocol and must not appear in 525 * legitimate Dovecot usernames, otherwise the protocol would break. 526 */ 527 for (; line != NULL; line = next) { 528 next = split_at(line, '\t'); 529 if (strncmp(line, "user=", 5) == 0) { 530 server->username = mystrdup(line + 5); 531 printable(server->username, '?'); 532 } else if (strncmp(line, "reason=", 7) == 0) { 533 if (!success) { 534 printable(line + 7, '?'); 535 vstring_strcpy(reply, line + 7); 536 } 537 } 538 } 539} 540 541/* xsasl_dovecot_handle_reply - receive and process auth reply */ 542 543static int xsasl_dovecot_handle_reply(XSASL_DOVECOT_SERVER *server, 544 VSTRING *reply) 545{ 546 const char *myname = "xsasl_dovecot_handle_reply"; 547 char *line, *cmd; 548 549 /* XXX Encapsulate for logging. */ 550 while (vstring_get_nonl(server->sasl_line, 551 server->impl->sasl_stream) != VSTREAM_EOF) { 552 line = vstring_str(server->sasl_line); 553 554 if (msg_verbose) 555 msg_info("%s: auth reply: %s", myname, line); 556 557 cmd = line; 558 line = split_at(line, '\t'); 559 560 if (strcmp(cmd, "OK") == 0) { 561 if (xsasl_dovecot_parse_reply(server, &line) == 0) { 562 /* authentication successful */ 563 xsasl_dovecot_parse_reply_args(server, line, reply, 1); 564 return XSASL_AUTH_DONE; 565 } 566 } else if (strcmp(cmd, "CONT") == 0) { 567 if (xsasl_dovecot_parse_reply(server, &line) == 0) { 568 vstring_strcpy(reply, line); 569 return XSASL_AUTH_MORE; 570 } 571 } else if (strcmp(cmd, "FAIL") == 0) { 572 if (xsasl_dovecot_parse_reply(server, &line) == 0) { 573 /* authentication failure */ 574 xsasl_dovecot_parse_reply_args(server, line, reply, 0); 575 return XSASL_AUTH_FAIL; 576 } 577 } else { 578 /* ignore */ 579 } 580 } 581 582 vstring_strcpy(reply, "Connection lost to authentication server"); 583 return XSASL_AUTH_FAIL; 584} 585 586/* is_valid_base64 - input sanitized */ 587 588static int is_valid_base64(const char *data) 589{ 590 591 /* 592 * XXX Maybe use ISALNUM() (isascii && isalnum, i.e. locale independent). 593 */ 594 for (; *data != '\0'; data++) { 595 if (!((*data >= '0' && *data <= '9') || 596 (*data >= 'a' && *data <= 'z') || 597 (*data >= 'A' && *data <= 'Z') || 598 *data == '+' || *data == '/' || *data == '=')) 599 return 0; 600 } 601 return 1; 602} 603 604/* xsasl_dovecot_server_first - per-session authentication */ 605 606int xsasl_dovecot_server_first(XSASL_SERVER *xp, const char *sasl_method, 607 const char *init_response, VSTRING *reply) 608{ 609 const char *myname = "xsasl_dovecot_server_first"; 610 XSASL_DOVECOT_SERVER *server = (XSASL_DOVECOT_SERVER *) xp; 611 int i; 612 char **cpp; 613 614#define IFELSE(e1,e2,e3) ((e1) ? (e2) : (e3)) 615 616 if (msg_verbose) 617 msg_info("%s: sasl_method %s%s%s", myname, sasl_method, 618 IFELSE(init_response, ", init_response ", ""), 619 IFELSE(init_response, init_response, "")); 620 621 if (server->mechanism_argv == 0) 622 msg_panic("%s: no mechanism list", myname); 623 624 for (cpp = server->mechanism_argv->argv; /* see below */ ; cpp++) { 625 if (*cpp == 0) { 626 vstring_strcpy(reply, "Invalid authentication mechanism"); 627 return XSASL_AUTH_FAIL; 628 } 629 if (strcasecmp(sasl_method, *cpp) == 0) 630 break; 631 } 632 if (init_response) 633 if (!is_valid_base64(init_response)) { 634 vstring_strcpy(reply, "Invalid base64 data in initial response"); 635 return XSASL_AUTH_FAIL; 636 } 637 for (i = 0; i < 2; i++) { 638 if (!server->impl->sasl_stream) { 639 if (xsasl_dovecot_server_connect(server->impl) < 0) 640 return (0); 641 } 642 /* send the request */ 643 server->last_request_id = ++server->impl->request_id_counter; 644 /* XXX Encapsulate for logging. */ 645 vstream_fprintf(server->impl->sasl_stream, 646 "AUTH\t%u\t%s\tservice=%s\tnologin\tlip=%s\trip=%s", 647 server->last_request_id, sasl_method, 648 server->service, server->server_addr, 649 server->client_addr); 650 if (server->tls_flag) 651 /* XXX Encapsulate for logging. */ 652 vstream_fputs("\tsecured", server->impl->sasl_stream); 653 if (init_response) { 654 655 /* 656 * initial response is already base64 encoded, so we can send it 657 * directly. 658 */ 659 /* XXX Encapsulate for logging. */ 660 vstream_fprintf(server->impl->sasl_stream, 661 "\tresp=%s", init_response); 662 } 663 /* XXX Encapsulate for logging. */ 664 VSTREAM_PUTC('\n', server->impl->sasl_stream); 665 666 if (vstream_fflush(server->impl->sasl_stream) != VSTREAM_EOF) 667 break; 668 669 if (i == 1) { 670 vstring_strcpy(reply, "Can't connect to authentication server"); 671 return XSASL_AUTH_FAIL; 672 } 673 674 /* 675 * Reconnect and try again. 676 */ 677 xsasl_dovecot_server_disconnect(server->impl); 678 } 679 680 return xsasl_dovecot_handle_reply(server, reply); 681} 682 683/* xsasl_dovecot_server_next - continue authentication */ 684 685static int xsasl_dovecot_server_next(XSASL_SERVER *xp, const char *request, 686 VSTRING *reply) 687{ 688 XSASL_DOVECOT_SERVER *server = (XSASL_DOVECOT_SERVER *) xp; 689 690 if (!is_valid_base64(request)) { 691 vstring_strcpy(reply, "Invalid base64 data in continued response"); 692 return XSASL_AUTH_FAIL; 693 } 694 /* XXX Encapsulate for logging. */ 695 vstream_fprintf(server->impl->sasl_stream, 696 "CONT\t%u\t%s\n", server->last_request_id, request); 697 if (vstream_fflush(server->impl->sasl_stream) == VSTREAM_EOF) { 698 vstring_strcpy(reply, "Connection lost to authentication server"); 699 return XSASL_AUTH_FAIL; 700 } 701 return xsasl_dovecot_handle_reply(server, reply); 702} 703 704/* xsasl_dovecot_server_get_username - get authenticated username */ 705 706static const char *xsasl_dovecot_server_get_username(XSASL_SERVER *xp) 707{ 708 XSASL_DOVECOT_SERVER *server = (XSASL_DOVECOT_SERVER *) xp; 709 710 return (server->username); 711} 712 713#endif 714