1 /* $NetBSD: xsasl_cyrus_server.c,v 1.3 2020/03/18 19:05:22 christos Exp $ */ 2 3 /*++ 4 /* NAME 5 /* xsasl_cyrus_server 3 6 /* SUMMARY 7 /* Cyrus SASL server-side plug-in 8 /* SYNOPSIS 9 /* #include <xsasl_cyrus_server.h> 10 /* 11 /* XSASL_SERVER_IMPL *xsasl_cyrus_server_init(server_type, path_info) 12 /* const char *server_type; 13 /* const char *path_info; 14 /* DESCRIPTION 15 /* This module implements the Cyrus SASL server-side authentication 16 /* plug-in. 17 /* 18 /* xsasl_cyrus_server_init() initializes the Cyrus SASL library and 19 /* returns an implementation handle that can be used to generate 20 /* SASL server instances. 21 /* 22 /* Arguments: 23 /* .IP server_type 24 /* The server type (cyrus). This argument is ignored, but it 25 /* could be used when one implementation provides multiple 26 /* variants. 27 /* .IP path_info 28 /* The base name of the SASL server configuration file (example: 29 /* smtpd becomes /usr/lib/sasl2/smtpd.conf). 30 /* DIAGNOSTICS 31 /* Fatal: out of memory. 32 /* 33 /* Panic: interface violation. 34 /* 35 /* Other: the routines log a warning and return an error result 36 /* as specified in xsasl_server(3). 37 /* LICENSE 38 /* .ad 39 /* .fi 40 /* The Secure Mailer license must be distributed with this software. 41 /* AUTHOR(S) 42 /* Initial implementation by: 43 /* Till Franke 44 /* SuSE Rhein/Main AG 45 /* 65760 Eschborn, Germany 46 /* 47 /* Adopted by: 48 /* Wietse Venema 49 /* IBM T.J. Watson Research 50 /* P.O. Box 704 51 /* Yorktown Heights, NY 10598, USA 52 /* 53 /* Wietse Venema 54 /* Google, Inc. 55 /* 111 8th Avenue 56 /* New York, NY 10011, USA 57 /*--*/ 58 59 /* System library. */ 60 61 #include <sys_defs.h> 62 #include <sys/socket.h> 63 #include <stdlib.h> 64 #include <string.h> 65 66 /* Utility library. */ 67 68 #include <msg.h> 69 #include <mymalloc.h> 70 #include <name_mask.h> 71 #include <stringops.h> 72 73 /* Global library. */ 74 75 #include <mail_params.h> 76 77 /* Application-specific. */ 78 79 #include <xsasl.h> 80 #include <xsasl_cyrus.h> 81 #include <xsasl_cyrus_common.h> 82 83 #if defined(USE_SASL_AUTH) && defined(USE_CYRUS_SASL) 84 85 #include <sasl.h> 86 #include <saslutil.h> 87 88 /* 89 * Silly little macros. 90 */ 91 #define STR(s) vstring_str(s) 92 93 /* 94 * Macros to handle API differences between SASLv1 and SASLv2. Specifics: 95 * 96 * The SASL_LOG_* constants were renamed in SASLv2. 97 * 98 * SASLv2's sasl_server_new takes two new parameters to specify local and 99 * remote IP addresses for auth mechs that use them. 100 * 101 * SASLv2's sasl_server_start and sasl_server_step no longer have the errstr 102 * parameter. 103 * 104 * SASLv2's sasl_decode64 function takes an extra parameter for the length of 105 * the output buffer. 106 * 107 * The other major change is that SASLv2 now takes more responsibility for 108 * deallocating memory that it allocates internally. Thus, some of the 109 * function parameters are now 'const', to make sure we don't try to free 110 * them too. This is dealt with in the code later on. 111 */ 112 113 #if SASL_VERSION_MAJOR < 2 114 /* SASL version 1.x */ 115 #define SASL_SERVER_NEW(srv, fqdn, rlm, lport, rport, cb, secflags, pconn) \ 116 sasl_server_new(srv, fqdn, rlm, cb, secflags, pconn) 117 #define SASL_SERVER_START(conn, mech, clin, clinlen, srvout, srvoutlen, err) \ 118 sasl_server_start(conn, mech, clin, clinlen, srvout, srvoutlen, err) 119 #define SASL_SERVER_STEP(conn, clin, clinlen, srvout, srvoutlen, err) \ 120 sasl_server_step(conn, clin, clinlen, srvout, srvoutlen, err) 121 #define SASL_DECODE64(in, inlen, out, outmaxlen, outlen) \ 122 sasl_decode64(in, inlen, out, outlen) 123 typedef char *MECHANISM_TYPE; 124 typedef unsigned MECHANISM_COUNT_TYPE; 125 typedef char *SERVEROUT_TYPE; 126 typedef void *VOID_SERVEROUT_TYPE; 127 128 #endif 129 130 #if SASL_VERSION_MAJOR >= 2 131 /* SASL version > 2.x */ 132 #define SASL_SERVER_NEW(srv, fqdn, rlm, lport, rport, cb, secflags, pconn) \ 133 sasl_server_new(srv, fqdn, rlm, lport, rport, cb, secflags, pconn) 134 #define SASL_SERVER_START(conn, mech, clin, clinlen, srvout, srvoutlen, err) \ 135 sasl_server_start(conn, mech, clin, clinlen, srvout, srvoutlen) 136 #define SASL_SERVER_STEP(conn, clin, clinlen, srvout, srvoutlen, err) \ 137 sasl_server_step(conn, clin, clinlen, srvout, srvoutlen) 138 #define SASL_DECODE64(in, inlen, out, outmaxlen, outlen) \ 139 sasl_decode64(in, inlen, out, outmaxlen, outlen) 140 typedef const char *MECHANISM_TYPE; 141 typedef int MECHANISM_COUNT_TYPE; 142 typedef const char *SERVEROUT_TYPE; 143 typedef const void *VOID_SERVEROUT_TYPE; 144 145 #endif 146 147 #ifndef NO_IP_CYRUS_SASL_AUTH 148 #define USE_IP_CYRUS_SASL_AUTH 149 #endif 150 151 /* 152 * The XSASL_CYRUS_SERVER object is derived from the generic XSASL_SERVER 153 * object. 154 */ 155 typedef struct { 156 XSASL_SERVER xsasl; /* generic members, must be first */ 157 VSTREAM *stream; /* client-server connection */ 158 sasl_conn_t *sasl_conn; /* SASL context */ 159 VSTRING *decoded; /* decoded challenge or response */ 160 char *username; /* authenticated user */ 161 char *mechanism_list; /* applicable mechanisms */ 162 } XSASL_CYRUS_SERVER; 163 164 /* 165 * Forward declarations. 166 */ 167 static void xsasl_cyrus_server_done(XSASL_SERVER_IMPL *); 168 static XSASL_SERVER *xsasl_cyrus_server_create(XSASL_SERVER_IMPL *, 169 XSASL_SERVER_CREATE_ARGS *); 170 static void xsasl_cyrus_server_free(XSASL_SERVER *); 171 static int xsasl_cyrus_server_first(XSASL_SERVER *, const char *, 172 const char *, VSTRING *); 173 static int xsasl_cyrus_server_next(XSASL_SERVER *, const char *, VSTRING *); 174 static int xsasl_cyrus_server_set_security(XSASL_SERVER *, const char *); 175 static const char *xsasl_cyrus_server_get_mechanism_list(XSASL_SERVER *); 176 static const char *xsasl_cyrus_server_get_username(XSASL_SERVER *); 177 178 /* 179 * SASL callback interface structure. These call-backs have no per-session 180 * context. 181 */ 182 #define NO_CALLBACK_CONTEXT 0 183 184 static sasl_callback_t callbacks[] = { 185 {SASL_CB_LOG, (XSASL_CYRUS_CB) &xsasl_cyrus_log, NO_CALLBACK_CONTEXT}, 186 {SASL_CB_LIST_END, 0, 0} 187 }; 188 189 /* xsasl_cyrus_server_init - create implementation handle */ 190 191 XSASL_SERVER_IMPL *xsasl_cyrus_server_init(const char *unused_server_type, 192 const char *path_info) 193 { 194 const char *myname = "xsasl_cyrus_server_init"; 195 XSASL_SERVER_IMPL *xp; 196 int sasl_status; 197 198 #if SASL_VERSION_MAJOR >= 2 && (SASL_VERSION_MINOR >= 2 \ 199 || (SASL_VERSION_MINOR == 1 && SASL_VERSION_STEP >= 19)) 200 int sasl_major; 201 int sasl_minor; 202 int sasl_step; 203 204 /* 205 * DLL hell guard. 206 */ 207 sasl_version_info((const char **) 0, (const char **) 0, 208 &sasl_major, &sasl_minor, 209 &sasl_step, (int *) 0); 210 if (sasl_major != SASL_VERSION_MAJOR 211 #if 0 212 || sasl_minor != SASL_VERSION_MINOR 213 || sasl_step != SASL_VERSION_STEP 214 #endif 215 ) { 216 msg_warn("incorrect SASL library version. " 217 "Postfix was built with include files from version %d.%d.%d, " 218 "but the run-time library version is %d.%d.%d", 219 SASL_VERSION_MAJOR, SASL_VERSION_MINOR, SASL_VERSION_STEP, 220 sasl_major, sasl_minor, sasl_step); 221 return (0); 222 } 223 #endif 224 225 if (*var_cyrus_conf_path) { 226 #ifdef SASL_PATH_TYPE_CONFIG /* Cyrus SASL 2.1.22 */ 227 if (sasl_set_path(SASL_PATH_TYPE_CONFIG, 228 var_cyrus_conf_path) != SASL_OK) 229 msg_warn("failed to set Cyrus SASL configuration path: \"%s\"", 230 var_cyrus_conf_path); 231 #else 232 msg_warn("%s is not empty, but setting the Cyrus SASL configuration " 233 "path is not supported with SASL library version %d.%d.%d", 234 VAR_CYRUS_CONF_PATH, SASL_VERSION_MAJOR, 235 SASL_VERSION_MINOR, SASL_VERSION_STEP); 236 #endif 237 } 238 239 /* 240 * Initialize the library: load SASL plug-in routines, etc. 241 */ 242 if (msg_verbose) 243 msg_info("%s: SASL config file is %s.conf", myname, path_info); 244 if ((sasl_status = sasl_server_init(callbacks, path_info)) != SASL_OK) { 245 msg_warn("SASL per-process initialization failed: %s", 246 xsasl_cyrus_strerror(sasl_status)); 247 return (0); 248 } 249 250 /* 251 * Return a generic XSASL_SERVER_IMPL object. We don't need to extend it 252 * with our own methods or data. 253 */ 254 xp = (XSASL_SERVER_IMPL *) mymalloc(sizeof(*xp)); 255 xp->create = xsasl_cyrus_server_create; 256 xp->done = xsasl_cyrus_server_done; 257 return (xp); 258 } 259 260 /* xsasl_cyrus_server_done - dispose of implementation */ 261 262 static void xsasl_cyrus_server_done(XSASL_SERVER_IMPL *impl) 263 { 264 myfree((void *) impl); 265 sasl_done(); 266 } 267 268 /* xsasl_cyrus_server_create - create server instance */ 269 270 static XSASL_SERVER *xsasl_cyrus_server_create(XSASL_SERVER_IMPL *unused_impl, 271 XSASL_SERVER_CREATE_ARGS *args) 272 { 273 const char *myname = "xsasl_cyrus_server_create"; 274 char *server_addr_port = 0; 275 char *client_addr_port = 0; 276 sasl_conn_t *sasl_conn = 0; 277 XSASL_CYRUS_SERVER *server = 0; 278 int sasl_status; 279 280 if (msg_verbose) 281 msg_info("%s: SASL service=%s, realm=%s", 282 myname, args->service, args->user_realm ? 283 args->user_realm : "(null)"); 284 285 /* 286 * The optimizer will eliminate code duplication and/or dead code. 287 */ 288 #define XSASL_CYRUS_SERVER_CREATE_ERROR_RETURN(x) \ 289 do { \ 290 if (server) { \ 291 xsasl_cyrus_server_free(&server->xsasl); \ 292 } else { \ 293 if (sasl_conn) \ 294 sasl_dispose(&sasl_conn); \ 295 } \ 296 XSASL_CYRUS_SERVER_CREATE_RETURN(x); \ 297 } while (0) 298 299 #define XSASL_CYRUS_SERVER_CREATE_RETURN(x) \ 300 do { \ 301 if (server_addr_port) \ 302 myfree(server_addr_port); \ 303 if (client_addr_port) \ 304 myfree(client_addr_port); \ 305 return (x); \ 306 } while (0) 307 308 /* 309 * Set up a new server context. 310 */ 311 #define NO_SECURITY_LAYERS (0) 312 #define NO_SESSION_CALLBACKS ((sasl_callback_t *) 0) 313 #define NO_AUTH_REALM ((char *) 0) 314 315 #if SASL_VERSION_MAJOR >= 2 && defined(USE_IP_CYRUS_SASL_AUTH) 316 317 /* 318 * Get IP address and port of local and remote endpoints for SASL. Some 319 * implementation supports "[ipv6addr]:port" and "ipv4addr:port" (e.g., 320 * https://illumos.org/man/3sasl/sasl_server_new), They still support the 321 * historical "address;port" syntax, so we stick with that for now. 322 */ 323 server_addr_port = (*args->server_addr && *args->server_port ? 324 concatenate(args->server_addr, ";", 325 args->server_port, (char *) 0) : 0); 326 client_addr_port = (*args->client_addr && *args->client_port ? 327 concatenate(args->client_addr, ";", 328 args->client_port, (char *) 0) : 0); 329 #else 330 331 /* 332 * Don't give any IP address information to SASL. 333 */ 334 #endif 335 336 if ((sasl_status = 337 SASL_SERVER_NEW(args->service, var_myhostname, 338 args->user_realm ? args->user_realm : NO_AUTH_REALM, 339 server_addr_port, client_addr_port, 340 NO_SESSION_CALLBACKS, NO_SECURITY_LAYERS, 341 &sasl_conn)) != SASL_OK) { 342 msg_warn("SASL per-connection server initialization: %s", 343 xsasl_cyrus_strerror(sasl_status)); 344 XSASL_CYRUS_SERVER_CREATE_ERROR_RETURN(0); 345 } 346 347 /* 348 * Extend the XSASL_SERVER object with our own data. We use long-lived 349 * conversion buffers rather than local variables to avoid memory leaks 350 * in case of read/write timeout or I/O error. 351 */ 352 server = (XSASL_CYRUS_SERVER *) mymalloc(sizeof(*server)); 353 server->xsasl.free = xsasl_cyrus_server_free; 354 server->xsasl.first = xsasl_cyrus_server_first; 355 server->xsasl.next = xsasl_cyrus_server_next; 356 server->xsasl.get_mechanism_list = xsasl_cyrus_server_get_mechanism_list; 357 server->xsasl.get_username = xsasl_cyrus_server_get_username; 358 server->stream = args->stream; 359 server->sasl_conn = sasl_conn; 360 server->decoded = vstring_alloc(20); 361 server->username = 0; 362 server->mechanism_list = 0; 363 364 if (xsasl_cyrus_server_set_security(&server->xsasl, args->security_options) 365 != XSASL_AUTH_OK) 366 XSASL_CYRUS_SERVER_CREATE_ERROR_RETURN(0); 367 368 XSASL_CYRUS_SERVER_CREATE_RETURN(&server->xsasl); 369 } 370 371 /* xsasl_cyrus_server_set_security - set security properties */ 372 373 static int xsasl_cyrus_server_set_security(XSASL_SERVER *xp, 374 const char *sasl_opts_val) 375 { 376 XSASL_CYRUS_SERVER *server = (XSASL_CYRUS_SERVER *) xp; 377 sasl_security_properties_t sec_props; 378 int sasl_status; 379 380 /* 381 * Security options. Some information can be found in the sasl.h include 382 * file. 383 */ 384 memset(&sec_props, 0, sizeof(sec_props)); 385 sec_props.min_ssf = 0; 386 sec_props.max_ssf = 0; /* don't allow real SASL 387 * security layer */ 388 if (*sasl_opts_val == 0) { 389 sec_props.security_flags = 0; 390 } else { 391 sec_props.security_flags = 392 xsasl_cyrus_security_parse_opts(sasl_opts_val); 393 if (sec_props.security_flags == 0) { 394 msg_warn("bad per-session SASL security properties"); 395 return (XSASL_AUTH_FAIL); 396 } 397 } 398 sec_props.maxbufsize = 0; 399 sec_props.property_names = 0; 400 sec_props.property_values = 0; 401 402 if ((sasl_status = sasl_setprop(server->sasl_conn, SASL_SEC_PROPS, 403 &sec_props)) != SASL_OK) { 404 msg_warn("SASL per-connection security setup; %s", 405 xsasl_cyrus_strerror(sasl_status)); 406 return (XSASL_AUTH_FAIL); 407 } 408 return (XSASL_AUTH_OK); 409 } 410 411 /* xsasl_cyrus_server_get_mechanism_list - get available mechanisms */ 412 413 static const char *xsasl_cyrus_server_get_mechanism_list(XSASL_SERVER *xp) 414 { 415 const char *myname = "xsasl_cyrus_server_get_mechanism_list"; 416 XSASL_CYRUS_SERVER *server = (XSASL_CYRUS_SERVER *) xp; 417 MECHANISM_TYPE mechanism_list; 418 MECHANISM_COUNT_TYPE mechanism_count; 419 int sasl_status; 420 421 /* 422 * Get the list of authentication mechanisms. 423 */ 424 #define UNSUPPORTED_USER ((char *) 0) 425 #define IGNORE_MECHANISM_LEN ((unsigned *) 0) 426 427 if ((sasl_status = sasl_listmech(server->sasl_conn, UNSUPPORTED_USER, 428 "", " ", "", 429 &mechanism_list, 430 IGNORE_MECHANISM_LEN, 431 &mechanism_count)) != SASL_OK) { 432 msg_warn("%s: %s", myname, xsasl_cyrus_strerror(sasl_status)); 433 return (0); 434 } 435 if (mechanism_count <= 0) { 436 msg_warn("%s: no applicable SASL mechanisms", myname); 437 return (0); 438 } 439 server->mechanism_list = mystrdup(mechanism_list); 440 #if SASL_VERSION_MAJOR < 2 441 /* SASL version 1 doesn't free memory that it allocates. */ 442 free(mechanism_list); 443 #endif 444 return (server->mechanism_list); 445 } 446 447 /* xsasl_cyrus_server_free - destroy server instance */ 448 449 static void xsasl_cyrus_server_free(XSASL_SERVER *xp) 450 { 451 XSASL_CYRUS_SERVER *server = (XSASL_CYRUS_SERVER *) xp; 452 453 sasl_dispose(&server->sasl_conn); 454 vstring_free(server->decoded); 455 if (server->username) 456 myfree(server->username); 457 if (server->mechanism_list) 458 myfree(server->mechanism_list); 459 myfree((void *) server); 460 } 461 462 /* xsasl_cyrus_server_auth_response - encode server first/next response */ 463 464 static int xsasl_cyrus_server_auth_response(int sasl_status, 465 SERVEROUT_TYPE serverout, 466 unsigned serveroutlen, 467 VSTRING *reply) 468 { 469 const char *myname = "xsasl_cyrus_server_auth_response"; 470 unsigned enc_length; 471 unsigned enc_length_out; 472 473 /* 474 * Encode the server first/next non-error response; otherwise return the 475 * unencoded error text that corresponds to the SASL error status. 476 * 477 * Regarding the hairy expression below: output from sasl_encode64() comes 478 * in multiples of four bytes for each triple of input bytes, plus four 479 * bytes for any incomplete last triple, plus one byte for the null 480 * terminator. 481 */ 482 if (sasl_status == SASL_OK) { 483 vstring_strcpy(reply, ""); 484 return (XSASL_AUTH_DONE); 485 } else if (sasl_status == SASL_CONTINUE) { 486 if (msg_verbose) 487 msg_info("%s: uncoded server challenge: %.*s", 488 myname, (int) serveroutlen, serverout); 489 enc_length = ((serveroutlen + 2) / 3) * 4 + 1; 490 VSTRING_RESET(reply); /* Fix 200512 */ 491 VSTRING_SPACE(reply, enc_length); 492 if ((sasl_status = sasl_encode64(serverout, serveroutlen, 493 STR(reply), vstring_avail(reply), 494 &enc_length_out)) != SASL_OK) 495 msg_panic("%s: sasl_encode64 botch: %s", 496 myname, xsasl_cyrus_strerror(sasl_status)); 497 return (XSASL_AUTH_MORE); 498 } else { 499 if (sasl_status == SASL_NOUSER) /* privacy */ 500 sasl_status = SASL_BADAUTH; 501 vstring_strcpy(reply, xsasl_cyrus_strerror(sasl_status)); 502 switch (sasl_status) { 503 case SASL_FAIL: 504 case SASL_NOMEM: 505 case SASL_TRYAGAIN: 506 case SASL_UNAVAIL: 507 return XSASL_AUTH_TEMP; 508 default: 509 return (XSASL_AUTH_FAIL); 510 } 511 } 512 } 513 514 /* xsasl_cyrus_server_first - per-session authentication */ 515 516 int xsasl_cyrus_server_first(XSASL_SERVER *xp, const char *sasl_method, 517 const char *init_response, VSTRING *reply) 518 { 519 const char *myname = "xsasl_cyrus_server_first"; 520 XSASL_CYRUS_SERVER *server = (XSASL_CYRUS_SERVER *) xp; 521 char *dec_buffer; 522 unsigned dec_length; 523 unsigned reply_len; 524 unsigned serveroutlen; 525 int sasl_status; 526 SERVEROUT_TYPE serverout = 0; 527 int xsasl_status; 528 529 #if SASL_VERSION_MAJOR < 2 530 const char *errstr = 0; 531 532 #endif 533 534 #define IFELSE(e1,e2,e3) ((e1) ? (e2) : (e3)) 535 536 if (msg_verbose) 537 msg_info("%s: sasl_method %s%s%s", myname, sasl_method, 538 IFELSE(init_response, ", init_response ", ""), 539 IFELSE(init_response, init_response, "")); 540 541 /* 542 * SASL authentication protocol start-up. Process any initial client 543 * response that was sent along in the AUTH command. 544 */ 545 if (init_response) { 546 reply_len = strlen(init_response); 547 VSTRING_RESET(server->decoded); /* Fix 200512 */ 548 VSTRING_SPACE(server->decoded, reply_len); 549 if ((sasl_status = SASL_DECODE64(init_response, reply_len, 550 dec_buffer = STR(server->decoded), 551 vstring_avail(server->decoded), 552 &dec_length)) != SASL_OK) { 553 vstring_strcpy(reply, xsasl_cyrus_strerror(sasl_status)); 554 return (XSASL_AUTH_FORM); 555 } 556 if (msg_verbose) 557 msg_info("%s: decoded initial response %s", myname, dec_buffer); 558 } else { 559 dec_buffer = 0; 560 dec_length = 0; 561 } 562 sasl_status = SASL_SERVER_START(server->sasl_conn, sasl_method, dec_buffer, 563 dec_length, &serverout, 564 &serveroutlen, &errstr); 565 xsasl_status = xsasl_cyrus_server_auth_response(sasl_status, serverout, 566 serveroutlen, reply); 567 #if SASL_VERSION_MAJOR < 2 568 /* SASL version 1 doesn't free memory that it allocates. */ 569 free(serverout); 570 #endif 571 return (xsasl_status); 572 } 573 574 /* xsasl_cyrus_server_next - continue authentication */ 575 576 static int xsasl_cyrus_server_next(XSASL_SERVER *xp, const char *request, 577 VSTRING *reply) 578 { 579 const char *myname = "xsasl_cyrus_server_next"; 580 XSASL_CYRUS_SERVER *server = (XSASL_CYRUS_SERVER *) xp; 581 unsigned dec_length; 582 unsigned request_len; 583 unsigned serveroutlen; 584 int sasl_status; 585 SERVEROUT_TYPE serverout = 0; 586 int xsasl_status; 587 588 #if SASL_VERSION_MAJOR < 2 589 const char *errstr = 0; 590 591 #endif 592 593 request_len = strlen(request); 594 VSTRING_RESET(server->decoded); /* Fix 200512 */ 595 VSTRING_SPACE(server->decoded, request_len); 596 if ((sasl_status = SASL_DECODE64(request, request_len, 597 STR(server->decoded), 598 vstring_avail(server->decoded), 599 &dec_length)) != SASL_OK) { 600 vstring_strcpy(reply, xsasl_cyrus_strerror(sasl_status)); 601 return (XSASL_AUTH_FORM); 602 } 603 if (msg_verbose) 604 msg_info("%s: decoded response: %.*s", 605 myname, (int) dec_length, STR(server->decoded)); 606 sasl_status = SASL_SERVER_STEP(server->sasl_conn, STR(server->decoded), 607 dec_length, &serverout, 608 &serveroutlen, &errstr); 609 xsasl_status = xsasl_cyrus_server_auth_response(sasl_status, serverout, 610 serveroutlen, reply); 611 #if SASL_VERSION_MAJOR < 2 612 /* SASL version 1 doesn't free memory that it allocates. */ 613 free(serverout); 614 #endif 615 return (xsasl_status); 616 } 617 618 /* xsasl_cyrus_server_get_username - get authenticated username */ 619 620 static const char *xsasl_cyrus_server_get_username(XSASL_SERVER *xp) 621 { 622 const char *myname = "xsasl_cyrus_server_get_username"; 623 XSASL_CYRUS_SERVER *server = (XSASL_CYRUS_SERVER *) xp; 624 VOID_SERVEROUT_TYPE serverout = 0; 625 int sasl_status; 626 627 /* 628 * XXX Do not free(serverout). 629 */ 630 sasl_status = sasl_getprop(server->sasl_conn, SASL_USERNAME, &serverout); 631 if (sasl_status != SASL_OK || serverout == 0) { 632 msg_warn("%s: sasl_getprop SASL_USERNAME botch: %s", 633 myname, xsasl_cyrus_strerror(sasl_status)); 634 return (0); 635 } 636 if (server->username) 637 myfree(server->username); 638 server->username = mystrdup(serverout); 639 printable(server->username, '?'); 640 return (server->username); 641 } 642 643 #endif 644