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