1 /* 2 * Copyright (c) 2001-2003,2009 Proofpoint, Inc. and its suppliers. 3 * All rights reserved. 4 * 5 * By using this file, you agree to the terms and conditions set 6 * forth in the LICENSE file which can be found at the top level of 7 * the sendmail distribution. 8 */ 9 10 #include <sm/gen.h> 11 SM_RCSID("@(#)$Id: mbdb.c,v 1.43 2014-01-08 17:03:15 ca Exp $") 12 13 #include <sys/param.h> 14 15 #include <ctype.h> 16 #include <errno.h> 17 #include <pwd.h> 18 #include <stdlib.h> 19 #include <setjmp.h> 20 #include <unistd.h> 21 22 #include <sm/limits.h> 23 #include <sm/conf.h> 24 #include <sm/assert.h> 25 #include <sm/bitops.h> 26 #include <sm/errstring.h> 27 #include <sm/heap.h> 28 #include <sm/mbdb.h> 29 #include <sm/string.h> 30 #include <sm/sysexits.h> 31 32 #if LDAPMAP && _LDAP_EXAMPLE_ 33 # include <sm/ldap.h> 34 #endif 35 36 typedef struct 37 { 38 char *mbdb_typename; 39 int (*mbdb_initialize) __P((char *)); 40 int (*mbdb_lookup) __P((char *name, SM_MBDB_T *user)); 41 void (*mbdb_terminate) __P((void)); 42 } SM_MBDB_TYPE_T; 43 44 static int mbdb_pw_initialize __P((char *)); 45 static int mbdb_pw_lookup __P((char *name, SM_MBDB_T *user)); 46 static void mbdb_pw_terminate __P((void)); 47 48 #if LDAPMAP && _LDAP_EXAMPLE_ 49 static struct sm_ldap_struct LDAPLMAP; 50 static int mbdb_ldap_initialize __P((char *)); 51 static int mbdb_ldap_lookup __P((char *name, SM_MBDB_T *user)); 52 static void mbdb_ldap_terminate __P((void)); 53 #endif /* LDAPMAP && _LDAP_EXAMPLE_ */ 54 55 static SM_MBDB_TYPE_T SmMbdbTypes[] = 56 { 57 { "pw", mbdb_pw_initialize, mbdb_pw_lookup, mbdb_pw_terminate }, 58 #if LDAPMAP && _LDAP_EXAMPLE_ 59 { "ldap", mbdb_ldap_initialize, mbdb_ldap_lookup, mbdb_ldap_terminate }, 60 #endif 61 { NULL, NULL, NULL, NULL } 62 }; 63 64 static SM_MBDB_TYPE_T *SmMbdbType = &SmMbdbTypes[0]; 65 66 /* 67 ** SM_MBDB_INITIALIZE -- specify which mailbox database to use 68 ** 69 ** If this function is not called, then the "pw" implementation 70 ** is used by default; this implementation uses getpwnam(). 71 ** 72 ** Parameters: 73 ** mbdb -- Which mailbox database to use. 74 ** The argument has the form "name" or "name.arg". 75 ** "pw" means use getpwnam(). 76 ** 77 ** Results: 78 ** EX_OK on success, or an EX_* code on failure. 79 */ 80 81 int 82 sm_mbdb_initialize(mbdb) 83 char *mbdb; 84 { 85 size_t namelen; 86 int err; 87 char *name; 88 char *arg; 89 SM_MBDB_TYPE_T *t; 90 91 SM_REQUIRE(mbdb != NULL); 92 93 name = mbdb; 94 arg = strchr(mbdb, '.'); 95 if (arg == NULL) 96 namelen = strlen(name); 97 else 98 { 99 namelen = arg - name; 100 ++arg; 101 } 102 103 for (t = SmMbdbTypes; t->mbdb_typename != NULL; ++t) 104 { 105 if (strlen(t->mbdb_typename) == namelen && 106 strncmp(name, t->mbdb_typename, namelen) == 0) 107 { 108 err = EX_OK; 109 if (t->mbdb_initialize != NULL) 110 err = t->mbdb_initialize(arg); 111 if (err == EX_OK) 112 SmMbdbType = t; 113 return err; 114 } 115 } 116 return EX_UNAVAILABLE; 117 } 118 119 /* 120 ** SM_MBDB_TERMINATE -- terminate connection to the mailbox database 121 ** 122 ** Because this function closes any cached file descriptors that 123 ** are being held open for the connection to the mailbox database, 124 ** it should be called for security reasons prior to dropping privileges 125 ** and execing another process. 126 ** 127 ** Parameters: 128 ** none. 129 ** 130 ** Results: 131 ** none. 132 */ 133 134 void 135 sm_mbdb_terminate() 136 { 137 if (SmMbdbType->mbdb_terminate != NULL) 138 SmMbdbType->mbdb_terminate(); 139 } 140 141 /* 142 ** SM_MBDB_LOOKUP -- look up a local mail recipient, given name 143 ** 144 ** Parameters: 145 ** name -- name of local mail recipient 146 ** user -- pointer to structure to fill in on success 147 ** 148 ** Results: 149 ** On success, fill in *user and return EX_OK. 150 ** If the user does not exist, return EX_NOUSER. 151 ** If a temporary failure (eg, a network failure) occurred, 152 ** return EX_TEMPFAIL. Otherwise return EX_OSERR. 153 */ 154 155 int 156 sm_mbdb_lookup(name, user) 157 char *name; 158 SM_MBDB_T *user; 159 { 160 int ret = EX_NOUSER; 161 162 if (SmMbdbType->mbdb_lookup != NULL) 163 ret = SmMbdbType->mbdb_lookup(name, user); 164 return ret; 165 } 166 167 /* 168 ** SM_MBDB_FROMPW -- copy from struct pw to SM_MBDB_T 169 ** 170 ** Parameters: 171 ** user -- destination user information structure 172 ** pw -- source passwd structure 173 ** 174 ** Results: 175 ** none. 176 */ 177 178 void 179 sm_mbdb_frompw(user, pw) 180 SM_MBDB_T *user; 181 struct passwd *pw; 182 { 183 SM_REQUIRE(user != NULL); 184 (void) sm_strlcpy(user->mbdb_name, pw->pw_name, 185 sizeof(user->mbdb_name)); 186 user->mbdb_uid = pw->pw_uid; 187 user->mbdb_gid = pw->pw_gid; 188 sm_pwfullname(pw->pw_gecos, pw->pw_name, user->mbdb_fullname, 189 sizeof(user->mbdb_fullname)); 190 (void) sm_strlcpy(user->mbdb_homedir, pw->pw_dir, 191 sizeof(user->mbdb_homedir)); 192 (void) sm_strlcpy(user->mbdb_shell, pw->pw_shell, 193 sizeof(user->mbdb_shell)); 194 } 195 196 /* 197 ** SM_PWFULLNAME -- build full name of user from pw_gecos field. 198 ** 199 ** This routine interprets the strange entry that would appear 200 ** in the GECOS field of the password file. 201 ** 202 ** Parameters: 203 ** gecos -- name to build. 204 ** user -- the login name of this user (for &). 205 ** buf -- place to put the result. 206 ** buflen -- length of buf. 207 ** 208 ** Returns: 209 ** none. 210 */ 211 212 #if _FFR_HANDLE_ISO8859_GECOS 213 static char Latin1ToASCII[128] = 214 { 215 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 216 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 33, 217 99, 80, 36, 89, 124, 36, 34, 99, 97, 60, 45, 45, 114, 45, 111, 42, 218 50, 51, 39, 117, 80, 46, 44, 49, 111, 62, 42, 42, 42, 63, 65, 65, 219 65, 65, 65, 65, 65, 67, 69, 69, 69, 69, 73, 73, 73, 73, 68, 78, 79, 220 79, 79, 79, 79, 88, 79, 85, 85, 85, 85, 89, 80, 66, 97, 97, 97, 97, 221 97, 97, 97, 99, 101, 101, 101, 101, 105, 105, 105, 105, 100, 110, 222 111, 111, 111, 111, 111, 47, 111, 117, 117, 117, 117, 121, 112, 121 223 }; 224 #endif /* _FFR_HANDLE_ISO8859_GECOS */ 225 226 void 227 sm_pwfullname(gecos, user, buf, buflen) 228 register char *gecos; 229 char *user; 230 char *buf; 231 size_t buflen; 232 { 233 register char *p; 234 register char *bp = buf; 235 236 if (*gecos == '*') 237 gecos++; 238 239 /* copy gecos, interpolating & to be full name */ 240 for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++) 241 { 242 if (bp >= &buf[buflen - 1]) 243 { 244 /* buffer overflow -- just use login name */ 245 (void) sm_strlcpy(buf, user, buflen); 246 return; 247 } 248 if (*p == '&') 249 { 250 /* interpolate full name */ 251 (void) sm_strlcpy(bp, user, buflen - (bp - buf)); 252 *bp = toupper(*bp); 253 bp += strlen(bp); 254 } 255 else 256 { 257 #if _FFR_HANDLE_ISO8859_GECOS 258 if ((unsigned char) *p >= 128) 259 *bp++ = Latin1ToASCII[(unsigned char) *p - 128]; 260 else 261 #endif 262 /* "else" in #if code above */ 263 *bp++ = *p; 264 } 265 } 266 *bp = '\0'; 267 } 268 269 /* 270 ** /etc/passwd implementation. 271 */ 272 273 /* 274 ** MBDB_PW_INITIALIZE -- initialize getpwnam() version 275 ** 276 ** Parameters: 277 ** arg -- unused. 278 ** 279 ** Results: 280 ** EX_OK. 281 */ 282 283 /* ARGSUSED0 */ 284 static int 285 mbdb_pw_initialize(arg) 286 char *arg; 287 { 288 return EX_OK; 289 } 290 291 /* 292 ** MBDB_PW_LOOKUP -- look up a local mail recipient, given name 293 ** 294 ** Parameters: 295 ** name -- name of local mail recipient 296 ** user -- pointer to structure to fill in on success 297 ** 298 ** Results: 299 ** On success, fill in *user and return EX_OK. 300 ** Failure: EX_NOUSER. 301 */ 302 303 static int 304 mbdb_pw_lookup(name, user) 305 char *name; 306 SM_MBDB_T *user; 307 { 308 struct passwd *pw; 309 310 #if HESIOD && !HESIOD_ALLOW_NUMERIC_LOGIN 311 /* DEC Hesiod getpwnam accepts numeric strings -- short circuit it */ 312 { 313 char *p; 314 315 for (p = name; *p != '\0'; p++) 316 if (!isascii(*p) || !isdigit(*p)) 317 break; 318 if (*p == '\0') 319 return EX_NOUSER; 320 } 321 #endif /* HESIOD && !HESIOD_ALLOW_NUMERIC_LOGIN */ 322 323 errno = 0; 324 pw = getpwnam(name); 325 if (pw == NULL) 326 { 327 #if _FFR_USE_GETPWNAM_ERRNO 328 /* 329 ** Only enable this code iff 330 ** user unknown <-> getpwnam() == NULL && errno == 0 331 ** (i.e., errno unchanged); see the POSIX spec. 332 */ 333 334 if (errno != 0) 335 return EX_TEMPFAIL; 336 #endif /* _FFR_USE_GETPWNAM_ERRNO */ 337 return EX_NOUSER; 338 } 339 340 sm_mbdb_frompw(user, pw); 341 return EX_OK; 342 } 343 344 /* 345 ** MBDB_PW_TERMINATE -- terminate connection to the mailbox database 346 ** 347 ** Parameters: 348 ** none. 349 ** 350 ** Results: 351 ** none. 352 */ 353 354 static void 355 mbdb_pw_terminate() 356 { 357 endpwent(); 358 } 359 360 #if LDAPMAP && _LDAP_EXAMPLE_ 361 /* 362 ** LDAP example implementation based on RFC 2307, "An Approach for Using 363 ** LDAP as a Network Information Service": 364 ** 365 ** ( nisSchema.1.0 NAME 'uidNumber' 366 ** DESC 'An integer uniquely identifying a user in an 367 ** administrative domain' 368 ** EQUALITY integerMatch SYNTAX 'INTEGER' SINGLE-VALUE ) 369 ** 370 ** ( nisSchema.1.1 NAME 'gidNumber' 371 ** DESC 'An integer uniquely identifying a group in an 372 ** administrative domain' 373 ** EQUALITY integerMatch SYNTAX 'INTEGER' SINGLE-VALUE ) 374 ** 375 ** ( nisSchema.1.2 NAME 'gecos' 376 ** DESC 'The GECOS field; the common name' 377 ** EQUALITY caseIgnoreIA5Match 378 ** SUBSTRINGS caseIgnoreIA5SubstringsMatch 379 ** SYNTAX 'IA5String' SINGLE-VALUE ) 380 ** 381 ** ( nisSchema.1.3 NAME 'homeDirectory' 382 ** DESC 'The absolute path to the home directory' 383 ** EQUALITY caseExactIA5Match 384 ** SYNTAX 'IA5String' SINGLE-VALUE ) 385 ** 386 ** ( nisSchema.1.4 NAME 'loginShell' 387 ** DESC 'The path to the login shell' 388 ** EQUALITY caseExactIA5Match 389 ** SYNTAX 'IA5String' SINGLE-VALUE ) 390 ** 391 ** ( nisSchema.2.0 NAME 'posixAccount' SUP top AUXILIARY 392 ** DESC 'Abstraction of an account with POSIX attributes' 393 ** MUST ( cn $ uid $ uidNumber $ gidNumber $ homeDirectory ) 394 ** MAY ( userPassword $ loginShell $ gecos $ description ) ) 395 ** 396 */ 397 398 # define MBDB_LDAP_LABEL "MailboxDatabase" 399 400 # ifndef MBDB_LDAP_FILTER 401 # define MBDB_LDAP_FILTER "(&(objectClass=posixAccount)(uid=%0))" 402 # endif 403 404 # ifndef MBDB_DEFAULT_LDAP_BASEDN 405 # define MBDB_DEFAULT_LDAP_BASEDN NULL 406 # endif 407 408 # ifndef MBDB_DEFAULT_LDAP_SERVER 409 # define MBDB_DEFAULT_LDAP_SERVER NULL 410 # endif 411 412 /* 413 ** MBDB_LDAP_INITIALIZE -- initialize LDAP version 414 ** 415 ** Parameters: 416 ** arg -- LDAP specification 417 ** 418 ** Results: 419 ** EX_OK on success, or an EX_* code on failure. 420 */ 421 422 static int 423 mbdb_ldap_initialize(arg) 424 char *arg; 425 { 426 sm_ldap_clear(&LDAPLMAP); 427 LDAPLMAP.ldap_base = MBDB_DEFAULT_LDAP_BASEDN; 428 LDAPLMAP.ldap_host = MBDB_DEFAULT_LDAP_SERVER; 429 LDAPLMAP.ldap_filter = MBDB_LDAP_FILTER; 430 431 /* Only want one match */ 432 LDAPLMAP.ldap_sizelimit = 1; 433 434 /* interpolate new ldap_base and ldap_host from arg if given */ 435 if (arg != NULL && *arg != '\0') 436 { 437 char *new; 438 char *sep; 439 size_t len; 440 441 len = strlen(arg) + 1; 442 new = sm_malloc(len); 443 if (new == NULL) 444 return EX_TEMPFAIL; 445 (void) sm_strlcpy(new, arg, len); 446 sep = strrchr(new, '@'); 447 if (sep != NULL) 448 { 449 *sep++ = '\0'; 450 LDAPLMAP.ldap_host = sep; 451 } 452 LDAPLMAP.ldap_base = new; 453 } 454 return EX_OK; 455 } 456 457 458 /* 459 ** MBDB_LDAP_LOOKUP -- look up a local mail recipient, given name 460 ** 461 ** Parameters: 462 ** name -- name of local mail recipient 463 ** user -- pointer to structure to fill in on success 464 ** 465 ** Results: 466 ** On success, fill in *user and return EX_OK. 467 ** Failure: EX_NOUSER. 468 */ 469 470 #define NEED_FULLNAME 0x01 471 #define NEED_HOMEDIR 0x02 472 #define NEED_SHELL 0x04 473 #define NEED_UID 0x08 474 #define NEED_GID 0x10 475 476 static int 477 mbdb_ldap_lookup(name, user) 478 char *name; 479 SM_MBDB_T *user; 480 { 481 int msgid; 482 int need; 483 int ret; 484 int save_errno; 485 LDAPMessage *entry; 486 BerElement *ber; 487 char *attr = NULL; 488 489 if (strlen(name) >= sizeof(user->mbdb_name)) 490 { 491 errno = EINVAL; 492 return EX_NOUSER; 493 } 494 495 if (LDAPLMAP.ldap_filter == NULL) 496 { 497 /* map not initialized, but don't have arg here */ 498 errno = EFAULT; 499 return EX_TEMPFAIL; 500 } 501 502 if (LDAPLMAP.ldap_pid != getpid()) 503 { 504 /* re-open map in this child process */ 505 LDAPLMAP.ldap_ld = NULL; 506 } 507 508 if (LDAPLMAP.ldap_ld == NULL) 509 { 510 /* map not open, try to open now */ 511 if (!sm_ldap_start(MBDB_LDAP_LABEL, &LDAPLMAP)) 512 return EX_TEMPFAIL; 513 } 514 515 sm_ldap_setopts(LDAPLMAP.ldap_ld, &LDAPLMAP); 516 msgid = sm_ldap_search(&LDAPLMAP, name); 517 if (msgid == -1) 518 { 519 save_errno = sm_ldap_geterrno(LDAPLMAP.ldap_ld) + E_LDAPBASE; 520 # ifdef LDAP_SERVER_DOWN 521 if (errno == LDAP_SERVER_DOWN) 522 { 523 /* server disappeared, try reopen on next search */ 524 sm_ldap_close(&LDAPLMAP); 525 } 526 # endif /* LDAP_SERVER_DOWN */ 527 errno = save_errno; 528 return EX_TEMPFAIL; 529 } 530 531 /* Get results */ 532 ret = ldap_result(LDAPLMAP.ldap_ld, msgid, 1, 533 (LDAPLMAP.ldap_timeout.tv_sec == 0 ? NULL : 534 &(LDAPLMAP.ldap_timeout)), 535 &(LDAPLMAP.ldap_res)); 536 537 if (ret != LDAP_RES_SEARCH_RESULT && 538 ret != LDAP_RES_SEARCH_ENTRY) 539 { 540 if (ret == 0) 541 errno = ETIMEDOUT; 542 else 543 errno = sm_ldap_geterrno(LDAPLMAP.ldap_ld); 544 ret = EX_TEMPFAIL; 545 goto abort; 546 } 547 548 entry = ldap_first_entry(LDAPLMAP.ldap_ld, LDAPLMAP.ldap_res); 549 if (entry == NULL) 550 { 551 int rc; 552 553 /* 554 ** We may have gotten an LDAP_RES_SEARCH_RESULT response 555 ** with an error inside it, so we have to extract that 556 ** with ldap_parse_result(). This can happen when talking 557 ** to an LDAP proxy whose backend has gone down. 558 */ 559 560 save_errno = ldap_parse_result(LDAPLMAP.ldap_ld, 561 LDAPLMAP.ldap_res, &rc, NULL, 562 NULL, NULL, NULL, 0); 563 if (save_errno == LDAP_SUCCESS) 564 save_errno = rc; 565 if (save_errno == LDAP_SUCCESS) 566 { 567 errno = ENOENT; 568 ret = EX_NOUSER; 569 } 570 else 571 { 572 errno = save_errno; 573 ret = EX_TEMPFAIL; 574 } 575 goto abort; 576 } 577 578 # if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT) 579 /* 580 ** Reset value to prevent lingering 581 ** LDAP_DECODING_ERROR due to 582 ** OpenLDAP 1.X's hack (see below) 583 */ 584 585 LDAPLMAP.ldap_ld->ld_errno = LDAP_SUCCESS; 586 # endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */ 587 588 ret = EX_OK; 589 need = NEED_FULLNAME|NEED_HOMEDIR|NEED_SHELL|NEED_UID|NEED_GID; 590 for (attr = ldap_first_attribute(LDAPLMAP.ldap_ld, entry, &ber); 591 attr != NULL; 592 attr = ldap_next_attribute(LDAPLMAP.ldap_ld, entry, ber)) 593 { 594 char **vals; 595 596 vals = ldap_get_values(LDAPLMAP.ldap_ld, entry, attr); 597 if (vals == NULL) 598 { 599 errno = sm_ldap_geterrno(LDAPLMAP.ldap_ld); 600 if (errno == LDAP_SUCCESS) 601 { 602 ldap_memfree(attr); 603 continue; 604 } 605 606 /* Must be an error */ 607 errno += E_LDAPBASE; 608 ret = EX_TEMPFAIL; 609 goto abort; 610 } 611 612 # if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT) 613 /* 614 ** Reset value to prevent lingering 615 ** LDAP_DECODING_ERROR due to 616 ** OpenLDAP 1.X's hack (see below) 617 */ 618 619 LDAPLMAP.ldap_ld->ld_errno = LDAP_SUCCESS; 620 # endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */ 621 622 if (vals[0] == NULL || vals[0][0] == '\0') 623 goto skip; 624 625 if (strcasecmp(attr, "gecos") == 0) 626 { 627 if (!bitset(NEED_FULLNAME, need) || 628 strlen(vals[0]) >= sizeof(user->mbdb_fullname)) 629 goto skip; 630 631 sm_pwfullname(vals[0], name, user->mbdb_fullname, 632 sizeof(user->mbdb_fullname)); 633 need &= ~NEED_FULLNAME; 634 } 635 else if (strcasecmp(attr, "homeDirectory") == 0) 636 { 637 if (!bitset(NEED_HOMEDIR, need) || 638 strlen(vals[0]) >= sizeof(user->mbdb_homedir)) 639 goto skip; 640 641 (void) sm_strlcpy(user->mbdb_homedir, vals[0], 642 sizeof(user->mbdb_homedir)); 643 need &= ~NEED_HOMEDIR; 644 } 645 else if (strcasecmp(attr, "loginShell") == 0) 646 { 647 if (!bitset(NEED_SHELL, need) || 648 strlen(vals[0]) >= sizeof(user->mbdb_shell)) 649 goto skip; 650 651 (void) sm_strlcpy(user->mbdb_shell, vals[0], 652 sizeof(user->mbdb_shell)); 653 need &= ~NEED_SHELL; 654 } 655 else if (strcasecmp(attr, "uidNumber") == 0) 656 { 657 char *p; 658 659 if (!bitset(NEED_UID, need)) 660 goto skip; 661 662 for (p = vals[0]; *p != '\0'; p++) 663 { 664 /* allow negative numbers */ 665 if (p == vals[0] && *p == '-') 666 { 667 /* but not simply '-' */ 668 if (*(p + 1) == '\0') 669 goto skip; 670 } 671 else if (!isascii(*p) || !isdigit(*p)) 672 goto skip; 673 } 674 user->mbdb_uid = atoi(vals[0]); 675 need &= ~NEED_UID; 676 } 677 else if (strcasecmp(attr, "gidNumber") == 0) 678 { 679 char *p; 680 681 if (!bitset(NEED_GID, need)) 682 goto skip; 683 684 for (p = vals[0]; *p != '\0'; p++) 685 { 686 /* allow negative numbers */ 687 if (p == vals[0] && *p == '-') 688 { 689 /* but not simply '-' */ 690 if (*(p + 1) == '\0') 691 goto skip; 692 } 693 else if (!isascii(*p) || !isdigit(*p)) 694 goto skip; 695 } 696 user->mbdb_gid = atoi(vals[0]); 697 need &= ~NEED_GID; 698 } 699 700 skip: 701 ldap_value_free(vals); 702 ldap_memfree(attr); 703 } 704 705 errno = sm_ldap_geterrno(LDAPLMAP.ldap_ld); 706 707 /* 708 ** We check errno != LDAP_DECODING_ERROR since 709 ** OpenLDAP 1.X has a very ugly *undocumented* 710 ** hack of returning this error code from 711 ** ldap_next_attribute() if the library freed the 712 ** ber attribute. See: 713 ** http://www.openldap.org/lists/openldap-devel/9901/msg00064.html 714 */ 715 716 if (errno != LDAP_SUCCESS && 717 errno != LDAP_DECODING_ERROR) 718 { 719 /* Must be an error */ 720 errno += E_LDAPBASE; 721 ret = EX_TEMPFAIL; 722 goto abort; 723 } 724 725 abort: 726 save_errno = errno; 727 if (attr != NULL) 728 { 729 ldap_memfree(attr); 730 attr = NULL; 731 } 732 if (LDAPLMAP.ldap_res != NULL) 733 { 734 ldap_msgfree(LDAPLMAP.ldap_res); 735 LDAPLMAP.ldap_res = NULL; 736 } 737 if (ret == EX_OK) 738 { 739 if (need == 0) 740 { 741 (void) sm_strlcpy(user->mbdb_name, name, 742 sizeof(user->mbdb_name)); 743 save_errno = 0; 744 } 745 else 746 { 747 ret = EX_NOUSER; 748 save_errno = EINVAL; 749 } 750 } 751 errno = save_errno; 752 return ret; 753 } 754 755 /* 756 ** MBDB_LDAP_TERMINATE -- terminate connection to the mailbox database 757 ** 758 ** Parameters: 759 ** none. 760 ** 761 ** Results: 762 ** none. 763 */ 764 765 static void 766 mbdb_ldap_terminate() 767 { 768 sm_ldap_close(&LDAPLMAP); 769 } 770 #endif /* LDAPMAP && _LDAP_EXAMPLE_ */ 771