PageRenderTime 62ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/contrib/sendmail/src/map.c

https://github.com/okuoku/freebsd-head
C | 2232 lines | 1681 code | 228 blank | 323 comment | 557 complexity | 3dea58c72cbf8c9252388b2b16c7335a MD5 | raw file
  1. /*
  2. * Copyright (c) 1998-2008 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. #include <sendmail.h>
  14. SM_RCSID("@(#)$Id: map.c,v 8.706 2010/07/27 03:35:42 ca Exp $")
  15. #if LDAPMAP
  16. # include <sm/ldap.h>
  17. #endif /* LDAPMAP */
  18. #if NDBM
  19. # include <ndbm.h>
  20. # ifdef R_FIRST
  21. ERROR README: You are running the Berkeley DB version of ndbm.h. See
  22. ERROR README: the README file about tweaking Berkeley DB so it can
  23. ERROR README: coexist with NDBM, or delete -DNDBM from the Makefile
  24. ERROR README: and use -DNEWDB instead.
  25. # endif /* R_FIRST */
  26. #endif /* NDBM */
  27. #if NEWDB
  28. # include "sm/bdb.h"
  29. #endif /* NEWDB */
  30. #if NIS
  31. struct dom_binding; /* forward reference needed on IRIX */
  32. # include <rpcsvc/ypclnt.h>
  33. # if NDBM
  34. # define NDBM_YP_COMPAT /* create YP-compatible NDBM files */
  35. # endif /* NDBM */
  36. #endif /* NIS */
  37. #include "map.h"
  38. #if NEWDB
  39. # if DB_VERSION_MAJOR < 2
  40. static bool db_map_open __P((MAP *, int, char *, DBTYPE, const void *));
  41. # endif /* DB_VERSION_MAJOR < 2 */
  42. # if DB_VERSION_MAJOR == 2
  43. static bool db_map_open __P((MAP *, int, char *, DBTYPE, DB_INFO *));
  44. # endif /* DB_VERSION_MAJOR == 2 */
  45. # if DB_VERSION_MAJOR > 2
  46. static bool db_map_open __P((MAP *, int, char *, DBTYPE, void **));
  47. # endif /* DB_VERSION_MAJOR > 2 */
  48. #endif /* NEWDB */
  49. static bool extract_canonname __P((char *, char *, char *, char[], int));
  50. static void map_close __P((STAB *, int));
  51. static void map_init __P((STAB *, int));
  52. #ifdef LDAPMAP
  53. static STAB * ldapmap_findconn __P((SM_LDAP_STRUCT *));
  54. #endif /* LDAPMAP */
  55. #if NISPLUS
  56. static bool nisplus_getcanonname __P((char *, int, int *));
  57. #endif /* NISPLUS */
  58. #if NIS
  59. static bool nis_getcanonname __P((char *, int, int *));
  60. #endif /* NIS */
  61. #if NETINFO
  62. static bool ni_getcanonname __P((char *, int, int *));
  63. #endif /* NETINFO */
  64. static bool text_getcanonname __P((char *, int, int *));
  65. #if SOCKETMAP
  66. static STAB *socket_map_findconn __P((const char*));
  67. /* XXX arbitrary limit for sanity */
  68. # define SOCKETMAP_MAXL 1000000
  69. #endif /* SOCKETMAP */
  70. /* default error message for trying to open a map in write mode */
  71. #ifdef ENOSYS
  72. # define SM_EMAPCANTWRITE ENOSYS
  73. #else /* ENOSYS */
  74. # ifdef EFTYPE
  75. # define SM_EMAPCANTWRITE EFTYPE
  76. # else /* EFTYPE */
  77. # define SM_EMAPCANTWRITE ENXIO
  78. # endif /* EFTYPE */
  79. #endif /* ENOSYS */
  80. /*
  81. ** MAP.C -- implementations for various map classes.
  82. **
  83. ** Each map class implements a series of functions:
  84. **
  85. ** bool map_parse(MAP *map, char *args)
  86. ** Parse the arguments from the config file. Return true
  87. ** if they were ok, false otherwise. Fill in map with the
  88. ** values.
  89. **
  90. ** char *map_lookup(MAP *map, char *key, char **args, int *pstat)
  91. ** Look up the key in the given map. If found, do any
  92. ** rewriting the map wants (including "args" if desired)
  93. ** and return the value. Set *pstat to the appropriate status
  94. ** on error and return NULL. Args will be NULL if called
  95. ** from the alias routines, although this should probably
  96. ** not be relied upon. It is suggested you call map_rewrite
  97. ** to return the results -- it takes care of null termination
  98. ** and uses a dynamically expanded buffer as needed.
  99. **
  100. ** void map_store(MAP *map, char *key, char *value)
  101. ** Store the key:value pair in the map.
  102. **
  103. ** bool map_open(MAP *map, int mode)
  104. ** Open the map for the indicated mode. Mode should
  105. ** be either O_RDONLY or O_RDWR. Return true if it
  106. ** was opened successfully, false otherwise. If the open
  107. ** failed and the MF_OPTIONAL flag is not set, it should
  108. ** also print an error. If the MF_ALIAS bit is set
  109. ** and this map class understands the @:@ convention, it
  110. ** should call aliaswait() before returning.
  111. **
  112. ** void map_close(MAP *map)
  113. ** Close the map.
  114. **
  115. ** This file also includes the implementation for getcanonname.
  116. ** It is currently implemented in a pretty ad-hoc manner; it ought
  117. ** to be more properly integrated into the map structure.
  118. */
  119. #if O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL
  120. # define LOCK_ON_OPEN 1 /* we can open/create a locked file */
  121. #else /* O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL */
  122. # define LOCK_ON_OPEN 0 /* no such luck -- bend over backwards */
  123. #endif /* O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL */
  124. /*
  125. ** MAP_PARSEARGS -- parse config line arguments for database lookup
  126. **
  127. ** This is a generic version of the map_parse method.
  128. **
  129. ** Parameters:
  130. ** map -- the map being initialized.
  131. ** ap -- a pointer to the args on the config line.
  132. **
  133. ** Returns:
  134. ** true -- if everything parsed OK.
  135. ** false -- otherwise.
  136. **
  137. ** Side Effects:
  138. ** null terminates the filename; stores it in map
  139. */
  140. bool
  141. map_parseargs(map, ap)
  142. MAP *map;
  143. char *ap;
  144. {
  145. register char *p = ap;
  146. /*
  147. ** There is no check whether there is really an argument,
  148. ** but that's not important enough to warrant extra code.
  149. */
  150. map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
  151. map->map_spacesub = SpaceSub; /* default value */
  152. for (;;)
  153. {
  154. while (isascii(*p) && isspace(*p))
  155. p++;
  156. if (*p != '-')
  157. break;
  158. switch (*++p)
  159. {
  160. case 'N':
  161. map->map_mflags |= MF_INCLNULL;
  162. map->map_mflags &= ~MF_TRY0NULL;
  163. break;
  164. case 'O':
  165. map->map_mflags &= ~MF_TRY1NULL;
  166. break;
  167. case 'o':
  168. map->map_mflags |= MF_OPTIONAL;
  169. break;
  170. case 'f':
  171. map->map_mflags |= MF_NOFOLDCASE;
  172. break;
  173. case 'm':
  174. map->map_mflags |= MF_MATCHONLY;
  175. break;
  176. case 'A':
  177. map->map_mflags |= MF_APPEND;
  178. break;
  179. case 'q':
  180. map->map_mflags |= MF_KEEPQUOTES;
  181. break;
  182. case 'a':
  183. map->map_app = ++p;
  184. break;
  185. case 'T':
  186. map->map_tapp = ++p;
  187. break;
  188. case 'k':
  189. while (isascii(*++p) && isspace(*p))
  190. continue;
  191. map->map_keycolnm = p;
  192. break;
  193. case 'v':
  194. while (isascii(*++p) && isspace(*p))
  195. continue;
  196. map->map_valcolnm = p;
  197. break;
  198. case 'z':
  199. if (*++p != '\\')
  200. map->map_coldelim = *p;
  201. else
  202. {
  203. switch (*++p)
  204. {
  205. case 'n':
  206. map->map_coldelim = '\n';
  207. break;
  208. case 't':
  209. map->map_coldelim = '\t';
  210. break;
  211. default:
  212. map->map_coldelim = '\\';
  213. }
  214. }
  215. break;
  216. case 't':
  217. map->map_mflags |= MF_NODEFER;
  218. break;
  219. case 'S':
  220. map->map_spacesub = *++p;
  221. break;
  222. case 'D':
  223. map->map_mflags |= MF_DEFER;
  224. break;
  225. default:
  226. syserr("Illegal option %c map %s", *p, map->map_mname);
  227. break;
  228. }
  229. while (*p != '\0' && !(isascii(*p) && isspace(*p)))
  230. p++;
  231. if (*p != '\0')
  232. *p++ = '\0';
  233. }
  234. if (map->map_app != NULL)
  235. map->map_app = newstr(map->map_app);
  236. if (map->map_tapp != NULL)
  237. map->map_tapp = newstr(map->map_tapp);
  238. if (map->map_keycolnm != NULL)
  239. map->map_keycolnm = newstr(map->map_keycolnm);
  240. if (map->map_valcolnm != NULL)
  241. map->map_valcolnm = newstr(map->map_valcolnm);
  242. if (*p != '\0')
  243. {
  244. map->map_file = p;
  245. while (*p != '\0' && !(isascii(*p) && isspace(*p)))
  246. p++;
  247. if (*p != '\0')
  248. *p++ = '\0';
  249. map->map_file = newstr(map->map_file);
  250. }
  251. while (*p != '\0' && isascii(*p) && isspace(*p))
  252. p++;
  253. if (*p != '\0')
  254. map->map_rebuild = newstr(p);
  255. if (map->map_file == NULL &&
  256. !bitset(MCF_OPTFILE, map->map_class->map_cflags))
  257. {
  258. syserr("No file name for %s map %s",
  259. map->map_class->map_cname, map->map_mname);
  260. return false;
  261. }
  262. return true;
  263. }
  264. /*
  265. ** MAP_REWRITE -- rewrite a database key, interpolating %n indications.
  266. **
  267. ** It also adds the map_app string. It can be used as a utility
  268. ** in the map_lookup method.
  269. **
  270. ** Parameters:
  271. ** map -- the map that causes this.
  272. ** s -- the string to rewrite, NOT necessarily null terminated.
  273. ** slen -- the length of s.
  274. ** av -- arguments to interpolate into buf.
  275. **
  276. ** Returns:
  277. ** Pointer to rewritten result. This is static data that
  278. ** should be copied if it is to be saved!
  279. */
  280. char *
  281. map_rewrite(map, s, slen, av)
  282. register MAP *map;
  283. register const char *s;
  284. size_t slen;
  285. char **av;
  286. {
  287. register char *bp;
  288. register char c;
  289. char **avp;
  290. register char *ap;
  291. size_t l;
  292. size_t len;
  293. static size_t buflen = 0;
  294. static char *buf = NULL;
  295. if (tTd(39, 1))
  296. {
  297. sm_dprintf("map_rewrite(%.*s), av =", (int) slen, s);
  298. if (av == NULL)
  299. sm_dprintf(" (nullv)");
  300. else
  301. {
  302. for (avp = av; *avp != NULL; avp++)
  303. sm_dprintf("\n\t%s", *avp);
  304. }
  305. sm_dprintf("\n");
  306. }
  307. /* count expected size of output (can safely overestimate) */
  308. l = len = slen;
  309. if (av != NULL)
  310. {
  311. const char *sp = s;
  312. while (l-- > 0 && (c = *sp++) != '\0')
  313. {
  314. if (c != '%')
  315. continue;
  316. if (l-- <= 0)
  317. break;
  318. c = *sp++;
  319. if (!(isascii(c) && isdigit(c)))
  320. continue;
  321. for (avp = av; --c >= '0' && *avp != NULL; avp++)
  322. continue;
  323. if (*avp == NULL)
  324. continue;
  325. len += strlen(*avp);
  326. }
  327. }
  328. if (map->map_app != NULL)
  329. len += strlen(map->map_app);
  330. if (buflen < ++len)
  331. {
  332. /* need to malloc additional space */
  333. buflen = len;
  334. if (buf != NULL)
  335. sm_free(buf);
  336. buf = sm_pmalloc_x(buflen);
  337. }
  338. bp = buf;
  339. if (av == NULL)
  340. {
  341. memmove(bp, s, slen);
  342. bp += slen;
  343. /* assert(len > slen); */
  344. len -= slen;
  345. }
  346. else
  347. {
  348. while (slen-- > 0 && (c = *s++) != '\0')
  349. {
  350. if (c != '%')
  351. {
  352. pushc:
  353. if (len-- <= 1)
  354. break;
  355. *bp++ = c;
  356. continue;
  357. }
  358. if (slen-- <= 0 || (c = *s++) == '\0')
  359. c = '%';
  360. if (c == '%')
  361. goto pushc;
  362. if (!(isascii(c) && isdigit(c)))
  363. {
  364. if (len-- <= 1)
  365. break;
  366. *bp++ = '%';
  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++) != '\0' && len > 0; --len)
  375. *bp++ = c;
  376. }
  377. }
  378. if (map->map_app != NULL && len > 0)
  379. (void) sm_strlcpy(bp, map->map_app, len);
  380. else
  381. *bp = '\0';
  382. if (tTd(39, 1))
  383. sm_dprintf("map_rewrite => %s\n", 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_symtype != 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. sm_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. sm_dprintf("\tnot rebuildable\n");
  443. return;
  444. }
  445. /* if already open, close it (for nested open) */
  446. if (bitset(MF_OPEN, map->map_mflags))
  447. {
  448. map->map_mflags |= MF_CLOSING;
  449. map->map_class->map_close(map);
  450. map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
  451. }
  452. (void) rebuildaliases(map, false);
  453. return;
  454. }
  455. /*
  456. ** OPENMAP -- open a map
  457. **
  458. ** Parameters:
  459. ** map -- map to open (it must not be open).
  460. **
  461. ** Returns:
  462. ** whether open succeeded.
  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. sm_dprintf("openmap()\t%s:%s %s: valid\n",
  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 = CurrentPid;
  498. }
  499. else
  500. {
  501. if (tTd(38, 4))
  502. sm_dprintf("openmap()\t%s:%s %s: invalid%s%s\n",
  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 ? "" : sm_errstring(errno));
  511. if (!bitset(MF_OPTIONAL, map->map_mflags))
  512. {
  513. extern MAPCLASS BogusMapClass;
  514. map->map_orgclass = map->map_class;
  515. map->map_class = &BogusMapClass;
  516. map->map_mflags |= MF_OPEN|MF_OPENBOGUS;
  517. map->map_pid = CurrentPid;
  518. }
  519. else
  520. {
  521. /* don't try again */
  522. map->map_mflags &= ~MF_VALID;
  523. }
  524. }
  525. if (restore)
  526. {
  527. Errors = saveerrors;
  528. HoldErrs = savehold;
  529. QuickAbort = savequick;
  530. }
  531. return bitset(MF_OPEN, map->map_mflags);
  532. }
  533. /*
  534. ** CLOSEMAPS -- close all open maps opened by the current pid.
  535. **
  536. ** Parameters:
  537. ** bogus -- only close bogus maps.
  538. **
  539. ** Returns:
  540. ** none.
  541. */
  542. void
  543. closemaps(bogus)
  544. bool bogus;
  545. {
  546. stabapply(map_close, bogus);
  547. }
  548. /*
  549. ** MAP_CLOSE -- close a map opened by the current pid.
  550. **
  551. ** Parameters:
  552. ** s -- STAB entry: if map: try to close
  553. ** bogus -- only close bogus maps or MCF_NOTPERSIST maps.
  554. **
  555. ** Returns:
  556. ** none.
  557. */
  558. /* ARGSUSED1 */
  559. static void
  560. map_close(s, bogus)
  561. register STAB *s;
  562. int bogus; /* int because of stabapply(), used as bool */
  563. {
  564. MAP *map;
  565. extern MAPCLASS BogusMapClass;
  566. if (s->s_symtype != ST_MAP)
  567. return;
  568. map = &s->s_map;
  569. /*
  570. ** close the map iff:
  571. ** it is valid and open and opened by this process
  572. ** and (!bogus or it's a bogus map or it is not persistent)
  573. ** negate this: return iff
  574. ** it is not valid or it is not open or not opened by this process
  575. ** or (bogus and it's not a bogus map and it's not not-persistent)
  576. */
  577. if (!bitset(MF_VALID, map->map_mflags) ||
  578. !bitset(MF_OPEN, map->map_mflags) ||
  579. bitset(MF_CLOSING, map->map_mflags) ||
  580. map->map_pid != CurrentPid ||
  581. (bogus && map->map_class != &BogusMapClass &&
  582. !bitset(MCF_NOTPERSIST, map->map_class->map_cflags)))
  583. return;
  584. if (map->map_class == &BogusMapClass && map->map_orgclass != NULL &&
  585. map->map_orgclass != &BogusMapClass)
  586. map->map_class = map->map_orgclass;
  587. if (tTd(38, 5))
  588. sm_dprintf("closemaps: closing %s (%s)\n",
  589. map->map_mname == NULL ? "NULL" : map->map_mname,
  590. map->map_file == NULL ? "NULL" : map->map_file);
  591. if (!bitset(MF_OPENBOGUS, map->map_mflags))
  592. {
  593. map->map_mflags |= MF_CLOSING;
  594. map->map_class->map_close(map);
  595. }
  596. map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_OPENBOGUS|MF_CLOSING);
  597. }
  598. #if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN)
  599. extern int getdomainname();
  600. /* this is mainly for backward compatibility in Sun environment */
  601. static char *
  602. sun_init_domain()
  603. {
  604. /*
  605. ** Get the domain name from the kernel.
  606. ** If it does not start with a leading dot, then remove
  607. ** the first component. Since leading dots are funny Unix
  608. ** files, we treat a leading "+" the same as a leading dot.
  609. ** Finally, force there to be at least one dot in the domain name
  610. ** (i.e. top-level domains are not allowed, like "com", must be
  611. ** something like "sun.com").
  612. */
  613. char buf[MAXNAME];
  614. char *period, *autodomain;
  615. if (getdomainname(buf, sizeof buf) < 0)
  616. return NULL;
  617. if (buf[0] == '\0')
  618. return NULL;
  619. if (tTd(0, 20))
  620. printf("domainname = %s\n", buf);
  621. if (buf[0] == '+')
  622. buf[0] = '.';
  623. period = strchr(buf, '.');
  624. if (period == NULL)
  625. autodomain = buf;
  626. else
  627. autodomain = period + 1;
  628. if (strchr(autodomain, '.') == NULL)
  629. return newstr(buf);
  630. else
  631. return newstr(autodomain);
  632. }
  633. #endif /* SUN_EXTENSIONS && SUN_INIT_DOMAIN */
  634. /*
  635. ** GETCANONNAME -- look up name using service switch
  636. **
  637. ** Parameters:
  638. ** host -- the host name to look up.
  639. ** hbsize -- the size of the host buffer.
  640. ** trymx -- if set, try MX records.
  641. ** pttl -- pointer to return TTL (can be NULL).
  642. **
  643. ** Returns:
  644. ** true -- if the host was found.
  645. ** false -- otherwise.
  646. */
  647. bool
  648. getcanonname(host, hbsize, trymx, pttl)
  649. char *host;
  650. int hbsize;
  651. bool trymx;
  652. int *pttl;
  653. {
  654. int nmaps;
  655. int mapno;
  656. bool found = false;
  657. bool got_tempfail = false;
  658. auto int status = EX_UNAVAILABLE;
  659. char *maptype[MAXMAPSTACK];
  660. short mapreturn[MAXMAPACTIONS];
  661. #if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN)
  662. bool should_try_nis_domain = false;
  663. static char *nis_domain = NULL;
  664. #endif
  665. nmaps = switch_map_find("hosts", maptype, mapreturn);
  666. if (pttl != 0)
  667. *pttl = SM_DEFAULT_TTL;
  668. for (mapno = 0; mapno < nmaps; mapno++)
  669. {
  670. int i;
  671. if (tTd(38, 20))
  672. sm_dprintf("getcanonname(%s), trying %s\n",
  673. host, maptype[mapno]);
  674. if (strcmp("files", maptype[mapno]) == 0)
  675. {
  676. found = text_getcanonname(host, hbsize, &status);
  677. }
  678. #if NIS
  679. else if (strcmp("nis", maptype[mapno]) == 0)
  680. {
  681. found = nis_getcanonname(host, hbsize, &status);
  682. # if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN)
  683. if (nis_domain == NULL)
  684. nis_domain = sun_init_domain();
  685. # endif /* defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN) */
  686. }
  687. #endif /* NIS */
  688. #if NISPLUS
  689. else if (strcmp("nisplus", maptype[mapno]) == 0)
  690. {
  691. found = nisplus_getcanonname(host, hbsize, &status);
  692. # if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN)
  693. if (nis_domain == NULL)
  694. nis_domain = sun_init_domain();
  695. # endif /* defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN) */
  696. }
  697. #endif /* NISPLUS */
  698. #if NAMED_BIND
  699. else if (strcmp("dns", maptype[mapno]) == 0)
  700. {
  701. found = dns_getcanonname(host, hbsize, trymx, &status, pttl);
  702. }
  703. #endif /* NAMED_BIND */
  704. #if NETINFO
  705. else if (strcmp("netinfo", maptype[mapno]) == 0)
  706. {
  707. found = ni_getcanonname(host, hbsize, &status);
  708. }
  709. #endif /* NETINFO */
  710. else
  711. {
  712. found = false;
  713. status = EX_UNAVAILABLE;
  714. }
  715. /*
  716. ** Heuristic: if $m is not set, we are running during system
  717. ** startup. In this case, when a name is apparently found
  718. ** but has no dot, treat is as not found. This avoids
  719. ** problems if /etc/hosts has no FQDN but is listed first
  720. ** in the service switch.
  721. */
  722. if (found &&
  723. (macvalue('m', CurEnv) != NULL || strchr(host, '.') != NULL))
  724. break;
  725. #if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN)
  726. if (found)
  727. should_try_nis_domain = true;
  728. /* but don't break, as we need to try all methods first */
  729. #endif /* defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN) */
  730. /* see if we should continue */
  731. if (status == EX_TEMPFAIL)
  732. {
  733. i = MA_TRYAGAIN;
  734. got_tempfail = true;
  735. }
  736. else if (status == EX_NOTFOUND)
  737. i = MA_NOTFOUND;
  738. else
  739. i = MA_UNAVAIL;
  740. if (bitset(1 << mapno, mapreturn[i]))
  741. break;
  742. }
  743. if (found)
  744. {
  745. char *d;
  746. if (tTd(38, 20))
  747. sm_dprintf("getcanonname(%s), found\n", host);
  748. /*
  749. ** If returned name is still single token, compensate
  750. ** by tagging on $m. This is because some sites set
  751. ** up their DNS or NIS databases wrong.
  752. */
  753. if ((d = strchr(host, '.')) == NULL || d[1] == '\0')
  754. {
  755. d = macvalue('m', CurEnv);
  756. if (d != NULL &&
  757. hbsize > (int) (strlen(host) + strlen(d) + 1))
  758. {
  759. if (host[strlen(host) - 1] != '.')
  760. (void) sm_strlcat2(host, ".", d,
  761. hbsize);
  762. else
  763. (void) sm_strlcat(host, d, hbsize);
  764. }
  765. else
  766. {
  767. #if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN)
  768. if (VendorCode == VENDOR_SUN &&
  769. should_try_nis_domain)
  770. {
  771. goto try_nis_domain;
  772. }
  773. #endif /* defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN) */
  774. return false;
  775. }
  776. }
  777. return true;
  778. }
  779. #if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN)
  780. if (VendorCode == VENDOR_SUN && should_try_nis_domain)
  781. {
  782. try_nis_domain:
  783. if (nis_domain != NULL &&
  784. strlen(nis_domain) + strlen(host) + 1 < hbsize)
  785. {
  786. (void) sm_strlcat2(host, ".", nis_domain, hbsize);
  787. return true;
  788. }
  789. }
  790. #endif /* defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN) */
  791. if (tTd(38, 20))
  792. sm_dprintf("getcanonname(%s), failed, status=%d\n", host,
  793. status);
  794. if (got_tempfail)
  795. SM_SET_H_ERRNO(TRY_AGAIN);
  796. else
  797. SM_SET_H_ERRNO(HOST_NOT_FOUND);
  798. return false;
  799. }
  800. /*
  801. ** EXTRACT_CANONNAME -- extract canonical name from /etc/hosts entry
  802. **
  803. ** Parameters:
  804. ** name -- the name against which to match.
  805. ** dot -- where to reinsert '.' to get FQDN
  806. ** line -- the /etc/hosts line.
  807. ** cbuf -- the location to store the result.
  808. ** cbuflen -- the size of cbuf.
  809. **
  810. ** Returns:
  811. ** true -- if the line matched the desired name.
  812. ** false -- otherwise.
  813. */
  814. static bool
  815. extract_canonname(name, dot, line, cbuf, cbuflen)
  816. char *name;
  817. char *dot;
  818. char *line;
  819. char cbuf[];
  820. int cbuflen;
  821. {
  822. int i;
  823. char *p;
  824. bool found = false;
  825. cbuf[0] = '\0';
  826. if (line[0] == '#')
  827. return false;
  828. for (i = 1; ; i++)
  829. {
  830. char nbuf[MAXNAME + 1];
  831. p = get_column(line, i, '\0', nbuf, sizeof(nbuf));
  832. if (p == NULL)
  833. break;
  834. if (*p == '\0')
  835. continue;
  836. if (cbuf[0] == '\0' ||
  837. (strchr(cbuf, '.') == NULL && strchr(p, '.') != NULL))
  838. {
  839. (void) sm_strlcpy(cbuf, p, cbuflen);
  840. }
  841. if (sm_strcasecmp(name, p) == 0)
  842. found = true;
  843. else if (dot != NULL)
  844. {
  845. /* try looking for the FQDN as well */
  846. *dot = '.';
  847. if (sm_strcasecmp(name, p) == 0)
  848. found = true;
  849. *dot = '\0';
  850. }
  851. }
  852. if (found && strchr(cbuf, '.') == NULL)
  853. {
  854. /* try to add a domain on the end of the name */
  855. char *domain = macvalue('m', CurEnv);
  856. if (domain != NULL &&
  857. strlen(domain) + (i = strlen(cbuf)) + 1 < (size_t) cbuflen)
  858. {
  859. p = &cbuf[i];
  860. *p++ = '.';
  861. (void) sm_strlcpy(p, domain, cbuflen - i - 1);
  862. }
  863. }
  864. return found;
  865. }
  866. /*
  867. ** DNS modules
  868. */
  869. #if NAMED_BIND
  870. # if DNSMAP
  871. # include "sm_resolve.h"
  872. # if NETINET || NETINET6
  873. # include <arpa/inet.h>
  874. # endif /* NETINET || NETINET6 */
  875. /*
  876. ** DNS_MAP_OPEN -- stub to check proper value for dns map type
  877. */
  878. bool
  879. dns_map_open(map, mode)
  880. MAP *map;
  881. int mode;
  882. {
  883. if (tTd(38,2))
  884. sm_dprintf("dns_map_open(%s, %d)\n", map->map_mname, mode);
  885. mode &= O_ACCMODE;
  886. if (mode != O_RDONLY)
  887. {
  888. /* issue a pseudo-error message */
  889. errno = SM_EMAPCANTWRITE;
  890. return false;
  891. }
  892. return true;
  893. }
  894. /*
  895. ** DNS_MAP_PARSEARGS -- parse dns map definition args.
  896. **
  897. ** Parameters:
  898. ** map -- pointer to MAP
  899. ** args -- pointer to the args on the config line.
  900. **
  901. ** Returns:
  902. ** true -- if everything parsed OK.
  903. ** false -- otherwise.
  904. */
  905. #define map_sizelimit map_lockfd /* overload field */
  906. struct dns_map
  907. {
  908. int dns_m_type;
  909. };
  910. bool
  911. dns_map_parseargs(map,args)
  912. MAP *map;
  913. char *args;
  914. {
  915. register char *p = args;
  916. struct dns_map *map_p;
  917. map_p = (struct dns_map *) xalloc(sizeof(*map_p));
  918. map_p->dns_m_type = -1;
  919. map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
  920. for (;;)
  921. {
  922. while (isascii(*p) && isspace(*p))
  923. p++;
  924. if (*p != '-')
  925. break;
  926. switch (*++p)
  927. {
  928. case 'N':
  929. map->map_mflags |= MF_INCLNULL;
  930. map->map_mflags &= ~MF_TRY0NULL;
  931. break;
  932. case 'O':
  933. map->map_mflags &= ~MF_TRY1NULL;
  934. break;
  935. case 'o':
  936. map->map_mflags |= MF_OPTIONAL;
  937. break;
  938. case 'f':
  939. map->map_mflags |= MF_NOFOLDCASE;
  940. break;
  941. case 'm':
  942. map->map_mflags |= MF_MATCHONLY;
  943. break;
  944. case 'A':
  945. map->map_mflags |= MF_APPEND;
  946. break;
  947. case 'q':
  948. map->map_mflags |= MF_KEEPQUOTES;
  949. break;
  950. case 't':
  951. map->map_mflags |= MF_NODEFER;
  952. break;
  953. case 'a':
  954. map->map_app = ++p;
  955. break;
  956. case 'T':
  957. map->map_tapp = ++p;
  958. break;
  959. case 'd':
  960. {
  961. char *h;
  962. ++p;
  963. h = strchr(p, ' ');
  964. if (h != NULL)
  965. *h = '\0';
  966. map->map_timeout = convtime(p, 's');
  967. if (h != NULL)
  968. *h = ' ';
  969. }
  970. break;
  971. case 'r':
  972. while (isascii(*++p) && isspace(*p))
  973. continue;
  974. map->map_retry = atoi(p);
  975. break;
  976. case 'z':
  977. if (*++p != '\\')
  978. map->map_coldelim = *p;
  979. else
  980. {
  981. switch (*++p)
  982. {
  983. case 'n':
  984. map->map_coldelim = '\n';
  985. break;
  986. case 't':
  987. map->map_coldelim = '\t';
  988. break;
  989. default:
  990. map->map_coldelim = '\\';
  991. }
  992. }
  993. break;
  994. case 'Z':
  995. while (isascii(*++p) && isspace(*p))
  996. continue;
  997. map->map_sizelimit = atoi(p);
  998. break;
  999. /* Start of dns_map specific args */
  1000. case 'R': /* search field */
  1001. {
  1002. char *h;
  1003. while (isascii(*++p) && isspace(*p))
  1004. continue;
  1005. h = strchr(p, ' ');
  1006. if (h != NULL)
  1007. *h = '\0';
  1008. map_p->dns_m_type = dns_string_to_type(p);
  1009. if (h != NULL)
  1010. *h = ' ';
  1011. if (map_p->dns_m_type < 0)
  1012. syserr("dns map %s: wrong type %s",
  1013. map->map_mname, p);
  1014. }
  1015. break;
  1016. case 'B': /* base domain */
  1017. {
  1018. char *h;
  1019. while (isascii(*++p) && isspace(*p))
  1020. continue;
  1021. h = strchr(p, ' ');
  1022. if (h != NULL)
  1023. *h = '\0';
  1024. /*
  1025. ** slight abuse of map->map_file; it isn't
  1026. ** used otherwise in this map type.
  1027. */
  1028. map->map_file = newstr(p);
  1029. if (h != NULL)
  1030. *h = ' ';
  1031. }
  1032. break;
  1033. }
  1034. while (*p != '\0' && !(isascii(*p) && isspace(*p)))
  1035. p++;
  1036. if (*p != '\0')
  1037. *p++ = '\0';
  1038. }
  1039. if (map_p->dns_m_type < 0)
  1040. syserr("dns map %s: missing -R type", map->map_mname);
  1041. if (map->map_app != NULL)
  1042. map->map_app = newstr(map->map_app);
  1043. if (map->map_tapp != NULL)
  1044. map->map_tapp = newstr(map->map_tapp);
  1045. /*
  1046. ** Assumption: assert(sizeof(int) <= sizeof(ARBPTR_T));
  1047. ** Even if this assumption is wrong, we use only one byte,
  1048. ** so it doesn't really matter.
  1049. */
  1050. map->map_db1 = (ARBPTR_T) map_p;
  1051. return true;
  1052. }
  1053. /*
  1054. ** DNS_MAP_LOOKUP -- perform dns map lookup.
  1055. **
  1056. ** Parameters:
  1057. ** map -- pointer to MAP
  1058. ** name -- name to lookup
  1059. ** av -- arguments to interpolate into buf.
  1060. ** statp -- pointer to status (EX_)
  1061. **
  1062. ** Returns:
  1063. ** result of lookup if succeeded.
  1064. ** NULL -- otherwise.
  1065. */
  1066. char *
  1067. dns_map_lookup(map, name, av, statp)
  1068. MAP *map;
  1069. char *name;
  1070. char **av;
  1071. int *statp;
  1072. {
  1073. int resnum = 0;
  1074. char *vp = NULL, *result = NULL;
  1075. size_t vsize;
  1076. struct dns_map *map_p;
  1077. RESOURCE_RECORD_T *rr = NULL;
  1078. DNS_REPLY_T *r = NULL;
  1079. # if NETINET6
  1080. static char buf6[INET6_ADDRSTRLEN];
  1081. # endif /* NETINET6 */
  1082. if (tTd(38, 20))
  1083. sm_dprintf("dns_map_lookup(%s, %s)\n",
  1084. map->map_mname, name);
  1085. map_p = (struct dns_map *)(map->map_db1);
  1086. if (map->map_file != NULL && *map->map_file != '\0')
  1087. {
  1088. size_t len;
  1089. char *appdomain;
  1090. len = strlen(map->map_file) + strlen(name) + 2;
  1091. appdomain = (char *) sm_malloc(len);
  1092. if (appdomain == NULL)
  1093. {
  1094. *statp = EX_UNAVAILABLE;
  1095. return NULL;
  1096. }
  1097. (void) sm_strlcpyn(appdomain, len, 3, name, ".", map->map_file);
  1098. r = dns_lookup_int(appdomain, C_IN, map_p->dns_m_type,
  1099. map->map_timeout, map->map_retry);
  1100. sm_free(appdomain);
  1101. }
  1102. else
  1103. {
  1104. r = dns_lookup_int(name, C_IN, map_p->dns_m_type,
  1105. map->map_timeout, map->map_retry);
  1106. }
  1107. if (r == NULL)
  1108. {
  1109. result = NULL;
  1110. if (h_errno == TRY_AGAIN || transienterror(errno))
  1111. *statp = EX_TEMPFAIL;
  1112. else
  1113. *statp = EX_NOTFOUND;
  1114. goto cleanup;
  1115. }
  1116. *statp = EX_OK;
  1117. for (rr = r->dns_r_head; rr != NULL; rr = rr->rr_next)
  1118. {
  1119. char *type = NULL;
  1120. char *value = NULL;
  1121. switch (rr->rr_type)
  1122. {
  1123. case T_NS:
  1124. type = "T_NS";
  1125. value = rr->rr_u.rr_txt;
  1126. break;
  1127. case T_CNAME:
  1128. type = "T_CNAME";
  1129. value = rr->rr_u.rr_txt;
  1130. break;
  1131. case T_AFSDB:
  1132. type = "T_AFSDB";
  1133. value = rr->rr_u.rr_mx->mx_r_domain;
  1134. break;
  1135. case T_SRV:
  1136. type = "T_SRV";
  1137. value = rr->rr_u.rr_srv->srv_r_target;
  1138. break;
  1139. case T_PTR:
  1140. type = "T_PTR";
  1141. value = rr->rr_u.rr_txt;
  1142. break;
  1143. case T_TXT:
  1144. type = "T_TXT";
  1145. value = rr->rr_u.rr_txt;
  1146. break;
  1147. case T_MX:
  1148. type = "T_MX";
  1149. value = rr->rr_u.rr_mx->mx_r_domain;
  1150. break;
  1151. # if NETINET
  1152. case T_A:
  1153. type = "T_A";
  1154. value = inet_ntoa(*(rr->rr_u.rr_a));
  1155. break;
  1156. # endif /* NETINET */
  1157. # if NETINET6
  1158. case T_AAAA:
  1159. type = "T_AAAA";
  1160. value = anynet_ntop(rr->rr_u.rr_aaaa, buf6,
  1161. sizeof(buf6));
  1162. break;
  1163. # endif /* NETINET6 */
  1164. }
  1165. (void) strreplnonprt(value, 'X');
  1166. if (map_p->dns_m_type != rr->rr_type)
  1167. {
  1168. if (tTd(38, 40))
  1169. sm_dprintf("\tskipping type %s (%d) value %s\n",
  1170. type != NULL ? type : "<UNKNOWN>",
  1171. rr->rr_type,
  1172. value != NULL ? value : "<NO VALUE>");
  1173. continue;
  1174. }
  1175. # if NETINET6
  1176. if (rr->rr_type == T_AAAA && value == NULL)
  1177. {
  1178. result = NULL;
  1179. *statp = EX_DATAERR;
  1180. if (tTd(38, 40))
  1181. sm_dprintf("\tbad T_AAAA conversion\n");
  1182. goto cleanup;
  1183. }
  1184. # endif /* NETINET6 */
  1185. if (tTd(38, 40))
  1186. sm_dprintf("\tfound type %s (%d) value %s\n",
  1187. type != NULL ? type : "<UNKNOWN>",
  1188. rr->rr_type,
  1189. value != NULL ? value : "<NO VALUE>");
  1190. if (value != NULL &&
  1191. (map->map_coldelim == '\0' ||
  1192. map->map_sizelimit == 1 ||
  1193. bitset(MF_MATCHONLY, map->map_mflags)))
  1194. {
  1195. /* Only care about the first match */
  1196. vp = newstr(value);
  1197. break;
  1198. }
  1199. else if (vp == NULL)
  1200. {
  1201. /* First result */
  1202. vp = newstr(value);
  1203. }
  1204. else
  1205. {
  1206. /* concatenate the results */
  1207. int sz;
  1208. char *new;
  1209. sz = strlen(vp) + strlen(value) + 2;
  1210. new = xalloc(sz);
  1211. (void) sm_snprintf(new, sz, "%s%c%s",
  1212. vp, map->map_coldelim, value);
  1213. sm_free(vp);
  1214. vp = new;
  1215. if (map->map_sizelimit > 0 &&
  1216. ++resnum >= map->map_sizelimit)
  1217. break;
  1218. }
  1219. }
  1220. if (vp == NULL)
  1221. {
  1222. result = NULL;
  1223. *statp = EX_NOTFOUND;
  1224. if (tTd(38, 40))
  1225. sm_dprintf("\tno match found\n");
  1226. goto cleanup;
  1227. }
  1228. /* Cleanly truncate for rulesets */
  1229. truncate_at_delim(vp, PSBUFSIZE / 2, map->map_coldelim);
  1230. vsize = strlen(vp);
  1231. if (LogLevel > 9)
  1232. sm_syslog(LOG_INFO, CurEnv->e_id, "dns %.100s => %s",
  1233. name, vp);
  1234. if (bitset(MF_MATCHONLY, map->map_mflags))
  1235. result = map_rewrite(map, name, strlen(name), NULL);
  1236. else
  1237. result = map_rewrite(map, vp, vsize, av);
  1238. cleanup:
  1239. if (vp != NULL)
  1240. sm_free(vp);
  1241. if (r != NULL)
  1242. dns_free_data(r);
  1243. return result;
  1244. }
  1245. # endif /* DNSMAP */
  1246. #endif /* NAMED_BIND */
  1247. /*
  1248. ** NDBM modules
  1249. */
  1250. #if NDBM
  1251. /*
  1252. ** NDBM_MAP_OPEN -- DBM-style map open
  1253. */
  1254. bool
  1255. ndbm_map_open(map, mode)
  1256. MAP *map;
  1257. int mode;
  1258. {
  1259. register DBM *dbm;
  1260. int save_errno;
  1261. int dfd;
  1262. int pfd;
  1263. long sff;
  1264. int ret;
  1265. int smode = S_IREAD;
  1266. char dirfile[MAXPATHLEN];
  1267. char pagfile[MAXPATHLEN];
  1268. struct stat st;
  1269. struct stat std, stp;
  1270. if (tTd(38, 2))
  1271. sm_dprintf("ndbm_map_open(%s, %s, %d)\n",
  1272. map->map_mname, map->map_file, mode);
  1273. map->map_lockfd = -1;
  1274. mode &= O_ACCMODE;
  1275. /* do initial file and directory checks */
  1276. if (sm_strlcpyn(dirfile, sizeof(dirfile), 2,
  1277. map->map_file, ".dir") >= sizeof(dirfile) ||
  1278. sm_strlcpyn(pagfile, sizeof(pagfile), 2,
  1279. map->map_file, ".pag") >= sizeof(pagfile))
  1280. {
  1281. errno = 0;
  1282. if (!bitset(MF_OPTIONAL, map->map_mflags))
  1283. syserr("dbm map \"%s\": map file %s name too long",
  1284. map->map_mname, map->map_file);
  1285. return false;
  1286. }
  1287. sff = SFF_ROOTOK|SFF_REGONLY;
  1288. if (mode == O_RDWR)
  1289. {
  1290. sff |= SFF_CREAT;
  1291. if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
  1292. sff |= SFF_NOSLINK;
  1293. if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
  1294. sff |= SFF_NOHLINK;
  1295. smode = S_IWRITE;
  1296. }
  1297. else
  1298. {
  1299. if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
  1300. sff |= SFF_NOWLINK;
  1301. }
  1302. if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
  1303. sff |= SFF_SAFEDIRPATH;
  1304. ret = safefile(dirfile, RunAsUid, RunAsGid, RunAsUserName,
  1305. sff, smode, &std);
  1306. if (ret == 0)
  1307. ret = safefile(pagfile, RunAsUid, RunAsGid, RunAsUserName,
  1308. sff, smode, &stp);
  1309. if (ret != 0)
  1310. {
  1311. char *prob = "unsafe";
  1312. /* cannot open this map */
  1313. if (ret == ENOENT)
  1314. prob = "missing";
  1315. if (tTd(38, 2))
  1316. sm_dprintf("\t%s map file: %d\n", prob, ret);
  1317. if (!bitset(MF_OPTIONAL, map->map_mflags))
  1318. syserr("dbm map \"%s\": %s map file %s",
  1319. map->map_mname, prob, map->map_file);
  1320. return false;
  1321. }
  1322. if (std.st_mode == ST_MODE_NOFILE)
  1323. mode |= O_CREAT|O_EXCL;
  1324. # if LOCK_ON_OPEN
  1325. if (mode == O_RDONLY)
  1326. mode |= O_SHLOCK;
  1327. else
  1328. mode |= O_TRUNC|O_EXLOCK;
  1329. # else /* LOCK_ON_OPEN */
  1330. if ((mode & O_ACCMODE) == O_RDWR)
  1331. {
  1332. # if NOFTRUNCATE
  1333. /*
  1334. ** Warning: race condition. Try to lock the file as
  1335. ** quickly as possible after opening it.
  1336. ** This may also have security problems on some systems,
  1337. ** but there isn't anything we can do about it.
  1338. */
  1339. mode |= O_TRUNC;
  1340. # else /* NOFTRUNCATE */
  1341. /*
  1342. ** This ugly code opens the map without truncating it,
  1343. ** locks the file, then truncates it. Necessary to
  1344. ** avoid race conditions.
  1345. */
  1346. int dirfd;
  1347. int pagfd;
  1348. long sff = SFF_CREAT|SFF_OPENASROOT;
  1349. if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
  1350. sff |= SFF_NOSLINK;
  1351. if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
  1352. sff |= SFF_NOHLINK;
  1353. dirfd = safeopen(dirfile, mode, DBMMODE, sff);
  1354. pagfd = safeopen(pagfile, mode, DBMMODE, sff);
  1355. if (dirfd < 0 || pagfd < 0)
  1356. {
  1357. save_errno = errno;
  1358. if (dirfd >= 0)
  1359. (void) close(dirfd);
  1360. if (pagfd >= 0)
  1361. (void) close(pagfd);
  1362. errno = save_errno;
  1363. syserr("ndbm_map_open: cannot create database %s",
  1364. map->map_file);
  1365. return false;
  1366. }
  1367. if (ftruncate(dirfd, (off_t) 0) < 0 ||
  1368. ftruncate(pagfd, (off_t) 0) < 0)
  1369. {
  1370. save_errno = errno;
  1371. (void) close(dirfd);
  1372. (void) close(pagfd);
  1373. errno = save_errno;
  1374. syserr("ndbm_map_open: cannot truncate %s.{dir,pag}",
  1375. map->map_file);
  1376. return false;
  1377. }
  1378. /* if new file, get "before" bits for later filechanged check */
  1379. if (std.st_mode == ST_MODE_NOFILE &&
  1380. (fstat(dirfd, &std) < 0 || fstat(pagfd, &stp) < 0))
  1381. {
  1382. save_errno = errno;
  1383. (void) close(dirfd);
  1384. (void) close(pagfd);
  1385. errno = save_errno;
  1386. syserr("ndbm_map_open(%s.{dir,pag}): cannot fstat pre-opened file",
  1387. map->map_file);
  1388. return false;
  1389. }
  1390. /* have to save the lock for the duration (bletch) */
  1391. map->map_lockfd = dirfd;
  1392. (void) close(pagfd);
  1393. /* twiddle bits for dbm_open */
  1394. mode &= ~(O_CREAT|O_EXCL);
  1395. # endif /* NOFTRUNCATE */
  1396. }
  1397. # endif /* LOCK_ON_OPEN */
  1398. /* open the database */
  1399. dbm = dbm_open(map->map_file, mode, DBMMODE);
  1400. if (dbm == NULL)
  1401. {
  1402. save_errno = errno;
  1403. if (bitset(MF_ALIAS, map->map_mflags) &&
  1404. aliaswait(map, ".pag", false))
  1405. return true;
  1406. # if !LOCK_ON_OPEN && !NOFTRUNCATE
  1407. if (map->map_lockfd >= 0)
  1408. (void) close(map->map_lockfd);
  1409. # endif /* !LOCK_ON_OPEN && !NOFTRUNCATE */
  1410. errno = save_errno;
  1411. if (!bitset(MF_OPTIONAL, map->map_mflags))
  1412. syserr("Cannot open DBM database %s", map->map_file);
  1413. return false;
  1414. }
  1415. dfd = dbm_dirfno(dbm);
  1416. pfd = dbm_pagfno(dbm);
  1417. if (dfd == pfd)
  1418. {
  1419. /* heuristic: if files are linked, this is actually gdbm */
  1420. dbm_close(dbm);
  1421. # if !LOCK_ON_OPEN && !NOFTRUNCATE
  1422. if (map->map_lockfd >= 0)
  1423. (void) close(map->map_lockfd);
  1424. # endif /* !LOCK_ON_OPEN && !NOFTRUNCATE */
  1425. errno = 0;
  1426. syserr("dbm map \"%s\": cannot support GDBM",
  1427. map->map_mname);
  1428. return false;
  1429. }
  1430. if (filechanged(dirfile, dfd, &std) ||
  1431. filechanged(pagfile, pfd, &stp))
  1432. {
  1433. save_errno = errno;
  1434. dbm_close(dbm);
  1435. # if !LOCK_ON_OPEN && !NOFTRUNCATE
  1436. if (map->map_lockfd >= 0)
  1437. (void) close(map->map_lockfd);
  1438. # endif /* !LOCK_ON_OPEN && !NOFTRUNCATE */
  1439. errno = save_errno;
  1440. syserr("ndbm_map_open(%s): file changed after open",
  1441. map->map_file);
  1442. return false;
  1443. }
  1444. map->map_db1 = (ARBPTR_T) dbm;
  1445. /*
  1446. ** Need to set map_mtime before the call to aliaswait()
  1447. ** as aliaswait() will call map_lookup() which requires
  1448. ** map_mtime to be set
  1449. */
  1450. if (fstat(pfd, &st) >= 0)
  1451. map->map_mtime = st.st_mtime;
  1452. if (mode == O_RDONLY)
  1453. {
  1454. # if LOCK_ON_OPEN
  1455. if (dfd >= 0)
  1456. (void) lockfile(dfd, map->map_file, ".dir", LOCK_UN);
  1457. if (pfd >= 0)
  1458. (void) lockfile(pfd, map->map_file, ".pag", LOCK_UN);
  1459. # endif /* LOCK_ON_OPEN */
  1460. if (bitset(MF_ALIAS, map->map_mflags) &&
  1461. !aliaswait(map, ".pag", true))
  1462. return false;
  1463. }
  1464. else
  1465. {
  1466. map->map_mflags |= MF_LOCKED;
  1467. if (geteuid() == 0 && TrustedUid != 0)
  1468. {
  1469. # if HASFCHOWN
  1470. if (fchown(dfd, TrustedUid, -1) < 0 ||
  1471. fchown(pfd, TrustedUid, -1) < 0)
  1472. {
  1473. int err = errno;
  1474. sm_syslog(LOG_ALERT, NOQID,
  1475. "ownership change on %s failed: %s",
  1476. map->map_file, sm_errstring(err));
  1477. message("050 ownership change on %s failed: %s",
  1478. map->map_file, sm_errstring(err));
  1479. }
  1480. # else /* HASFCHOWN */
  1481. sm_syslog(LOG_ALERT, NOQID,
  1482. "no fchown(): cannot change ownership on %s",
  1483. map->map_file);
  1484. message("050 no fchown(): cannot change ownership on %s",
  1485. map->map_file);
  1486. # endif /* HASFCHOWN */
  1487. }
  1488. }
  1489. return true;
  1490. }
  1491. /*
  1492. ** NDBM_MAP_LOOKUP -- look up a datum in a DBM-type map
  1493. */
  1494. char *
  1495. ndbm_map_lookup(map, name, av, statp)
  1496. MAP *map;
  1497. char *name;
  1498. char **av;
  1499. int *statp;
  1500. {
  1501. datum key, val;
  1502. int dfd, pfd;
  1503. char keybuf[MAXNAME + 1];
  1504. struct stat stbuf;
  1505. if (tTd(38, 20))
  1506. sm_dprintf("ndbm_map_lookup(%s, %s)\n",
  1507. map->map_mname, name);
  1508. key.dptr = name;
  1509. key.dsize = strlen(name);
  1510. if (!bitset(MF_NOFOLDCASE, map->map_mflags))
  1511. {
  1512. if (key.dsize > sizeof(keybuf) - 1)
  1513. key.dsize = sizeof(keybuf) - 1;
  1514. memmove(keybuf, key.dptr, key.dsize);
  1515. keybuf[key.dsize] = '\0';
  1516. makelower(keybuf);
  1517. key.dptr = keybuf;
  1518. }
  1519. lockdbm:
  1520. dfd = dbm_dirfno((DBM *) map->map_db1);
  1521. if (dfd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
  1522. (void) lockfile(dfd, map->map_file, ".dir", LOCK_SH);
  1523. pfd = dbm_pagfno((DBM *) map->map_db1);
  1524. if (pfd < 0 || fstat(pfd, &stbuf) < 0 ||
  1525. stbuf.st_mtime > map->map_mtime)
  1526. {
  1527. /* Reopen the database to sync the cache */
  1528. int omode = bitset(map->map_mflags, MF_WRITABLE) ? O_RDWR
  1529. : O_RDONLY;
  1530. if (dfd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
  1531. (void) lockfile(dfd, map->map_file, ".dir", LOCK_UN);
  1532. map->map_mflags |= MF_CLOSING;
  1533. map->map_class->map_close(map);
  1534. map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
  1535. if (map->map_class->map_open(map, omode))
  1536. {
  1537. map->map_mflags |= MF_OPEN;
  1538. map->map_pid = CurrentPid;
  1539. if ((omode & O_ACCMODE) == O_RDWR)
  1540. map->map_mflags |= MF_WRITABLE;
  1541. goto lockdbm;
  1542. }
  1543. else
  1544. {
  1545. if (!bitset(MF_OPTIONAL, map->map_mflags))
  1546. {
  1547. extern MAPCLASS BogusMapClass;
  1548. *statp = EX_TEMPFAIL;
  1549. map->map_orgclass = map->map_class;
  1550. map->map_class = &BogusMapClass;
  1551. map->map_mflags |= MF_OPEN;
  1552. map->map_pid = CurrentPid;
  1553. syserr("Cannot reopen NDBM database %s",
  1554. map->map_file);
  1555. }
  1556. return NULL;
  1557. }
  1558. }
  1559. val.dptr = NULL;
  1560. if (bitset(MF_TRY0NULL, map->map_mflags))
  1561. {
  1562. val = dbm_fetch((DBM *) map->map_db1, key);
  1563. if (val.dptr != NULL)
  1564. map->map_mflags &= ~MF_TRY1NULL;
  1565. }
  1566. if (val.dptr == NULL && bitset(MF_TRY1NULL, map->map_mflags))
  1567. {
  1568. key.dsize++;
  1569. val = dbm_fetch((DBM *) map->map_db1, key);
  1570. if (val.dptr != NULL)
  1571. map->map_mflags &= ~MF_TRY0NULL;
  1572. }
  1573. if (dfd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
  1574. (void) lockfile(dfd, map->map_file, ".dir", LOCK_UN);
  1575. if (val.dptr == NULL)
  1576. return NULL;
  1577. if (bitset(MF_MATCHONLY, map->map_mflags))
  1578. return map_rewrite(map, name, strlen(name), NULL);
  1579. else
  1580. return map_rewrite(map, val.dptr, val.dsize, av);
  1581. }
  1582. /*
  1583. ** NDBM_MAP_STORE -- store a datum in the database
  1584. */
  1585. void
  1586. ndbm_map_store(map, lhs, rhs)
  1587. register MAP *map;
  1588. char *lhs;
  1589. char *rhs;
  1590. {
  1591. datum key;
  1592. datum data;
  1593. int status;
  1594. char keybuf[MAXNAME + 1];
  1595. if (tTd(38, 12))
  1596. sm_dprintf("ndbm_map_store(%s, %s, %s)\n",
  1597. map->map_mname, lhs, rhs);
  1598. key.dsize = strlen(lhs);
  1599. key.dptr = lhs;
  1600. if (!bitset(MF_NOFOLDCASE, map->map_mflags))
  1601. {
  1602. if (key.dsize > sizeof(keybuf) - 1)
  1603. key.dsize = sizeof(keybuf) - 1;
  1604. memmove(keybuf, key.dptr, key.dsize);
  1605. keybuf[key.dsize] = '\0';
  1606. makelower(keybuf);
  1607. key.dptr = keybuf;
  1608. }
  1609. data.dsize = strlen(rhs);
  1610. data.dptr = rhs;
  1611. if (bitset(MF_INCLNULL, map->map_mflags))
  1612. {
  1613. key.dsize++;
  1614. data.dsize++;
  1615. }
  1616. status = dbm_store((DBM *) map->map_db1, key, data, DBM_INSERT);
  1617. if (status > 0)
  1618. {
  1619. if (!bitset(MF_APPEND, map->map_mflags))
  1620. message("050 Warning: duplicate alias name %s", lhs);
  1621. else
  1622. {
  1623. static char *buf = NULL;
  1624. static int bufsiz = 0;
  1625. auto int xstat;
  1626. datum old;
  1627. old.dptr = ndbm_map_lookup(map, key.dptr,
  1628. (char **) NULL, &xstat);
  1629. if (old.dptr != NULL && *(char *) old.dptr != '\0')
  1630. {
  1631. old.dsize = strlen(old.dptr);
  1632. if (data.dsize + old.dsize + 2 > bufsiz)
  1633. {
  1634. if (buf != NULL)
  1635. (void) sm_free(buf);
  1636. bufsiz = data.dsize + old.dsize + 2;
  1637. buf = sm_pmalloc_x(bufsiz);
  1638. }
  1639. (void) sm_strlcpyn(buf, bufsiz, 3,
  1640. data.dptr, ",", old.dptr);
  1641. data.dsize = data.dsize + old.dsize + 1;
  1642. data.dptr = buf;
  1643. if (tTd(38, 9))
  1644. sm_dprintf("ndbm_map_store append=%s\n",
  1645. data.dptr);
  1646. }
  1647. }
  1648. status = dbm_store((DBM *) map->map_db1,
  1649. key, data, DBM_REPLACE);
  1650. }
  1651. if (status != 0)
  1652. syserr("readaliases: dbm put (%s): %d", lhs, status);
  1653. }
  1654. /*
  1655. ** NDBM_MAP_CLOSE -- close the database
  1656. */
  1657. void
  1658. ndbm_map_close(map)
  1659. register MAP *map;
  1660. {
  1661. if (tTd(38, 9))
  1662. sm_dprintf("ndbm_map_close(%s, %s, %lx)\n",
  1663. map->map_mname, map->map_file, map->map_mflags);
  1664. if (bitset(MF_WRITABLE, map->map_mflags))
  1665. {
  1666. # ifdef NDBM_YP_COMPAT
  1667. bool inclnull;
  1668. char buf[MAXHOSTNAMELEN];
  1669. inclnull = bitset(MF_INCLNULL, map->map_mflags);
  1670. map->map_mflags &= ~MF_INCLNULL;
  1671. if (strstr(map->map_file, "/yp/") != NULL)
  1672. {
  1673. long save_mflags = map->map_mflags;
  1674. map->map_mflags |= MF_NOFOLDCASE;
  1675. (void) sm_snprintf(buf, sizeof(buf), "%010ld", curtime());
  1676. ndbm_map_store(map, "YP_LAST_MODIFIED", buf);
  1677. (void) gethostname(buf, sizeof(buf));
  1678. ndbm_map_store(map, "YP_MASTER_NAME", buf);
  1679. map->map_mflags = save_mflags;
  1680. }
  1681. if (inclnull)
  1682. map->map_mflags |= MF_INCLNULL;
  1683. # endif /* NDBM_YP_COMPAT */
  1684. /* write out the distinguished alias */
  1685. ndbm_map_store(map, "@", "@");
  1686. }
  1687. dbm_close((DBM *) map->map_db1);
  1688. /* release lock (if needed) */
  1689. # if !LOCK_ON_OPEN
  1690. if (map->map_lockfd >= 0)
  1691. (void) close(map->map_lockfd);
  1692. # endif /* !LOCK_ON_OPEN */
  1693. }
  1694. #endif /* NDBM */
  1695. /*
  1696. ** NEWDB (Hash and BTree) Modules
  1697. */
  1698. #if NEWDB
  1699. /*
  1700. ** BT_MAP_OPEN, HASH_MAP_OPEN -- database open primitives.
  1701. **
  1702. ** These do rather bizarre locking. If you can lock on open,
  1703. ** do that to avoid the condition of opening a database that
  1704. ** is being rebuilt. If you don't, we'll try to fake it, but
  1705. ** there will be a race condition. If opening for read-only,
  1706. ** we immediately release the lock to avoid freezing things up.
  1707. ** We really ought to hold the lock, but guarantee that we won't
  1708. ** be pokey about it. That's hard to do.
  1709. */
  1710. /* these should be K line arguments */
  1711. # if DB_VERSION_MAJOR < 2
  1712. # define db_cachesize cachesize
  1713. # define h_nelem nelem
  1714. # ifndef DB_CACHE_SIZE
  1715. # define DB_CACHE_SIZE (1024 * 1024) /* database memory cache size */
  1716. # endif /* ! DB_CACHE_SIZE */
  1717. # ifndef DB_HASH_NELEM
  1718. # define DB_HASH_NELEM 4096 /* (starting) size of hash table */
  1719. # endif /* ! DB_HASH_NELEM */
  1720. # endif /* DB_VERSION_MAJOR < 2 */
  1721. bool
  1722. bt_map_open(map, mode)
  1723. MAP *map;
  1724. int mode;
  1725. {
  1726. # if DB_VERSION_MAJOR < 2
  1727. BTREEINFO btinfo;
  1728. # endif /* DB_VERSION_MAJOR < 2 */
  1729. # if DB_VERSION_MAJOR == 2
  1730. DB_INFO btinfo;
  1731. # endif /* DB_VERSION_MAJOR == 2 */
  1732. # if DB_VERSION_MAJOR > 2
  1733. void *btinfo = NULL;
  1734. # endif /* DB_VERSION_MAJOR > 2 */
  1735. if (tTd(38, 2))
  1736. sm_dprintf("bt_map_open(%s, %s, %d)\n",
  1737. map->map_mname, map->map_file, mode);
  1738. # if DB_VERSION_MAJOR < 3
  1739. memset(&btinfo, '\0', sizeof(btinfo));
  1740. # ifdef DB_CACHE_SIZE
  1741. btinfo.db_cachesize = DB_CACHE_SIZE;
  1742. # endif /* DB_CACHE_SIZE */
  1743. # endif /* DB_VERSION_MAJOR < 3 */
  1744. return db_map_open(map, mode, "btree", DB_BTREE, &btinfo);
  1745. }
  1746. bool
  1747. hash_map_open(map, mode)
  1748. MAP *map;
  1749. int mode;
  1750. {
  1751. # if DB_VERSION_MAJOR < 2
  1752. HASHINFO hinfo;
  1753. # endif /* DB_VERSION_MAJOR < 2 */
  1754. # if DB_VERSION_MAJOR == 2
  1755. DB_INFO hinfo;
  1756. # endif /* DB_VERSION_MAJOR == 2 */
  1757. # if DB_VERSION_MAJOR > 2
  1758. void *hinfo = NULL;
  1759. # endif /* DB_VERSION_MAJOR > 2 */
  1760. if (tTd(38, 2))
  1761. sm_dprintf("hash_map_open(%s, %s, %d)\n",
  1762. map->map_mname, map->map_file, mode);
  1763. # if DB_VERSION_MAJOR < 3
  1764. memset(&hinfo, '\0', sizeof(hinfo));
  1765. # ifdef DB_HASH_NELEM
  1766. hinfo.h_nelem = DB_HASH_NELEM;
  1767. # endif /* DB_HASH_NELEM */
  1768. # ifdef DB_CACHE_SIZE
  1769. hinfo.db_cachesize = DB_CACHE_SIZE;
  1770. # endif /* DB_CACHE_SIZE */
  1771. # endif /* DB_VERSION_MAJOR < 3 */
  1772. return db_map_open(map, mode, "hash", DB_HASH, &hinfo);
  1773. }
  1774. static bool
  1775. db_map_open(map, mode, mapclassname, dbtype, openinfo)
  1776. MAP *map;
  1777. int mode;
  1778. char *mapclassname;
  1779. DBTYPE dbtype;
  1780. # if DB_VERSION_MAJOR < 2
  1781. const void *openinfo;
  1782. # endif /* DB_VERSION_MAJOR < 2 */
  1783. # if DB_VERSION_MAJOR == 2
  1784. DB_INFO *openinfo;
  1785. # endif /* DB_VERSION_MAJOR == 2 */
  1786. # if DB_VERSION_MAJOR > 2
  1787. void **openinfo;
  1788. # endif /* DB_VERSION_MAJOR > 2 */
  1789. {
  1790. DB *db = NULL;
  1791. int i;
  1792. int omode;
  1793. int smode = S_IREAD;
  1794. int fd;
  1795. long sff;
  1796. int save_errno;
  1797. struct stat st;
  1798. char buf[MAXPATHLEN];
  1799. /* do initial file and directory checks */
  1800. if (sm_strlcpy(buf, map->map_file, sizeof(buf)) >= sizeof(buf))
  1801. {
  1802. errno = 0;
  1803. if (!bitset(MF_OPTIONAL, map->map_mflags))
  1804. syserr("map \"%s\": map file %s name too long",
  1805. map->map_mname, map->map_file);
  1806. return false;
  1807. }
  1808. i = strlen(buf);
  1809. if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
  1810. {
  1811. if (sm_strlcat(buf, ".db", sizeof(buf)) >= sizeof(buf))
  1812. {
  1813. errno = 0;
  1814. if (!bitset(MF_OPTIONAL, map->map_mflags))
  1815. syserr("map \"%s\": map file %s name too long",
  1816. map->map_mname, map->map_file);
  1817. return false;
  1818. }
  1819. }
  1820. mode &= O_ACCMODE;
  1821. omode = mode;
  1822. sff = SFF_ROOTOK|SFF_REGONLY;
  1823. if (mode == O_RDWR)
  1824. {
  1825. sff |= SFF_CREAT;
  1826. if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
  1827. sff |= SFF_NOSLINK;
  1828. if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
  1829. sff |= SFF_NOHLINK;
  1830. smode = S_IWRITE;
  1831. }
  1832. else
  1833. {
  1834. if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
  1835. sff |= SFF_NOWLINK;
  1836. }
  1837. if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
  1838. sff |= SFF_SAFEDIRPATH;
  1839. i = safefile(buf, RunAsUid, RunAsGid, RunAsUserName, sff, smode, &st);
  1840. if (i != 0)
  1841. {
  1842. char *prob = "unsafe";
  1843. /* cannot open this map */
  1844. if (i == ENOENT)
  1845. prob = "missing";
  1846. if (tTd(38, 2))
  1847. sm_dprintf("\t%s map file: %s\n", prob, sm_errstring(i));
  1848. errno = i;
  1849. if (!bitset(MF_OPTIONAL, map->map_mflags))
  1850. syserr("%s map \"%s\": %s map file %s",
  1851. mapclassname, map->map_mname, prob, buf);
  1852. return false;
  1853. }
  1854. if (st.st_mode == ST_MODE_NOFILE)
  1855. omode |= O_CREAT|O_EXCL;
  1856. map->map_lockfd = -1;
  1857. # if LOCK_ON_OPEN
  1858. if (mode == O_RDWR)
  1859. omode |= O_TRUNC|O_EXLOCK;
  1860. else
  1861. omode |= O_SHLOCK;
  1862. # else /* LOCK_ON_OPEN */
  1863. /*
  1864. ** Pre-lock the file to avoid race conditions. In particular,
  1865. ** since dbopen returns NULL if the file is zero length, we
  1866. ** must have a locked instance around the dbopen.
  1867. */
  1868. fd = open(buf, omode, DBMMODE);
  1869. if (fd < 0)
  1870. {
  1871. if (!bitset(MF_OPTIONAL, map->map_mflags))
  1872. syserr("db_map_open: cannot pre-open database %s", buf);
  1873. return false;
  1874. }
  1875. /* make sure no baddies slipped in just before the open... */
  1876. if (filechanged(buf, fd, &st))
  1877. {
  1878. save_errno = errno;
  1879. (void) close(fd);
  1880. errno = save_errno;
  1881. syserr("db_map_open(%s): file changed after pre-open", buf);
  1882. return false;
  1883. }
  1884. /* if new file, get the "before" bits for later filechanged check */
  1885. if (st.st_mode == ST_MODE_NOFILE && fstat(fd, &st) < 0)
  1886. {
  1887. save_errno = errno;
  1888. (void) close(fd);
  1889. errno = save_errno;
  1890. syserr("db_map_open(%s): cannot fstat pre-opened file",
  1891. buf);
  1892. return false;
  1893. }
  1894. /* actually lock the pre-opened file */
  1895. if (!lockfile(fd, buf, NULL, mode == O_RDONLY ? LOCK_SH : LOCK_EX))
  1896. syserr("db_map_open: cannot lock %s", buf);
  1897. /* set up mode bits for dbopen */
  1898. if (mode == O_RDWR)
  1899. omode |= O_TRUNC;
  1900. omode &= ~(O_EXCL|O_CREAT);
  1901. # endif /* LOCK_ON_OPEN */
  1902. # if DB_VERSION_MAJOR < 2
  1903. db = dbopen(buf, omode, DBMMODE, dbtype, openinfo);
  1904. # else /* DB_VERSION_MAJOR < 2 */
  1905. {
  1906. int flags = 0;
  1907. # if DB_VERSION_MAJOR > 2
  1908. int ret;
  1909. # endif /* DB_VERSION_MAJOR > 2 */
  1910. if (mode == O_RDONLY)
  1911. flags |= DB_RDONLY;
  1912. if (bitset(O_CREAT, omode))
  1913. flags |= DB_CREATE;
  1914. if (bitset(O_TRUNC, omode))
  1915. flags |= DB_TRUNCATE;
  1916. SM_DB_FLAG_ADD(flags);
  1917. # if DB_VERSION_MAJOR > 2
  1918. ret = db_create(&db, NULL, 0);
  1919. # ifdef DB_CACHE_SIZE
  1920. if (ret == 0 && db != NULL)
  1921. {
  1922. ret = db->set_cachesize(db, 0, DB_CACHE_SIZE, 0);
  1923. if (ret != 0)
  1924. {
  1925. (void) db->close(db, 0);
  1926. db = NULL;
  1927. }
  1928. }
  1929. # endif /* DB_CACHE_SIZE */
  1930. # ifdef DB_HASH_NELEM
  1931. if (dbtype == DB_HASH && ret == 0 && db != NULL)
  1932. {
  1933. ret = db->set_h_nelem(db, DB_HASH_NELEM);
  1934. if (ret != 0)
  1935. {
  1936. (void) db->close(db, 0);
  1937. db = NULL;
  1938. }
  1939. }
  1940. # endif /* DB_HASH_NELEM */
  1941. if (ret == 0 && db != NULL)
  1942. {
  1943. ret = db->open(db,
  1944. DBTXN /* transaction for DB 4.1 */
  1945. buf, NULL, dbtype, flags, DBMMODE);
  1946. if (ret != 0)
  1947. {
  1948. #ifdef DB_OLD_VERSION
  1949. if (ret == DB_OLD_VERSION)
  1950. ret = EINVAL;
  1951. #endif /* DB_OLD_VERSION */
  1952. (void) db->close(db, 0);
  1953. db = NULL;
  1954. }
  1955. }
  1956. errno = ret;
  1957. # else /* DB_VERSION_MAJOR > 2 */
  1958. errno = db_open(buf, dbtype, flags, DBMMODE,
  1959. NULL, openinfo, &db);
  1960. # endif /* DB_VERSION_MAJOR > 2 */
  1961. }
  1962. # endif /* DB_VERSION_MAJOR < 2 */
  1963. save_errno = errno;
  1964. # if !LOCK_ON_OPEN
  1965. if (mode == O_RDWR)
  1966. map->map_lockfd = fd;
  1967. else
  1968. (void) close(fd);
  1969. # endif /* !LOCK_ON_OPEN */
  1970. if (db == NULL)
  1971. {
  1972. if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags) &&
  1973. aliaswait(map, ".db", false))
  1974. return true;
  1975. # if !LOCK_ON_OPEN
  1976. if (map->map_lockfd >= 0)
  1977. (void) close(map->map_lockfd);
  1978. # endif /* !LOCK_ON_OPEN */
  1979. errno = save_errno;
  1980. if (!bitset(MF_OPTIONAL, map->map_mflags))
  1981. syserr("Cannot open %s database %s",
  1982. mapclassname, buf);
  1983. return false;
  1984. }
  1985. # if DB_VERSION_MAJOR < 2
  1986. fd = db->fd(db);
  1987. # else /* DB_VERSION_MAJOR < 2 */
  1988. fd = -1;
  1989. errno = db->fd(db, &fd);
  1990. # endif /* DB_VERSION_MAJOR < 2 */
  1991. if (filechanged(buf, fd, &st))
  1992. {
  1993. save_errno = errno;
  1994. # if DB_VERSION_MAJOR < 2
  1995. (void) db->close(db);
  1996. # else /* DB_VERSION_MAJOR < 2 */
  1997. errno = db->close(db, 0);
  1998. # endif /* DB_VERSION_MAJOR < 2 */
  1999. # if !LOCK_ON_OPEN
  2000. if (map->map_lockfd >= 0)
  2001. (void) close(map->map_lockfd);
  2002. # endif /* !LOCK_ON_OPEN */
  2003. errno = save_errno;
  2004. syserr("db