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
sm_mbdb_initialize(mbdb)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
sm_mbdb_terminate()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
sm_mbdb_lookup(name,user)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
sm_mbdb_frompw(user,pw)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
sm_pwfullname(gecos,user,buf,buflen)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
mbdb_pw_initialize(arg)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
mbdb_pw_lookup(name,user)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
mbdb_pw_terminate()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
mbdb_ldap_initialize(arg)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
mbdb_ldap_lookup(name,user)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
mbdb_ldap_terminate()766 mbdb_ldap_terminate()
767 {
768 sm_ldap_close(&LDAPLMAP);
769 }
770 #endif /* LDAPMAP && _LDAP_EXAMPLE_ */
771