map.c
上传用户:xu_441
上传日期:2007-01-04
资源大小:1640k
文件大小:144k
源码类别:

Email客户端

开发平台:

Unix_Linux

  1. /*
  2.  * Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
  3.  * All rights reserved.
  4.  * Copyright (c) 1992, 1995-1997 Eric P. Allman.  All rights reserved.
  5.  * Copyright (c) 1992, 1993
  6.  * The Regents of the University of California.  All rights reserved.
  7.  *
  8.  * By using this file, you agree to the terms and conditions set
  9.  * forth in the LICENSE file which can be found at the top level of
  10.  * the sendmail distribution.
  11.  *
  12.  */
  13. #ifndef lint
  14. static char id[] = "@(#)$Id: map.c,v 8.398 1999/12/09 19:06:59 gshapiro Exp $";
  15. #endif /* ! lint */
  16. #include <sendmail.h>
  17. #ifdef NDBM
  18. # include <ndbm.h>
  19. # ifdef R_FIRST
  20.   ERROR README: You are running the Berkeley DB version of ndbm.h.  See
  21.   ERROR README: the README file about tweaking Berkeley DB so it can
  22.   ERROR README: coexist with NDBM, or delete -DNDBM from the Makefile
  23.   ERROR README: and use -DNEWDB instead.
  24. # endif /* R_FIRST */
  25. #endif /* NDBM */
  26. #ifdef NEWDB
  27. # include <db.h>
  28. # ifndef DB_VERSION_MAJOR
  29. #  define DB_VERSION_MAJOR 1
  30. # endif /* ! DB_VERSION_MAJOR */
  31. #endif /* NEWDB */
  32. #ifdef NIS
  33.   struct dom_binding; /* forward reference needed on IRIX */
  34. # include <rpcsvc/ypclnt.h>
  35. # ifdef NDBM
  36. #  define NDBM_YP_COMPAT /* create YP-compatible NDBM files */
  37. # endif /* NDBM */
  38. #endif /* NIS */
  39. #ifdef NEWDB
  40. # if DB_VERSION_MAJOR < 2
  41. static bool db_map_open __P((MAP *, int, char *, DBTYPE, const void *));
  42. # endif /* DB_VERSION_MAJOR < 2 */
  43. # if DB_VERSION_MAJOR == 2
  44. static bool db_map_open __P((MAP *, int, char *, DBTYPE, DB_INFO *));
  45. # endif /* DB_VERSION_MAJOR == 2 */
  46. # if DB_VERSION_MAJOR > 2
  47. static bool db_map_open __P((MAP *, int, char *, DBTYPE, void **));
  48. # endif /* DB_VERSION_MAJOR > 2 */
  49. #endif /* NEWDB */
  50. static bool extract_canonname __P((char *, char *, char[], int));
  51. #ifdef LDAPMAP
  52. static void ldapmap_clear __P((LDAPMAP_STRUCT *));
  53. static STAB *ldapmap_findconn __P((LDAPMAP_STRUCT *));
  54. static int ldapmap_geterrno __P((LDAP *));
  55. static void ldapmap_setopts __P((LDAP *, LDAPMAP_STRUCT *));
  56. static bool ldapmap_start __P((MAP *));
  57. static void ldaptimeout __P((int));
  58. #endif /* LDAPMAP */
  59. static void map_close __P((STAB *, int));
  60. static void map_init __P((STAB *, int));
  61. #ifdef NISPLUS
  62. static bool nisplus_getcanonname __P((char *, int, int *));
  63. #endif /* NISPLUS */
  64. #ifdef NIS
  65. static bool nis_getcanonname __P((char *, int, int *));
  66. #endif /* NIS */
  67. #if NETINFO
  68. static bool ni_getcanonname __P((char *, int, int *));
  69. #endif /* NETINFO */
  70. static bool text_getcanonname __P((char *, int, int *));
  71. /*
  72. **  MAP.C -- implementations for various map classes.
  73. **
  74. ** Each map class implements a series of functions:
  75. **
  76. ** bool map_parse(MAP *map, char *args)
  77. ** Parse the arguments from the config file.  Return TRUE
  78. ** if they were ok, FALSE otherwise.  Fill in map with the
  79. ** values.
  80. **
  81. ** char *map_lookup(MAP *map, char *key, char **args, int *pstat)
  82. ** Look up the key in the given map.  If found, do any
  83. ** rewriting the map wants (including "args" if desired)
  84. ** and return the value.  Set *pstat to the appropriate status
  85. ** on error and return NULL.  Args will be NULL if called
  86. ** from the alias routines, although this should probably
  87. ** not be relied upon.  It is suggested you call map_rewrite
  88. ** to return the results -- it takes care of null termination
  89. ** and uses a dynamically expanded buffer as needed.
  90. **
  91. ** void map_store(MAP *map, char *key, char *value)
  92. ** Store the key:value pair in the map.
  93. **
  94. ** bool map_open(MAP *map, int mode)
  95. ** Open the map for the indicated mode.  Mode should
  96. ** be either O_RDONLY or O_RDWR.  Return TRUE if it
  97. ** was opened successfully, FALSE otherwise.  If the open
  98. ** failed an the MF_OPTIONAL flag is not set, it should
  99. ** also print an error.  If the MF_ALIAS bit is set
  100. ** and this map class understands the @:@ convention, it
  101. ** should call aliaswait() before returning.
  102. **
  103. ** void map_close(MAP *map)
  104. ** Close the map.
  105. **
  106. ** This file also includes the implementation for getcanonname.
  107. ** It is currently implemented in a pretty ad-hoc manner; it ought
  108. ** to be more properly integrated into the map structure.
  109. */
  110. #define DBMMODE 0644
  111. #ifndef EX_NOTFOUND
  112. # define EX_NOTFOUND EX_NOHOST
  113. #endif /* ! EX_NOTFOUND */
  114. #if O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL
  115. # define LOCK_ON_OPEN 1 /* we can open/create a locked file */
  116. #else /* O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL */
  117. # define LOCK_ON_OPEN 0 /* no such luck -- bend over backwards */
  118. #endif /* O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL */
  119. #ifndef O_ACCMODE
  120. # define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR)
  121. #endif /* ! O_ACCMODE */
  122. /*
  123. **  MAP_PARSEARGS -- parse config line arguments for database lookup
  124. **
  125. ** This is a generic version of the map_parse method.
  126. **
  127. ** Parameters:
  128. ** map -- the map being initialized.
  129. ** ap -- a pointer to the args on the config line.
  130. **
  131. ** Returns:
  132. ** TRUE -- if everything parsed OK.
  133. ** FALSE -- otherwise.
  134. **
  135. ** Side Effects:
  136. ** null terminates the filename; stores it in map
  137. */
  138. bool
  139. map_parseargs(map, ap)
  140. MAP *map;
  141. char *ap;
  142. {
  143. register char *p = ap;
  144. /*
  145. **  there is no check whether there is really an argument,
  146. **  but that's not important enough to warrant extra code
  147. */
  148. map->map_mflags |= MF_TRY0NULL | MF_TRY1NULL;
  149. map->map_spacesub = SpaceSub; /* default value */
  150. for (;;)
  151. {
  152. while (isascii(*p) && isspace(*p))
  153. p++;
  154. if (*p != '-')
  155. break;
  156. switch (*++p)
  157. {
  158.   case 'N':
  159. map->map_mflags |= MF_INCLNULL;
  160. map->map_mflags &= ~MF_TRY0NULL;
  161. break;
  162.   case 'O':
  163. map->map_mflags &= ~MF_TRY1NULL;
  164. break;
  165.   case 'o':
  166. map->map_mflags |= MF_OPTIONAL;
  167. break;
  168.   case 'f':
  169. map->map_mflags |= MF_NOFOLDCASE;
  170. break;
  171.   case 'm':
  172. map->map_mflags |= MF_MATCHONLY;
  173. break;
  174.   case 'A':
  175. map->map_mflags |= MF_APPEND;
  176. break;
  177.   case 'q':
  178. map->map_mflags |= MF_KEEPQUOTES;
  179. break;
  180.   case 'a':
  181. map->map_app = ++p;
  182. break;
  183.   case 'T':
  184. map->map_tapp = ++p;
  185. break;
  186.   case 'k':
  187. while (isascii(*++p) && isspace(*p))
  188. continue;
  189. map->map_keycolnm = p;
  190. break;
  191.   case 'v':
  192. while (isascii(*++p) && isspace(*p))
  193. continue;
  194. map->map_valcolnm = p;
  195. break;
  196.   case 'z':
  197. if (*++p != '\')
  198. map->map_coldelim = *p;
  199. else
  200. {
  201. switch (*++p)
  202. {
  203.   case 'n':
  204. map->map_coldelim = 'n';
  205. break;
  206.   case 't':
  207. map->map_coldelim = 't';
  208. break;
  209.   default:
  210. map->map_coldelim = '\';
  211. }
  212. }
  213. break;
  214.   case 't':
  215. map->map_mflags |= MF_NODEFER;
  216. break;
  217.   case 'S':
  218. map->map_spacesub = *++p;
  219. break;
  220.   case 'D':
  221. map->map_mflags |= MF_DEFER;
  222. break;
  223.   default:
  224. syserr("Illegal option %c map %s", *p, map->map_mname);
  225. break;
  226. }
  227. while (*p != '' && !(isascii(*p) && isspace(*p)))
  228. p++;
  229. if (*p != '')
  230. *p++ = '';
  231. }
  232. if (map->map_app != NULL)
  233. map->map_app = newstr(map->map_app);
  234. if (map->map_tapp != NULL)
  235. map->map_tapp = newstr(map->map_tapp);
  236. if (map->map_keycolnm != NULL)
  237. map->map_keycolnm = newstr(map->map_keycolnm);
  238. if (map->map_valcolnm != NULL)
  239. map->map_valcolnm = newstr(map->map_valcolnm);
  240. if (*p != '')
  241. {
  242. map->map_file = p;
  243. while (*p != '' && !(isascii(*p) && isspace(*p)))
  244. p++;
  245. if (*p != '')
  246. *p++ = '';
  247. map->map_file = newstr(map->map_file);
  248. }
  249. while (*p != '' && isascii(*p) && isspace(*p))
  250. p++;
  251. if (*p != '')
  252. map->map_rebuild = newstr(p);
  253. if (map->map_file == NULL &&
  254.     !bitset(MCF_OPTFILE, map->map_class->map_cflags))
  255. {
  256. syserr("No file name for %s map %s",
  257. map->map_class->map_cname, map->map_mname);
  258. return FALSE;
  259. }
  260. return TRUE;
  261. }
  262. /*
  263. **  MAP_REWRITE -- rewrite a database key, interpolating %n indications.
  264. **
  265. ** It also adds the map_app string.  It can be used as a utility
  266. ** in the map_lookup method.
  267. **
  268. ** Parameters:
  269. ** map -- the map that causes this.
  270. ** s -- the string to rewrite, NOT necessarily null terminated.
  271. ** slen -- the length of s.
  272. ** av -- arguments to interpolate into buf.
  273. **
  274. ** Returns:
  275. ** Pointer to rewritten result.  This is static data that
  276. ** should be copied if it is to be saved!
  277. **
  278. ** Side Effects:
  279. ** none.
  280. */
  281. char *
  282. map_rewrite(map, s, slen, av)
  283. register MAP *map;
  284. register const char *s;
  285. size_t slen;
  286. char **av;
  287. {
  288. register char *bp;
  289. register char c;
  290. char **avp;
  291. register char *ap;
  292. size_t l;
  293. size_t len;
  294. static size_t buflen = 0;
  295. static char *buf = NULL;
  296. if (tTd(39, 1))
  297. {
  298. dprintf("map_rewrite(%.*s), av =", (int)slen, s);
  299. if (av == NULL)
  300. dprintf(" (nullv)");
  301. else
  302. {
  303. for (avp = av; *avp != NULL; avp++)
  304. dprintf("nt%s", *avp);
  305. }
  306. dprintf("n");
  307. }
  308. /* count expected size of output (can safely overestimate) */
  309. l = len = slen;
  310. if (av != NULL)
  311. {
  312. const char *sp = s;
  313. while (l-- > 0 && (c = *sp++) != '')
  314. {
  315. if (c != '%')
  316. continue;
  317. if (l-- <= 0)
  318. break;
  319. c = *sp++;
  320. if (!(isascii(c) && isdigit(c)))
  321. continue;
  322. for (avp = av; --c >= '0' && *avp != NULL; avp++)
  323. continue;
  324. if (*avp == NULL)
  325. continue;
  326. len += strlen(*avp);
  327. }
  328. }
  329. if (map->map_app != NULL)
  330. len += strlen(map->map_app);
  331. if (buflen < ++len)
  332. {
  333. /* need to malloc additional space */
  334. buflen = len;
  335. if (buf != NULL)
  336. free(buf);
  337. buf = xalloc(buflen);
  338. }
  339. bp = buf;
  340. if (av == NULL)
  341. {
  342. memmove(bp, s, slen);
  343. bp += slen;
  344. /* assert(len > slen); */
  345. len -= slen;
  346. }
  347. else
  348. {
  349. while (slen-- > 0 && (c = *s++) != '')
  350. {
  351. if (c != '%')
  352. {
  353.   pushc:
  354.         if (--len <= 0)
  355.      break;
  356. *bp++ = c;
  357. continue;
  358. }
  359. if (slen-- <= 0 || (c = *s++) == '')
  360. c = '%';
  361. if (c == '%')
  362. goto pushc;
  363. if (!(isascii(c) && isdigit(c)))
  364. {
  365. *bp++ = '%';
  366. --len;
  367. goto pushc;
  368. }
  369. for (avp = av; --c >= '0' && *avp != NULL; avp++)
  370. continue;
  371. if (*avp == NULL)
  372. continue;
  373. /* transliterate argument into output string */
  374. for (ap = *avp; (c = *ap++) != '' && len > 0; --len)
  375. *bp++ = c;
  376. }
  377. }
  378. if (map->map_app != NULL && len > 0)
  379. (void) strlcpy(bp, map->map_app, len);
  380. else
  381. *bp = '';
  382. if (tTd(39, 1))
  383. dprintf("map_rewrite => %sn", buf);
  384. return buf;
  385. }
  386. /*
  387. **  INITMAPS -- rebuild alias maps
  388. **
  389. ** Parameters:
  390. ** none.
  391. **
  392. ** Returns:
  393. ** none.
  394. */
  395. void
  396. initmaps()
  397. {
  398. #if XDEBUG
  399. checkfd012("entering initmaps");
  400. #endif /* XDEBUG */
  401. stabapply(map_init, 0);
  402. #if XDEBUG
  403. checkfd012("exiting initmaps");
  404. #endif /* XDEBUG */
  405. }
  406. /*
  407. **  MAP_INIT -- rebuild a map
  408. **
  409. ** Parameters:
  410. ** s -- STAB entry: if map: try to rebuild
  411. ** unused -- unused variable
  412. **
  413. ** Returns:
  414. ** none.
  415. **
  416. ** Side Effects:
  417. ** will close already open rebuildable map.
  418. */
  419. /* ARGSUSED1 */
  420. static void
  421. map_init(s, unused)
  422. register STAB *s;
  423. int unused;
  424. {
  425. register MAP *map;
  426. /* has to be a map */
  427. if (s->s_type != ST_MAP)
  428. return;
  429. map = &s->s_map;
  430. if (!bitset(MF_VALID, map->map_mflags))
  431. return;
  432. if (tTd(38, 2))
  433. dprintf("map_init(%s:%s, %s)n",
  434. map->map_class->map_cname == NULL ? "NULL" :
  435. map->map_class->map_cname,
  436. map->map_mname == NULL ? "NULL" : map->map_mname,
  437. map->map_file == NULL ? "NULL" : map->map_file);
  438. if (!bitset(MF_ALIAS, map->map_mflags) ||
  439.     !bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
  440. {
  441. if (tTd(38, 3))
  442. dprintf("tnot rebuildablen");
  443. return;
  444. }
  445. /* if already open, close it (for nested open) */
  446. if (bitset(MF_OPEN, map->map_mflags))
  447. {
  448. map->map_class->map_close(map);
  449. map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
  450. }
  451. (void) rebuildaliases(map, FALSE);
  452. return;
  453. }
  454. /*
  455. **  OPENMAP -- open a map
  456. **
  457. ** Parameters:
  458. ** map -- map to open (it must not be open).
  459. **
  460. ** Returns:
  461. ** whether open succeeded.
  462. **
  463. */
  464. bool
  465. openmap(map)
  466. MAP *map;
  467. {
  468. bool restore = FALSE;
  469. bool savehold = HoldErrs;
  470. bool savequick = QuickAbort;
  471. int saveerrors = Errors;
  472. if (!bitset(MF_VALID, map->map_mflags))
  473. return FALSE;
  474. /* better safe than sorry... */
  475. if (bitset(MF_OPEN, map->map_mflags))
  476. return TRUE;
  477. /* Don't send a map open error out via SMTP */
  478. if ((OnlyOneError || QuickAbort) &&
  479.     (OpMode == MD_SMTP || OpMode == MD_DAEMON))
  480. {
  481. restore = TRUE;
  482. HoldErrs = TRUE;
  483. QuickAbort = FALSE;
  484. }
  485. errno = 0;
  486. if (map->map_class->map_open(map, O_RDONLY))
  487. {
  488. if (tTd(38, 4))
  489. dprintf("openmap()t%s:%s %s: validn",
  490. map->map_class->map_cname == NULL ? "NULL" :
  491. map->map_class->map_cname,
  492. map->map_mname == NULL ? "NULL" :
  493. map->map_mname,
  494. map->map_file == NULL ? "NULL" :
  495. map->map_file);
  496. map->map_mflags |= MF_OPEN;
  497. map->map_pid = getpid();
  498. }
  499. else
  500. {
  501. if (tTd(38, 4))
  502. dprintf("openmap()t%s:%s %s: invalid%s%sn",
  503. map->map_class->map_cname == NULL ? "NULL" :
  504. map->map_class->map_cname,
  505. map->map_mname == NULL ? "NULL" :
  506. map->map_mname,
  507. map->map_file == NULL ? "NULL" :
  508. map->map_file,
  509. errno == 0 ? "" : ": ",
  510. errno == 0 ? "" : errstring(errno));
  511. if (!bitset(MF_OPTIONAL, map->map_mflags))
  512. {
  513. extern MAPCLASS BogusMapClass;
  514. map->map_class = &BogusMapClass;
  515. map->map_mflags |= MF_OPEN;
  516. map->map_pid = getpid();
  517. }
  518. else
  519. {
  520. /* don't try again */
  521. map->map_mflags &= ~MF_VALID;
  522. }
  523. }
  524. if (restore)
  525. {
  526. Errors = saveerrors;
  527. HoldErrs = savehold;
  528. QuickAbort = savequick;
  529. }
  530. return bitset(MF_OPEN, map->map_mflags);
  531. }
  532. /*
  533. **  CLOSEMAPS -- close all open maps opened by the current pid.
  534. **
  535. ** Parameters:
  536. ** none
  537. **
  538. ** Returns:
  539. ** none.
  540. */
  541. void
  542. closemaps()
  543. {
  544. stabapply(map_close, 0);
  545. }
  546. /*
  547. **  MAP_CLOSE -- close a map opened by the current pid.
  548. **
  549. ** Parameters:
  550. ** s -- STAB entry: if map: try to open
  551. ** second parameter is unused (required by stabapply())
  552. **
  553. ** Returns:
  554. ** none.
  555. */
  556. /* ARGSUSED1 */
  557. static void
  558. map_close(s, unused)
  559. register STAB *s;
  560. int unused;
  561. {
  562. MAP *map;
  563. if (s->s_type != ST_MAP)
  564. return;
  565. map = &s->s_map;
  566. if (!bitset(MF_VALID, map->map_mflags) ||
  567.     !bitset(MF_OPEN, map->map_mflags) ||
  568.     map->map_pid != getpid())
  569. return;
  570. if (tTd(38, 5))
  571. dprintf("closemaps: closing %s (%s)n",
  572. map->map_mname == NULL ? "NULL" : map->map_mname,
  573. map->map_file == NULL ? "NULL" : map->map_file);
  574. map->map_class->map_close(map);
  575. map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
  576. }
  577. /*
  578. **  GETCANONNAME -- look up name using service switch
  579. **
  580. ** Parameters:
  581. ** host -- the host name to look up.
  582. ** hbsize -- the size of the host buffer.
  583. ** trymx -- if set, try MX records.
  584. **
  585. ** Returns:
  586. ** TRUE -- if the host was found.
  587. ** FALSE -- otherwise.
  588. */
  589. bool
  590. getcanonname(host, hbsize, trymx)
  591. char *host;
  592. int hbsize;
  593. bool trymx;
  594. {
  595. int nmaps;
  596. int mapno;
  597. bool found = FALSE;
  598. bool got_tempfail = FALSE;
  599. auto int status;
  600. char *maptype[MAXMAPSTACK];
  601. short mapreturn[MAXMAPACTIONS];
  602. nmaps = switch_map_find("hosts", maptype, mapreturn);
  603. for (mapno = 0; mapno < nmaps; mapno++)
  604. {
  605. int i;
  606. if (tTd(38, 20))
  607. dprintf("getcanonname(%s), trying %sn",
  608. host, maptype[mapno]);
  609. if (strcmp("files", maptype[mapno]) == 0)
  610. {
  611. found = text_getcanonname(host, hbsize, &status);
  612. }
  613. #ifdef NIS
  614. else if (strcmp("nis", maptype[mapno]) == 0)
  615. {
  616. found = nis_getcanonname(host, hbsize, &status);
  617. }
  618. #endif /* NIS */
  619. #ifdef NISPLUS
  620. else if (strcmp("nisplus", maptype[mapno]) == 0)
  621. {
  622. found = nisplus_getcanonname(host, hbsize, &status);
  623. }
  624. #endif /* NISPLUS */
  625. #if NAMED_BIND
  626. else if (strcmp("dns", maptype[mapno]) == 0)
  627. {
  628. found = dns_getcanonname(host, hbsize, trymx, &status);
  629. }
  630. #endif /* NAMED_BIND */
  631. #if NETINFO
  632. else if (strcmp("netinfo", maptype[mapno]) == 0)
  633. {
  634. found = ni_getcanonname(host, hbsize, &status);
  635. }
  636. #endif /* NETINFO */
  637. else
  638. {
  639. found = FALSE;
  640. status = EX_UNAVAILABLE;
  641. }
  642. /*
  643. **  Heuristic: if $m is not set, we are running during system
  644. **  startup.  In this case, when a name is apparently found
  645. **  but has no dot, treat is as not found.  This avoids
  646. **  problems if /etc/hosts has no FQDN but is listed first
  647. **  in the service switch.
  648. */
  649. if (found &&
  650.     (macvalue('m', CurEnv) != NULL || strchr(host, '.') != NULL))
  651. break;
  652. /* see if we should continue */
  653. if (status == EX_TEMPFAIL)
  654. {
  655. i = MA_TRYAGAIN;
  656. got_tempfail = TRUE;
  657. }
  658. else if (status == EX_NOTFOUND)
  659. i = MA_NOTFOUND;
  660. else
  661. i = MA_UNAVAIL;
  662. if (bitset(1 << mapno, mapreturn[i]))
  663. break;
  664. }
  665. if (found)
  666. {
  667. char *d;
  668. if (tTd(38, 20))
  669. dprintf("getcanonname(%s), foundn", host);
  670. /*
  671. **  If returned name is still single token, compensate
  672. **  by tagging on $m.  This is because some sites set
  673. **  up their DNS or NIS databases wrong.
  674. */
  675. if ((d = strchr(host, '.')) == NULL || d[1] == '')
  676. {
  677. d = macvalue('m', CurEnv);
  678. if (d != NULL &&
  679.     hbsize > (int) (strlen(host) + strlen(d) + 1))
  680. {
  681. if (host[strlen(host) - 1] != '.')
  682. (void) strlcat(host, ".", hbsize);
  683. (void) strlcat(host, d, hbsize);
  684. }
  685. else
  686. return FALSE;
  687. }
  688. return TRUE;
  689. }
  690. if (tTd(38, 20))
  691. dprintf("getcanonname(%s), failed, status=%dn", host, status);
  692. #if NAMED_BIND
  693. if (got_tempfail)
  694. h_errno = TRY_AGAIN;
  695. else
  696. h_errno = HOST_NOT_FOUND;
  697. #endif /* NAMED_BIND */
  698. return FALSE;
  699. }
  700. /*
  701. **  EXTRACT_CANONNAME -- extract canonical name from /etc/hosts entry
  702. **
  703. ** Parameters:
  704. ** name -- the name against which to match.
  705. ** line -- the /etc/hosts line.
  706. ** cbuf -- the location to store the result.
  707. ** cbuflen -- the size of cbuf.
  708. **
  709. ** Returns:
  710. ** TRUE -- if the line matched the desired name.
  711. ** FALSE -- otherwise.
  712. */
  713. static bool
  714. extract_canonname(name, line, cbuf, cbuflen)
  715. char *name;
  716. char *line;
  717. char cbuf[];
  718. int cbuflen;
  719. {
  720. int i;
  721. char *p;
  722. bool found = FALSE;
  723. cbuf[0] = '';
  724. if (line[0] == '#')
  725. return FALSE;
  726. for (i = 1; ; i++)
  727. {
  728. char nbuf[MAXNAME + 1];
  729. p = get_column(line, i, '', nbuf, sizeof nbuf);
  730. if (p == NULL)
  731. break;
  732. if (*p == '')
  733. continue;
  734. if (cbuf[0] == '' ||
  735.     (strchr(cbuf, '.') == NULL && strchr(p, '.') != NULL))
  736. {
  737. snprintf(cbuf, cbuflen, "%s", p);
  738. }
  739. if (strcasecmp(name, p) == 0)
  740. found = TRUE;
  741. }
  742. if (found && strchr(cbuf, '.') == NULL)
  743. {
  744. /* try to add a domain on the end of the name */
  745. char *domain = macvalue('m', CurEnv);
  746. if (domain != NULL &&
  747.     strlen(domain) + (i = strlen(cbuf)) + 1 < cbuflen)
  748. {
  749. p = &cbuf[i];
  750. *p++ = '.';
  751. (void) strlcpy(p, domain, cbuflen - i - 1);
  752. }
  753. }
  754. return found;
  755. }
  756. /*
  757. **  NDBM modules
  758. */
  759. #ifdef NDBM
  760. /*
  761. **  NDBM_MAP_OPEN -- DBM-style map open
  762. */
  763. bool
  764. ndbm_map_open(map, mode)
  765. MAP *map;
  766. int mode;
  767. {
  768. register DBM *dbm;
  769. int save_errno;
  770. int dfd;
  771. int pfd;
  772. long sff;
  773. int ret;
  774. int smode = S_IREAD;
  775. char dirfile[MAXNAME + 1];
  776. char pagfile[MAXNAME + 1];
  777. struct stat st;
  778. struct stat std, stp;
  779. if (tTd(38, 2))
  780. dprintf("ndbm_map_open(%s, %s, %d)n",
  781. map->map_mname, map->map_file, mode);
  782. map->map_lockfd = -1;
  783. mode &= O_ACCMODE;
  784. /* do initial file and directory checks */
  785. snprintf(dirfile, sizeof dirfile, "%s.dir", map->map_file);
  786. snprintf(pagfile, sizeof pagfile, "%s.pag", map->map_file);
  787. sff = SFF_ROOTOK|SFF_REGONLY;
  788. if (mode == O_RDWR)
  789. {
  790. sff |= SFF_CREAT;
  791. if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
  792. sff |= SFF_NOSLINK;
  793. if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
  794. sff |= SFF_NOHLINK;
  795. smode = S_IWRITE;
  796. }
  797. else
  798. {
  799. if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
  800. sff |= SFF_NOWLINK;
  801. }
  802. if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
  803. sff |= SFF_SAFEDIRPATH;
  804. ret = safefile(dirfile, RunAsUid, RunAsGid, RunAsUserName,
  805.     sff, smode, &std);
  806. if (ret == 0)
  807. ret = safefile(pagfile, RunAsUid, RunAsGid, RunAsUserName,
  808.        sff, smode, &stp);
  809. # if !_FFR_REMOVE_AUTOREBUILD
  810. if (ret == ENOENT && AutoRebuild &&
  811.     bitset(MCF_REBUILDABLE, map->map_class->map_cflags) &&
  812.     (bitset(MF_IMPL_NDBM, map->map_mflags) ||
  813.      bitset(MF_ALIAS, map->map_mflags)) &&
  814.     mode == O_RDONLY)
  815. {
  816. bool impl = bitset(MF_IMPL_NDBM, map->map_mflags);
  817. /* may be able to rebuild */
  818. map->map_mflags &= ~MF_IMPL_NDBM;
  819. if (!rebuildaliases(map, TRUE))
  820. return FALSE;
  821. if (impl)
  822. return impl_map_open(map, O_RDONLY);
  823. else
  824. return ndbm_map_open(map, O_RDONLY);
  825. }
  826. # endif /* !_FFR_REMOVE_AUTOREBUILD */
  827. if (ret != 0)
  828. {
  829. char *prob = "unsafe";
  830. /* cannot open this map */
  831. if (ret == ENOENT)
  832. prob = "missing";
  833. if (tTd(38, 2))
  834. dprintf("t%s map file: %dn", prob, ret);
  835. if (!bitset(MF_OPTIONAL, map->map_mflags))
  836. syserr("dbm map "%s": %s map file %s",
  837. map->map_mname, prob, map->map_file);
  838. return FALSE;
  839. }
  840. if (std.st_mode == ST_MODE_NOFILE)
  841. mode |= O_CREAT|O_EXCL;
  842. # if LOCK_ON_OPEN
  843. if (mode == O_RDONLY)
  844. mode |= O_SHLOCK;
  845. else
  846. mode |= O_TRUNC|O_EXLOCK;
  847. # else /* LOCK_ON_OPEN */
  848. if ((mode & O_ACCMODE) == O_RDWR)
  849. {
  850. #  if NOFTRUNCATE
  851. /*
  852. **  Warning: race condition.  Try to lock the file as
  853. **  quickly as possible after opening it.
  854. ** This may also have security problems on some systems,
  855. ** but there isn't anything we can do about it.
  856. */
  857. mode |= O_TRUNC;
  858. #  else /* NOFTRUNCATE */
  859. /*
  860. **  This ugly code opens the map without truncating it,
  861. **  locks the file, then truncates it.  Necessary to
  862. **  avoid race conditions.
  863. */
  864. int dirfd;
  865. int pagfd;
  866. long sff = SFF_CREAT|SFF_OPENASROOT;
  867. if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
  868. sff |= SFF_NOSLINK;
  869. if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
  870. sff |= SFF_NOHLINK;
  871. dirfd = safeopen(dirfile, mode, DBMMODE, sff);
  872. pagfd = safeopen(pagfile, mode, DBMMODE, sff);
  873. if (dirfd < 0 || pagfd < 0)
  874. {
  875. save_errno = errno;
  876. if (dirfd >= 0)
  877. (void) close(dirfd);
  878. if (pagfd >= 0)
  879. (void) close(pagfd);
  880. errno = save_errno;
  881. syserr("ndbm_map_open: cannot create database %s",
  882. map->map_file);
  883. return FALSE;
  884. }
  885. if (ftruncate(dirfd, (off_t) 0) < 0 ||
  886.     ftruncate(pagfd, (off_t) 0) < 0)
  887. {
  888. save_errno = errno;
  889. (void) close(dirfd);
  890. (void) close(pagfd);
  891. errno = save_errno;
  892. syserr("ndbm_map_open: cannot truncate %s.{dir,pag}",
  893. map->map_file);
  894. return FALSE;
  895. }
  896. /* if new file, get "before" bits for later filechanged check */
  897. if (std.st_mode == ST_MODE_NOFILE &&
  898.     (fstat(dirfd, &std) < 0 || fstat(pagfd, &stp) < 0))
  899. {
  900. save_errno = errno;
  901. (void) close(dirfd);
  902. (void) close(pagfd);
  903. errno = save_errno;
  904. syserr("ndbm_map_open(%s.{dir,pag}): cannot fstat pre-opened file",
  905. map->map_file);
  906. return FALSE;
  907. }
  908. /* have to save the lock for the duration (bletch) */
  909. map->map_lockfd = dirfd;
  910. (void) close(pagfd);
  911. /* twiddle bits for dbm_open */
  912. mode &= ~(O_CREAT|O_EXCL);
  913. #  endif /* NOFTRUNCATE */
  914. }
  915. # endif /* LOCK_ON_OPEN */
  916. /* open the database */
  917. dbm = dbm_open(map->map_file, mode, DBMMODE);
  918. if (dbm == NULL)
  919. {
  920. save_errno = errno;
  921. if (bitset(MF_ALIAS, map->map_mflags) &&
  922.     aliaswait(map, ".pag", FALSE))
  923. return TRUE;
  924. # if !LOCK_ON_OPEN && !NOFTRUNCATE
  925. if (map->map_lockfd >= 0)
  926. (void) close(map->map_lockfd);
  927. # endif /* !LOCK_ON_OPEN && !NOFTRUNCATE */
  928. errno = save_errno;
  929. if (!bitset(MF_OPTIONAL, map->map_mflags))
  930. syserr("Cannot open DBM database %s", map->map_file);
  931. return FALSE;
  932. }
  933. dfd = dbm_dirfno(dbm);
  934. pfd = dbm_pagfno(dbm);
  935. if (dfd == pfd)
  936. {
  937. /* heuristic: if files are linked, this is actually gdbm */
  938. dbm_close(dbm);
  939. # if !LOCK_ON_OPEN && !NOFTRUNCATE
  940. if (map->map_lockfd >= 0)
  941. (void) close(map->map_lockfd);
  942. # endif /* !LOCK_ON_OPEN && !NOFTRUNCATE */
  943. errno = 0;
  944. syserr("dbm map "%s": cannot support GDBM",
  945. map->map_mname);
  946. return FALSE;
  947. }
  948. if (filechanged(dirfile, dfd, &std) ||
  949.     filechanged(pagfile, pfd, &stp))
  950. {
  951. save_errno = errno;
  952. dbm_close(dbm);
  953. # if !LOCK_ON_OPEN && !NOFTRUNCATE
  954. if (map->map_lockfd >= 0)
  955. (void) close(map->map_lockfd);
  956. # endif /* !LOCK_ON_OPEN && !NOFTRUNCATE */
  957. errno = save_errno;
  958. syserr("ndbm_map_open(%s): file changed after open",
  959. map->map_file);
  960. return FALSE;
  961. }
  962. map->map_db1 = (ARBPTR_T) dbm;
  963. /*
  964. **  Need to set map_mtime before the call to aliaswait()
  965. **  as aliaswait() will call map_lookup() which requires
  966. **  map_mtime to be set
  967. */
  968. if (fstat(dfd, &st) >= 0)
  969. map->map_mtime = st.st_mtime;
  970. if (mode == O_RDONLY)
  971. {
  972. # if LOCK_ON_OPEN
  973. if (dfd >= 0)
  974. (void) lockfile(dfd, map->map_file, ".dir", LOCK_UN);
  975. if (pfd >= 0)
  976. (void) lockfile(pfd, map->map_file, ".pag", LOCK_UN);
  977. # endif /* LOCK_ON_OPEN */
  978. if (bitset(MF_ALIAS, map->map_mflags) &&
  979.     !aliaswait(map, ".pag", TRUE))
  980. return FALSE;
  981. }
  982. else
  983. {
  984. map->map_mflags |= MF_LOCKED;
  985. if (geteuid() == 0 && TrustedUid != 0)
  986. {
  987. # if HASFCHOWN
  988. if (fchown(dfd, TrustedUid, -1) < 0 ||
  989.     fchown(pfd, TrustedUid, -1) < 0)
  990. {
  991. int err = errno;
  992. sm_syslog(LOG_ALERT, NOQID,
  993.   "ownership change on %s failed: %s",
  994.   map->map_file, errstring(err));
  995. message("050 ownership change on %s failed: %s",
  996. map->map_file, errstring(err));
  997. }
  998. # endif /* HASFCHOWN */
  999. }
  1000. }
  1001. return TRUE;
  1002. }
  1003. /*
  1004. **  NDBM_MAP_LOOKUP -- look up a datum in a DBM-type map
  1005. */
  1006. char *
  1007. ndbm_map_lookup(map, name, av, statp)
  1008. MAP *map;
  1009. char *name;
  1010. char **av;
  1011. int *statp;
  1012. {
  1013. datum key, val;
  1014. int fd;
  1015. char keybuf[MAXNAME + 1];
  1016. struct stat stbuf;
  1017. if (tTd(38, 20))
  1018. dprintf("ndbm_map_lookup(%s, %s)n",
  1019. map->map_mname, name);
  1020. key.dptr = name;
  1021. key.dsize = strlen(name);
  1022. if (!bitset(MF_NOFOLDCASE, map->map_mflags))
  1023. {
  1024. if (key.dsize > sizeof keybuf - 1)
  1025. key.dsize = sizeof keybuf - 1;
  1026. memmove(keybuf, key.dptr, key.dsize);
  1027. keybuf[key.dsize] = '';
  1028. makelower(keybuf);
  1029. key.dptr = keybuf;
  1030. }
  1031. lockdbm:
  1032. fd = dbm_dirfno((DBM *) map->map_db1);
  1033. if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
  1034. (void) lockfile(fd, map->map_file, ".dir", LOCK_SH);
  1035. if (fd < 0 || fstat(fd, &stbuf) < 0 || stbuf.st_mtime > map->map_mtime)
  1036. {
  1037. /* Reopen the database to sync the cache */
  1038. int omode = bitset(map->map_mflags, MF_WRITABLE) ? O_RDWR
  1039.  : O_RDONLY;
  1040. if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
  1041. (void) lockfile(fd, map->map_file, ".dir", LOCK_UN);
  1042. map->map_class->map_close(map);
  1043. map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
  1044. if (map->map_class->map_open(map, omode))
  1045. {
  1046. map->map_mflags |= MF_OPEN;
  1047. map->map_pid = getpid();
  1048. if ((omode && O_ACCMODE) == O_RDWR)
  1049. map->map_mflags |= MF_WRITABLE;
  1050. goto lockdbm;
  1051. }
  1052. else
  1053. {
  1054. if (!bitset(MF_OPTIONAL, map->map_mflags))
  1055. {
  1056. extern MAPCLASS BogusMapClass;
  1057. *statp = EX_TEMPFAIL;
  1058. map->map_class = &BogusMapClass;
  1059. map->map_mflags |= MF_OPEN;
  1060. map->map_pid = getpid();
  1061. syserr("Cannot reopen NDBM database %s",
  1062. map->map_file);
  1063. }
  1064. return NULL;
  1065. }
  1066. }
  1067. val.dptr = NULL;
  1068. if (bitset(MF_TRY0NULL, map->map_mflags))
  1069. {
  1070. val = dbm_fetch((DBM *) map->map_db1, key);
  1071. if (val.dptr != NULL)
  1072. map->map_mflags &= ~MF_TRY1NULL;
  1073. }
  1074. if (val.dptr == NULL && bitset(MF_TRY1NULL, map->map_mflags))
  1075. {
  1076. key.dsize++;
  1077. val = dbm_fetch((DBM *) map->map_db1, key);
  1078. if (val.dptr != NULL)
  1079. map->map_mflags &= ~MF_TRY0NULL;
  1080. }
  1081. if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
  1082. (void) lockfile(fd, map->map_file, ".dir", LOCK_UN);
  1083. if (val.dptr == NULL)
  1084. return NULL;
  1085. if (bitset(MF_MATCHONLY, map->map_mflags))
  1086. return map_rewrite(map, name, strlen(name), NULL);
  1087. else
  1088. return map_rewrite(map, val.dptr, val.dsize, av);
  1089. }
  1090. /*
  1091. **  NDBM_MAP_STORE -- store a datum in the database
  1092. */
  1093. void
  1094. ndbm_map_store(map, lhs, rhs)
  1095. register MAP *map;
  1096. char *lhs;
  1097. char *rhs;
  1098. {
  1099. datum key;
  1100. datum data;
  1101. int status;
  1102. char keybuf[MAXNAME + 1];
  1103. if (tTd(38, 12))
  1104. dprintf("ndbm_map_store(%s, %s, %s)n",
  1105. map->map_mname, lhs, rhs);
  1106. key.dsize = strlen(lhs);
  1107. key.dptr = lhs;
  1108. if (!bitset(MF_NOFOLDCASE, map->map_mflags))
  1109. {
  1110. if (key.dsize > sizeof keybuf - 1)
  1111. key.dsize = sizeof keybuf - 1;
  1112. memmove(keybuf, key.dptr, key.dsize);
  1113. keybuf[key.dsize] = '';
  1114. makelower(keybuf);
  1115. key.dptr = keybuf;
  1116. }
  1117. data.dsize = strlen(rhs);
  1118. data.dptr = rhs;
  1119. if (bitset(MF_INCLNULL, map->map_mflags))
  1120. {
  1121. key.dsize++;
  1122. data.dsize++;
  1123. }
  1124. status = dbm_store((DBM *) map->map_db1, key, data, DBM_INSERT);
  1125. if (status > 0)
  1126. {
  1127. if (!bitset(MF_APPEND, map->map_mflags))
  1128. message("050 Warning: duplicate alias name %s", lhs);
  1129. else
  1130. {
  1131. static char *buf = NULL;
  1132. static int bufsiz = 0;
  1133. auto int xstat;
  1134. datum old;
  1135. old.dptr = ndbm_map_lookup(map, key.dptr,
  1136.    (char **)NULL, &xstat);
  1137. if (old.dptr != NULL && *(char *) old.dptr != '')
  1138. {
  1139. old.dsize = strlen(old.dptr);
  1140. if (data.dsize + old.dsize + 2 > bufsiz)
  1141. {
  1142. if (buf != NULL)
  1143. (void) free(buf);
  1144. bufsiz = data.dsize + old.dsize + 2;
  1145. buf = xalloc(bufsiz);
  1146. }
  1147. snprintf(buf, bufsiz, "%s,%s",
  1148. data.dptr, old.dptr);
  1149. data.dsize = data.dsize + old.dsize + 1;
  1150. data.dptr = buf;
  1151. if (tTd(38, 9))
  1152. dprintf("ndbm_map_store append=%sn",
  1153. data.dptr);
  1154. }
  1155. }
  1156. status = dbm_store((DBM *) map->map_db1,
  1157.    key, data, DBM_REPLACE);
  1158. }
  1159. if (status != 0)
  1160. syserr("readaliases: dbm put (%s)", lhs);
  1161. }
  1162. /*
  1163. **  NDBM_MAP_CLOSE -- close the database
  1164. */
  1165. void
  1166. ndbm_map_close(map)
  1167. register MAP  *map;
  1168. {
  1169. if (tTd(38, 9))
  1170. dprintf("ndbm_map_close(%s, %s, %lx)n",
  1171. map->map_mname, map->map_file, map->map_mflags);
  1172. if (bitset(MF_WRITABLE, map->map_mflags))
  1173. {
  1174. # ifdef NDBM_YP_COMPAT
  1175. bool inclnull;
  1176. char buf[MAXHOSTNAMELEN];
  1177. inclnull = bitset(MF_INCLNULL, map->map_mflags);
  1178. map->map_mflags &= ~MF_INCLNULL;
  1179. if (strstr(map->map_file, "/yp/") != NULL)
  1180. {
  1181. long save_mflags = map->map_mflags;
  1182. map->map_mflags |= MF_NOFOLDCASE;
  1183. (void) snprintf(buf, sizeof buf, "%010ld", curtime());
  1184. ndbm_map_store(map, "YP_LAST_MODIFIED", buf);
  1185. (void) gethostname(buf, sizeof buf);
  1186. ndbm_map_store(map, "YP_MASTER_NAME", buf);
  1187. map->map_mflags = save_mflags;
  1188. }
  1189. if (inclnull)
  1190. map->map_mflags |= MF_INCLNULL;
  1191. # endif /* NDBM_YP_COMPAT */
  1192. /* write out the distinguished alias */
  1193. ndbm_map_store(map, "@", "@");
  1194. }
  1195. dbm_close((DBM *) map->map_db1);
  1196. /* release lock (if needed) */
  1197. # if !LOCK_ON_OPEN
  1198. if (map->map_lockfd >= 0)
  1199. (void) close(map->map_lockfd);
  1200. # endif /* !LOCK_ON_OPEN */
  1201. }
  1202. #endif /* NDBM */
  1203. /*
  1204. **  NEWDB (Hash and BTree) Modules
  1205. */
  1206. #ifdef NEWDB
  1207. /*
  1208. **  BT_MAP_OPEN, HASH_MAP_OPEN -- database open primitives.
  1209. **
  1210. ** These do rather bizarre locking.  If you can lock on open,
  1211. ** do that to avoid the condition of opening a database that
  1212. ** is being rebuilt.  If you don't, we'll try to fake it, but
  1213. ** there will be a race condition.  If opening for read-only,
  1214. ** we immediately release the lock to avoid freezing things up.
  1215. ** We really ought to hold the lock, but guarantee that we won't
  1216. ** be pokey about it.  That's hard to do.
  1217. */
  1218. /* these should be K line arguments */
  1219. # if DB_VERSION_MAJOR < 2
  1220. #  define db_cachesize cachesize
  1221. #  define h_nelem nelem
  1222. #  ifndef DB_CACHE_SIZE
  1223. #   define DB_CACHE_SIZE (1024 * 1024) /* database memory cache size */
  1224. #  endif /* ! DB_CACHE_SIZE */
  1225. #  ifndef DB_HASH_NELEM
  1226. #   define DB_HASH_NELEM 4096 /* (starting) size of hash table */
  1227. #  endif /* ! DB_HASH_NELEM */
  1228. # endif /* DB_VERSION_MAJOR < 2 */
  1229. bool
  1230. bt_map_open(map, mode)
  1231. MAP *map;
  1232. int mode;
  1233. {
  1234. # if DB_VERSION_MAJOR < 2
  1235. BTREEINFO btinfo;
  1236. # endif /* DB_VERSION_MAJOR < 2 */
  1237. # if DB_VERSION_MAJOR == 2
  1238. DB_INFO btinfo;
  1239. # endif /* DB_VERSION_MAJOR == 2 */
  1240. # if DB_VERSION_MAJOR > 2
  1241. void *btinfo = NULL;
  1242. # endif /* DB_VERSION_MAJOR > 2 */
  1243. if (tTd(38, 2))
  1244. dprintf("bt_map_open(%s, %s, %d)n",
  1245. map->map_mname, map->map_file, mode);
  1246. # if DB_VERSION_MAJOR < 3
  1247. memset(&btinfo, '', sizeof btinfo);
  1248. #  ifdef DB_CACHE_SIZE
  1249. btinfo.db_cachesize = DB_CACHE_SIZE;
  1250. #  endif /* DB_CACHE_SIZE */
  1251. # endif /* DB_VERSION_MAJOR < 3 */
  1252. return db_map_open(map, mode, "btree", DB_BTREE, &btinfo);
  1253. }
  1254. bool
  1255. hash_map_open(map, mode)
  1256. MAP *map;
  1257. int mode;
  1258. {
  1259. # if DB_VERSION_MAJOR < 2
  1260. HASHINFO hinfo;
  1261. # endif /* DB_VERSION_MAJOR < 2 */
  1262. # if DB_VERSION_MAJOR == 2
  1263. DB_INFO hinfo;
  1264. # endif /* DB_VERSION_MAJOR == 2 */
  1265. # if DB_VERSION_MAJOR > 2
  1266. void *hinfo = NULL;
  1267. # endif /* DB_VERSION_MAJOR > 2 */
  1268. if (tTd(38, 2))
  1269. dprintf("hash_map_open(%s, %s, %d)n",
  1270. map->map_mname, map->map_file, mode);
  1271. # if DB_VERSION_MAJOR < 3
  1272. memset(&hinfo, '', sizeof hinfo);
  1273. #  ifdef DB_HASH_NELEM
  1274. hinfo.h_nelem = DB_HASH_NELEM;
  1275. #  endif /* DB_HASH_NELEM */
  1276. #  ifdef DB_CACHE_SIZE
  1277. hinfo.db_cachesize = DB_CACHE_SIZE;
  1278. #  endif /* DB_CACHE_SIZE */
  1279. # endif /* DB_VERSION_MAJOR < 3 */
  1280. return db_map_open(map, mode, "hash", DB_HASH, &hinfo);
  1281. }
  1282. static bool
  1283. db_map_open(map, mode, mapclassname, dbtype, openinfo)
  1284. MAP *map;
  1285. int mode;
  1286. char *mapclassname;
  1287. DBTYPE dbtype;
  1288. # if DB_VERSION_MAJOR < 2
  1289. const void *openinfo;
  1290. # endif /* DB_VERSION_MAJOR < 2 */
  1291. # if DB_VERSION_MAJOR == 2
  1292. DB_INFO *openinfo;
  1293. # endif /* DB_VERSION_MAJOR == 2 */
  1294. # if DB_VERSION_MAJOR > 2
  1295. void **openinfo;
  1296. # endif /* DB_VERSION_MAJOR > 2 */
  1297. {
  1298. DB *db = NULL;
  1299. int i;
  1300. int omode;
  1301. int smode = S_IREAD;
  1302. int fd;
  1303. long sff;
  1304. int save_errno;
  1305. struct stat st;
  1306. char buf[MAXNAME + 1];
  1307. /* do initial file and directory checks */
  1308. (void) strlcpy(buf, map->map_file, sizeof buf - 3);
  1309. i = strlen(buf);
  1310. if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
  1311. (void) strlcat(buf, ".db", sizeof buf);
  1312. mode &= O_ACCMODE;
  1313. omode = mode;
  1314. sff = SFF_ROOTOK|SFF_REGONLY;
  1315. if (mode == O_RDWR)
  1316. {
  1317. sff |= SFF_CREAT;
  1318. if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
  1319. sff |= SFF_NOSLINK;
  1320. if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
  1321. sff |= SFF_NOHLINK;
  1322. smode = S_IWRITE;
  1323. }
  1324. else
  1325. {
  1326. if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
  1327. sff |= SFF_NOWLINK;
  1328. }
  1329. if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
  1330. sff |= SFF_SAFEDIRPATH;
  1331. i = safefile(buf, RunAsUid, RunAsGid, RunAsUserName, sff, smode, &st);
  1332. # if !_FFR_REMOVE_AUTOREBUILD
  1333. if (i == ENOENT && AutoRebuild &&
  1334.     bitset(MCF_REBUILDABLE, map->map_class->map_cflags) &&
  1335.     (bitset(MF_IMPL_HASH, map->map_mflags) ||
  1336.      bitset(MF_ALIAS, map->map_mflags)) &&
  1337.     mode == O_RDONLY)
  1338. {
  1339. bool impl = bitset(MF_IMPL_HASH, map->map_mflags);
  1340. /* may be able to rebuild */
  1341. map->map_mflags &= ~MF_IMPL_HASH;
  1342. if (!rebuildaliases(map, TRUE))
  1343. return FALSE;
  1344. if (impl)
  1345. return impl_map_open(map, O_RDONLY);
  1346. else
  1347. return db_map_open(map, O_RDONLY, mapclassname,
  1348.    dbtype, openinfo);
  1349. }
  1350. # endif /* !_FFR_REMOVE_AUTOREBUILD */
  1351. if (i != 0)
  1352. {
  1353. char *prob = "unsafe";
  1354. /* cannot open this map */
  1355. if (i == ENOENT)
  1356. prob = "missing";
  1357. if (tTd(38, 2))
  1358. dprintf("t%s map file: %sn", prob, errstring(i));
  1359. errno = i;
  1360. if (!bitset(MF_OPTIONAL, map->map_mflags))
  1361. syserr("%s map "%s": %s map file %s",
  1362. mapclassname, map->map_mname, prob, buf);
  1363. return FALSE;
  1364. }
  1365. if (st.st_mode == ST_MODE_NOFILE)
  1366. omode |= O_CREAT|O_EXCL;
  1367. map->map_lockfd = -1;
  1368. # if LOCK_ON_OPEN
  1369. if (mode == O_RDWR)
  1370. omode |= O_TRUNC|O_EXLOCK;
  1371. else
  1372. omode |= O_SHLOCK;
  1373. # else /* LOCK_ON_OPEN */
  1374. /*
  1375. **  Pre-lock the file to avoid race conditions.  In particular,
  1376. **  since dbopen returns NULL if the file is zero length, we
  1377. **  must have a locked instance around the dbopen.
  1378. */
  1379. fd = open(buf, omode, DBMMODE);
  1380. if (fd < 0)
  1381. {
  1382. if (!bitset(MF_OPTIONAL, map->map_mflags))
  1383. syserr("db_map_open: cannot pre-open database %s", buf);
  1384. return FALSE;
  1385. }
  1386. /* make sure no baddies slipped in just before the open... */
  1387. if (filechanged(buf, fd, &st))
  1388. {
  1389. save_errno = errno;
  1390. (void) close(fd);
  1391. errno = save_errno;
  1392. syserr("db_map_open(%s): file changed after pre-open", buf);
  1393. return FALSE;
  1394. }
  1395. /* if new file, get the "before" bits for later filechanged check */
  1396. if (st.st_mode == ST_MODE_NOFILE && fstat(fd, &st) < 0)
  1397. {
  1398. save_errno = errno;
  1399. (void) close(fd);
  1400. errno = save_errno;
  1401. syserr("db_map_open(%s): cannot fstat pre-opened file",
  1402. buf);
  1403. return FALSE;
  1404. }
  1405. /* actually lock the pre-opened file */
  1406. if (!lockfile(fd, buf, NULL, mode == O_RDONLY ? LOCK_SH : LOCK_EX))
  1407. syserr("db_map_open: cannot lock %s", buf);
  1408. /* set up mode bits for dbopen */
  1409. if (mode == O_RDWR)
  1410. omode |= O_TRUNC;
  1411. omode &= ~(O_EXCL|O_CREAT);
  1412. # endif /* LOCK_ON_OPEN */
  1413. # if DB_VERSION_MAJOR < 2
  1414. db = dbopen(buf, omode, DBMMODE, dbtype, openinfo);
  1415. # else /* DB_VERSION_MAJOR < 2 */
  1416. {
  1417. int flags = 0;
  1418. #  if DB_VERSION_MAJOR > 2
  1419. int ret;
  1420. #  endif /* DB_VERSION_MAJOR > 2 */
  1421. if (mode == O_RDONLY)
  1422. flags |= DB_RDONLY;
  1423. if (bitset(O_CREAT, omode))
  1424. flags |= DB_CREATE;
  1425. if (bitset(O_TRUNC, omode))
  1426. flags |= DB_TRUNCATE;
  1427. #  if !HASFLOCK && defined(DB_FCNTL_LOCKING)
  1428. flags |= DB_FCNTL_LOCKING;
  1429. #  endif /* !HASFLOCK && defined(DB_FCNTL_LOCKING) */
  1430. #  if DB_VERSION_MAJOR > 2
  1431. ret = db_create(&db, NULL, 0);
  1432. #  ifdef DB_CACHE_SIZE
  1433. if (ret == 0 && db != NULL)
  1434. {
  1435. ret = db->set_cachesize(db, 0, DB_CACHE_SIZE, 0);
  1436. if (ret != 0)
  1437. {
  1438. (void) db->close(db, 0);
  1439. db = NULL;
  1440. }
  1441. }
  1442. #  endif /* DB_CACHE_SIZE */
  1443. #  ifdef DB_HASH_NELEM
  1444. if (dbtype == DB_HASH && ret == 0 && db != NULL)
  1445. {
  1446. ret = db->set_h_nelem(db, DB_HASH_NELEM);
  1447. if (ret != 0)
  1448. {
  1449. (void) db->close(db, 0);
  1450. db = NULL;
  1451. }
  1452. }
  1453. #  endif /* DB_HASH_NELEM */
  1454. if (ret == 0 && db != NULL)
  1455. {
  1456. ret = db->open(db, buf, NULL, dbtype, flags, DBMMODE);
  1457. if (ret != 0)
  1458. {
  1459. (void) db->close(db, 0);
  1460. db = NULL;
  1461. }
  1462. }
  1463. errno = ret;
  1464. #  else /* DB_VERSION_MAJOR > 2 */
  1465. errno = db_open(buf, dbtype, flags, DBMMODE,
  1466. NULL, openinfo, &db);
  1467. #  endif /* DB_VERSION_MAJOR > 2 */
  1468. }
  1469. # endif /* DB_VERSION_MAJOR < 2 */
  1470. save_errno = errno;
  1471. # if !LOCK_ON_OPEN
  1472. if (mode == O_RDWR)
  1473. map->map_lockfd = fd;
  1474. else
  1475. (void) close(fd);
  1476. # endif /* !LOCK_ON_OPEN */
  1477. if (db == NULL)
  1478. {
  1479. if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags) &&
  1480.     aliaswait(map, ".db", FALSE))
  1481. return TRUE;
  1482. # if !LOCK_ON_OPEN
  1483. if (map->map_lockfd >= 0)
  1484. (void) close(map->map_lockfd);
  1485. # endif /* !LOCK_ON_OPEN */
  1486. errno = save_errno;
  1487. if (!bitset(MF_OPTIONAL, map->map_mflags))
  1488. syserr("Cannot open %s database %s",
  1489. mapclassname, buf);
  1490. return FALSE;
  1491. }
  1492. # if DB_VERSION_MAJOR < 2
  1493. fd = db->fd(db);
  1494. # else /* DB_VERSION_MAJOR < 2 */
  1495. fd = -1;
  1496. errno = db->fd(db, &fd);
  1497. # endif /* DB_VERSION_MAJOR < 2 */
  1498. if (filechanged(buf, fd, &st))
  1499. {
  1500. save_errno = errno;
  1501. # if DB_VERSION_MAJOR < 2
  1502. (void) db->close(db);
  1503. # else /* DB_VERSION_MAJOR < 2 */
  1504. errno = db->close(db, 0);
  1505. # endif /* DB_VERSION_MAJOR < 2 */
  1506. # if !LOCK_ON_OPEN
  1507. if (map->map_lockfd >= 0)
  1508. (void) close(map->map_lockfd);
  1509. # endif /* !LOCK_ON_OPEN */
  1510. errno = save_errno;
  1511. syserr("db_map_open(%s): file changed after open", buf);
  1512. return FALSE;
  1513. }
  1514. if (mode == O_RDWR)
  1515. map->map_mflags |= MF_LOCKED;
  1516. # if LOCK_ON_OPEN
  1517. if (fd >= 0 && mode == O_RDONLY)
  1518. {
  1519. (void) lockfile(fd, buf, NULL, LOCK_UN);
  1520. }
  1521. # endif /* LOCK_ON_OPEN */
  1522. /* try to make sure that at least the database header is on disk */
  1523. if (mode == O_RDWR)
  1524. {
  1525. (void) db->sync(db, 0);
  1526. if (geteuid() == 0 && TrustedUid != 0)
  1527. {
  1528. # if HASFCHOWN
  1529. if (fchown(fd, TrustedUid, -1) < 0)
  1530. {
  1531. int err = errno;
  1532. sm_syslog(LOG_ALERT, NOQID,
  1533.   "ownership change on %s failed: %s",
  1534.   buf, errstring(err));
  1535. message("050 ownership change on %s failed: %s",
  1536. buf, errstring(err));
  1537. }
  1538. # endif /* HASFCHOWN */
  1539. }
  1540. }
  1541. map->map_db2 = (ARBPTR_T) db;
  1542. /*
  1543. **  Need to set map_mtime before the call to aliaswait()
  1544. **  as aliaswait() will call map_lookup() which requires
  1545. **  map_mtime to be set
  1546. */
  1547. if (fd >= 0 && fstat(fd, &st) >= 0)
  1548. map->map_mtime = st.st_mtime;
  1549. if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags) &&
  1550.     !aliaswait(map, ".db", TRUE))
  1551. return FALSE;
  1552. return TRUE;
  1553. }
  1554. /*
  1555. **  DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map
  1556. */
  1557. char *
  1558. db_map_lookup(map, name, av, statp)
  1559. MAP *map;
  1560. char *name;
  1561. char **av;
  1562. int *statp;
  1563. {
  1564. DBT key, val;
  1565. register DB *db = (DB *) map->map_db2;
  1566. int i;
  1567. int st;
  1568. int save_errno;
  1569. int fd;
  1570. struct stat stbuf;
  1571. char keybuf[MAXNAME + 1];
  1572. char buf[MAXNAME + 1];
  1573. memset(&key, '', sizeof key);
  1574. memset(&val, '', sizeof val);
  1575. if (tTd(38, 20))
  1576. dprintf("db_map_lookup(%s, %s)n",
  1577. map->map_mname, name);
  1578. i = strlen(map->map_file);
  1579. if (i > MAXNAME)
  1580. i = MAXNAME;
  1581. (void) strlcpy(buf, map->map_file, i + 1);
  1582. if (i > 3 && strcmp(&buf[i - 3], ".db") == 0)
  1583. buf[i - 3] = '';
  1584. key.size = strlen(name);
  1585. if (key.size > sizeof keybuf - 1)
  1586. key.size = sizeof keybuf - 1;
  1587. key.data = keybuf;
  1588. memmove(keybuf, name, key.size);
  1589. keybuf[key.size] = '';
  1590. if (!bitset(MF_NOFOLDCASE, map->map_mflags))
  1591. makelower(keybuf);
  1592.   lockdb:
  1593. # if DB_VERSION_MAJOR < 2
  1594. fd = db->fd(db);
  1595. # else /* DB_VERSION_MAJOR < 2 */
  1596. fd = -1;
  1597. errno = db->fd(db, &fd);
  1598. # endif /* DB_VERSION_MAJOR < 2 */
  1599. if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
  1600. (void) lockfile(fd, buf, ".db", LOCK_SH);
  1601. if (fd < 0 || fstat(fd, &stbuf) < 0 || stbuf.st_mtime > map->map_mtime)
  1602. {
  1603. /* Reopen the database to sync the cache */
  1604. int omode = bitset(map->map_mflags, MF_WRITABLE) ? O_RDWR
  1605.  : O_RDONLY;
  1606. if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
  1607. (void) lockfile(fd, buf, ".db", LOCK_UN);
  1608. map->map_class->map_close(map);
  1609. map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
  1610. if (map->map_class->map_open(map, omode))
  1611. {
  1612. map->map_mflags |= MF_OPEN;
  1613. map->map_pid = getpid();
  1614. if ((omode && O_ACCMODE) == O_RDWR)
  1615. map->map_mflags |= MF_WRITABLE;
  1616. db = (DB *) map->map_db2;
  1617. goto lockdb;
  1618. }
  1619. else
  1620. {
  1621. if (!bitset(MF_OPTIONAL, map->map_mflags))
  1622. {
  1623. extern MAPCLASS BogusMapClass;
  1624. *statp = EX_TEMPFAIL;
  1625. map->map_class = &BogusMapClass;
  1626. map->map_mflags |= MF_OPEN;
  1627. map->map_pid = getpid();
  1628. syserr("Cannot reopen DB database %s",
  1629. map->map_file);
  1630. }
  1631. return NULL;
  1632. }
  1633. }
  1634. st = 1;
  1635. if (bitset(MF_TRY0NULL, map->map_mflags))
  1636. {
  1637. # if DB_VERSION_MAJOR < 2
  1638. st = db->get(db, &key, &val, 0);
  1639. # else /* DB_VERSION_MAJOR < 2 */
  1640. errno = db->get(db, NULL, &key, &val, 0);
  1641. switch (errno)
  1642. {
  1643.   case DB_NOTFOUND:
  1644.   case DB_KEYEMPTY:
  1645. st = 1;
  1646. break;
  1647.   case 0:
  1648. st = 0;
  1649. break;
  1650.   default:
  1651. st = -1;
  1652. break;
  1653. }
  1654. # endif /* DB_VERSION_MAJOR < 2 */
  1655. if (st == 0)
  1656. map->map_mflags &= ~MF_TRY1NULL;
  1657. }
  1658. if (st != 0 && bitset(MF_TRY1NULL, map->map_mflags))
  1659. {
  1660. key.size++;
  1661. # if DB_VERSION_MAJOR < 2
  1662. st = db->get(db, &key, &val, 0);
  1663. # else /* DB_VERSION_MAJOR < 2 */
  1664. errno = db->get(db, NULL, &key, &val, 0);
  1665. switch (errno)
  1666. {
  1667.   case DB_NOTFOUND:
  1668.   case DB_KEYEMPTY:
  1669. st = 1;
  1670. break;
  1671.   case 0:
  1672. st = 0;
  1673. break;
  1674.   default:
  1675. st = -1;
  1676. break;
  1677. }
  1678. # endif /* DB_VERSION_MAJOR < 2 */
  1679. if (st == 0)
  1680. map->map_mflags &= ~MF_TRY0NULL;
  1681. }
  1682. save_errno = errno;
  1683. if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
  1684. (void) lockfile(fd, buf, ".db", LOCK_UN);
  1685. if (st != 0)
  1686. {
  1687. errno = save_errno;
  1688. if (st < 0)
  1689. syserr("db_map_lookup: get (%s)", name);
  1690. return NULL;
  1691. }
  1692. if (bitset(MF_MATCHONLY, map->map_mflags))
  1693. return map_rewrite(map, name, strlen(name), NULL);
  1694. else
  1695. return map_rewrite(map, val.data, val.size, av);
  1696. }
  1697. /*
  1698. **  DB_MAP_STORE -- store a datum in the NEWDB database
  1699. */
  1700. void
  1701. db_map_store(map, lhs, rhs)
  1702. register MAP *map;
  1703. char *lhs;
  1704. char *rhs;
  1705. {
  1706. int status;
  1707. DBT key;
  1708. DBT data;
  1709. register DB *db = map->map_db2;
  1710. char keybuf[MAXNAME + 1];
  1711. memset(&key, '', sizeof key);
  1712. memset(&data, '', sizeof data);
  1713. if (tTd(38, 12))
  1714. dprintf("db_map_store(%s, %s, %s)n",
  1715. map->map_mname, lhs, rhs);
  1716. key.size = strlen(lhs);
  1717. key.data = lhs;
  1718. if (!bitset(MF_NOFOLDCASE, map->map_mflags))
  1719. {
  1720. if (key.size > sizeof keybuf - 1)
  1721. key.size = sizeof keybuf - 1;
  1722. memmove(keybuf, key.data, key.size);
  1723. keybuf[key.size] = '';
  1724. makelower(keybuf);
  1725. key.data = keybuf;
  1726. }
  1727. data.size = strlen(rhs);
  1728. data.data = rhs;
  1729. if (bitset(MF_INCLNULL, map->map_mflags))
  1730. {
  1731. key.size++;
  1732. data.size++;
  1733. }
  1734. # if DB_VERSION_MAJOR < 2
  1735. status = db->put(db, &key, &data, R_NOOVERWRITE);
  1736. # else /* DB_VERSION_MAJOR < 2 */
  1737. errno = db->put(db, NULL, &key, &data, DB_NOOVERWRITE);
  1738. switch (errno)
  1739. {
  1740.   case DB_KEYEXIST:
  1741. status = 1;
  1742. break;
  1743.   case 0:
  1744. status = 0;
  1745. break;
  1746.   default:
  1747. status = -1;
  1748. break;
  1749. }
  1750. # endif /* DB_VERSION_MAJOR < 2 */
  1751. if (status > 0)
  1752. {
  1753. if (!bitset(MF_APPEND, map->map_mflags))
  1754. message("050 Warning: duplicate alias name %s", lhs);
  1755. else
  1756. {
  1757. static char *buf = NULL;
  1758. static int bufsiz = 0;
  1759. DBT old;
  1760. memset(&old, '', sizeof old);
  1761. old.data = db_map_lookup(map, key.data,
  1762.  (char **)NULL, &status);
  1763. if (old.data != NULL)
  1764. {
  1765. old.size = strlen(old.data);
  1766. if (data.size + old.size + 2 > bufsiz)
  1767. {
  1768. if (buf != NULL)
  1769. (void) free(buf);
  1770. bufsiz = data.size + old.size + 2;
  1771. buf = xalloc(bufsiz);
  1772. }
  1773. snprintf(buf, bufsiz, "%s,%s",
  1774. (char *) data.data, (char *) old.data);
  1775. data.size = data.size + old.size + 1;
  1776. data.data = buf;
  1777. if (tTd(38, 9))
  1778. dprintf("db_map_store append=%sn",
  1779. (char *) data.data);
  1780. }
  1781. }
  1782. # if DB_VERSION_MAJOR < 2
  1783. status = db->put(db, &key, &data, 0);
  1784. # else /* DB_VERSION_MAJOR < 2 */
  1785. status = errno = db->put(db, NULL, &key, &data, 0);
  1786. # endif /* DB_VERSION_MAJOR < 2 */
  1787. }
  1788. if (status != 0)
  1789. syserr("readaliases: db put (%s)", lhs);
  1790. }
  1791. /*
  1792. **  DB_MAP_CLOSE -- add distinguished entries and close the database
  1793. */
  1794. void
  1795. db_map_close(map)
  1796. MAP *map;
  1797. {
  1798. register DB *db = map->map_db2;
  1799. if (tTd(38, 9))
  1800. dprintf("db_map_close(%s, %s, %lx)n",
  1801. map->map_mname, map->map_file, map->map_mflags);
  1802. if (bitset(MF_WRITABLE, map->map_mflags))
  1803. {
  1804. /* write out the distinguished alias */
  1805. db_map_store(map, "@", "@");
  1806. }
  1807. (void) db->sync(db, 0);
  1808. # if !LOCK_ON_OPEN
  1809. if (map->map_lockfd >= 0)
  1810. (void) close(map->map_lockfd);
  1811. # endif /* !LOCK_ON_OPEN */
  1812. # if DB_VERSION_MAJOR < 2
  1813. if (db->close(db) != 0)
  1814. # else /* DB_VERSION_MAJOR < 2 */
  1815. /*
  1816. **  Berkeley DB can use internal shared memory
  1817. **  locking for its memory pool.  Closing a map
  1818. **  opened by another process will interfere
  1819. **  with the shared memory and locks of the parent
  1820. **  process leaving things in a bad state.
  1821. */
  1822. /*
  1823. **  If this map was not opened by the current
  1824. **  process, do not close the map but recover
  1825. **  the file descriptor.
  1826. */
  1827. if (map->map_pid != getpid())
  1828. {
  1829. int fd = -1;
  1830. errno = db->fd(db, &fd);
  1831. if (fd >= 0)
  1832. (void) close(fd);
  1833. return;
  1834. }
  1835. if ((errno = db->close(db, 0)) != 0)
  1836. # endif /* DB_VERSION_MAJOR < 2 */
  1837. syserr("db_map_close(%s, %s, %lx): db close failure",
  1838. map->map_mname, map->map_file, map->map_mflags);
  1839. }
  1840. #endif /* NEWDB */
  1841. /*
  1842. **  NIS Modules
  1843. */
  1844. #ifdef NIS
  1845. # ifndef YPERR_BUSY
  1846. #  define YPERR_BUSY 16
  1847. # endif /* ! YPERR_BUSY */
  1848. /*
  1849. **  NIS_MAP_OPEN -- open DBM map
  1850. */
  1851. bool
  1852. nis_map_open(map, mode)
  1853. MAP *map;
  1854. int mode;
  1855. {
  1856. int yperr;
  1857. register char *p;
  1858. auto char *vp;
  1859. auto int vsize;
  1860. if (tTd(38, 2))
  1861. dprintf("nis_map_open(%s, %s, %d)n",
  1862. map->map_mname, map->map_file, mode);
  1863. mode &= O_ACCMODE;
  1864. if (mode != O_RDONLY)
  1865. {
  1866. /* issue a pseudo-error message */
  1867. # ifdef ENOSYS
  1868. errno = ENOSYS;
  1869. # else /* ENOSYS */
  1870. #  ifdef EFTYPE
  1871. errno = EFTYPE;
  1872. #  else /* EFTYPE */
  1873. errno = ENXIO;
  1874. #  endif /* EFTYPE */
  1875. # endif /* ENOSYS */
  1876. return FALSE;
  1877. }
  1878. p = strchr(map->map_file, '@');
  1879. if (p != NULL)
  1880. {
  1881. *p++ = '';
  1882. if (*p != '')
  1883. map->map_domain = p;
  1884. }
  1885. if (*map->map_file == '')
  1886. map->map_file = "mail.aliases";
  1887. if (map->map_domain == NULL)
  1888. {
  1889. yperr = yp_get_default_domain(&map->map_domain);
  1890. if (yperr != 0)
  1891. {
  1892. if (!bitset(MF_OPTIONAL, map->map_mflags))
  1893. syserr("421 4.3.5 NIS map %s specified, but NIS not running",
  1894.        map->map_file);
  1895. return FALSE;
  1896. }
  1897. }
  1898. /* check to see if this map actually exists */
  1899. yperr = yp_match(map->map_domain, map->map_file, "@", 1,
  1900. &vp, &vsize);
  1901. if (tTd(38, 10))
  1902. dprintf("nis_map_open: yp_match(@, %s, %s) => %sn",
  1903. map->map_domain, map->map_file, yperr_string(yperr));
  1904. if (yperr == 0 || yperr == YPERR_KEY || yperr == YPERR_BUSY)
  1905. {
  1906. /*
  1907. **  We ought to be calling aliaswait() here if this is an
  1908. **  alias file, but powerful HP-UX NIS servers  apparently
  1909. **  don't insert the @:@ token into the alias map when it
  1910. **  is rebuilt, so aliaswait() just hangs.  I hate HP-UX.
  1911. */
  1912. # if 0
  1913. if (!bitset(MF_ALIAS, map->map_mflags) ||
  1914.     aliaswait(map, NULL, TRUE))
  1915. # endif /* 0 */
  1916. return TRUE;
  1917. }
  1918. if (!bitset(MF_OPTIONAL, map->map_mflags))
  1919. {
  1920. syserr("421 4.0.0 Cannot bind to map %s in domain %s: %s",
  1921. map->map_file, map->map_domain, yperr_string(yperr));
  1922. }
  1923. return FALSE;
  1924. }
  1925. /*
  1926. **  NIS_MAP_LOOKUP -- look up a datum in a NIS map
  1927. */
  1928. /* ARGSUSED3 */
  1929. char *
  1930. nis_map_lookup(map, name, av, statp)
  1931. MAP *map;
  1932. char *name;
  1933. char **av;
  1934. int *statp;
  1935. {
  1936. char *vp;
  1937. auto int vsize;
  1938. int buflen;
  1939. int yperr;
  1940. char keybuf[MAXNAME + 1];
  1941. if (tTd(38, 20))
  1942. dprintf("nis_map_lookup(%s, %s)n",
  1943. map->map_mname, name);
  1944. buflen = strlen(name);
  1945. if (buflen > sizeof keybuf - 1)
  1946. buflen = sizeof keybuf - 1;
  1947. memmove(keybuf, name, buflen);
  1948. keybuf[buflen] = '';
  1949. if (!bitset(MF_NOFOLDCASE, map->map_mflags))
  1950. makelower(keybuf);
  1951. yperr = YPERR_KEY;
  1952. if (bitset(MF_TRY0NULL, map->map_mflags))
  1953. {
  1954. yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
  1955.      &vp, &vsize);
  1956. if (yperr == 0)
  1957. map->map_mflags &= ~MF_TRY1NULL;
  1958. }
  1959. if (yperr == YPERR_KEY && bitset(MF_TRY1NULL, map->map_mflags))
  1960. {
  1961. buflen++;
  1962. yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
  1963.      &vp, &vsize);
  1964. if (yperr == 0)
  1965. map->map_mflags &= ~MF_TRY0NULL;
  1966. }
  1967. if (yperr != 0)
  1968. {
  1969. if (yperr != YPERR_KEY && yperr != YPERR_BUSY)
  1970. map->map_mflags &= ~(MF_VALID|MF_OPEN);
  1971. return NULL;
  1972. }
  1973. if (bitset(MF_MATCHONLY, map->map_mflags))
  1974. return map_rewrite(map, name, strlen(name), NULL);
  1975. else
  1976. return map_rewrite(map, vp, vsize, av);
  1977. }
  1978. /*
  1979. **  NIS_GETCANONNAME -- look up canonical name in NIS
  1980. */
  1981. static bool
  1982. nis_getcanonname(name, hbsize, statp)
  1983. char *name;
  1984. int hbsize;
  1985. int *statp;
  1986. {
  1987. char *vp;
  1988. auto int vsize;
  1989. int keylen;
  1990. int yperr;
  1991. static bool try0null = TRUE;
  1992. static bool try1null = TRUE;
  1993. static char *yp_domain = NULL;
  1994. char host_record[MAXLINE];
  1995. char cbuf[MAXNAME];
  1996. char nbuf[MAXNAME + 1];
  1997. if (tTd(38, 20))
  1998. dprintf("nis_getcanonname(%s)n", name);
  1999. if (strlcpy(nbuf, name, sizeof nbuf) >= sizeof nbuf)
  2000. {
  2001. *statp = EX_UNAVAILABLE;
  2002. return FALSE;
  2003. }
  2004. shorten_hostname(nbuf);
  2005. keylen = strlen(nbuf);
  2006. if (yp_domain == NULL)
  2007. (void) yp_get_default_domain(&yp_domain);
  2008. makelower(nbuf);
  2009. yperr = YPERR_KEY;
  2010. if (try0null)
  2011. {
  2012. yperr = yp_match(yp_domain, "hosts.byname", nbuf, keylen,
  2013.      &vp, &vsize);
  2014. if (yperr == 0)
  2015. try1null = FALSE;
  2016. }
  2017. if (yperr == YPERR_KEY && try1null)
  2018. {
  2019. keylen++;
  2020. yperr = yp_match(yp_domain, "hosts.byname", nbuf, keylen,
  2021.      &vp, &vsize);
  2022. if (yperr == 0)
  2023. try0null = FALSE;
  2024. }
  2025. if (yperr != 0)
  2026. {
  2027. if (yperr == YPERR_KEY)
  2028. *statp = EX_NOHOST;
  2029. else if (yperr == YPERR_BUSY)
  2030. *statp = EX_TEMPFAIL;
  2031. else
  2032. *statp = EX_UNAVAILABLE;
  2033. return FALSE;
  2034. }
  2035. (void) strlcpy(host_record, vp, sizeof host_record);
  2036. if (tTd(38, 44))
  2037. dprintf("got record `%s'n", host_record);
  2038. if (!extract_canonname(nbuf, host_record, cbuf, sizeof cbuf))
  2039. {
  2040. /* this should not happen, but.... */
  2041. *statp = EX_NOHOST;
  2042. return FALSE;
  2043. }
  2044. if (hbsize < strlen(cbuf))
  2045. {
  2046. *statp = EX_UNAVAILABLE;
  2047. return FALSE;
  2048. }
  2049. (void) strlcpy(name, cbuf, hbsize);
  2050. *statp = EX_OK;
  2051. return TRUE;
  2052. }
  2053. #endif /* NIS */
  2054. /*
  2055. **  NISPLUS Modules
  2056. **
  2057. ** This code donated by Sun Microsystems.
  2058. */
  2059. #ifdef NISPLUS
  2060. # undef NIS /* symbol conflict in nis.h */
  2061. # undef T_UNSPEC /* symbol conflict in nis.h -> ... -> sys/tiuser.h */
  2062. # include <rpcsvc/nis.h>
  2063. # include <rpcsvc/nislib.h>
  2064. # define EN_col(col) zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val
  2065. # define COL_NAME(res,i) ((res->objects.objects_val)->TA_data.ta_cols.ta_cols_val)[i].tc_name
  2066. # define COL_MAX(res) ((res->objects.objects_val)->TA_data.ta_cols.ta_cols_len)
  2067. # define PARTIAL_NAME(x) ((x)[strlen(x) - 1] != '.')
  2068. /*
  2069. **  NISPLUS_MAP_OPEN -- open nisplus table
  2070. */
  2071. bool
  2072. nisplus_map_open(map, mode)
  2073. MAP *map;
  2074. int mode;
  2075. {
  2076. nis_result *res = NULL;
  2077. int retry_cnt, max_col, i;
  2078. char qbuf[MAXLINE + NIS_MAXNAMELEN];
  2079. if (tTd(38, 2))
  2080. dprintf("nisplus_map_open(%s, %s, %d)n",
  2081. map->map_mname, map->map_file, mode);
  2082. mode &= O_ACCMODE;
  2083. if (mode != O_RDONLY)
  2084. {
  2085. errno = EPERM;
  2086. return FALSE;
  2087. }
  2088. if (*map->map_file == '')
  2089. map->map_file = "mail_aliases.org_dir";
  2090. if (PARTIAL_NAME(map->map_file) && map->map_domain == NULL)
  2091. {
  2092. /* set default NISPLUS Domain to $m */
  2093. map->map_domain = newstr(nisplus_default_domain());
  2094. if (tTd(38, 2))
  2095. dprintf("nisplus_map_open(%s): using domain %sn",
  2096. map->map_file, map->map_domain);
  2097. }
  2098. if (!PARTIAL_NAME(map->map_file))
  2099. {
  2100. map->map_domain = newstr("");
  2101. snprintf(qbuf, sizeof qbuf, "%s", map->map_file);
  2102. }
  2103. else
  2104. {
  2105. /* check to see if this map actually exists */
  2106. snprintf(qbuf, sizeof qbuf, "%s.%s",
  2107. map->map_file, map->map_domain);
  2108. }
  2109. retry_cnt = 0;
  2110. while (res == NULL || res->status != NIS_SUCCESS)
  2111. {
  2112. res = nis_lookup(qbuf, FOLLOW_LINKS);
  2113. switch (res->status)
  2114. {
  2115.   case NIS_SUCCESS:
  2116. break;
  2117.   case NIS_TRYAGAIN:
  2118.   case NIS_RPCERROR:
  2119.   case NIS_NAMEUNREACHABLE:
  2120. if (retry_cnt++ > 4)
  2121. {
  2122. errno = EAGAIN;
  2123. return FALSE;
  2124. }
  2125. /* try not to overwhelm hosed server */
  2126. sleep(2);
  2127. break;
  2128.   default: /* all other nisplus errors */
  2129. # if 0
  2130. if (!bitset(MF_OPTIONAL, map->map_mflags))
  2131. syserr("421 4.0.0 Cannot find table %s.%s: %s",
  2132. map->map_file, map->map_domain,
  2133. nis_sperrno(res->status));
  2134. # endif /* 0 */
  2135. errno = EAGAIN;
  2136. return FALSE;
  2137. }
  2138. }
  2139. if (NIS_RES_NUMOBJ(res) != 1 ||
  2140.     (NIS_RES_OBJECT(res)->zo_data.zo_type != TABLE_OBJ))
  2141. {
  2142. if (tTd(38, 10))
  2143. dprintf("nisplus_map_open: %s is not a tablen", qbuf);
  2144. # if 0
  2145. if (!bitset(MF_OPTIONAL, map->map_mflags))
  2146. syserr("421 4.0.0 %s.%s: %s is not a table",
  2147. map->map_file, map->map_domain,
  2148. nis_sperrno(res->status));
  2149. # endif /* 0 */
  2150. errno = EBADF;
  2151. return FALSE;
  2152. }
  2153. /* default key column is column 0 */
  2154. if (map->map_keycolnm == NULL)
  2155. map->map_keycolnm = newstr(COL_NAME(res,0));
  2156. max_col = COL_MAX(res);
  2157. /* verify the key column exist */
  2158. for (i = 0; i< max_col; i++)
  2159. {
  2160. if (!strcmp(map->map_keycolnm, COL_NAME(res,i)))
  2161. break;
  2162. }
  2163. if (i == max_col)
  2164. {
  2165. if (tTd(38, 2))
  2166. dprintf("nisplus_map_open(%s): can not find key column %sn",
  2167. map->map_file, map->map_keycolnm);
  2168. errno = ENOENT;
  2169. return FALSE;
  2170. }
  2171. /* default value column is the last column */
  2172. if (map->map_valcolnm == NULL)
  2173. {
  2174. map->map_valcolno = max_col - 1;
  2175. return TRUE;
  2176. }
  2177. for (i = 0; i< max_col; i++)
  2178. {
  2179. if (strcmp(map->map_valcolnm, COL_NAME(res,i)) == 0)
  2180. {
  2181. map->map_valcolno = i;
  2182. return TRUE;
  2183. }
  2184. }
  2185. if (tTd(38, 2))
  2186. dprintf("nisplus_map_open(%s): can not find column %sn",
  2187. map->map_file, map->map_keycolnm);
  2188. errno = ENOENT;
  2189. return FALSE;
  2190. }
  2191. /*
  2192. **  NISPLUS_MAP_LOOKUP -- look up a datum in a NISPLUS table
  2193. */
  2194. char *
  2195. nisplus_map_lookup(map, name, av, statp)
  2196. MAP *map;
  2197. char *name;
  2198. char **av;
  2199. int *statp;
  2200. {
  2201. char *p;
  2202. auto int vsize;
  2203. char *skp;
  2204. int skleft;
  2205. char search_key[MAXNAME + 4];
  2206. char qbuf[MAXLINE + NIS_MAXNAMELEN];
  2207. nis_result *result;
  2208. if (tTd(38, 20))
  2209. dprintf("nisplus_map_lookup(%s, %s)n",
  2210. map->map_mname, name);
  2211. if (!bitset(MF_OPEN, map->map_mflags))
  2212. {
  2213. if (nisplus_map_open(map, O_RDONLY))
  2214. {
  2215. map->map_mflags |= MF_OPEN;
  2216. map->map_pid = getpid();
  2217. }
  2218. else
  2219. {
  2220. *statp = EX_UNAVAILABLE;
  2221. return NULL;
  2222. }
  2223. }
  2224. /*
  2225. **  Copy the name to the key buffer, escaping double quote characters
  2226. **  by doubling them and quoting "]" and "," to avoid having the
  2227. **  NIS+ parser choke on them.
  2228. */
  2229. skleft = sizeof search_key - 4;
  2230. skp = search_key;
  2231. for (p = name; *p != '' && skleft > 0; p++)
  2232. {
  2233. switch (*p)
  2234. {
  2235.   case ']':
  2236.   case ',':
  2237. /* quote the character */
  2238. *skp++ = '"';
  2239. *skp++ = *p;
  2240. *skp++ = '"';
  2241. skleft -= 3;
  2242. break;
  2243.   case '"':
  2244. /* double the quote */
  2245. *skp++ = '"';
  2246. skleft--;
  2247. /* FALLTHROUGH */
  2248.   default:
  2249. *skp++ = *p;
  2250. skleft--;
  2251. break;
  2252. }
  2253. }
  2254. *skp = '';
  2255. if (!bitset(MF_NOFOLDCASE, map->map_mflags))
  2256. makelower(search_key);
  2257. /* construct the query */
  2258. if (PARTIAL_NAME(map->map_file))
  2259. snprintf(qbuf, sizeof qbuf, "[%s=%s],%s.%s",
  2260. map->map_keycolnm, search_key, map->map_file,
  2261. map->map_domain);
  2262. else
  2263. snprintf(qbuf, sizeof qbuf, "[%s=%s],%s",
  2264. map->map_keycolnm, search_key, map->map_file);
  2265. if (tTd(38, 20))
  2266. dprintf("qbuf=%sn", qbuf);
  2267. result = nis_list(qbuf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
  2268. if (result->status == NIS_SUCCESS)
  2269. {
  2270. int count;
  2271. char *str;
  2272. if ((count = NIS_RES_NUMOBJ(result)) != 1)
  2273. {
  2274. if (LogLevel > 10)
  2275. sm_syslog(LOG_WARNING, CurEnv->e_id,
  2276.   "%s: lookup error, expected 1 entry, got %d",
  2277.   map->map_file, count);
  2278. /* ignore second entry */
  2279. if (tTd(38, 20))
  2280. dprintf("nisplus_map_lookup(%s), got %d entries, additional entries ignoredn",
  2281. name, count);
  2282. }
  2283. p = ((NIS_RES_OBJECT(result))->EN_col(map->map_valcolno));
  2284. /* set the length of the result */
  2285. if (p == NULL)
  2286. p = "";
  2287. vsize = strlen(p);
  2288. if (tTd(38, 20))
  2289. dprintf("nisplus_map_lookup(%s), found %sn",
  2290. name, p);
  2291. if (bitset(MF_MATCHONLY, map->map_mflags))
  2292. str = map_rewrite(map, name, strlen(name), NULL);
  2293. else
  2294. str = map_rewrite(map, p, vsize, av);
  2295. nis_freeresult(result);
  2296. *statp = EX_OK;
  2297. return str;
  2298. }
  2299. else
  2300. {
  2301. if (result->status == NIS_NOTFOUND)
  2302. *statp = EX_NOTFOUND;
  2303. else if (result->status == NIS_TRYAGAIN)
  2304. *statp = EX_TEMPFAIL;
  2305. else
  2306. {
  2307. *statp = EX_UNAVAILABLE;
  2308. map->map_mflags &= ~(MF_VALID|MF_OPEN);
  2309. }
  2310. }
  2311. if (tTd(38, 20))
  2312. dprintf("nisplus_map_lookup(%s), failedn", name);
  2313. nis_freeresult(result);
  2314. return NULL;
  2315. }
  2316. /*
  2317. **  NISPLUS_GETCANONNAME -- look up canonical name in NIS+
  2318. */
  2319. static bool
  2320. nisplus_getcanonname(name, hbsize, statp)
  2321. char *name;
  2322. int hbsize;
  2323. int *statp;
  2324. {
  2325. char *vp;
  2326. auto int vsize;
  2327. nis_result *result;
  2328. char *p;
  2329. char nbuf[MAXNAME + 1];
  2330. char qbuf[MAXLINE + NIS_MAXNAMELEN];
  2331. if (strlen(name) >= sizeof nbuf)
  2332. {
  2333. *statp = EX_UNAVAILABLE;
  2334. return FALSE;
  2335. }
  2336. (void) strlcpy(nbuf, name, sizeof nbuf);
  2337. shorten_hostname(nbuf);
  2338. p = strchr(nbuf, '.');
  2339. if (p == NULL)
  2340. {
  2341. /* single token */
  2342. snprintf(qbuf, sizeof qbuf, "[name=%s],hosts.org_dir", nbuf);
  2343. }
  2344. else if (p[1] != '')
  2345. {
  2346. /* multi token -- take only first token in nbuf */
  2347. *p = '';
  2348. snprintf(qbuf, sizeof qbuf, "[name=%s],hosts.org_dir.%s",
  2349. nbuf, &p[1]);
  2350. }
  2351. else
  2352. {
  2353. *statp = EX_NOHOST;
  2354. return FALSE;
  2355. }
  2356. if (tTd(38, 20))
  2357. dprintf("nnisplus_getcanoname(%s), qbuf=%sn",
  2358. name, qbuf);
  2359. result = nis_list(qbuf, EXPAND_NAME|FOLLOW_LINKS|FOLLOW_PATH,
  2360. NULL, NULL);
  2361. if (result->status == NIS_SUCCESS)
  2362. {
  2363. int count;
  2364. char *domain;
  2365. if ((count = NIS_RES_NUMOBJ(result)) != 1)
  2366. {
  2367. if (LogLevel > 10)
  2368. sm_syslog(LOG_WARNING, CurEnv->e_id,
  2369.   "nisplus_getcanonname: lookup error, expected 1 entry, got %d",
  2370.   count);
  2371. /* ignore second entry */
  2372. if (tTd(38, 20))
  2373. dprintf("nisplus_getcanoname(%s), got %d entries, all but first ignoredn",
  2374. name, count);
  2375. }
  2376. if (tTd(38, 20))
  2377. dprintf("nisplus_getcanoname(%s), found in directory "%s"n",
  2378. name, (NIS_RES_OBJECT(result))->zo_domain);
  2379. vp = ((NIS_RES_OBJECT(result))->EN_col(0));
  2380. vsize = strlen(vp);
  2381. if (tTd(38, 20))
  2382. dprintf("nisplus_getcanonname(%s), found %sn",
  2383. name, vp);
  2384. if (strchr(vp, '.') != NULL)
  2385. {
  2386. domain = "";
  2387. }
  2388. else
  2389. {
  2390. domain = macvalue('m', CurEnv);
  2391. if (domain == NULL)
  2392. domain = "";
  2393. }
  2394. if (hbsize > vsize + (int) strlen(domain) + 1)
  2395. {
  2396. if (domain[0] == '')
  2397. (void) strlcpy(name, vp, hbsize);
  2398. else
  2399. snprintf(name, hbsize, "%s.%s", vp, domain);
  2400. *statp = EX_OK;
  2401. }
  2402. else
  2403. *statp = EX_NOHOST;
  2404. nis_freeresult(result);
  2405. return TRUE;
  2406. }
  2407. else
  2408. {
  2409. if (result->status == NIS_NOTFOUND)
  2410. *statp = EX_NOHOST;
  2411. else if (result->status == NIS_TRYAGAIN)
  2412. *statp = EX_TEMPFAIL;
  2413. else
  2414. *statp = EX_UNAVAILABLE;
  2415. }
  2416. if (tTd(38, 20))
  2417. dprintf("nisplus_getcanonname(%s), failed, status=%d, nsw_stat=%dn",
  2418. name, result->status, *statp);
  2419. nis_freeresult(result);
  2420. return FALSE;
  2421. }
  2422. char *
  2423. nisplus_default_domain()
  2424. {
  2425. static char default_domain[MAXNAME + 1] = "";
  2426. char *p;
  2427. if (default_domain[0] != '')
  2428. return default_domain;
  2429. p = nis_local_directory();
  2430. snprintf(default_domain, sizeof default_domain, "%s", p);
  2431. return default_domain;
  2432. }
  2433. #endif /* NISPLUS */
  2434. /*
  2435. **  LDAP Modules
  2436. */
  2437. /*
  2438. **  LDAPMAP_DEQUOTE - helper routine for ldapmap_parseargs
  2439. */
  2440. #if defined(LDAPMAP) || defined(PH_MAP)
  2441. # ifdef PH_MAP
  2442. #  define ph_map_dequote ldapmap_dequote
  2443. # endif /* PH_MAP */
  2444. char *
  2445. ldapmap_dequote(str)
  2446. char *str;
  2447. {
  2448. char *p;
  2449. char *start;
  2450. if (str == NULL)
  2451. return NULL;
  2452. p = str;
  2453. if (*p == '"')
  2454. {
  2455. /* Should probably swallow initial whitespace here */
  2456. start = ++p;
  2457. }
  2458. else
  2459. return str;
  2460. while (*p != '"' && *p != '')
  2461. p++;
  2462. if (*p != '')
  2463. *p = '';
  2464. return start;
  2465. }
  2466. #endif /* defined(LDAPMAP) || defined(PH_MAP) */
  2467. #ifdef LDAPMAP
  2468. LDAPMAP_STRUCT *LDAPDefaults = NULL;
  2469. /*
  2470. **  LDAPMAP_OPEN -- open LDAP map
  2471. **
  2472. ** Connect to the LDAP server.  Re-use existing connections since a
  2473. ** single server connection to a host (with the same host, port,
  2474. ** bind DN, and secret) can answer queries for multiple maps.
  2475. */
  2476. bool
  2477. ldapmap_open(map, mode)
  2478. MAP *map;
  2479. int mode;
  2480. {
  2481. LDAPMAP_STRUCT *lmap;
  2482. STAB *s;
  2483. if (tTd(38, 2))
  2484. dprintf("ldapmap_open(%s, %d)n", map->map_mname, mode);
  2485. mode &= O_ACCMODE;
  2486. /* sendmail doesn't have the ability to write to LDAP (yet) */
  2487. if (mode != O_RDONLY)
  2488. {
  2489. /* issue a pseudo-error message */
  2490. # ifdef ENOSYS
  2491. errno = ENOSYS;
  2492. # else /* ENOSYS */
  2493. #  ifdef EFTYPE
  2494. errno = EFTYPE;
  2495. #  else /* EFTYPE */
  2496. errno = ENXIO;
  2497. #  endif /* EFTYPE */
  2498. # endif /* ENOSYS */
  2499. return FALSE;
  2500. }
  2501. /* Comma separate if used as an alias file */
  2502. if (map->map_coldelim == '' && bitset(MF_ALIAS, map->map_mflags))
  2503. map->map_coldelim = ',';
  2504. lmap = (LDAPMAP_STRUCT *) map->map_db1;
  2505. s = ldapmap_findconn(lmap);
  2506. if (s->s_ldap != NULL)
  2507. {
  2508. /* Already have a connection open to this LDAP server */
  2509. lmap->ldap_ld = s->s_ldap;
  2510. return TRUE;
  2511. }
  2512. /* No connection yet, connect */
  2513. if (!ldapmap_start(map))
  2514. return FALSE;
  2515. /* Save connection for reuse */
  2516. s->s_ldap = lmap->ldap_ld;
  2517. return TRUE;
  2518. }
  2519. /*
  2520. **  LDAPMAP_START -- actually connect to an LDAP server
  2521. **
  2522. ** Parameters:
  2523. ** map -- the map being opened.
  2524. **
  2525. ** Returns:
  2526. ** TRUE if connection is successful, FALSE otherwise.
  2527. **
  2528. ** Side Effects:
  2529. ** Populates lmap->ldap_ld.
  2530. */
  2531. static jmp_buf LDAPTimeout;
  2532. static bool
  2533. ldapmap_start(map)
  2534. MAP *map;
  2535. {
  2536. register int bind_result;
  2537. int save_errno;
  2538. register EVENT *ev = NULL;
  2539. LDAPMAP_STRUCT *lmap;
  2540. LDAP *ld;
  2541. if (tTd(38, 2))
  2542. dprintf("ldapmap_start(%s)n", map->map_mname);
  2543. lmap = (LDAPMAP_STRUCT *) map->map_db1;
  2544. if (tTd(38,9))
  2545. dprintf("ldapmap_start(%s, %d)n", lmap->ldap_host,
  2546. lmap->ldap_port);
  2547. # if USE_LDAP_INIT
  2548. ld = ldap_init(lmap->ldap_host, lmap->ldap_port);
  2549. # else /* USE_LDAP_INIT */
  2550. /*
  2551. **  If using ldap_open(), the actual connection to the server
  2552. **  happens now so we need the timeout here.  For ldap_init(),
  2553. **  the connection happens at bind time.
  2554. */
  2555. /* set the timeout */
  2556. if (lmap->ldap_timeout.tv_sec != 0)
  2557. {
  2558. if (setjmp(LDAPTimeout) != 0)
  2559. {
  2560. if (LogLevel > 1)
  2561. sm_syslog(LOG_NOTICE, CurEnv->e_id,
  2562.   "timeout conning to LDAP server %.100s",
  2563.   lmap->ldap_host);
  2564. return FALSE;
  2565. }
  2566. ev = setevent(lmap->ldap_timeout.tv_sec, ldaptimeout, 0);
  2567. }
  2568. ld = ldap_open(lmap->ldap_host, lmap->ldap_port);
  2569. save_errno = errno;
  2570. /* clear the event if it has not sprung */
  2571. if (ev != NULL)
  2572. clrevent(ev);
  2573. # endif /* USE_LDAP_INIT */
  2574. errno = save_errno;
  2575. if (ld == NULL)
  2576. {
  2577. if (!bitset(MF_OPTIONAL, map->map_mflags))
  2578. {
  2579. if (bitset(MF_NODEFER, map->map_mflags))
  2580. syserr("%s failed to %s in map %s",
  2581. # if USE_LDAP_INIT
  2582.        "ldap_init",
  2583. # else /* USE_LDAP_INIT */
  2584.        "ldap_open",
  2585. # endif /* USE_LDAP_INIT */
  2586.        lmap->ldap_host, map->map_mname);
  2587. else
  2588. syserr("421 4.0.0 %s failed to %s in map %s",
  2589. # if USE_LDAP_INIT
  2590.        "ldap_init",
  2591. # else /* USE_LDAP_INIT */
  2592.        "ldap_open",
  2593. # endif /* USE_LDAP_INIT */
  2594.        lmap->ldap_host, map->map_mname);
  2595. }
  2596. return FALSE;
  2597. }
  2598. ldapmap_setopts(ld, lmap);
  2599. # if USE_LDAP_INIT
  2600. /*
  2601. **  If using ldap_init(), the actual connection to the server
  2602. **  happens at ldap_bind_s() so we need the timeout here.
  2603. */
  2604. /* set the timeout */
  2605. if (lmap->ldap_timeout.tv_sec != 0)
  2606. {
  2607. if (setjmp(LDAPTimeout) != 0)
  2608. {
  2609. if (LogLevel > 1)
  2610. sm_syslog(LOG_NOTICE, CurEnv->e_id,
  2611.   "timeout conning to LDAP server %.100s",
  2612.   lmap->ldap_host);
  2613. return FALSE;
  2614. }
  2615. ev = setevent(lmap->ldap_timeout.tv_sec, ldaptimeout, 0);
  2616. }
  2617. # endif /* USE_LDAP_INIT */
  2618. if (lmap->ldap_method == LDAP_AUTH_KRBV4 &&
  2619.     lmap->ldap_secret != NULL)
  2620. {
  2621. /*
  2622. **  Need to put ticket in environment here instead of
  2623. **  during parseargs as there may be different tickets
  2624. **  for different LDAP connections.
  2625. */
  2626. (void) putenv(lmap->ldap_secret);
  2627. }
  2628. bind_result = ldap_bind_s(ld, lmap->ldap_binddn,
  2629.   lmap->ldap_secret, lmap->ldap_method);
  2630. # if USE_LDAP_INIT
  2631. /* clear the event if it has not sprung */
  2632. if (ev != NULL)
  2633. clrevent(ev);
  2634. # endif /* USE_LDAP_INIT */
  2635. if (bind_result != LDAP_SUCCESS)
  2636. {
  2637. errno = bind_result + E_LDAPBASE;
  2638. if (!bitset(MF_OPTIONAL, map->map_mflags))
  2639. {
  2640. syserr("421 4.0.0 Cannot bind to map %s in ldap server %s",
  2641.        map->map_mname,
  2642.        (lmap->ldap_host == NULL ? "localhost" : lmap->ldap_host));
  2643. }
  2644. return FALSE;
  2645. }
  2646. /* We need to cast ld into the map structure */
  2647. lmap->ldap_ld = ld;
  2648. return TRUE;
  2649. }
  2650. /* ARGSUSED */
  2651. static void
  2652. ldaptimeout(sig_no)
  2653. int sig_no;
  2654. {
  2655. longjmp(LDAPTimeout, 1);
  2656. }
  2657. /*
  2658. **  LDAPMAP_CLOSE -- close ldap map
  2659. */
  2660. void
  2661. ldapmap_close(map)
  2662. MAP *map;
  2663. {
  2664. LDAPMAP_STRUCT *lmap;
  2665. STAB *s;
  2666. lmap = (LDAPMAP_STRUCT *) map->map_db1;
  2667. /* Check if already closed */
  2668. if (lmap->ldap_ld == NULL)
  2669. return;
  2670. s = ldapmap_findconn(lmap);
  2671. /* Check if already closed */
  2672. if (s->s_ldap == NULL)
  2673. return;
  2674. /* If same as saved connection, stored connection is going away */
  2675. if (s->s_ldap == lmap->ldap_ld)
  2676. s->s_ldap = NULL;
  2677. if (lmap->ldap_ld != NULL)
  2678. {
  2679. ldap_unbind(lmap->ldap_ld);
  2680. lmap->ldap_ld = NULL;
  2681. }
  2682. }
  2683. # ifdef SUNET_ID
  2684. /*
  2685. **  SUNET_ID_HASH -- Convert a string to it's Sunet_id canonical form
  2686. **  This only makes sense at Stanford University.
  2687. */
  2688. char *
  2689. sunet_id_hash(str)
  2690. char *str;
  2691. {
  2692. char *p, *p_last;
  2693. p = str;
  2694. p_last = p;
  2695. while (*p != '')
  2696. {
  2697. if (islower(*p) || isdigit(*p))
  2698. {
  2699. *p_last = *p;
  2700. p_last++;
  2701. }
  2702. else if (isupper(*p))
  2703. {
  2704. *p_last = tolower(*p);
  2705. p_last++;
  2706. }
  2707. ++p;
  2708. }
  2709. if (*p_last != '')
  2710. *p_last = '';
  2711. return str;
  2712. }
  2713. # endif /* SUNET_ID */
  2714. /*
  2715. **  LDAPMAP_LOOKUP -- look up a datum in a LDAP map
  2716. */
  2717. char *
  2718. ldapmap_lookup(map, name, av, statp)
  2719. MAP *map;
  2720. char *name;
  2721. char **av;
  2722. int *statp;
  2723. {
  2724. int i;
  2725. int entries = 0;
  2726. int msgid;
  2727. int ret;
  2728. int vsize;
  2729. char *fp, *vp;
  2730. char *p, *q;
  2731. char *result = NULL;
  2732. LDAPMAP_STRUCT *lmap = NULL;
  2733. char keybuf[MAXNAME + 1];
  2734. char filter[LDAPMAP_MAX_FILTER + 1];
  2735. if (tTd(38, 20))
  2736. dprintf("ldapmap_lookup(%s, %s)n", map->map_mname, name);
  2737. /* Get ldap struct pointer from map */
  2738. lmap = (LDAPMAP_STRUCT *) map->map_db1;
  2739. ldapmap_setopts(lmap->ldap_ld, lmap);
  2740. (void) strlcpy(keybuf, name, sizeof keybuf);
  2741. if (!bitset(MF_NOFOLDCASE, map->map_mflags))
  2742. {
  2743. # ifdef SUNET_ID
  2744. sunet_id_hash(keybuf);
  2745. # else /* SUNET_ID */
  2746. makelower(keybuf);
  2747. # endif /* SUNET_ID */
  2748. }
  2749. /* substitute keybuf into filter, perhaps multiple times */
  2750. memset(filter, '', sizeof filter);
  2751. fp = filter;
  2752. p = lmap->ldap_filter;
  2753. while ((q = strchr(p, '%')) != NULL)
  2754. {
  2755. if (q[1] == 's')
  2756. {
  2757. snprintf(fp, SPACELEFT(filter, fp), "%.*s%s",
  2758.  q - p, p, keybuf);
  2759. fp += strlen(fp);
  2760. p = q + 2;
  2761. }
  2762. else if (q[1] == '0')
  2763. {
  2764. char *k = keybuf;
  2765. snprintf(fp, SPACELEFT(filter, fp), "%.*s",
  2766.  q - p, p);
  2767. fp += strlen(fp);
  2768. p = q + 2;
  2769. /* Properly escape LDAP special characters */
  2770. while (SPACELEFT(filter, fp) > 0 &&
  2771.        *k != '')
  2772. {
  2773. if (*k == '*' || *k == '(' ||
  2774.     *k == ')' || *k == '\')
  2775. {
  2776. (void) strlcat(fp,
  2777.        (*k == '*' ? "\2A" :
  2778. (*k == '(' ? "\28" :
  2779.  (*k == ')' ? "\29" :
  2780.   (*k == '\' ? "\5C" :
  2781.    "0")))),
  2782. SPACELEFT(filter, fp));
  2783. fp += strlen(fp);
  2784. k++;
  2785. }
  2786. else
  2787. *fp++ = *k++;
  2788. }
  2789. }
  2790. else
  2791. {
  2792. snprintf(fp, SPACELEFT(filter, fp), "%.*s",
  2793.  q - p + 1, p);
  2794. p = q + (q[1] == '%' ? 2 : 1);
  2795. fp += strlen(fp);
  2796. }
  2797. }
  2798. snprintf(fp, SPACELEFT(filter, fp), "%s", p);
  2799. if (tTd(38, 20))
  2800. dprintf("ldap search filter=%sn", filter);
  2801. lmap->ldap_res = NULL;
  2802. msgid = ldap_search(lmap->ldap_ld, lmap->ldap_base, lmap->ldap_scope,
  2803.     filter,
  2804.     (lmap->ldap_attr[0] == NULL ? NULL :
  2805.      lmap->ldap_attr),
  2806.     lmap->ldap_attrsonly);
  2807. if (msgid == -1)
  2808. {
  2809. errno = ldapmap_geterrno(lmap->ldap_ld) + E_LDAPBASE;
  2810. if (!bitset(MF_OPTIONAL, map->map_mflags))
  2811. {
  2812. if (bitset(MF_NODEFER, map->map_mflags))
  2813. syserr("Error in ldap_search_st using %s in map %s",
  2814.        filter, map->map_mname);
  2815. else
  2816. syserr("421 4.0.0 Error in ldap_search_st using %s in map %s",
  2817.        filter, map->map_mname);
  2818. }
  2819. *statp = EX_TEMPFAIL;
  2820. return NULL;
  2821. }
  2822. *statp = EX_NOTFOUND;
  2823. vp = NULL;
  2824. /* Get results (all if MF_NOREWRITE, otherwise one by one) */
  2825. while ((ret = ldap_result(lmap->ldap_ld, msgid,
  2826.   bitset(MF_NOREWRITE, map->map_mflags),
  2827.   (lmap->ldap_timeout.tv_sec == 0 ? NULL :
  2828.    &(lmap->ldap_timeout)),
  2829.   &(lmap->ldap_res))) == LDAP_RES_SEARCH_ENTRY)
  2830. {
  2831. LDAPMessage *entry;
  2832. if (bitset(MF_SINGLEMATCH, map->map_mflags))
  2833. {
  2834. entries += ldap_count_entries(lmap->ldap_ld,
  2835.       lmap->ldap_res);
  2836. if (entries > 1)
  2837. {
  2838. *statp = EX_NOTFOUND;
  2839. if (lmap->ldap_res != NULL)
  2840. {
  2841. ldap_msgfree(lmap->ldap_res);
  2842. lmap->ldap_res = NULL;
  2843. }
  2844. (void) ldap_abandon(lmap->ldap_ld, msgid);
  2845. if (vp != NULL)
  2846. free(vp);
  2847. return NULL;
  2848. }
  2849. }
  2850. /* Cycle through all entries */
  2851. for (entry = ldap_first_entry(lmap->ldap_ld, lmap->ldap_res);
  2852.      entry != NULL;
  2853.      entry = ldap_next_entry(lmap->ldap_ld, lmap->ldap_res))
  2854. {
  2855. BerElement *ber;
  2856. char *attr;
  2857. char **vals;
  2858. /*
  2859. **  If matching only and found an entry,
  2860. **  no need to spin through attributes
  2861. */
  2862. if (*statp == EX_OK &&
  2863.     bitset(MF_MATCHONLY, map->map_mflags))
  2864. continue;
  2865. for (attr = ldap_first_attribute(lmap->ldap_ld, entry,
  2866.  &ber);
  2867.      attr != NULL;
  2868.      attr = ldap_next_attribute(lmap->ldap_ld, entry,
  2869. ber))
  2870. {
  2871. char *tmp, *vp_tmp;
  2872. vals = ldap_get_values(lmap->ldap_ld, entry,
  2873.        attr);
  2874. if (vals == NULL)
  2875. {
  2876. errno = ldapmap_geterrno(lmap->ldap_ld);
  2877. if (errno == LDAP_SUCCESS)
  2878. continue;
  2879. /* Must be an error */
  2880. errno += E_LDAPBASE;
  2881. if (!bitset(MF_OPTIONAL,
  2882.     map->map_mflags))
  2883. {
  2884. if (bitset(MF_NODEFER,
  2885.    map->map_mflags))
  2886. syserr("Error getting LDAP values in map %s",
  2887.        map->map_mname);
  2888. else
  2889. syserr("421 4.0.0 Error getting LDAP values in map %s",
  2890.        map->map_mname);
  2891. }
  2892. *statp = EX_TEMPFAIL;
  2893. # if USING_NETSCAPE_LDAP
  2894. ldap_mem_free(attr);
  2895. # endif /* USING_NETSCAPE_LDAP */
  2896. if (lmap->ldap_res != NULL)
  2897. {
  2898. ldap_msgfree(lmap->ldap_res);
  2899. lmap->ldap_res = NULL;
  2900. }
  2901. (void) ldap_abandon(lmap->ldap_ld,
  2902.     msgid);
  2903. if (vp != NULL)
  2904. free(vp);
  2905. return NULL;
  2906. }
  2907. *statp = EX_OK;
  2908. /*
  2909. **  If matching only,
  2910. **  no need to spin through entries
  2911. */
  2912. if (bitset(MF_MATCHONLY, map->map_mflags))
  2913. continue;
  2914. /*
  2915. **  If we don't want multiple values,
  2916. **  return first found.
  2917. */
  2918. if (map->map_coldelim == '')
  2919. {
  2920. if (vals[0] == NULL)
  2921. {
  2922. ldap_value_free(vals);
  2923. # if USING_NETSCAPE_LDAP
  2924. ldap_mem_free(attr);
  2925. # endif /* USING_NETSCAPE_LDAP */
  2926. continue;
  2927. }
  2928. vp = newstr(vals[0]);
  2929. ldap_value_free(vals);
  2930. # if USING_NETSCAPE_LDAP
  2931. ldap_mem_free(attr);
  2932. # endif /* USING_NETSCAPE_LDAP */
  2933. break;
  2934. }
  2935. /*
  2936. **  If there is more than one,
  2937. **  munge then into a map_coldelim
  2938. **  separated string
  2939. */
  2940. vsize = 0;
  2941. for (i = 0; vals[i] != NULL; i++)
  2942. vsize += strlen(vals[i]) + 1;
  2943. vp_tmp = xalloc(vsize);
  2944. *vp_tmp = '';
  2945. p = vp_tmp;
  2946. for (i = 0; vals[i] != NULL; i++)
  2947. {
  2948. p += strlcpy(p, vals[i],
  2949.      vsize - (p - vp_tmp));
  2950. if (p >= vp_tmp + vsize)
  2951. syserr("ldapmap_lookup: Internal error: buffer too small for LDAP values");
  2952. if (vals[i + 1] != NULL)
  2953. *p++ = map->map_coldelim;
  2954. }
  2955. ldap_value_free(vals);
  2956. # if USING_NETSCAPE_LDAP
  2957. ldap_mem_free(attr);
  2958. # endif /* USING_NETSCAPE_LDAP */
  2959. if (vp == NULL)
  2960. {
  2961. vp = vp_tmp;
  2962. continue;
  2963. }
  2964. vsize = strlen(vp) + strlen(vp_tmp) + 2;
  2965. tmp = xalloc(vsize);
  2966. snprintf(tmp, vsize, "%s%c%s",
  2967.  vp, map->map_coldelim, vp_tmp);
  2968. free(vp);
  2969. free(vp_tmp);
  2970. vp = tmp;
  2971. }
  2972. errno = ldapmap_geterrno(lmap->ldap_ld);
  2973. /*
  2974. **  We check errno != LDAP_DECODING_ERROR since
  2975. **  OpenLDAP 1.X has a very ugly *undocumented*
  2976. **  hack of returning this error code from
  2977. **  ldap_next_attribute() if the library freed the
  2978. **  ber attribute.  See:
  2979. **  http://www.openldap.org/lists/openldap-devel/9901/msg00064.html
  2980. */
  2981. if (errno != LDAP_SUCCESS &&
  2982.     errno != LDAP_DECODING_ERROR)
  2983. {
  2984. /* Must be an error */
  2985. errno += E_LDAPBASE;
  2986. if (!bitset(MF_OPTIONAL, map->map_mflags))
  2987. {
  2988. if (bitset(MF_NODEFER, map->map_mflags))
  2989. syserr("Error getting LDAP attributes in map %s",
  2990.        map->map_mname);
  2991. else
  2992. syserr("421 4.0.0 Error getting LDAP attributes in map %s",
  2993.        map->map_mname);
  2994. }
  2995. *statp = EX_TEMPFAIL;
  2996. if (lmap->ldap_res != NULL)
  2997. {
  2998. ldap_msgfree(lmap->ldap_res);
  2999. lmap->ldap_res = NULL;
  3000. }
  3001. (void) ldap_abandon(lmap->ldap_ld, msgid);
  3002. if (vp != NULL)
  3003. free(vp);
  3004. return NULL;
  3005. }
  3006. /* We don't want multiple values and we have one */
  3007. if (map->map_coldelim == '' && vp != NULL)
  3008. break;
  3009. }
  3010. errno = ldapmap_geterrno(lmap->ldap_ld);
  3011. if (errno != LDAP_SUCCESS)
  3012. {
  3013. /* Must be an error */
  3014. errno += E_LDAPBASE;
  3015. if (!bitset(MF_OPTIONAL, map->map_mflags))
  3016. {
  3017. if (bitset(MF_NODEFER, map->map_mflags))
  3018. syserr("Error getting LDAP entries in map %s",
  3019.        map->map_mname);
  3020. else
  3021. syserr("421 4.0.0 Error getting LDAP entries in map %s",
  3022.        map->map_mname);
  3023. }
  3024. *statp = EX_TEMPFAIL;
  3025. if (lmap->ldap_res != NULL)
  3026. {
  3027. ldap_msgfree(lmap->ldap_res);
  3028. lmap->ldap_res = NULL;
  3029. }
  3030. (void) ldap_abandon(lmap->ldap_ld, msgid);
  3031. if (vp != NULL)
  3032. free(vp);
  3033. return NULL;
  3034. }
  3035. ldap_msgfree(lmap->ldap_res);
  3036. lmap->ldap_res = NULL;
  3037. /* If we don't want multiple values and we have one, break */
  3038. if (map->map_coldelim == '' && vp != NULL)
  3039. break;
  3040. }
  3041. /*
  3042. **  If grabbing all results at once for MF_NOREWRITE and
  3043. **  only want a single match, make sure that's all we have
  3044. */
  3045. if (ret == LDAP_RES_SEARCH_RESULT &&
  3046.     bitset(MF_NOREWRITE|MF_SINGLEMATCH, map->map_mflags))
  3047. {
  3048. entries += ldap_count_entries(lmap->ldap_ld, lmap->ldap_res);
  3049. if (entries > 1)
  3050. {
  3051. *statp = EX_NOTFOUND;
  3052. if (lmap->ldap_res != NULL)
  3053. {
  3054. ldap_msgfree(lmap->ldap_res);
  3055. lmap->ldap_res = NULL;
  3056. }
  3057. if (vp != NULL)
  3058. free(vp);
  3059. return NULL;
  3060. }
  3061. *statp = EX_OK;
  3062. }
  3063. if (ret == 0)
  3064. errno = ETIMEDOUT;
  3065. else
  3066. errno = ldapmap_geterrno(lmap->ldap_ld);
  3067. if (errno != LDAP_SUCCESS)
  3068. {
  3069. /* Must be an error */
  3070. if (ret != 0)
  3071. errno += E_LDAPBASE;
  3072. if (!bitset(MF_OPTIONAL, map->map_mflags))
  3073. {
  3074. if (bitset(MF_NODEFER, map->map_mflags))
  3075. syserr("Error getting LDAP results in map %s",
  3076.        map->map_mname);
  3077. else
  3078. syserr("421 4.0.0 Error getting LDAP results in map %s",
  3079.        map->map_mname);
  3080. }
  3081. *statp = EX_TEMPFAIL;
  3082. if (vp != NULL)
  3083. free(vp);
  3084. return NULL;
  3085. }
  3086. /* Did we match anything? */
  3087. if (vp == NULL)
  3088. return NULL;
  3089. /*
  3090. **  If MF_NOREWRITE, we are special map which doesn't
  3091. **  actually return a map value.  Instead, we don't free
  3092. **  ldap_res and let the calling function process the LDAP
  3093. **  results.  The caller should ldap_msgfree(lmap->ldap_res).
  3094. */
  3095. if (bitset(MF_NOREWRITE, map->map_mflags))
  3096. {
  3097. /* vp != NULL due to test above */
  3098. free(vp);
  3099. return "";
  3100. }
  3101. if (*statp == EX_OK)
  3102. {
  3103. /* vp != NULL due to test above */
  3104. if (LogLevel > 9)
  3105. sm_syslog(LOG_INFO, CurEnv->e_id,
  3106.   "ldap %.100s => %s", name, vp);
  3107. if (bitset(MF_MATCHONLY, map->map_mflags))
  3108. result = map_rewrite(map, name, strlen(name), NULL);
  3109. else
  3110. result = map_rewrite(map, vp, strlen(vp), av);
  3111. free(vp);
  3112. }
  3113. return result;
  3114. }
  3115. /*
  3116. **  LDAPMAP_FINDCONN -- find an LDAP connection to the server
  3117. **
  3118. ** Cache LDAP connections based on the host, port, bind DN,
  3119. ** and secret so we don't have multiple connections open to
  3120. ** the same server for different maps.
  3121. **
  3122. ** Parameters:
  3123. ** lmap -- LDAP map information
  3124. **
  3125. ** Returns:
  3126. ** Symbol table entry for the LDAP connection.
  3127. **
  3128. */
  3129. static STAB *
  3130. ldapmap_findconn(lmap)
  3131. LDAPMAP_STRUCT *lmap;
  3132. {
  3133. int len;
  3134. char *nbuf;
  3135. STAB *s;
  3136. len = (lmap->ldap_host == NULL ? strlen("localhost") :
  3137.  strlen(lmap->ldap_host)) + 1 + 8 + 1 +