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