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