1 /* 2 * Copyright (c) 2001-2002 Sendmail, 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.38 2002/04/05 22:59:56 gshapiro 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 21 #include <sm/limits.h> 22 #include <sm/conf.h> 23 #include <sm/assert.h> 24 #include <sm/bitops.h> 25 #include <sm/errstring.h> 26 #include <sm/heap.h> 27 #include <sm/mbdb.h> 28 #include <sm/string.h> 29 # ifdef EX_OK 30 # undef EX_OK /* for SVr4.2 SMP */ 31 # endif /* EX_OK */ 32 #include <sm/sysexits.h> 33 34 #if LDAPMAP 35 # if _LDAP_EXAMPLE_ 36 # include <sm/ldap.h> 37 # endif /* _LDAP_EXAMPLE_ */ 38 #endif /* LDAPMAP */ 39 40 typedef struct 41 { 42 char *mbdb_typename; 43 int (*mbdb_initialize) __P((char *)); 44 int (*mbdb_lookup) __P((char *name, SM_MBDB_T *user)); 45 void (*mbdb_terminate) __P((void)); 46 } SM_MBDB_TYPE_T; 47 48 static int mbdb_pw_initialize __P((char *)); 49 static int mbdb_pw_lookup __P((char *name, SM_MBDB_T *user)); 50 static void mbdb_pw_terminate __P((void)); 51 52 #if LDAPMAP 53 # if _LDAP_EXAMPLE_ 54 static struct sm_ldap_struct LDAPLMAP; 55 static int mbdb_ldap_initialize __P((char *)); 56 static int mbdb_ldap_lookup __P((char *name, SM_MBDB_T *user)); 57 static void mbdb_ldap_terminate __P((void)); 58 # endif /* _LDAP_EXAMPLE_ */ 59 #endif /* LDAPMAP */ 60 61 static SM_MBDB_TYPE_T SmMbdbTypes[] = 62 { 63 { "pw", mbdb_pw_initialize, mbdb_pw_lookup, mbdb_pw_terminate }, 64 #if LDAPMAP 65 # if _LDAP_EXAMPLE_ 66 { "ldap", mbdb_ldap_initialize, mbdb_ldap_lookup, mbdb_ldap_terminate }, 67 # endif /* _LDAP_EXAMPLE_ */ 68 #endif /* LDAPMAP */ 69 { NULL, NULL, NULL, NULL } 70 }; 71 72 static SM_MBDB_TYPE_T *SmMbdbType = &SmMbdbTypes[0]; 73 74 /* 75 ** SM_MBDB_INITIALIZE -- specify which mailbox database to use 76 ** 77 ** If this function is not called, then the "pw" implementation 78 ** is used by default; this implementation uses getpwnam(). 79 ** 80 ** Parameters: 81 ** mbdb -- Which mailbox database to use. 82 ** The argument has the form "name" or "name.arg". 83 ** "pw" means use getpwnam(). 84 ** 85 ** Results: 86 ** EX_OK on success, or an EX_* code on failure. 87 */ 88 89 int 90 sm_mbdb_initialize(mbdb) 91 char *mbdb; 92 { 93 size_t namelen; 94 int err; 95 char *name; 96 char *arg; 97 SM_MBDB_TYPE_T *t; 98 99 SM_REQUIRE(mbdb != NULL); 100 101 name = mbdb; 102 arg = strchr(mbdb, '.'); 103 if (arg == NULL) 104 namelen = strlen(name); 105 else 106 { 107 namelen = arg - name; 108 ++arg; 109 } 110 111 for (t = SmMbdbTypes; t->mbdb_typename != NULL; ++t) 112 { 113 if (strlen(t->mbdb_typename) == namelen && 114 strncmp(name, t->mbdb_typename, namelen) == 0) 115 { 116 err = EX_OK; 117 if (t->mbdb_initialize != NULL) 118 err = t->mbdb_initialize(arg); 119 if (err == EX_OK) 120 SmMbdbType = t; 121 return err; 122 } 123 } 124 return EX_UNAVAILABLE; 125 } 126 127 /* 128 ** SM_MBDB_TERMINATE -- terminate connection to the mailbox database 129 ** 130 ** Because this function closes any cached file descriptors that 131 ** are being held open for the connection to the mailbox database, 132 ** it should be called for security reasons prior to dropping privileges 133 ** and execing another process. 134 ** 135 ** Parameters: 136 ** none. 137 ** 138 ** Results: 139 ** none. 140 */ 141 142 void 143 sm_mbdb_terminate() 144 { 145 if (SmMbdbType->mbdb_terminate != NULL) 146 SmMbdbType->mbdb_terminate(); 147 } 148 149 /* 150 ** SM_MBDB_LOOKUP -- look up a local mail recipient, given name 151 ** 152 ** Parameters: 153 ** name -- name of local mail recipient 154 ** user -- pointer to structure to fill in on success 155 ** 156 ** Results: 157 ** On success, fill in *user and return EX_OK. 158 ** If the user does not exist, return EX_NOUSER. 159 ** If a temporary failure (eg, a network failure) occurred, 160 ** return EX_TEMPFAIL. Otherwise return EX_OSERR. 161 */ 162 163 int 164 sm_mbdb_lookup(name, user) 165 char *name; 166 SM_MBDB_T *user; 167 { 168 int ret = EX_NOUSER; 169 170 if (SmMbdbType->mbdb_lookup != NULL) 171 ret = SmMbdbType->mbdb_lookup(name, user); 172 return ret; 173 } 174 175 /* 176 ** SM_MBDB_FROMPW -- copy from struct pw to SM_MBDB_T 177 ** 178 ** Parameters: 179 ** user -- destination user information structure 180 ** pw -- source passwd structure 181 ** 182 ** Results: 183 ** none. 184 */ 185 186 void 187 sm_mbdb_frompw(user, pw) 188 SM_MBDB_T *user; 189 struct passwd *pw; 190 { 191 SM_REQUIRE(user != NULL); 192 (void) sm_strlcpy(user->mbdb_name, pw->pw_name, 193 sizeof(user->mbdb_name)); 194 user->mbdb_uid = pw->pw_uid; 195 user->mbdb_gid = pw->pw_gid; 196 sm_pwfullname(pw->pw_gecos, pw->pw_name, user->mbdb_fullname, 197 sizeof(user->mbdb_fullname)); 198 (void) sm_strlcpy(user->mbdb_homedir, pw->pw_dir, 199 sizeof(user->mbdb_homedir)); 200 (void) sm_strlcpy(user->mbdb_shell, pw->pw_shell, 201 sizeof(user->mbdb_shell)); 202 } 203 204 /* 205 ** SM_PWFULLNAME -- build full name of user from pw_gecos field. 206 ** 207 ** This routine interprets the strange entry that would appear 208 ** in the GECOS field of the password file. 209 ** 210 ** Parameters: 211 ** gecos -- name to build. 212 ** user -- the login name of this user (for &). 213 ** buf -- place to put the result. 214 ** buflen -- length of buf. 215 ** 216 ** Returns: 217 ** none. 218 */ 219 220 #if _FFR_HANDLE_ISO8859_GECOS 221 static char Latin1ToASCII[128] = 222 { 223 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 224 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 33, 225 99, 80, 36, 89, 124, 36, 34, 99, 97, 60, 45, 45, 114, 45, 111, 42, 226 50, 51, 39, 117, 80, 46, 44, 49, 111, 62, 42, 42, 42, 63, 65, 65, 227 65, 65, 65, 65, 65, 67, 69, 69, 69, 69, 73, 73, 73, 73, 68, 78, 79, 228 79, 79, 79, 79, 88, 79, 85, 85, 85, 85, 89, 80, 66, 97, 97, 97, 97, 229 97, 97, 97, 99, 101, 101, 101, 101, 105, 105, 105, 105, 100, 110, 230 111, 111, 111, 111, 111, 47, 111, 117, 117, 117, 117, 121, 112, 121 231 }; 232 #endif /* _FFR_HANDLE_ISO8859_GECOS */ 233 234 void 235 sm_pwfullname(gecos, user, buf, buflen) 236 register char *gecos; 237 char *user; 238 char *buf; 239 size_t buflen; 240 { 241 register char *p; 242 register char *bp = buf; 243 244 if (*gecos == '*') 245 gecos++; 246 247 /* copy gecos, interpolating & to be full name */ 248 for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++) 249 { 250 if (bp >= &buf[buflen - 1]) 251 { 252 /* buffer overflow -- just use login name */ 253 (void) sm_strlcpy(buf, user, buflen); 254 return; 255 } 256 if (*p == '&') 257 { 258 /* interpolate full name */ 259 (void) sm_strlcpy(bp, user, buflen - (bp - buf)); 260 *bp = toupper(*bp); 261 bp += strlen(bp); 262 } 263 else 264 { 265 #if _FFR_HANDLE_ISO8859_GECOS 266 if ((unsigned char) *p >= 128) 267 *bp++ = Latin1ToASCII[(unsigned char) *p - 128]; 268 else 269 #endif /* _FFR_HANDLE_ISO8859_GECOS */ 270 *bp++ = *p; 271 } 272 } 273 *bp = '\0'; 274 } 275 276 /* 277 ** /etc/passwd implementation. 278 */ 279 280 /* 281 ** MBDB_PW_INITIALIZE -- initialize getpwnam() version 282 ** 283 ** Parameters: 284 ** arg -- unused. 285 ** 286 ** Results: 287 ** EX_OK. 288 */ 289 290 /* ARGSUSED0 */ 291 static int 292 mbdb_pw_initialize(arg) 293 char *arg; 294 { 295 return EX_OK; 296 } 297 298 /* 299 ** MBDB_PW_LOOKUP -- look up a local mail recipient, given name 300 ** 301 ** Parameters: 302 ** name -- name of local mail recipient 303 ** user -- pointer to structure to fill in on success 304 ** 305 ** Results: 306 ** On success, fill in *user and return EX_OK. 307 ** Failure: EX_NOUSER. 308 */ 309 310 static int 311 mbdb_pw_lookup(name, user) 312 char *name; 313 SM_MBDB_T *user; 314 { 315 struct passwd *pw; 316 317 #ifdef HESIOD 318 /* DEC Hesiod getpwnam accepts numeric strings -- short circuit it */ 319 { 320 char *p; 321 322 for (p = name; *p != '\0'; p++) 323 if (!isascii(*p) || !isdigit(*p)) 324 break; 325 if (*p == '\0') 326 return EX_NOUSER; 327 } 328 #endif /* HESIOD */ 329 330 errno = 0; 331 pw = getpwnam(name); 332 if (pw == NULL) 333 { 334 #if 0 335 /* 336 ** getpwnam() isn't advertised as setting errno. 337 ** In fact, under FreeBSD, non-root getpwnam() on 338 ** non-existant users returns NULL with errno = EPERM. 339 ** This test won't work. 340 */ 341 switch (errno) 342 { 343 case 0: 344 return EX_NOUSER; 345 case EIO: 346 return EX_OSERR; 347 default: 348 return EX_TEMPFAIL; 349 } 350 #endif /* 0 */ 351 return EX_NOUSER; 352 } 353 354 sm_mbdb_frompw(user, pw); 355 return EX_OK; 356 } 357 358 /* 359 ** MBDB_PW_TERMINATE -- terminate connection to the mailbox database 360 ** 361 ** Parameters: 362 ** none. 363 ** 364 ** Results: 365 ** none. 366 */ 367 368 static void 369 mbdb_pw_terminate() 370 { 371 endpwent(); 372 } 373 374 #if LDAPMAP 375 # if _LDAP_EXAMPLE_ 376 /* 377 ** LDAP example implementation based on RFC 2307, "An Approach for Using 378 ** LDAP as a Network Information Service": 379 ** 380 ** ( nisSchema.1.0 NAME 'uidNumber' 381 ** DESC 'An integer uniquely identifying a user in an 382 ** administrative domain' 383 ** EQUALITY integerMatch SYNTAX 'INTEGER' SINGLE-VALUE ) 384 ** 385 ** ( nisSchema.1.1 NAME 'gidNumber' 386 ** DESC 'An integer uniquely identifying a group in an 387 ** administrative domain' 388 ** EQUALITY integerMatch SYNTAX 'INTEGER' SINGLE-VALUE ) 389 ** 390 ** ( nisSchema.1.2 NAME 'gecos' 391 ** DESC 'The GECOS field; the common name' 392 ** EQUALITY caseIgnoreIA5Match 393 ** SUBSTRINGS caseIgnoreIA5SubstringsMatch 394 ** SYNTAX 'IA5String' SINGLE-VALUE ) 395 ** 396 ** ( nisSchema.1.3 NAME 'homeDirectory' 397 ** DESC 'The absolute path to the home directory' 398 ** EQUALITY caseExactIA5Match 399 ** SYNTAX 'IA5String' SINGLE-VALUE ) 400 ** 401 ** ( nisSchema.1.4 NAME 'loginShell' 402 ** DESC 'The path to the login shell' 403 ** EQUALITY caseExactIA5Match 404 ** SYNTAX 'IA5String' SINGLE-VALUE ) 405 ** 406 ** ( nisSchema.2.0 NAME 'posixAccount' SUP top AUXILIARY 407 ** DESC 'Abstraction of an account with POSIX attributes' 408 ** MUST ( cn $ uid $ uidNumber $ gidNumber $ homeDirectory ) 409 ** MAY ( userPassword $ loginShell $ gecos $ description ) ) 410 ** 411 */ 412 413 # define MBDB_LDAP_LABEL "MailboxDatabase" 414 415 # ifndef MBDB_LDAP_FILTER 416 # define MBDB_LDAP_FILTER "(&(objectClass=posixAccount)(uid=%0))" 417 # endif /* MBDB_LDAP_FILTER */ 418 419 # ifndef MBDB_DEFAULT_LDAP_BASEDN 420 # define MBDB_DEFAULT_LDAP_BASEDN NULL 421 # endif /* MBDB_DEFAULT_LDAP_BASEDN */ 422 423 # ifndef MBDB_DEFAULT_LDAP_SERVER 424 # define MBDB_DEFAULT_LDAP_SERVER NULL 425 # endif /* MBDB_DEFAULT_LDAP_SERVER */ 426 427 /* 428 ** MBDB_LDAP_INITIALIZE -- initialize LDAP version 429 ** 430 ** Parameters: 431 ** arg -- LDAP specification 432 ** 433 ** Results: 434 ** EX_OK on success, or an EX_* code on failure. 435 */ 436 437 static int 438 mbdb_ldap_initialize(arg) 439 char *arg; 440 { 441 sm_ldap_clear(&LDAPLMAP); 442 LDAPLMAP.ldap_base = MBDB_DEFAULT_LDAP_BASEDN; 443 LDAPLMAP.ldap_target = MBDB_DEFAULT_LDAP_SERVER; 444 LDAPLMAP.ldap_filter = MBDB_LDAP_FILTER; 445 446 /* Only want one match */ 447 LDAPLMAP.ldap_sizelimit = 1; 448 449 /* interpolate new ldap_base and ldap_target from arg if given */ 450 if (arg != NULL && *arg != '\0') 451 { 452 char *new; 453 char *sep; 454 size_t len; 455 456 len = strlen(arg) + 1; 457 new = sm_malloc(len); 458 if (new == NULL) 459 return EX_TEMPFAIL; 460 (void) sm_strlcpy(new, arg, len); 461 sep = strrchr(new, '@'); 462 if (sep != NULL) 463 { 464 *sep++ = '\0'; 465 LDAPLMAP.ldap_target = sep; 466 } 467 LDAPLMAP.ldap_base = new; 468 } 469 470 /* No connection yet, connect */ 471 if (!sm_ldap_start(MBDB_LDAP_LABEL, &LDAPLMAP)) 472 return EX_UNAVAILABLE; 473 return EX_OK; 474 } 475 476 477 /* 478 ** MBDB_LDAP_LOOKUP -- look up a local mail recipient, given name 479 ** 480 ** Parameters: 481 ** name -- name of local mail recipient 482 ** user -- pointer to structure to fill in on success 483 ** 484 ** Results: 485 ** On success, fill in *user and return EX_OK. 486 ** Failure: EX_NOUSER. 487 */ 488 489 #define NEED_FULLNAME 0x01 490 #define NEED_HOMEDIR 0x02 491 #define NEED_SHELL 0x04 492 #define NEED_UID 0x08 493 #define NEED_GID 0x10 494 495 static int 496 mbdb_ldap_lookup(name, user) 497 char *name; 498 SM_MBDB_T *user; 499 { 500 int msgid; 501 int need; 502 int ret; 503 int save_errno; 504 LDAPMessage *entry; 505 BerElement *ber; 506 char *attr = NULL; 507 508 if (strlen(name) >= sizeof(user->mbdb_name)) 509 { 510 errno = EINVAL; 511 return EX_NOUSER; 512 } 513 514 if (LDAPLMAP.ldap_filter == NULL) 515 { 516 /* map not initialized, but don't have arg here */ 517 errno = EFAULT; 518 return EX_TEMPFAIL; 519 } 520 521 if (LDAPLMAP.ldap_ld == NULL) 522 { 523 /* map not open, try to open now */ 524 if (!sm_ldap_start(MBDB_LDAP_LABEL, &LDAPLMAP)) 525 return EX_TEMPFAIL; 526 } 527 528 sm_ldap_setopts(LDAPLMAP.ldap_ld, &LDAPLMAP); 529 msgid = sm_ldap_search(&LDAPLMAP, name); 530 if (msgid == -1) 531 { 532 save_errno = sm_ldap_geterrno(LDAPLMAP.ldap_ld) + E_LDAPBASE; 533 # ifdef LDAP_SERVER_DOWN 534 if (errno == LDAP_SERVER_DOWN) 535 { 536 /* server disappeared, try reopen on next search */ 537 sm_ldap_close(&LDAPLMAP); 538 } 539 # endif /* LDAP_SERVER_DOWN */ 540 errno = save_errno; 541 return EX_TEMPFAIL; 542 } 543 544 /* Get results */ 545 ret = ldap_result(LDAPLMAP.ldap_ld, msgid, 1, 546 (LDAPLMAP.ldap_timeout.tv_sec == 0 ? NULL : 547 &(LDAPLMAP.ldap_timeout)), 548 &(LDAPLMAP.ldap_res)); 549 550 if (ret != LDAP_RES_SEARCH_RESULT && 551 ret != LDAP_RES_SEARCH_ENTRY) 552 { 553 if (ret == 0) 554 errno = ETIMEDOUT; 555 else 556 errno = sm_ldap_geterrno(LDAPLMAP.ldap_ld); 557 ret = EX_TEMPFAIL; 558 goto abort; 559 } 560 561 entry = ldap_first_entry(LDAPLMAP.ldap_ld, LDAPLMAP.ldap_res); 562 if (entry == NULL) 563 { 564 save_errno = sm_ldap_geterrno(LDAPLMAP.ldap_ld); 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 /* _LDAP_EXAMPLE_ */ 771 #endif /* LDAPMAP */ 772