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