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