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

Email客户端

开发平台:

Unix_Linux

  1. (lmap->ldap_binddn == NULL ? 0 : strlen(lmap->ldap_binddn)) +
  2. 1 +
  3. (lmap->ldap_secret == NULL ? 0 : strlen(lmap->ldap_secret)) +
  4. 1;
  5. nbuf = xalloc(len);
  6. snprintf(nbuf, len, "%s%c%d%c%s%c%s",
  7.  (lmap->ldap_host == NULL ? "localhost" : lmap->ldap_host),
  8.  CONDELSE,
  9.  lmap->ldap_port,
  10.  CONDELSE,
  11.  (lmap->ldap_binddn == NULL ? "" : lmap->ldap_binddn),
  12.  CONDELSE,
  13.  (lmap->ldap_secret == NULL ? "" : lmap->ldap_secret));
  14. s = stab(nbuf, ST_LDAP, ST_ENTER);
  15. free(nbuf);
  16. return s;
  17. }
  18. /*
  19. **  LDAPMAP_SETOPTS -- set LDAP options
  20. **
  21. ** Parameters:
  22. ** ld -- LDAP session handle
  23. ** lmap -- LDAP map information
  24. **
  25. ** Returns:
  26. ** None.
  27. **
  28. */
  29. static void
  30. ldapmap_setopts(ld, lmap)
  31. LDAP *ld;
  32. LDAPMAP_STRUCT *lmap;
  33. {
  34. # if USE_LDAP_SET_OPTION
  35. ldap_set_option(ld, LDAP_OPT_DEREF, &lmap->ldap_deref);
  36. if (bitset(LDAP_OPT_REFERRALS, lmap->ldap_options))
  37. ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON);
  38. else
  39. ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
  40. ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &lmap->ldap_sizelimit);
  41. ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &lmap->ldap_timelimit);
  42. # else /* USE_LDAP_SET_OPTION */
  43. /* From here on in we can use ldap internal timelimits */
  44. ld->ld_deref = lmap->ldap_deref;
  45. ld->ld_options = lmap->ldap_options;
  46. ld->ld_sizelimit = lmap->ldap_sizelimit;
  47. ld->ld_timelimit = lmap->ldap_timelimit;
  48. # endif /* USE_LDAP_SET_OPTION */
  49. }
  50. /*
  51. **  LDAPMAP_GETERRNO -- get ldap errno value
  52. **
  53. ** Parameters:
  54. ** ld -- LDAP session handle
  55. **
  56. ** Returns:
  57. ** LDAP errno.
  58. **
  59. */
  60. static int
  61. ldapmap_geterrno(ld)
  62. LDAP *ld;
  63. {
  64. int err = LDAP_SUCCESS;
  65. # if defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3
  66. (void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err);
  67. # else /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */
  68. #  ifdef LDAP_OPT_SIZELIMIT
  69. err = ldap_get_lderrno(ld, NULL, NULL);
  70. #  else /* LDAP_OPT_SIZELIMIT */
  71. err = ld->ld_errno;
  72. /*
  73. **  Reset value to prevent lingering LDAP_DECODING_ERROR due to
  74. **  OpenLDAP 1.X's hack (see above)
  75. */
  76. ld->ld_errno = LDAP_SUCCESS;
  77. #  endif /* LDAP_OPT_SIZELIMIT */
  78. # endif /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */
  79. return err;
  80. }
  81. /*
  82. **  LDAPX_MAP_PARSEARGS -- print warning about use of ldapx map.
  83. */
  84. bool
  85. ldapx_map_parseargs(map, args)
  86. MAP *map;
  87. char *args;
  88. {
  89. printf("Warning: The "ldapx" map class is deprecated and will be removed in a futuren");
  90. printf("         version.  Use the "ldap" map class instead for map "%s".n",
  91.        map->map_mname);
  92. return ldapmap_parseargs(map, args);
  93. }
  94. /*
  95. **  LDAPMAP_PARSEARGS -- parse ldap map definition args.
  96. */
  97. struct lamvalues LDAPAuthMethods[] =
  98. {
  99. { "none", LDAP_AUTH_NONE },
  100. { "simple", LDAP_AUTH_SIMPLE },
  101. { "krbv4", LDAP_AUTH_KRBV4 },
  102. { NULL, 0 }
  103. };
  104. struct ladvalues LDAPAliasDereference[] =
  105. {
  106. { "never", LDAP_DEREF_NEVER },
  107. { "always", LDAP_DEREF_ALWAYS },
  108. { "search", LDAP_DEREF_SEARCHING },
  109. { "find", LDAP_DEREF_FINDING },
  110. { NULL, 0 }
  111. };
  112. struct lssvalues LDAPSearchScope[] =
  113. {
  114. { "base", LDAP_SCOPE_BASE },
  115. { "one", LDAP_SCOPE_ONELEVEL },
  116. { "sub", LDAP_SCOPE_SUBTREE },
  117. { NULL, 0 }
  118. };
  119. bool
  120. ldapmap_parseargs(map, args)
  121. MAP *map;
  122. char *args;
  123. {
  124. bool secretread = TRUE;
  125. int i;
  126. register char *p = args;
  127. LDAPMAP_STRUCT *lmap;
  128. struct lamvalues *lam;
  129. struct ladvalues *lad;
  130. struct lssvalues *lss;
  131. char m_tmp[MAXPATHLEN + LDAPMAP_MAX_PASSWD];
  132. /* Get ldap struct pointer from map */
  133. lmap = (LDAPMAP_STRUCT *) map->map_db1;
  134. /* Check if setting the initial LDAP defaults */
  135. if (lmap == NULL || lmap != LDAPDefaults)
  136. {
  137. /* We need to alloc an LDAPMAP_STRUCT struct */
  138. lmap = (LDAPMAP_STRUCT *) xalloc(sizeof *lmap);
  139. if (LDAPDefaults == NULL)
  140. ldapmap_clear(lmap);
  141. else
  142. STRUCTCOPY(*LDAPDefaults, *lmap);
  143. }
  144. /* there is no check whether there is really an argument */
  145. map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
  146. map->map_spacesub = SpaceSub; /* default value */
  147. for (;;)
  148. {
  149. while (isascii(*p) && isspace(*p))
  150. p++;
  151. if (*p != '-')
  152. break;
  153. switch (*++p)
  154. {
  155.   case 'N':
  156. map->map_mflags |= MF_INCLNULL;
  157. map->map_mflags &= ~MF_TRY0NULL;
  158. break;
  159.   case 'O':
  160. map->map_mflags &= ~MF_TRY1NULL;
  161. break;
  162.   case 'o':
  163. map->map_mflags |= MF_OPTIONAL;
  164. break;
  165.   case 'f':
  166. map->map_mflags |= MF_NOFOLDCASE;
  167. break;
  168.   case 'm':
  169. map->map_mflags |= MF_MATCHONLY;
  170. break;
  171.   case 'A':
  172. map->map_mflags |= MF_APPEND;
  173. break;
  174.   case 'q':
  175. map->map_mflags |= MF_KEEPQUOTES;
  176. break;
  177.   case 'a':
  178. map->map_app = ++p;
  179. break;
  180.   case 'T':
  181. map->map_tapp = ++p;
  182. break;
  183.   case 't':
  184. map->map_mflags |= MF_NODEFER;
  185. break;
  186.   case 'S':
  187. map->map_spacesub = *++p;
  188. break;
  189.   case 'D':
  190. map->map_mflags |= MF_DEFER;
  191. break;
  192.   case 'z':
  193. if (*++p != '\')
  194. map->map_coldelim = *p;
  195. else
  196. {
  197. switch (*++p)
  198. {
  199.   case 'n':
  200. map->map_coldelim = 'n';
  201. break;
  202.   case 't':
  203. map->map_coldelim = 't';
  204. break;
  205.   default:
  206. map->map_coldelim = '\';
  207. }
  208. }
  209. break;
  210. /* Start of ldapmap specific args */
  211.   case 'k': /* search field */
  212. while (isascii(*++p) && isspace(*p))
  213. continue;
  214. lmap->ldap_filter = p;
  215. break;
  216.   case 'v': /* attr to return */
  217. while (isascii(*++p) && isspace(*p))
  218. continue;
  219. lmap->ldap_attr[0] = p;
  220. lmap->ldap_attr[1] = NULL;
  221. break;
  222.   case '1':
  223. map->map_mflags |= MF_SINGLEMATCH;
  224. break;
  225. /* args stolen from ldapsearch.c */
  226.   case 'R': /* don't auto chase referrals */
  227. # ifdef LDAP_REFERRALS
  228. lmap->ldap_options &= ~LDAP_OPT_REFERRALS;
  229. # else /* LDAP_REFERRALS */
  230. syserr("compile with -DLDAP_REFERRALS for referral supportn");
  231. # endif /* LDAP_REFERRALS */
  232. break;
  233.   case 'n': /* retrieve attribute names only */
  234. lmap->ldap_attrsonly = LDAPMAP_TRUE;
  235. break;
  236.   case 'r': /* alias dereferencing */
  237. while (isascii(*++p) && isspace(*p))
  238. continue;
  239. if (strncasecmp(p, "LDAP_DEREF_", 11) == 0)
  240. p += 11;
  241. for (lad = LDAPAliasDereference;
  242.      lad != NULL && lad->lad_name != NULL; lad++)
  243. {
  244. if (strncasecmp(p, lad->lad_name,
  245. strlen(lad->lad_name)) == 0)
  246. break;
  247. }
  248. if (lad->lad_name != NULL)
  249. lmap->ldap_deref = lad->lad_code;
  250. else
  251. {
  252. /* bad config line */
  253. if (!bitset(MCF_OPTFILE,
  254.     map->map_class->map_cflags))
  255. {
  256. char *ptr;
  257. if ((ptr = strchr(p, ' ')) != NULL)
  258. *ptr = '';
  259. syserr("Deref must be [never|always|search|find] not %s in map %s",
  260. p, map->map_mname);
  261. if (ptr != NULL)
  262. *ptr = ' ';
  263. return FALSE;
  264. }
  265. }
  266. break;
  267.   case 's': /* search scope */
  268. while (isascii(*++p) && isspace(*p))
  269. continue;
  270. if (strncasecmp(p, "LDAP_SCOPE_", 11) == 0)
  271. p += 11;
  272. for (lss = LDAPSearchScope;
  273.      lss != NULL && lss->lss_name != NULL; lss++)
  274. {
  275. if (strncasecmp(p, lss->lss_name,
  276. strlen(lss->lss_name)) == 0)
  277. break;
  278. }
  279. if (lss->lss_name != NULL)
  280. lmap->ldap_scope = lss->lss_code;
  281. else
  282. {
  283. /* bad config line */
  284. if (!bitset(MCF_OPTFILE,
  285.     map->map_class->map_cflags))
  286. {
  287. char *ptr;
  288. if ((ptr = strchr(p, ' ')) != NULL)
  289. *ptr = '';
  290. syserr("Scope must be [base|one|sub] not %s in map %s",
  291. p, map->map_mname);
  292. if (ptr != NULL)
  293. *ptr = ' ';
  294. return FALSE;
  295. }
  296. }
  297. break;
  298.   case 'h': /* ldap host */
  299. while (isascii(*++p) && isspace(*p))
  300. continue;
  301. lmap->ldap_host = p;
  302. break;
  303.   case 'b': /* search base */
  304. while (isascii(*++p) && isspace(*p))
  305. continue;
  306. lmap->ldap_base = p;
  307. break;
  308.   case 'p': /* ldap port */
  309. while (isascii(*++p) && isspace(*p))
  310. continue;
  311. lmap->ldap_port = atoi(p);
  312. break;
  313.   case 'l': /* time limit */
  314. while (isascii(*++p) && isspace(*p))
  315. continue;
  316. lmap->ldap_timelimit = atoi(p);
  317. lmap->ldap_timeout.tv_sec = lmap->ldap_timelimit;
  318. break;
  319.   case 'Z':
  320. while (isascii(*++p) && isspace(*p))
  321. continue;
  322. lmap->ldap_sizelimit = atoi(p);
  323. break;
  324.   case 'd': /* Dn to bind to server as */
  325. while (isascii(*++p) && isspace(*p))
  326. continue;
  327. lmap->ldap_binddn = p;
  328. break;
  329.   case 'M': /* Method for binding */
  330. while (isascii(*++p) && isspace(*p))
  331. continue;
  332. if (strncasecmp(p, "LDAP_AUTH_", 10) == 0)
  333. p += 10;
  334. for (lam = LDAPAuthMethods;
  335.      lam != NULL && lam->lam_name != NULL; lam++)
  336. {
  337. if (strncasecmp(p, lam->lam_name,
  338. strlen(lam->lam_name)) == 0)
  339. break;
  340. }
  341. if (lam->lam_name != NULL)
  342. lmap->ldap_method = lam->lam_code;
  343. else
  344. {
  345. /* bad config line */
  346. if (!bitset(MCF_OPTFILE,
  347.     map->map_class->map_cflags))
  348. {
  349. char *ptr;
  350. if ((ptr = strchr(p, ' ')) != NULL)
  351. *ptr = '';
  352. syserr("Method for binding must be [none|simple|krbv4] not %s in map %s",
  353. p, map->map_mname);
  354. if (ptr != NULL)
  355. *ptr = ' ';
  356. return FALSE;
  357. }
  358. }
  359. break;
  360. /*
  361. **  This is a string that is dependent on the
  362. **  method used defined above.
  363. */
  364.   case 'P': /* Secret password for binding */
  365.  while (isascii(*++p) && isspace(*p))
  366. continue;
  367. lmap->ldap_secret = p;
  368. secretread = FALSE;
  369. break;
  370.   default:
  371. syserr("Illegal option %c map %s", *p, map->map_mname);
  372. break;
  373. }
  374. /* need to account for quoted strings here */
  375. while (*p != '' && !(isascii(*p) && isspace(*p)))
  376. {
  377. if (*p == '"')
  378. {
  379. while (*++p != '"' && *p != '')
  380. continue;
  381. if (*p != '')
  382. p++;
  383. }
  384. else
  385. p++;
  386. }
  387. if (*p != '')
  388. *p++ = '';
  389. }
  390. if (map->map_app != NULL)
  391. map->map_app = newstr(ldapmap_dequote(map->map_app));
  392. if (map->map_tapp != NULL)
  393. map->map_tapp = newstr(ldapmap_dequote(map->map_tapp));
  394. /*
  395. **  We need to swallow up all the stuff into a struct
  396. **  and dump it into map->map_dbptr1
  397. */
  398. if (lmap->ldap_host != NULL)
  399. lmap->ldap_host = newstr(ldapmap_dequote(lmap->ldap_host));
  400. map->map_domain = lmap->ldap_host;
  401. if (lmap->ldap_binddn != NULL)
  402. lmap->ldap_binddn = newstr(ldapmap_dequote(lmap->ldap_binddn));
  403. if (lmap->ldap_secret != NULL)
  404. {
  405. FILE *sfd;
  406. long sff = SFF_OPENASROOT|SFF_ROOTOK|SFF_NOWLINK|SFF_NOWWFILES|SFF_NOGWFILES;
  407. if (DontLockReadFiles)
  408. sff |= SFF_NOLOCK;
  409. /* need to use method to map secret to passwd string */
  410. switch (lmap->ldap_method)
  411. {
  412.   case LDAP_AUTH_NONE:
  413. /* Do nothing */
  414. break;
  415.   case LDAP_AUTH_SIMPLE:
  416. /*
  417. **  Secret is the name of a file with
  418. **  the first line as the password.
  419. */
  420. /* Already read in the secret? */
  421. if (secretread)
  422. break;
  423. sfd = safefopen(ldapmap_dequote(lmap->ldap_secret),
  424. O_RDONLY, 0, sff);
  425. if (sfd == NULL)
  426. {
  427. syserr("LDAP map: cannot open secret %s",
  428.        ldapmap_dequote(lmap->ldap_secret));
  429. return FALSE;
  430. }
  431. lmap->ldap_secret = sfgets(m_tmp, LDAPMAP_MAX_PASSWD,
  432.    sfd, 0, "ldapmap_parseargs");
  433. (void) fclose(sfd);
  434. if (lmap->ldap_secret != NULL &&
  435.     strlen(m_tmp) > 0)
  436. {
  437. /* chomp newline */
  438. if (m_tmp[strlen(m_tmp) - 1] == 'n')
  439. m_tmp[strlen(m_tmp) - 1] = '';
  440. lmap->ldap_secret = m_tmp;
  441. }
  442. break;
  443.   case LDAP_AUTH_KRBV4:
  444. /*
  445. **  Secret is where the ticket file is
  446. **  stashed
  447. */
  448. snprintf(m_tmp, MAXPATHLEN + LDAPMAP_MAX_PASSWD,
  449.  "KRBTKFILE=%s",
  450.  ldapmap_dequote(lmap->ldap_secret));
  451. lmap->ldap_secret = m_tmp;
  452. break;
  453.   default:        /* Should NEVER get here */
  454. syserr("LDAP map: Illegal value in lmap method");
  455. return FALSE;
  456. break;
  457. }
  458. }
  459. if (lmap->ldap_secret != NULL)
  460. lmap->ldap_secret = newstr(ldapmap_dequote(lmap->ldap_secret));
  461. if (lmap->ldap_base != NULL)
  462. lmap->ldap_base = newstr(ldapmap_dequote(lmap->ldap_base));
  463. /*
  464. **  Save the server from extra work.  If request is for a single
  465. **  match, tell the server to only return enough records to
  466. **  determine if there is a single match or not.  This can not
  467. **  be one since the server would only return one and we wouldn't
  468. **  know if there were others available.
  469. */
  470. if (bitset(MF_SINGLEMATCH, map->map_mflags))
  471. lmap->ldap_sizelimit = 2;
  472. /* If setting defaults, don't process ldap_filter and ldap_attr */
  473. if (lmap == LDAPDefaults)
  474. return TRUE;
  475. if (lmap->ldap_filter != NULL)
  476. lmap->ldap_filter = newstr(ldapmap_dequote(lmap->ldap_filter));
  477. else
  478. {
  479. if (!bitset(MCF_OPTFILE, map->map_class->map_cflags))
  480. {
  481. syserr("No filter given in map %s", map->map_mname);
  482. return FALSE;
  483. }
  484. }
  485. if (lmap->ldap_attr[0] != NULL)
  486. {
  487. i = 0;
  488. p = lmap->ldap_attr[0];
  489. lmap->ldap_attr[0] = NULL;
  490. while (p != NULL)
  491. {
  492. char *v;
  493. while (isascii(*p) && isspace(*p))
  494. p++;
  495. if (*p == '')
  496. break;
  497. v = p;
  498. p = strchr(v, ',');
  499. if (p != NULL)
  500. *p++ = '';
  501. if (i == LDAPMAP_MAX_ATTR)
  502. {
  503. if (bitset(MCF_OPTFILE, map->map_class->map_cflags))
  504. {
  505. syserr("Too many return attributes in %s (max %d)",
  506.        map->map_mname, LDAPMAP_MAX_ATTR);
  507. return FALSE;
  508. }
  509. else
  510. break;
  511. }
  512. if (*v != '')
  513. lmap->ldap_attr[i++] = newstr(v);
  514. }
  515. lmap->ldap_attr[i] = NULL;
  516. }
  517. map->map_db1 = (ARBPTR_T) lmap;
  518. return TRUE;
  519. }
  520. /*
  521. **  LDAPMAP_CLEAR -- set default values for LDAPMAP_STRUCT
  522. **
  523. ** Parameters:
  524. ** lmap -- pointer to LDAPMAP_STRUCT to clear
  525. **
  526. ** Returns:
  527. ** None.
  528. **
  529. */
  530. static void
  531. ldapmap_clear(lmap)
  532. LDAPMAP_STRUCT *lmap;
  533. {
  534. lmap->ldap_host = NULL;
  535. lmap->ldap_port = LDAP_PORT;
  536. lmap->ldap_deref = LDAP_DEREF_NEVER;
  537. lmap->ldap_timelimit = LDAP_NO_LIMIT;
  538. lmap->ldap_sizelimit = LDAP_NO_LIMIT;
  539. # ifdef LDAP_REFERRALS
  540. lmap->ldap_options = LDAP_OPT_REFERRALS;
  541. # else /* LDAP_REFERRALS */
  542. lmap->ldap_options = 0;
  543. # endif /* LDAP_REFERRALS */
  544. lmap->ldap_binddn = NULL;
  545. lmap->ldap_secret = NULL;
  546. lmap->ldap_method = LDAP_AUTH_SIMPLE;
  547. lmap->ldap_base = NULL;
  548. lmap->ldap_scope = LDAP_SCOPE_SUBTREE;
  549. lmap->ldap_attrsonly = LDAPMAP_FALSE;
  550. lmap->ldap_timeout.tv_sec = 0;
  551. lmap->ldap_timeout.tv_usec = 0;
  552. lmap->ldap_ld = NULL;
  553. lmap->ldap_filter = NULL;
  554. lmap->ldap_attr[0] = NULL;
  555. lmap->ldap_res = NULL;
  556. }
  557. /*
  558. **  LDAPMAP_SET_DEFAULTS -- Read default map spec from LDAPDefaults in .cf
  559. **
  560. ** Parameters:
  561. ** spec -- map argument string from LDAPDefaults option
  562. **
  563. ** Returns:
  564. ** None.
  565. **
  566. */
  567. void
  568. ldapmap_set_defaults(spec)
  569. char *spec;
  570. {
  571. MAP map;
  572. /* Allocate and set the default values */
  573. if (LDAPDefaults == NULL)
  574. LDAPDefaults = (LDAPMAP_STRUCT *) xalloc(sizeof *LDAPDefaults);
  575. ldapmap_clear(LDAPDefaults);
  576. memset(&map, '', sizeof map);
  577. map.map_db1 = (ARBPTR_T) LDAPDefaults;
  578. (void) ldapmap_parseargs(&map, spec);
  579. /* These should never be set in LDAPDefaults */
  580. if (map.map_mflags != (MF_TRY0NULL|MF_TRY1NULL) ||
  581.     map.map_spacesub != SpaceSub ||
  582.     map.map_app != NULL ||
  583.     map.map_tapp != NULL)
  584. {
  585. syserr("readcf: option LDAPDefaultSpec: Do not set non-LDAP specific flags");
  586. if (map.map_app != NULL)
  587. {
  588. free(map.map_app);
  589. map.map_app = NULL;
  590. }
  591. if (map.map_tapp != NULL)
  592. {
  593. free(map.map_tapp);
  594. map.map_tapp = NULL;
  595. }
  596. }
  597. if (LDAPDefaults->ldap_filter != NULL)
  598. {
  599. syserr("readcf: option LDAPDefaultSpec: Do not set the LDAP search filter");
  600. /* don't free, it isn't malloc'ed in parseargs */
  601. LDAPDefaults->ldap_filter = NULL;
  602. }
  603. if (LDAPDefaults->ldap_attr[0] != NULL)
  604. {
  605. syserr("readcf: option LDAPDefaultSpec: Do not set the requested LDAP attributes");
  606. /* don't free, they aren't malloc'ed in parseargs */
  607. LDAPDefaults->ldap_attr[0] = NULL;
  608. }
  609. }
  610. #endif /* LDAPMAP */
  611. /*
  612. **  PH map
  613. */
  614. #ifdef PH_MAP
  615. /*
  616. **  Support for the CCSO Nameserver (ph/qi).
  617. **  This code is intended to replace the so-called "ph mailer".
  618. **  Contributed by Mark D. Roth <roth@uiuc.edu>.  Contact him for support.
  619. */
  620. # include <qiapi.h>
  621. # include <qicode.h>
  622. /*
  623. **  PH_MAP_PARSEARGS -- parse ph map definition args.
  624. */
  625. bool
  626. ph_map_parseargs(map, args)
  627. MAP *map;
  628. char *args;
  629. {
  630. int i;
  631. register int done;
  632. PH_MAP_STRUCT *pmap = NULL;
  633. register char *p = args;
  634. pmap = (PH_MAP_STRUCT *) xalloc(sizeof *pmap);
  635. /* defaults */
  636. pmap->ph_servers = NULL;
  637. pmap->ph_field_list = NULL;
  638. pmap->ph_to_server = NULL;
  639. pmap->ph_from_server = NULL;
  640. pmap->ph_sockfd = -1;
  641. pmap->ph_timeout = 0;
  642. map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
  643. for (;;)
  644. {
  645. while (isascii(*p) && isspace(*p))
  646. p++;
  647. if (*p != '-')
  648. break;
  649. switch (*++p)
  650. {
  651.   case 'N':
  652. map->map_mflags |= MF_INCLNULL;
  653. map->map_mflags &= ~MF_TRY0NULL;
  654. break;
  655.   case 'O':
  656. map->map_mflags &= ~MF_TRY1NULL;
  657. break;
  658.   case 'o':
  659. map->map_mflags |= MF_OPTIONAL;
  660. break;
  661.   case 'f':
  662. map->map_mflags |= MF_NOFOLDCASE;
  663. break;
  664.   case 'm':
  665. map->map_mflags |= MF_MATCHONLY;
  666. break;
  667.   case 'A':
  668. map->map_mflags |= MF_APPEND;
  669. break;
  670.   case 'q':
  671. map->map_mflags |= MF_KEEPQUOTES;
  672. break;
  673.   case 't':
  674. map->map_mflags |= MF_NODEFER;
  675. break;
  676.   case 'a':
  677. map->map_app = ++p;
  678. break;
  679.   case 'T':
  680. map->map_tapp = ++p;
  681. break;
  682. #if _FFR_PHMAP_TIMEOUT
  683.   case 'l':
  684. while (isascii(*++p) && isspace(*p))
  685. continue;
  686. pmap->ph_timeout = atoi(p);
  687. break;
  688. #endif /* _FFR_PHMAP_TIMEOUT */
  689.   case 'S':
  690. map->map_spacesub = *++p;
  691. break;
  692.   case 'D':
  693. map->map_mflags |= MF_DEFER;
  694. break;
  695.   case 'h': /* PH server list */
  696. while (isascii(*++p) && isspace(*p))
  697. continue;
  698. pmap->ph_servers = p;
  699. break;
  700.   case 'v': /* fields to search for */
  701. while (isascii(*++p) && isspace(*p))
  702. continue;
  703. pmap->ph_field_list = p;
  704. break;
  705.   default:
  706. syserr("ph_map_parseargs: unknown option -%cn", *p);
  707. }
  708. /* try to account for quoted strings */
  709. done = isascii(*p) && isspace(*p);
  710. while (*p != '' && !done)
  711. {
  712. if (*p == '"')
  713. {
  714. while (*++p != '"' && *p != '')
  715. continue;
  716. if (*p != '')
  717. p++;
  718. }
  719. else
  720. p++;
  721. done = isascii(*p) && isspace(*p);
  722. }
  723. if (*p != '')
  724. *p++ = '';
  725. }
  726. if (map->map_app != NULL)
  727. map->map_app = newstr(ph_map_dequote(map->map_app));
  728. if (map->map_tapp != NULL)
  729. map->map_tapp = newstr(ph_map_dequote(map->map_tapp));
  730. if (pmap->ph_field_list != NULL)
  731. pmap->ph_field_list = newstr(ph_map_dequote(pmap->ph_field_list));
  732. else
  733. pmap->ph_field_list = DEFAULT_PH_MAP_FIELDS;
  734. if (pmap->ph_servers != NULL)
  735. pmap->ph_servers = newstr(ph_map_dequote(pmap->ph_servers));
  736. else
  737. {
  738. syserr("ph_map_parseargs: -h flag is required");
  739. return FALSE;
  740. }
  741. map->map_db1 = (ARBPTR_T) pmap;
  742. return TRUE;
  743. }
  744. #if _FFR_PHMAP_TIMEOUT
  745. /*
  746. **  PH_MAP_CLOSE -- close the connection to the ph server
  747. */
  748. static void
  749. ph_map_safeclose(map)
  750. MAP *map;
  751. {
  752. int save_errno = errno;
  753. PH_MAP_STRUCT *pmap;
  754. pmap = (PH_MAP_STRUCT *)map->map_db1;
  755. if (pmap->ph_sockfd != -1)
  756. {
  757. (void) close(pmap->ph_sockfd);
  758. pmap->ph_sockfd = -1;
  759. }
  760. if (pmap->ph_from_server != NULL)
  761. {
  762. (void) fclose(pmap->ph_from_server);
  763. pmap->ph_from_server = NULL;
  764. }
  765. if (pmap->ph_to_server != NULL)
  766. {
  767. (void) fclose(pmap->ph_to_server);
  768. pmap->ph_to_server = NULL;
  769. }
  770. map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
  771. errno = save_errno;
  772. }
  773. void
  774. ph_map_close(map)
  775. MAP *map;
  776. {
  777. PH_MAP_STRUCT *pmap;
  778. pmap = (PH_MAP_STRUCT *)map->map_db1;
  779. (void) fprintf(pmap->ph_to_server, "quitn");
  780. (void) fflush(pmap->ph_to_server);
  781. ph_map_safeclose(map);
  782. }
  783. static jmp_buf  PHTimeout;
  784. /* ARGSUSED */
  785. static void
  786. ph_timeout_func(sig_no)
  787. int sig_no;
  788. {
  789. longjmp(PHTimeout, 1);
  790. }
  791. #else /* _FFR_PHMAP_TIMEOUT */
  792. /*
  793. **  PH_MAP_CLOSE -- close the connection to the ph server
  794. */
  795. void
  796. ph_map_close(map)
  797. MAP *map;
  798. {
  799. PH_MAP_STRUCT *pmap;
  800. pmap = (PH_MAP_STRUCT *)map->map_db1;
  801. CloseQi(pmap->ph_to_server, pmap->ph_from_server);
  802. pmap->ph_to_server = NULL;
  803. pmap->ph_from_server = NULL;
  804. }
  805. #endif /* _FFR_PHMAP_TIMEOUT */
  806. /*
  807. **  PH_MAP_OPEN -- sub for opening PH map
  808. */
  809. bool
  810. ph_map_open(map, mode)
  811. MAP *map;
  812. int mode;
  813. {
  814. #if !_FFR_PHMAP_TIMEOUT
  815. int save_errno = 0;
  816. #endif /* !_FFR_PHMAP_TIMEOUT */
  817. int j;
  818. char *hostlist, *tmp;
  819. QIR *server_data = NULL;
  820. PH_MAP_STRUCT *pmap;
  821. #if _FFR_PHMAP_TIMEOUT
  822. register EVENT *ev = NULL;
  823. #endif /* _FFR_PHMAP_TIMEOUT */
  824. if (tTd(38, 2))
  825. dprintf("ph_map_open(%s)n", map->map_mname);
  826. mode &= O_ACCMODE;
  827. if (mode != O_RDONLY)
  828. {
  829. /* issue a pseudo-error message */
  830. # ifdef ENOSYS
  831. errno = ENOSYS;
  832. # else /* ENOSYS */
  833. #  ifdef EFTYPE
  834. errno = EFTYPE;
  835. #  else /* EFTYPE */
  836. errno = ENXIO;
  837. #  endif /* EFTYPE */
  838. # endif /* ENOSYS */
  839. return FALSE;
  840. }
  841. pmap = (PH_MAP_STRUCT *)map->map_db1;
  842. hostlist = newstr(pmap->ph_servers);
  843. tmp = strtok(hostlist, " ");
  844. do {
  845. #if _FFR_PHMAP_TIMEOUT
  846. if (pmap->ph_timeout != 0)
  847. {
  848. if (setjmp(PHTimeout) != 0)
  849. {
  850. ev = NULL;
  851. if (LogLevel > 1)
  852. sm_syslog(LOG_NOTICE, CurEnv->e_id,
  853.   "timeout connecting to PH server %.100s",
  854.   tmp);
  855. # ifdef ETIMEDOUT
  856. errno = ETIMEDOUT;
  857. # else /* ETIMEDOUT */
  858. errno = 0;
  859. # endif /* ETIMEDOUT */
  860. goto ph_map_open_abort;
  861. }
  862. ev = setevent(pmap->ph_timeout, ph_timeout_func, 0);
  863. }
  864. if (!OpenQiSock(tmp, &(pmap->ph_sockfd)) &&
  865.     !Sock2FILEs(pmap->ph_sockfd, &(pmap->ph_to_server),
  866. &(pmap->ph_from_server)) &&
  867.     fprintf(pmap->ph_to_server, "id sendmail+phmapn") >= 0 &&
  868.     fflush(pmap->ph_to_server) == 0 &&
  869.     (server_data = ReadQi(pmap->ph_from_server, &j)) != NULL &&
  870.     server_data->code == 200)
  871. {
  872. if (ev != NULL)
  873. clrevent(ev);
  874. FreeQIR(server_data);
  875. #else /* _FFR_PHMAP_TIMEOUT */
  876. if (OpenQi(tmp, &(pmap->ph_to_server),
  877.    &(pmap->ph_from_server)) >= 0)
  878. {
  879. if (fprintf(pmap->ph_to_server,
  880.     "id sendmail+phmapn") < 0 ||
  881.     fflush(pmap->ph_to_server) < 0 ||
  882.     (server_data = ReadQi(pmap->ph_from_server,
  883.   &j)) == NULL ||
  884.     server_data->code != 200)
  885. {
  886. save_errno = errno;
  887. CloseQi(pmap->ph_to_server,
  888. pmap->ph_from_server);
  889. continue;
  890. }
  891. if (server_data != NULL)
  892. free(server_data);
  893. #endif /* _FFR_PHMAP_TIMEOUT */
  894. free(hostlist);
  895. return TRUE;
  896. }
  897. #if _FFR_PHMAP_TIMEOUT
  898.   ph_map_open_abort:
  899. if (ev != NULL)
  900. clrevent(ev);
  901. ph_map_safeclose(map);
  902. if (server_data != NULL)
  903. {
  904. FreeQIR(server_data);
  905. server_data = NULL;
  906. }
  907. #else /* _FFR_PHMAP_TIMEOUT */
  908. save_errno = errno;
  909. #endif /* _FFR_PHMAP_TIMEOUT */
  910. } while (tmp = strtok(NULL, " "));
  911. #if !_FFR_PHMAP_TIMEOUT
  912. errno = save_errno;
  913. #endif /* !_FFR_PHMAP_TIMEOUT */
  914. if (!bitset(MF_OPTIONAL, map->map_mflags))
  915. {
  916. if (errno == 0 && !bitset(MF_NODEFER,map->map_mflags))
  917. errno = EAGAIN;
  918. syserr("ph_map_open: cannot connect to PH server");
  919. }
  920. else if (LogLevel > 1)
  921. sm_syslog(LOG_NOTICE, CurEnv->e_id,
  922.   "ph_map_open: cannot connect to PH server");
  923. free(hostlist);
  924. return FALSE;
  925. }
  926. /*
  927. **  PH_MAP_LOOKUP -- look up key from ph server
  928. */
  929. #if _FFR_PHMAP_TIMEOUT
  930. # define MAX_PH_FIELDS 20
  931. #endif /* _FFR_PHMAP_TIMEOUT */
  932. char *
  933. ph_map_lookup(map, key, args, pstat)
  934. MAP *map;
  935. char *key;
  936. char **args;
  937. int *pstat;
  938. {
  939. int j;
  940. size_t sz;
  941. char *tmp, *tmp2;
  942. char *message = NULL, *field = NULL, *fmtkey;
  943. QIR *server_data = NULL;
  944. char keybuf[MAXKEY + 1], fieldbuf[101];
  945. #if _FFR_PHMAP_TIMEOUT
  946. QIR *hold_data[MAX_PH_FIELDS];
  947. int hold_data_idx = 0;
  948. register EVENT *ev = NULL;
  949. #endif /* _FFR_PHMAP_TIMEOUT */
  950. PH_MAP_STRUCT *pmap;
  951. pmap = (PH_MAP_STRUCT *)map->map_db1;
  952. *pstat = EX_OK;
  953. #if _FFR_PHMAP_TIMEOUT
  954. if (pmap->ph_timeout != 0)
  955. {
  956. if (setjmp(PHTimeout) != 0)
  957. {
  958. ev = NULL;
  959. if (LogLevel > 1)
  960. sm_syslog(LOG_NOTICE, CurEnv->e_id,
  961.   "timeout during PH lookup of %.100s",
  962.   key);
  963. # ifdef ETIMEDOUT
  964. errno = ETIMEDOUT;
  965. # else /* ETIMEDOUT */
  966. errno = 0;
  967. # endif /* ETIMEDOUT */
  968. *pstat = EX_TEMPFAIL;
  969. goto ph_map_lookup_abort;
  970. }
  971. ev = setevent(pmap->ph_timeout, ph_timeout_func, 0);
  972. }
  973. #endif /* _FFR_PHMAP_TIMEOUT */
  974. /* check all relevant fields */
  975. tmp = pmap->ph_field_list;
  976. do {
  977. #if _FFR_PHMAP_TIMEOUT
  978. server_data = NULL;
  979. #endif /* _FFR_PHMAP_TIMEOUT */
  980. while (isascii(*tmp) && isspace(*tmp))
  981. tmp++;
  982. if (*tmp == '')
  983. break;
  984. sz = strcspn(tmp, " ") + 1;
  985. if (sz > sizeof fieldbuf)
  986. sz = sizeof fieldbuf;
  987. (void) strlcpy(fieldbuf, tmp, sz);
  988. field = fieldbuf;
  989. tmp += sz;
  990. (void) strlcpy(keybuf, key, sizeof keybuf);
  991. fmtkey = keybuf;
  992. if (strcmp(field, "alias") == 0)
  993. {
  994. /*
  995. **  for alias lookups, replace any punctuation
  996. **  characters with '-'
  997. */
  998. for (tmp2 = fmtkey; *tmp2 !=  ''; tmp2++)
  999. {
  1000. if (ispunct(*tmp2))
  1001. *tmp2 = '-';
  1002. }
  1003. tmp2 = field;
  1004. }
  1005. else if (strcmp(field,"spacedname") == 0)
  1006. {
  1007. /*
  1008. **  for "spaced" name lookups, replace any
  1009. **  punctuation characters with a space
  1010. */
  1011. for (tmp2 = fmtkey; *tmp2 != ''; tmp2++)
  1012. if (ispunct(*tmp2) && *tmp2 != '*')
  1013. *tmp2 = ' ';
  1014. tmp2 = &(field[6]);
  1015. }
  1016. else
  1017. tmp2 = field;
  1018. if (LogLevel > 9)
  1019. sm_syslog(LOG_NOTICE, CurEnv->e_id,
  1020.   "ph_map_lookup: query %s="%s" return email",
  1021.   tmp2, fmtkey);
  1022. if (tTd(38, 20))
  1023. dprintf("ph_map_lookup: query %s="%s" return emailn",
  1024. tmp2, fmtkey);
  1025. j = 0;
  1026. if (fprintf(pmap->ph_to_server, "query %s=%s return emailn",
  1027.     tmp2, fmtkey) < 0)
  1028. message = "qi query command failed";
  1029. else if (fflush(pmap->ph_to_server) < 0)
  1030. message = "qi fflush failed";
  1031. else if ((server_data = ReadQi(pmap->ph_from_server,
  1032.        &j)) == NULL)
  1033. message = "ReadQi() returned NULL";
  1034. #if _FFR_PHMAP_TIMEOUT
  1035. if ((hold_data[hold_data_idx] = server_data) != NULL)
  1036. {
  1037. /* save pointer for later free() */
  1038. hold_data_idx++;
  1039. }
  1040. #endif /* _FFR_PHMAP_TIMEOUT */
  1041. if (server_data == NULL ||
  1042.     (server_data->code >= 400 &&
  1043.      server_data->code < 500))
  1044. {
  1045. /* temporary failure */
  1046. *pstat = EX_TEMPFAIL;
  1047. #if _FFR_PHMAP_TIMEOUT
  1048. break;
  1049. #else /* _FFR_PHMAP_TIMEOUT */
  1050. if (server_data != NULL)
  1051. {
  1052. free(server_data);
  1053. server_data = NULL;
  1054. }
  1055. return NULL;
  1056. #endif /* _FFR_PHMAP_TIMEOUT */
  1057. }
  1058. /*
  1059. **  if we found a single match, break out.
  1060. **  otherwise, try the next field.
  1061. */
  1062. if (j == 1)
  1063. break;
  1064. #if _FFR_PHMAP_TIMEOUT
  1065. } while (*tmp != '' && hold_data_idx < MAX_PH_FIELDS);
  1066. #else /* _FFR_PHMAP_TIMEOUT */
  1067. } while (*tmp != '');
  1068. #endif /* _FFR_PHMAP_TIMEOUT */
  1069. #if _FFR_PHMAP_TIMEOUT
  1070.   ph_map_lookup_abort:
  1071. if (ev != NULL)
  1072. clrevent(ev);
  1073. /*
  1074. **  Return EX_TEMPFAIL if the timer popped
  1075. **  or we got a temporary PH error
  1076. */
  1077. if (*pstat == EX_TEMPFAIL)
  1078. ph_map_safeclose(map);
  1079. /* if we didn't find a single match, bail out */
  1080. if (*pstat == EX_OK && j != 1)
  1081. *pstat = EX_UNAVAILABLE;
  1082. if (*pstat == EX_OK)
  1083. {
  1084. if (tTd(38,20))
  1085. dprintf("ph_map_lookup: %s => %sn",
  1086. key, server_data->message);
  1087. if (bitset(MF_MATCHONLY, map->map_mflags))
  1088. message = map_rewrite(map, key, strlen(key), NULL);
  1089. else
  1090. message = map_rewrite(map, server_data->message,
  1091.       strlen(server_data->message),
  1092.       args);
  1093. }
  1094. /*
  1095. **  Deferred free() of returned server_data values
  1096. **  the deferral is to avoid the risk of a free() being
  1097. **  interrupted by the event timer.  By now the timeout event
  1098. **  has been cleared and none of the data is still in use.
  1099. */
  1100. while (--hold_data_idx >= 0)
  1101. {
  1102. if (hold_data[hold_data_idx] != NULL)
  1103. FreeQIR(hold_data[hold_data_idx]);
  1104. }
  1105. if (*pstat == EX_OK)
  1106. return message;
  1107. return NULL;
  1108. #else /* _FFR_PHMAP_TIMEOUT */
  1109. /* if we didn't find a single match, bail out */
  1110. if (j != 1)
  1111. {
  1112. *pstat = EX_UNAVAILABLE;
  1113. if (server_data != NULL)
  1114. {
  1115. free(server_data);
  1116. server_data = NULL;
  1117. }
  1118. return NULL;
  1119. }
  1120. if (tTd(38,20))
  1121. dprintf("ph_map_lookup: %s => %sn",
  1122. key, server_data->message);
  1123. if (bitset(MF_MATCHONLY, map->map_mflags))
  1124. message = map_rewrite(map, key, strlen(key), NULL);
  1125. else
  1126. message = map_rewrite(map, server_data->message,
  1127.       strlen(server_data->message), args);
  1128. if (server_data != NULL)
  1129. {
  1130. free(server_data);
  1131. server_data = NULL;
  1132. }
  1133. return message;
  1134. #endif /* _FFR_PHMAP_TIMEOUT */
  1135. }
  1136. #endif /* PH_MAP */
  1137. /*
  1138. **  syslog map
  1139. */
  1140. #define map_prio map_lockfd /* overload field */
  1141. /*
  1142. **  SYSLOG_MAP_PARSEARGS -- check for priority level to syslog messages.
  1143. */
  1144. bool
  1145. syslog_map_parseargs(map, args)
  1146. MAP *map;
  1147. char *args;
  1148. {
  1149. char *p = args;
  1150. char *priority = NULL;
  1151. /* there is no check whether there is really an argument */
  1152. while (*p != '')
  1153. {
  1154. while (isascii(*p) && isspace(*p))
  1155. p++;
  1156. if (*p != '-')
  1157. break;
  1158. ++p;
  1159. if (*p == 'D')
  1160. {
  1161. map->map_mflags |= MF_DEFER;
  1162. ++p;
  1163. }
  1164. else if (*p == 'S')
  1165. {
  1166. map->map_spacesub = *++p;
  1167. if (*p != '')
  1168. p++;
  1169. }
  1170. else if (*p == 'L')
  1171. {
  1172. while (*++p != '' && isascii(*p) && isspace(*p))
  1173. continue;
  1174. if (*p == '')
  1175. break;
  1176. priority = p;
  1177. while (*p != '' && !(isascii(*p) && isspace(*p)))
  1178. p++;
  1179. if (*p != '')
  1180. *p++ = '';
  1181. }
  1182. else
  1183. {
  1184. syserr("Illegal option %c map syslog", *p);
  1185. ++p;
  1186. }
  1187. }
  1188. if (priority == NULL)
  1189. map->map_prio = LOG_INFO;
  1190. else
  1191. {
  1192. if (strncasecmp("LOG_", priority, 4) == 0)
  1193. priority += 4;
  1194. #ifdef LOG_EMERG
  1195. if (strcasecmp("EMERG", priority) == 0)
  1196. map->map_prio = LOG_EMERG;
  1197. else
  1198. #endif /* LOG_EMERG */
  1199. #ifdef LOG_ALERT
  1200. if (strcasecmp("ALERT", priority) == 0)
  1201. map->map_prio = LOG_ALERT;
  1202. else
  1203. #endif /* LOG_ALERT */
  1204. #ifdef LOG_CRIT
  1205. if (strcasecmp("CRIT", priority) == 0)
  1206. map->map_prio = LOG_CRIT;
  1207. else
  1208. #endif /* LOG_CRIT */
  1209. #ifdef LOG_ERR
  1210. if (strcasecmp("ERR", priority) == 0)
  1211. map->map_prio = LOG_ERR;
  1212. else
  1213. #endif /* LOG_ERR */
  1214. #ifdef LOG_WARNING
  1215. if (strcasecmp("WARNING", priority) == 0)
  1216. map->map_prio = LOG_WARNING;
  1217. else
  1218. #endif /* LOG_WARNING */
  1219. #ifdef LOG_NOTICE
  1220. if (strcasecmp("NOTICE", priority) == 0)
  1221. map->map_prio = LOG_NOTICE;
  1222. else
  1223. #endif /* LOG_NOTICE */
  1224. #ifdef LOG_INFO
  1225. if (strcasecmp("INFO", priority) == 0)
  1226. map->map_prio = LOG_INFO;
  1227. else
  1228. #endif /* LOG_INFO */
  1229. #ifdef LOG_DEBUG
  1230. if (strcasecmp("DEBUG", priority) == 0)
  1231. map->map_prio = LOG_DEBUG;
  1232. else
  1233. #endif /* LOG_DEBUG */
  1234. {
  1235. syserr("syslog_map_parseargs: Unknown priority %sn",
  1236.        priority);
  1237. return FALSE;
  1238. }
  1239. }
  1240. return TRUE;
  1241. }
  1242. /*
  1243. **  SYSLOG_MAP_LOOKUP -- rewrite and syslog message.  Always return empty string
  1244. */
  1245. char *
  1246. syslog_map_lookup(map, string, args, statp)
  1247. MAP *map;
  1248. char *string;
  1249. char **args;
  1250. int *statp;
  1251. {
  1252. char *ptr = map_rewrite(map, string, strlen(string), args);
  1253. if (ptr != NULL)
  1254. {
  1255. if (tTd(38, 20))
  1256. dprintf("syslog_map_lookup(%s (priority %d): %sn",
  1257. map->map_mname, map->map_prio, ptr);
  1258. sm_syslog(map->map_prio, CurEnv->e_id, "%s", ptr);
  1259. }
  1260. *statp = EX_OK;
  1261. return "";
  1262. }
  1263. /*
  1264. **  HESIOD Modules
  1265. */
  1266. #ifdef HESIOD
  1267. bool
  1268. hes_map_open(map, mode)
  1269. MAP *map;
  1270. int mode;
  1271. {
  1272. if (tTd(38, 2))
  1273. dprintf("hes_map_open(%s, %s, %d)n",
  1274. map->map_mname, map->map_file, mode);
  1275. if (mode != O_RDONLY)
  1276. {
  1277. /* issue a pseudo-error message */
  1278. # ifdef ENOSYS
  1279. errno = ENOSYS;
  1280. # else /* ENOSYS */
  1281. #  ifdef EFTYPE
  1282. errno = EFTYPE;
  1283. #  else /* EFTYPE */
  1284. errno = ENXIO;
  1285. #  endif /* EFTYPE */
  1286. # endif /* ENOSYS */
  1287. return FALSE;
  1288. }
  1289. # ifdef HESIOD_INIT
  1290. if (HesiodContext != NULL || hesiod_init(&HesiodContext) == 0)
  1291. return TRUE;
  1292. if (!bitset(MF_OPTIONAL, map->map_mflags))
  1293. syserr("421 4.0.0 cannot initialize Hesiod map (%s)",
  1294. errstring(errno));
  1295. return FALSE;
  1296. # else /* HESIOD_INIT */
  1297. if (hes_error() == HES_ER_UNINIT)
  1298. hes_init();
  1299. switch (hes_error())
  1300. {
  1301.   case HES_ER_OK:
  1302.   case HES_ER_NOTFOUND:
  1303. return TRUE;
  1304. }
  1305. if (!bitset(MF_OPTIONAL, map->map_mflags))
  1306. syserr("421 4.0.0 cannot initialize Hesiod map (%d)", hes_error());
  1307. return FALSE;
  1308. # endif /* HESIOD_INIT */
  1309. }
  1310. char *
  1311. hes_map_lookup(map, name, av, statp)
  1312. MAP *map;
  1313. char *name;
  1314. char **av;
  1315. int *statp;
  1316. {
  1317. char **hp;
  1318. if (tTd(38, 20))
  1319. dprintf("hes_map_lookup(%s, %s)n", map->map_file, name);
  1320. if (name[0] == '\')
  1321. {
  1322. char *np;
  1323. int nl;
  1324. char nbuf[MAXNAME];
  1325. nl = strlen(name);
  1326. if (nl < sizeof nbuf - 1)
  1327. np = nbuf;
  1328. else
  1329. np = xalloc(strlen(name) + 2);
  1330. np[0] = '\';
  1331. (void) strlcpy(&np[1], name, (sizeof nbuf) - 1);
  1332. # ifdef HESIOD_INIT
  1333. hp = hesiod_resolve(HesiodContext, np, map->map_file);
  1334. # else /* HESIOD_INIT */
  1335. hp = hes_resolve(np, map->map_file);
  1336. # endif /* HESIOD_INIT */
  1337. if (np != nbuf)
  1338. free(np);
  1339. }
  1340. else
  1341. {
  1342. # ifdef HESIOD_INIT
  1343. hp = hesiod_resolve(HesiodContext, name, map->map_file);
  1344. # else /* HESIOD_INIT */
  1345. hp = hes_resolve(name, map->map_file);
  1346. # endif /* HESIOD_INIT */
  1347. }
  1348. # ifdef HESIOD_INIT
  1349. if (hp == NULL)
  1350. return NULL;
  1351. if (*hp == NULL)
  1352. {
  1353. hesiod_free_list(HesiodContext, hp);
  1354. switch (errno)
  1355. {
  1356.   case ENOENT:
  1357.   *statp = EX_NOTFOUND;
  1358.   break;
  1359.   case ECONNREFUSED:
  1360.   case EMSGSIZE:
  1361.   *statp = EX_TEMPFAIL;
  1362.   break;
  1363.   case ENOMEM:
  1364.   default:
  1365.   *statp = EX_UNAVAILABLE;
  1366.   break;
  1367. }
  1368. return NULL;
  1369. }
  1370. # else /* HESIOD_INIT */
  1371. if (hp == NULL || hp[0] == NULL)
  1372. {
  1373. switch (hes_error())
  1374. {
  1375.   case HES_ER_OK:
  1376. *statp = EX_OK;
  1377. break;
  1378.   case HES_ER_NOTFOUND:
  1379. *statp = EX_NOTFOUND;
  1380. break;
  1381.   case HES_ER_CONFIG:
  1382. *statp = EX_UNAVAILABLE;
  1383. break;
  1384.   case HES_ER_NET:
  1385. *statp = EX_TEMPFAIL;
  1386. break;
  1387. }
  1388. return NULL;
  1389. }
  1390. # endif /* HESIOD_INIT */
  1391. if (bitset(MF_MATCHONLY, map->map_mflags))
  1392. return map_rewrite(map, name, strlen(name), NULL);
  1393. else
  1394. return map_rewrite(map, hp[0], strlen(hp[0]), av);
  1395. }
  1396. #endif /* HESIOD */
  1397. /*
  1398. **  NeXT NETINFO Modules
  1399. */
  1400. #if NETINFO
  1401. # define NETINFO_DEFAULT_DIR "/aliases"
  1402. # define NETINFO_DEFAULT_PROPERTY "members"
  1403. /*
  1404. **  NI_MAP_OPEN -- open NetInfo Aliases
  1405. */
  1406. bool
  1407. ni_map_open(map, mode)
  1408. MAP *map;
  1409. int mode;
  1410. {
  1411. if (tTd(38, 2))
  1412. dprintf("ni_map_open(%s, %s, %d)n",
  1413. map->map_mname, map->map_file, mode);
  1414. mode &= O_ACCMODE;
  1415. if (*map->map_file == '')
  1416. map->map_file = NETINFO_DEFAULT_DIR;
  1417. if (map->map_valcolnm == NULL)
  1418. map->map_valcolnm = NETINFO_DEFAULT_PROPERTY;
  1419. if (map->map_coldelim == '' && bitset(MF_ALIAS, map->map_mflags))
  1420. map->map_coldelim = ',';
  1421. return TRUE;
  1422. }
  1423. /*
  1424. **  NI_MAP_LOOKUP -- look up a datum in NetInfo
  1425. */
  1426. char *
  1427. ni_map_lookup(map, name, av, statp)
  1428. MAP *map;
  1429. char *name;
  1430. char **av;
  1431. int *statp;
  1432. {
  1433. char *res;
  1434. char *propval;
  1435. if (tTd(38, 20))
  1436. dprintf("ni_map_lookup(%s, %s)n", map->map_mname, name);
  1437. propval = ni_propval(map->map_file, map->map_keycolnm, name,
  1438.      map->map_valcolnm, map->map_coldelim);
  1439. if (propval == NULL)
  1440. return NULL;
  1441. if (bitset(MF_MATCHONLY, map->map_mflags))
  1442. res = map_rewrite(map, name, strlen(name), NULL);
  1443. else
  1444. res = map_rewrite(map, propval, strlen(propval), av);
  1445. free(propval);
  1446. return res;
  1447. }
  1448. static bool
  1449. ni_getcanonname(name, hbsize, statp)
  1450. char *name;
  1451. int hbsize;
  1452. int *statp;
  1453. {
  1454. char *vptr;
  1455. char *ptr;
  1456. char nbuf[MAXNAME + 1];
  1457. if (tTd(38, 20))
  1458. dprintf("ni_getcanonname(%s)n", name);
  1459. if (strlcpy(nbuf, name, sizeof nbuf) >= sizeof nbuf)
  1460. {
  1461. *statp = EX_UNAVAILABLE;
  1462. return FALSE;
  1463. }
  1464. shorten_hostname(nbuf);
  1465. /* we only accept single token search key */
  1466. if (strchr(nbuf, '.'))
  1467. {
  1468. *statp = EX_NOHOST;
  1469. return FALSE;
  1470. }
  1471. /* Do the search */
  1472. vptr = ni_propval("/machines", NULL, nbuf, "name", 'n');
  1473. if (vptr == NULL)
  1474. {
  1475. *statp = EX_NOHOST;
  1476. return FALSE;
  1477. }
  1478. /* Only want the first machine name */
  1479. if ((ptr = strchr(vptr, 'n')) != NULL)
  1480. *ptr = '';
  1481. if (hbsize >= strlen(vptr))
  1482. {
  1483. (void) strlcpy(name, vptr, hbsize);
  1484. free(vptr);
  1485. *statp = EX_OK;
  1486. return TRUE;
  1487. }
  1488. *statp = EX_UNAVAILABLE;
  1489. free(vptr);
  1490. return FALSE;
  1491. }
  1492. /*
  1493. **  NI_PROPVAL -- NetInfo property value lookup routine
  1494. **
  1495. ** Parameters:
  1496. ** keydir -- the NetInfo directory name in which to search
  1497. ** for the key.
  1498. ** keyprop -- the name of the property in which to find the
  1499. ** property we are interested.  Defaults to "name".
  1500. ** keyval -- the value for which we are really searching.
  1501. ** valprop -- the property name for the value in which we
  1502. ** are interested.
  1503. ** sepchar -- if non-nil, this can be multiple-valued, and
  1504. ** we should return a string separated by this
  1505. ** character.
  1506. **
  1507. ** Returns:
  1508. ** NULL -- if:
  1509. ** 1. the directory is not found
  1510. ** 2. the property name is not found
  1511. ** 3. the property contains multiple values
  1512. ** 4. some error occurred
  1513. ** else -- the value of the lookup.
  1514. **
  1515. ** Example:
  1516. ** To search for an alias value, use:
  1517. **   ni_propval("/aliases", "name", aliasname, "members", ',')
  1518. **
  1519. ** Notes:
  1520. ** Caller should free the return value of ni_proval
  1521. */
  1522. # include <netinfo/ni.h>
  1523. # define LOCAL_NETINFO_DOMAIN "."
  1524. # define PARENT_NETINFO_DOMAIN ".."
  1525. # define MAX_NI_LEVELS 256
  1526. char *
  1527. ni_propval(keydir, keyprop, keyval, valprop, sepchar)
  1528. char *keydir;
  1529. char *keyprop;
  1530. char *keyval;
  1531. char *valprop;
  1532. int sepchar;
  1533. {
  1534. char *propval = NULL;
  1535. int i;
  1536. int j, alen, l;
  1537. void *ni = NULL;
  1538. void *lastni = NULL;
  1539. ni_status nis;
  1540. ni_id nid;
  1541. ni_namelist ninl;
  1542. register char *p;
  1543. char keybuf[1024];
  1544. /*
  1545. **  Create the full key from the two parts.
  1546. **
  1547. ** Note that directory can end with, e.g., "name=" to specify
  1548. ** an alternate search property.
  1549. */
  1550. i = strlen(keydir) + strlen(keyval) + 2;
  1551. if (keyprop != NULL)
  1552. i += strlen(keyprop) + 1;
  1553. if (i >= sizeof keybuf)
  1554. return NULL;
  1555. (void) strlcpy(keybuf, keydir, sizeof keybuf);
  1556. (void) strlcat(keybuf, "/", sizeof keybuf);
  1557. if (keyprop != NULL)
  1558. {
  1559. (void) strlcat(keybuf, keyprop, sizeof keybuf);
  1560. (void) strlcat(keybuf, "=", sizeof keybuf);
  1561. }
  1562. (void) strlcat(keybuf, keyval, sizeof keybuf);
  1563. if (tTd(38, 21))
  1564. dprintf("ni_propval(%s, %s, %s, %s, %d) keybuf='%s'n",
  1565. keydir, keyprop, keyval, valprop, sepchar, keybuf);
  1566. /*
  1567. **  If the passed directory and property name are found
  1568. **  in one of netinfo domains we need to search (starting
  1569. **  from the local domain moving all the way back to the
  1570. **  root domain) set propval to the property's value
  1571. **  and return it.
  1572. */
  1573. for (i = 0; i < MAX_NI_LEVELS && propval == NULL; i++)
  1574. {
  1575. if (i == 0)
  1576. {
  1577. nis = ni_open(NULL, LOCAL_NETINFO_DOMAIN, &ni);
  1578. if (tTd(38, 20))
  1579. dprintf("ni_open(LOCAL) = %dn", nis);
  1580. }
  1581. else
  1582. {
  1583. if (lastni != NULL)
  1584. ni_free(lastni);
  1585. lastni = ni;
  1586. nis = ni_open(lastni, PARENT_NETINFO_DOMAIN, &ni);
  1587. if (tTd(38, 20))
  1588. dprintf("ni_open(PARENT) = %dn", nis);
  1589. }
  1590. /*
  1591. **  Don't bother if we didn't get a handle on a
  1592. **  proper domain.  This is not necessarily an error.
  1593. **  We would get a positive ni_status if, for instance
  1594. **  we never found the directory or property and tried
  1595. **  to open the parent of the root domain!
  1596. */
  1597. if (nis != 0)
  1598. break;
  1599. /*
  1600. **  Find the path to the server information.
  1601. */
  1602. if (ni_pathsearch(ni, &nid, keybuf) != 0)
  1603. continue;
  1604. /*
  1605. **  Find associated value information.
  1606. */
  1607. if (ni_lookupprop(ni, &nid, valprop, &ninl) != 0)
  1608. continue;
  1609. if (tTd(38, 20))
  1610. dprintf("ni_lookupprop: len=%dn",
  1611. ninl.ni_namelist_len);
  1612. /*
  1613. **  See if we have an acceptable number of values.
  1614. */
  1615. if (ninl.ni_namelist_len <= 0)
  1616. continue;
  1617. if (sepchar == '' && ninl.ni_namelist_len > 1)
  1618. {
  1619. ni_namelist_free(&ninl);
  1620. continue;
  1621. }
  1622. /*
  1623. **  Calculate number of bytes needed and build result
  1624. */
  1625. alen = 1;
  1626. for (j = 0; j < ninl.ni_namelist_len; j++)
  1627. alen += strlen(ninl.ni_namelist_val[j]) + 1;
  1628. propval = p = xalloc(alen);
  1629. for (j = 0; j < ninl.ni_namelist_len; j++)
  1630. {
  1631. (void) strlcpy(p, ninl.ni_namelist_val[j], alen);
  1632. l = strlen(p);
  1633. p += l;
  1634. *p++ = sepchar;
  1635. alen -= l + 1;
  1636. }
  1637. *--p = '';
  1638. ni_namelist_free(&ninl);
  1639. }
  1640. /*
  1641. **  Clean up.
  1642. */
  1643. if (ni != NULL)
  1644. ni_free(ni);
  1645. if (lastni != NULL && ni != lastni)
  1646. ni_free(lastni);
  1647. if (tTd(38, 20))
  1648. dprintf("ni_propval returns: '%s'n", propval);
  1649. return propval;
  1650. }
  1651. #endif /* NETINFO */
  1652. /*
  1653. **  TEXT (unindexed text file) Modules
  1654. **
  1655. ** This code donated by Sun Microsystems.
  1656. */
  1657. #define map_sff map_lockfd /* overload field */
  1658. /*
  1659. **  TEXT_MAP_OPEN -- open text table
  1660. */
  1661. bool
  1662. text_map_open(map, mode)
  1663. MAP *map;
  1664. int mode;
  1665. {
  1666. long sff;
  1667. int i;
  1668. if (tTd(38, 2))
  1669. dprintf("text_map_open(%s, %s, %d)n",
  1670. map->map_mname, map->map_file, mode);
  1671. mode &= O_ACCMODE;
  1672. if (mode != O_RDONLY)
  1673. {
  1674. errno = EPERM;
  1675. return FALSE;
  1676. }
  1677. if (*map->map_file == '')
  1678. {
  1679. syserr("text map "%s": file name required",
  1680. map->map_mname);
  1681. return FALSE;
  1682. }
  1683. if (map->map_file[0] != '/')
  1684. {
  1685. syserr("text map "%s": file name must be fully qualified",
  1686. map->map_mname);
  1687. return FALSE;
  1688. }
  1689. sff = SFF_ROOTOK|SFF_REGONLY;
  1690. if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
  1691. sff |= SFF_NOWLINK;
  1692. if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
  1693. sff |= SFF_SAFEDIRPATH;
  1694. if ((i = safefile(map->map_file, RunAsUid, RunAsGid, RunAsUserName,
  1695.   sff, S_IRUSR, NULL)) != 0)
  1696. {
  1697. int save_errno = errno;
  1698. /* cannot open this map */
  1699. if (tTd(38, 2))
  1700. dprintf("tunsafe map file: %dn", i);
  1701. errno = save_errno;
  1702. if (!bitset(MF_OPTIONAL, map->map_mflags))
  1703. syserr("text map "%s": unsafe map file %s",
  1704. map->map_mname, map->map_file);
  1705. return FALSE;
  1706. }
  1707. if (map->map_keycolnm == NULL)
  1708. map->map_keycolno = 0;
  1709. else
  1710. {
  1711. if (!(isascii(*map->map_keycolnm) && isdigit(*map->map_keycolnm)))
  1712. {
  1713. syserr("text map "%s", file %s: -k should specify a number, not %s",
  1714. map->map_mname, map->map_file,
  1715. map->map_keycolnm);
  1716. return FALSE;
  1717. }
  1718. map->map_keycolno = atoi(map->map_keycolnm);
  1719. }
  1720. if (map->map_valcolnm == NULL)
  1721. map->map_valcolno = 0;
  1722. else
  1723. {
  1724. if (!(isascii(*map->map_valcolnm) && isdigit(*map->map_valcolnm)))
  1725. {
  1726. syserr("text map "%s", file %s: -v should specify a number, not %s",
  1727. map->map_mname, map->map_file,
  1728. map->map_valcolnm);
  1729. return FALSE;
  1730. }
  1731. map->map_valcolno = atoi(map->map_valcolnm);
  1732. }
  1733. if (tTd(38, 2))
  1734. {
  1735. dprintf("text_map_open(%s, %s): delimiter = ",
  1736. map->map_mname, map->map_file);
  1737. if (map->map_coldelim == '')
  1738. dprintf("(white space)n");
  1739. else
  1740. dprintf("%cn", map->map_coldelim);
  1741. }
  1742. map->map_sff = sff;
  1743. return TRUE;
  1744. }
  1745. /*
  1746. **  TEXT_MAP_LOOKUP -- look up a datum in a TEXT table
  1747. */
  1748. char *
  1749. text_map_lookup(map, name, av, statp)
  1750. MAP *map;
  1751. char *name;
  1752. char **av;
  1753. int *statp;
  1754. {
  1755. char *vp;
  1756. auto int vsize;
  1757. int buflen;
  1758. FILE *f;
  1759. char delim;
  1760. int key_idx;
  1761. bool found_it;
  1762. long sff = map->map_sff;
  1763. char search_key[MAXNAME + 1];
  1764. char linebuf[MAXLINE];
  1765. char buf[MAXNAME + 1];
  1766. found_it = FALSE;
  1767. if (tTd(38, 20))
  1768. dprintf("text_map_lookup(%s, %s)n", map->map_mname,  name);
  1769. buflen = strlen(name);
  1770. if (buflen > sizeof search_key - 1)
  1771. buflen = sizeof search_key - 1;
  1772. memmove(search_key, name, buflen);
  1773. search_key[buflen] = '';
  1774. if (!bitset(MF_NOFOLDCASE, map->map_mflags))
  1775. makelower(search_key);
  1776. f = safefopen(map->map_file, O_RDONLY, FileMode, sff);
  1777. if (f == NULL)
  1778. {
  1779. map->map_mflags &= ~(MF_VALID|MF_OPEN);
  1780. *statp = EX_UNAVAILABLE;
  1781. return NULL;
  1782. }
  1783. key_idx = map->map_keycolno;
  1784. delim = map->map_coldelim;
  1785. while (fgets(linebuf, MAXLINE, f) != NULL)
  1786. {
  1787. char *p;
  1788. /* skip comment line */
  1789. if (linebuf[0] == '#')
  1790. continue;
  1791. p = strchr(linebuf, 'n');
  1792. if (p != NULL)
  1793. *p = '';
  1794. p = get_column(linebuf, key_idx, delim, buf, sizeof buf);
  1795. if (p != NULL && strcasecmp(search_key, p) == 0)
  1796. {
  1797. found_it = TRUE;
  1798. break;
  1799. }
  1800. }
  1801. (void) fclose(f);
  1802. if (!found_it)
  1803. {
  1804. *statp = EX_NOTFOUND;
  1805. return NULL;
  1806. }
  1807. vp = get_column(linebuf, map->map_valcolno, delim, buf, sizeof buf);
  1808. if (vp == NULL)
  1809. {
  1810. *statp = EX_NOTFOUND;
  1811. return NULL;
  1812. }
  1813. vsize = strlen(vp);
  1814. *statp = EX_OK;
  1815. if (bitset(MF_MATCHONLY, map->map_mflags))
  1816. return map_rewrite(map, name, strlen(name), NULL);
  1817. else
  1818. return map_rewrite(map, vp, vsize, av);
  1819. }
  1820. /*
  1821. **  TEXT_GETCANONNAME -- look up canonical name in hosts file
  1822. */
  1823. static bool
  1824. text_getcanonname(name, hbsize, statp)
  1825. char *name;
  1826. int hbsize;
  1827. int *statp;
  1828. {
  1829. bool found;
  1830. FILE *f;
  1831. char linebuf[MAXLINE];
  1832. char cbuf[MAXNAME + 1];
  1833. char nbuf[MAXNAME + 1];
  1834. if (tTd(38, 20))
  1835. dprintf("text_getcanonname(%s)n", name);
  1836. if (strlen(name) >= (SIZE_T) sizeof nbuf)
  1837. {
  1838. *statp = EX_UNAVAILABLE;
  1839. return FALSE;
  1840. }
  1841. (void) strlcpy(nbuf, name, sizeof nbuf);
  1842. shorten_hostname(nbuf);
  1843. f = fopen(HostsFile, "r");
  1844. if (f == NULL)
  1845. {
  1846. *statp = EX_UNAVAILABLE;
  1847. return FALSE;
  1848. }
  1849. found = FALSE;
  1850. while (!found && fgets(linebuf, MAXLINE, f) != NULL)
  1851. {
  1852. char *p = strpbrk(linebuf, "#n");
  1853. if (p != NULL)
  1854. *p = '';
  1855. if (linebuf[0] != '')
  1856. found = extract_canonname(nbuf, linebuf, cbuf, sizeof cbuf);
  1857. }
  1858. (void) fclose(f);
  1859. if (!found)
  1860. {
  1861. *statp = EX_NOHOST;
  1862. return FALSE;
  1863. }
  1864. if ((SIZE_T) hbsize >= strlen(cbuf))
  1865. {
  1866. (void) strlcpy(name, cbuf, hbsize);
  1867. *statp = EX_OK;
  1868. return TRUE;
  1869. }
  1870. *statp = EX_UNAVAILABLE;
  1871. return FALSE;
  1872. }
  1873. /*
  1874. **  STAB (Symbol Table) Modules
  1875. */
  1876. /*
  1877. **  STAB_MAP_LOOKUP -- look up alias in symbol table
  1878. */
  1879. /* ARGSUSED2 */
  1880. char *
  1881. stab_map_lookup(map, name, av, pstat)
  1882. register MAP *map;
  1883. char *name;
  1884. char **av;
  1885. int *pstat;
  1886. {
  1887. register STAB *s;
  1888. if (tTd(38, 20))
  1889. dprintf("stab_lookup(%s, %s)n",
  1890. map->map_mname, name);
  1891. s = stab(name, ST_ALIAS, ST_FIND);
  1892. if (s != NULL)
  1893. return s->s_alias;
  1894. return NULL;
  1895. }
  1896. /*
  1897. **  STAB_MAP_STORE -- store in symtab (actually using during init, not rebuild)
  1898. */
  1899. void
  1900. stab_map_store(map, lhs, rhs)
  1901. register MAP *map;
  1902. char *lhs;
  1903. char *rhs;
  1904. {
  1905. register STAB *s;
  1906. s = stab(lhs, ST_ALIAS, ST_ENTER);
  1907. s->s_alias = newstr(rhs);
  1908. }
  1909. /*
  1910. **  STAB_MAP_OPEN -- initialize (reads data file)
  1911. **
  1912. ** This is a wierd case -- it is only intended as a fallback for
  1913. ** aliases.  For this reason, opens for write (only during a
  1914. ** "newaliases") always fails, and opens for read open the
  1915. ** actual underlying text file instead of the database.
  1916. */
  1917. bool
  1918. stab_map_open(map, mode)
  1919. register MAP *map;
  1920. int mode;
  1921. {
  1922. FILE *af;
  1923. long sff;
  1924. struct stat st;
  1925. if (tTd(38, 2))
  1926. dprintf("stab_map_open(%s, %s, %d)n",
  1927. map->map_mname, map->map_file, mode);
  1928. mode &= O_ACCMODE;
  1929. if (mode != O_RDONLY)
  1930. {
  1931. errno = EPERM;
  1932. return FALSE;
  1933. }
  1934. sff = SFF_ROOTOK|SFF_REGONLY;
  1935. if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
  1936. sff |= SFF_NOWLINK;
  1937. if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
  1938. sff |= SFF_SAFEDIRPATH;
  1939. af = safefopen(map->map_file, O_RDONLY, 0444, sff);
  1940. if (af == NULL)
  1941. return FALSE;
  1942. readaliases(map, af, FALSE, FALSE);
  1943. if (fstat(fileno(af), &st) >= 0)
  1944. map->map_mtime = st.st_mtime;
  1945. (void) fclose(af);
  1946. return TRUE;
  1947. }
  1948. /*
  1949. **  Implicit Modules
  1950. **
  1951. ** Tries several types.  For back compatibility of aliases.
  1952. */
  1953. /*
  1954. **  IMPL_MAP_LOOKUP -- lookup in best open database
  1955. */
  1956. char *
  1957. impl_map_lookup(map, name, av, pstat)
  1958. MAP *map;
  1959. char *name;
  1960. char **av;
  1961. int *pstat;
  1962. {
  1963. if (tTd(38, 20))
  1964. dprintf("impl_map_lookup(%s, %s)n",
  1965. map->map_mname, name);
  1966. #ifdef NEWDB
  1967. if (bitset(MF_IMPL_HASH, map->map_mflags))
  1968. return db_map_lookup(map, name, av, pstat);
  1969. #endif /* NEWDB */
  1970. #ifdef NDBM
  1971. if (bitset(MF_IMPL_NDBM, map->map_mflags))
  1972. return ndbm_map_lookup(map, name, av, pstat);
  1973. #endif /* NDBM */
  1974. return stab_map_lookup(map, name, av, pstat);
  1975. }
  1976. /*
  1977. **  IMPL_MAP_STORE -- store in open databases
  1978. */
  1979. void
  1980. impl_map_store(map, lhs, rhs)
  1981. MAP *map;
  1982. char *lhs;
  1983. char *rhs;
  1984. {
  1985. if (tTd(38, 12))
  1986. dprintf("impl_map_store(%s, %s, %s)n",
  1987. map->map_mname, lhs, rhs);
  1988. #ifdef NEWDB
  1989. if (bitset(MF_IMPL_HASH, map->map_mflags))
  1990. db_map_store(map, lhs, rhs);
  1991. #endif /* NEWDB */
  1992. #ifdef NDBM
  1993. if (bitset(MF_IMPL_NDBM, map->map_mflags))
  1994. ndbm_map_store(map, lhs, rhs);
  1995. #endif /* NDBM */
  1996. stab_map_store(map, lhs, rhs);
  1997. }
  1998. /*
  1999. **  IMPL_MAP_OPEN -- implicit database open
  2000. */
  2001. bool
  2002. impl_map_open(map, mode)
  2003. MAP *map;
  2004. int mode;
  2005. {
  2006. if (tTd(38, 2))
  2007. dprintf("impl_map_open(%s, %s, %d)n",
  2008. map->map_mname, map->map_file, mode);
  2009. mode &= O_ACCMODE;
  2010. #ifdef NEWDB
  2011. map->map_mflags |= MF_IMPL_HASH;
  2012. if (hash_map_open(map, mode))
  2013. {
  2014. # ifdef NDBM_YP_COMPAT
  2015. if (mode == O_RDONLY || strstr(map->map_file, "/yp/") == NULL)
  2016. # endif /* NDBM_YP_COMPAT */
  2017. return TRUE;
  2018. }
  2019. else
  2020. map->map_mflags &= ~MF_IMPL_HASH;
  2021. #endif /* NEWDB */
  2022. #ifdef NDBM
  2023. map->map_mflags |= MF_IMPL_NDBM;
  2024. if (ndbm_map_open(map, mode))
  2025. {
  2026. return TRUE;
  2027. }
  2028. else
  2029. map->map_mflags &= ~MF_IMPL_NDBM;
  2030. #endif /* NDBM */
  2031. #if defined(NEWDB) || defined(NDBM)
  2032. if (Verbose)
  2033. message("WARNING: cannot open alias database %s%s",
  2034. map->map_file,
  2035. mode == O_RDONLY ? "; reading text version" : "");
  2036. #else /* defined(NEWDB) || defined(NDBM) */
  2037. if (mode != O_RDONLY)
  2038. usrerr("Cannot rebuild aliases: no database format defined");
  2039. #endif /* defined(NEWDB) || defined(NDBM) */
  2040. if (mode == O_RDONLY)
  2041. return stab_map_open(map, mode);
  2042. else
  2043. return FALSE;
  2044. }
  2045. /*
  2046. **  IMPL_MAP_CLOSE -- close any open database(s)
  2047. */
  2048. void
  2049. impl_map_close(map)
  2050. MAP *map;
  2051. {
  2052. if (tTd(38, 9))
  2053. dprintf("impl_map_close(%s, %s, %lx)n",
  2054. map->map_mname, map->map_file, map->map_mflags);
  2055. #ifdef NEWDB
  2056. if (bitset(MF_IMPL_HASH, map->map_mflags))
  2057. {
  2058. db_map_close(map);
  2059. map->map_mflags &= ~MF_IMPL_HASH;
  2060. }
  2061. #endif /* NEWDB */
  2062. #ifdef NDBM
  2063. if (bitset(MF_IMPL_NDBM, map->map_mflags))
  2064. {
  2065. ndbm_map_close(map);
  2066. map->map_mflags &= ~MF_IMPL_NDBM;
  2067. }
  2068. #endif /* NDBM */
  2069. }
  2070. /*
  2071. **  User map class.
  2072. **
  2073. ** Provides access to the system password file.
  2074. */
  2075. /*
  2076. **  USER_MAP_OPEN -- open user map
  2077. **
  2078. ** Really just binds field names to field numbers.
  2079. */
  2080. bool
  2081. user_map_open(map, mode)
  2082. MAP *map;
  2083. int mode;
  2084. {
  2085. if (tTd(38, 2))
  2086. dprintf("user_map_open(%s, %d)n",
  2087. map->map_mname, mode);
  2088. mode &= O_ACCMODE;
  2089. if (mode != O_RDONLY)
  2090. {
  2091. /* issue a pseudo-error message */
  2092. #ifdef ENOSYS
  2093. errno = ENOSYS;
  2094. #else /* ENOSYS */
  2095. # ifdef EFTYPE
  2096. errno = EFTYPE;
  2097. # else /* EFTYPE */
  2098. errno = ENXIO;
  2099. # endif /* EFTYPE */
  2100. #endif /* ENOSYS */
  2101. return FALSE;
  2102. }
  2103. if (map->map_valcolnm == NULL)
  2104. /* EMPTY */
  2105. /* nothing */ ;
  2106. else if (strcasecmp(map->map_valcolnm, "name") == 0)
  2107. map->map_valcolno = 1;
  2108. else if (strcasecmp(map->map_valcolnm, "passwd") == 0)
  2109. map->map_valcolno = 2;
  2110. else if (strcasecmp(map->map_valcolnm, "uid") == 0)
  2111. map->map_valcolno = 3;
  2112. else if (strcasecmp(map->map_valcolnm, "gid") == 0)
  2113. map->map_valcolno = 4;
  2114. else if (strcasecmp(map->map_valcolnm, "gecos") == 0)
  2115. map->map_valcolno = 5;
  2116. else if (strcasecmp(map->map_valcolnm, "dir") == 0)
  2117. map->map_valcolno = 6;
  2118. else if (strcasecmp(map->map_valcolnm, "shell") == 0)
  2119. map->map_valcolno = 7;
  2120. else
  2121. {
  2122. syserr("User map %s: unknown column name %s",
  2123. map->map_mname, map->map_valcolnm);
  2124. return FALSE;
  2125. }
  2126. return TRUE;
  2127. }
  2128. /*
  2129. **  USER_MAP_LOOKUP -- look up a user in the passwd file.
  2130. */
  2131. /* ARGSUSED3 */
  2132. char *
  2133. user_map_lookup(map, key, av, statp)
  2134. MAP *map;
  2135. char *key;
  2136. char **av;
  2137. int *statp;
  2138. {
  2139. struct passwd *pw;
  2140. auto bool fuzzy;
  2141. if (tTd(38, 20))
  2142. dprintf("user_map_lookup(%s, %s)n",
  2143. map->map_mname, key);
  2144. pw = finduser(key, &fuzzy);
  2145. if (pw == NULL)
  2146. return NULL;
  2147. if (bitset(MF_MATCHONLY, map->map_mflags))
  2148. return map_rewrite(map, key, strlen(key), NULL);
  2149. else
  2150. {
  2151. char *rwval = NULL;
  2152. char buf[30];
  2153. switch (map->map_valcolno)
  2154. {
  2155.   case 0:
  2156.   case 1:
  2157. rwval = pw->pw_name;
  2158. break;
  2159.   case 2:
  2160. rwval = pw->pw_passwd;
  2161. break;
  2162.   case 3:
  2163. snprintf(buf, sizeof buf, "%d", (int) pw->pw_uid);
  2164. rwval = buf;
  2165. break;
  2166.   case 4:
  2167. snprintf(buf, sizeof buf, "%d", (int) pw->pw_gid);
  2168. rwval = buf;
  2169. break;
  2170.   case 5:
  2171. rwval = pw->pw_gecos;
  2172. break;
  2173.   case 6:
  2174. rwval = pw->pw_dir;
  2175. break;
  2176.   case 7:
  2177. rwval = pw->pw_shell;
  2178. break;
  2179. }
  2180. return map_rewrite(map, rwval, strlen(rwval), av);
  2181. }
  2182. }
  2183. /*
  2184. **  Program map type.
  2185. **
  2186. ** This provides access to arbitrary programs.  It should be used
  2187. ** only very sparingly, since there is no way to bound the cost
  2188. ** of invoking an arbitrary program.
  2189. */
  2190. char *
  2191. prog_map_lookup(map, name, av, statp)
  2192. MAP *map;
  2193. char *name;
  2194. char **av;
  2195. int *statp;
  2196. {
  2197. int i;
  2198. int save_errno;
  2199. int fd;
  2200. int status;
  2201. auto pid_t pid;
  2202. register char *p;
  2203. char *rval;
  2204. char *argv[MAXPV + 1];
  2205. char buf[MAXLINE];
  2206. if (tTd(38, 20))
  2207. dprintf("prog_map_lookup(%s, %s) %sn",
  2208. map->map_mname, name, map->map_file);
  2209. i = 0;
  2210. argv[i++] = map->map_file;
  2211. if (map->map_rebuild != NULL)
  2212. {
  2213. snprintf(buf, sizeof buf, "%s", map->map_rebuild);
  2214. for (p = strtok(buf, " t"); p != NULL; p = strtok(NULL, " t"))
  2215. {
  2216. if (i >= MAXPV - 1)
  2217. break;
  2218. argv[i++] = p;
  2219. }
  2220. }
  2221. argv[i++] = name;
  2222. argv[i] = NULL;
  2223. if (tTd(38, 21))
  2224. {
  2225. dprintf("prog_open:");
  2226. for (i = 0; argv[i] != NULL; i++)
  2227. dprintf(" %s", argv[i]);
  2228. dprintf("n");
  2229. }
  2230. (void) blocksignal(SIGCHLD);
  2231. pid = prog_open(argv, &fd, CurEnv);
  2232. if (pid < 0)
  2233. {
  2234. if (!bitset(MF_OPTIONAL, map->map_mflags))
  2235. syserr("prog_map_lookup(%s) failed (%s) -- closing",
  2236. map->map_mname, errstring(errno));
  2237. else if (tTd(38, 9))
  2238. dprintf("prog_map_lookup(%s) failed (%s) -- closing",
  2239. map->map_mname, errstring(errno));
  2240. map->map_mflags &= ~(MF_VALID|MF_OPEN);
  2241. *statp = EX_OSFILE;
  2242. return NULL;
  2243. }
  2244. i = read(fd, buf, sizeof buf - 1);
  2245. if (i < 0)
  2246. {
  2247. syserr("prog_map_lookup(%s): read error %sn",
  2248. map->map_mname, errstring(errno));
  2249. rval = NULL;
  2250. }
  2251. else if (i == 0)
  2252. {
  2253. if (tTd(38, 20))
  2254. dprintf("prog_map_lookup(%s): empty answern",
  2255. map->map_mname);
  2256. rval = NULL;
  2257. }
  2258. else
  2259. {
  2260. buf[i] = '';
  2261. p = strchr(buf, 'n');
  2262. if (p != NULL)
  2263. *p = '';
  2264. /* collect the return value */
  2265. if (bitset(MF_MATCHONLY, map->map_mflags))
  2266. rval = map_rewrite(map, name, strlen(name), NULL);
  2267. else
  2268. rval = map_rewrite(map, buf, strlen(buf), NULL);
  2269. /* now flush any additional output */
  2270. while ((i = read(fd, buf, sizeof buf)) > 0)
  2271. continue;
  2272. }
  2273. /* wait for the process to terminate */
  2274. (void) close(fd);
  2275. status = waitfor(pid);
  2276. save_errno = errno;
  2277. (void) releasesignal(SIGCHLD);
  2278. errno = save_errno;
  2279. if (status == -1)
  2280. {
  2281. syserr("prog_map_lookup(%s): wait error %sn",
  2282. map->map_mname, errstring(errno));
  2283. *statp = EX_SOFTWARE;
  2284. rval = NULL;
  2285. }
  2286. else if (WIFEXITED(status))
  2287. {
  2288. if ((*statp = WEXITSTATUS(status)) != EX_OK)
  2289. rval = NULL;
  2290. }
  2291. else
  2292. {
  2293. syserr("prog_map_lookup(%s): child died on signal %d",
  2294. map->map_mname, status);
  2295. *statp = EX_UNAVAILABLE;
  2296. rval = NULL;
  2297. }
  2298. return rval;
  2299. }
  2300. /*
  2301. **  Sequenced map type.
  2302. **
  2303. ** Tries each map in order until something matches, much like
  2304. ** implicit.  Stores go to the first map in the list that can
  2305. ** support storing.
  2306. **
  2307. ** This is slightly unusual in that there are two interfaces.
  2308. ** The "sequence" interface lets you stack maps arbitrarily.
  2309. ** The "switch" interface builds a sequence map by looking
  2310. ** at a system-dependent configuration file such as
  2311. ** /etc/nsswitch.conf on Solaris or /etc/svc.conf on Ultrix.
  2312. **
  2313. ** We don't need an explicit open, since all maps are
  2314. ** opened during startup, including underlying maps.
  2315. */
  2316. /*
  2317. **  SEQ_MAP_PARSE -- Sequenced map parsing
  2318. */
  2319. bool
  2320. seq_map_parse(map, ap)
  2321. MAP *map;
  2322. char *ap;
  2323. {
  2324. int maxmap;
  2325. if (tTd(38, 2))
  2326. dprintf("seq_map_parse(%s, %s)n", map->map_mname, ap);
  2327. maxmap = 0;
  2328. while (*ap != '')
  2329. {
  2330. register char *p;
  2331. STAB *s;
  2332. /* find beginning of map name */
  2333. while (isascii(*ap) && isspace(*ap))
  2334. ap++;
  2335. for (p = ap; isascii(*p) && isalnum(*p); p++)
  2336. continue;
  2337. if (*p != '')
  2338. *p++ = '';
  2339. while (*p != '' && (!isascii(*p) || !isalnum(*p)))
  2340. p++;
  2341. if (*ap == '')
  2342. {
  2343. ap = p;
  2344. continue;
  2345. }
  2346. s = stab(ap, ST_MAP, ST_FIND);
  2347. if (s == NULL)
  2348. {
  2349. syserr("Sequence map %s: unknown member map %s",
  2350. map->map_mname, ap);
  2351. }
  2352. else if (maxmap == MAXMAPSTACK)
  2353. {
  2354. syserr("Sequence map %s: too many member maps (%d max)",
  2355. map->map_mname, MAXMAPSTACK);
  2356. maxmap++;
  2357. }
  2358. else if (maxmap < MAXMAPSTACK)
  2359. {
  2360. map->map_stack[maxmap++] = &s->s_map;
  2361. }
  2362. ap = p;
  2363. }
  2364. return TRUE;
  2365. }
  2366. /*
  2367. **  SWITCH_MAP_OPEN -- open a switched map
  2368. **
  2369. ** This looks at the system-dependent configuration and builds
  2370. ** a sequence map that does the same thing.
  2371. **
  2372. ** Every system must define a switch_map_find routine in conf.c
  2373. ** that will return the list of service types associated with a
  2374. ** given service class.
  2375. */
  2376. bool
  2377. switch_map_open(map, mode)
  2378. MAP *map;
  2379. int mode;
  2380. {
  2381. int mapno;
  2382. int nmaps;
  2383. char *maptype[MAXMAPSTACK];
  2384. if (tTd(38, 2))
  2385. dprintf("switch_map_open(%s, %s, %d)n",
  2386. map->map_mname, map->map_file, mode);
  2387. mode &= O_ACCMODE;
  2388. nmaps = switch_map_find(map->map_file, maptype, map->map_return);
  2389. if (tTd(38, 19))
  2390. {
  2391. dprintf("tswitch_map_find => %dn", nmaps);
  2392. for (mapno = 0; mapno < nmaps; mapno++)
  2393. dprintf("tt%sn", maptype[mapno]);
  2394. }
  2395. if (nmaps <= 0 || nmaps > MAXMAPSTACK)
  2396. return FALSE;
  2397. for (mapno = 0; mapno < nmaps; mapno++)
  2398. {
  2399. register STAB *s;
  2400. char nbuf[MAXNAME + 1];
  2401. if (maptype[mapno] == NULL)
  2402. continue;
  2403. (void) snprintf(nbuf, sizeof nbuf, "%s.%s",
  2404. map->map_mname, maptype[mapno]);
  2405. s = stab(nbuf, ST_MAP, ST_FIND);
  2406. if (s == NULL)
  2407. {
  2408. syserr("Switch map %s: unknown member map %s",
  2409. map->map_mname, nbuf);
  2410. }
  2411. else
  2412. {
  2413. map->map_stack[mapno] = &s->s_map;
  2414. if (tTd(38, 4))
  2415. dprintf("tmap_stack[%d] = %s:%sn",
  2416. mapno, s->s_map.map_class->map_cname,
  2417. nbuf);
  2418. }
  2419. }
  2420. return TRUE;
  2421. }
  2422. /*
  2423. **  SEQ_MAP_CLOSE -- close all underlying maps
  2424. */
  2425. void
  2426. seq_map_close(map)
  2427. MAP *map;
  2428. {
  2429. int mapno;
  2430. if (tTd(38, 9))
  2431. dprintf("seq_map_close(%s)n", map->map_mname);
  2432. for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
  2433. {
  2434. MAP *mm = map->map_stack[mapno];
  2435. if (mm == NULL || !bitset(MF_OPEN, mm->map_mflags))
  2436. continue;
  2437. mm->map_class->map_close(mm);
  2438. mm->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
  2439. }
  2440. }
  2441. /*
  2442. **  SEQ_MAP_LOOKUP -- sequenced map lookup
  2443. */
  2444. char *
  2445. seq_map_lookup(map, key, args, pstat)
  2446. MAP *map;
  2447. char *key;
  2448. char **args;
  2449. int *pstat;
  2450. {
  2451. int mapno;
  2452. int mapbit = 0x01;
  2453. bool tempfail = FALSE;
  2454. if (tTd(38, 20))
  2455. dprintf("seq_map_lookup(%s, %s)n", map->map_mname, key);
  2456. for (mapno = 0; mapno < MAXMAPSTACK; mapbit <<= 1, mapno++)
  2457. {
  2458. MAP *mm = map->map_stack[mapno];
  2459. char *rv;
  2460. if (mm == NULL)
  2461. continue;
  2462. if (!bitset(MF_OPEN, mm->map_mflags) &&
  2463.     !openmap(mm))
  2464. {
  2465. if (bitset(mapbit, map->map_return[MA_UNAVAIL]))
  2466. {
  2467. *pstat = EX_UNAVAILABLE;
  2468. return NULL;
  2469. }
  2470. continue;
  2471. }
  2472. *pstat = EX_OK;
  2473. rv = mm->map_class->map_lookup(mm, key, args, pstat);
  2474. if (rv != NULL)
  2475. return rv;
  2476. if (*pstat == EX_TEMPFAIL)
  2477. {
  2478. if (bitset(mapbit, map->map_return[MA_TRYAGAIN]))
  2479. return NULL;
  2480. tempfail = TRUE;
  2481. }
  2482. else if (bitset(mapbit, map->map_return[MA_NOTFOUND]))
  2483. break;
  2484. }
  2485. if (tempfail)
  2486. *pstat = EX_TEMPFAIL;
  2487. else if (*pstat == EX_OK)
  2488. *pstat = EX_NOTFOUND;
  2489. return NULL;
  2490. }
  2491. /*
  2492. **  SEQ_MAP_STORE -- sequenced map store
  2493. */
  2494. void
  2495. seq_map_store(map, key, val)
  2496. MAP *map;
  2497. char *key;
  2498. char *val;
  2499. {
  2500. int mapno;
  2501. if (tTd(38, 12))
  2502. dprintf("seq_map_store(%s, %s, %s)n",
  2503. map->map_mname, key, val);
  2504. for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
  2505. {
  2506. MAP *mm = map->map_stack[mapno];
  2507. if (mm == NULL || !bitset(MF_WRITABLE, mm->map_mflags))
  2508. continue;
  2509. mm->map_class->map_store(mm, key, val);
  2510. return;
  2511. }
  2512. syserr("seq_map_store(%s, %s, %s): no writable map",
  2513. map->map_mname, key, val);
  2514. }
  2515. /*
  2516. **  NULL stubs
  2517. */
  2518. /* ARGSUSED */
  2519. bool
  2520. null_map_open(map, mode)
  2521. MAP *map;
  2522. int mode;
  2523. {
  2524. return TRUE;
  2525. }
  2526. /* ARGSUSED */
  2527. void
  2528. null_map_close(map)
  2529. MAP *map;
  2530. {
  2531. return;
  2532. }
  2533. char *
  2534. null_map_lookup(map, key, args, pstat)
  2535. MAP *map;
  2536. char *key;
  2537. char **args;
  2538. int *pstat;
  2539. {
  2540. *pstat = EX_NOTFOUND;
  2541. return NULL;
  2542. }
  2543. /* ARGSUSED */
  2544. void
  2545. null_map_store(map, key, val)
  2546. MAP *map;
  2547. char *key;
  2548. char *val;
  2549. {
  2550. return;
  2551. }
  2552. /*
  2553. **  BOGUS stubs
  2554. */
  2555. char *
  2556. bogus_map_lookup(map, key, args, pstat)
  2557. MAP *map;
  2558. char *key;
  2559. char **args;
  2560. int *pstat;
  2561. {
  2562. *pstat = EX_TEMPFAIL;
  2563. return NULL;
  2564. }
  2565. MAPCLASS BogusMapClass =
  2566. {
  2567. "bogus-map", NULL, 0,
  2568. NULL, bogus_map_lookup, null_map_store,
  2569. null_map_open, null_map_close,
  2570. };
  2571. /*
  2572. **  MACRO modules
  2573. */
  2574. char *
  2575. macro_map_lookup(map, name, av, statp)
  2576. MAP *map;
  2577. char *name;
  2578. char **av;
  2579. int *statp;
  2580. {
  2581. int mid;
  2582. if (tTd(38, 20))
  2583. dprintf("macro_map_lookup(%s, %s)n", map->map_mname,
  2584. name == NULL ? "NULL" : name);
  2585. if (name == NULL ||
  2586.     *name == '' ||
  2587.     (mid = macid(name, NULL)) == '')
  2588. {
  2589. *statp = EX_CONFIG;
  2590. return NULL;
  2591. }
  2592. if (av[1] == NULL)
  2593. define(mid, NULL, CurEnv);
  2594. else
  2595. define(mid, newstr(av[1]), CurEnv);
  2596. *statp = EX_OK;
  2597. return "";
  2598. }
  2599. /*
  2600. **  REGEX modules
  2601. */
  2602. #ifdef MAP_REGEX
  2603. # include <regex.h>
  2604. # define DEFAULT_DELIM CONDELSE
  2605. # define END_OF_FIELDS -1
  2606. # define ERRBUF_SIZE 80
  2607. # define MAX_MATCH 32
  2608. # define xnalloc(s) memset(xalloc(s), '', s);
  2609. struct regex_map
  2610. {
  2611. regex_t regex_pattern_buf; /* xalloc it */
  2612. int *regex_subfields; /* move to type MAP */
  2613. char *regex_delim; /* move to type MAP */
  2614. };
  2615. static int
  2616. parse_fields(s, ibuf, blen, nr_substrings)
  2617. char *s;
  2618. int *ibuf; /* array */
  2619. int blen; /* number of elements in ibuf */
  2620. int nr_substrings; /* number of substrings in the pattern */
  2621. {
  2622. register char *cp;
  2623. int i = 0;
  2624. bool lastone = FALSE;
  2625. blen--; /* for terminating END_OF_FIELDS */
  2626. cp = s;
  2627. do
  2628. {
  2629. for (;; cp++)
  2630. {
  2631. if (*cp == ',')
  2632. {
  2633. *cp = '';
  2634. break;
  2635. }
  2636. if (*cp == '')
  2637. {
  2638. lastone = TRUE;
  2639. break;
  2640. }
  2641. }
  2642. if (i < blen)
  2643. {
  2644. int val = atoi(s);
  2645. if (val < 0 || val >= nr_substrings)
  2646. {
  2647. syserr("field (%d) out of range, only %d substrings in pattern",
  2648.        val, nr_substrings);
  2649. return -1;
  2650. }
  2651. ibuf[i++] = val;
  2652. }
  2653. else
  2654. {
  2655. syserr("too many fields, %d maxn", blen);
  2656. return -1;
  2657. }
  2658. s = ++cp;
  2659. } while (!lastone);
  2660. ibuf[i] = END_OF_FIELDS;
  2661. return i;
  2662. }
  2663. bool
  2664. regex_map_init(map, ap)
  2665. MAP *map;
  2666. char *ap;
  2667. {
  2668. int regerr;
  2669. struct regex_map *map_p;
  2670. register char *p;
  2671. char *sub_param = NULL;
  2672. int pflags;
  2673. static char defdstr[] = { (char)DEFAULT_DELIM, '' };
  2674. if (tTd(38, 2))
  2675. dprintf("regex_map_init: mapname '%s', args '%s'n",
  2676. map->map_mname, ap);
  2677. pflags = REG_ICASE | REG_EXTENDED | REG_NOSUB;
  2678. p = ap;
  2679. map_p = (struct regex_map *) xnalloc(sizeof *map_p);
  2680. for (;;)
  2681. {
  2682. while (isascii(*p) && isspace(*p))
  2683. p++;
  2684. if (*p != '-')
  2685. break;
  2686. switch (*++p)
  2687. {
  2688.   case 'n': /* not */
  2689. map->map_mflags |= MF_REGEX_NOT;
  2690. break;
  2691.   case 'f': /* case sensitive */
  2692. map->map_mflags |= MF_NOFOLDCASE;
  2693. pflags &= ~REG_ICASE;
  2694. break;
  2695.   case 'b': /* basic regular expressions */
  2696. pflags &= ~REG_EXTENDED;
  2697. break;
  2698.   case 's': /* substring match () syntax */
  2699. sub_param = ++p;
  2700. pflags &= ~REG_NOSUB;
  2701. break;
  2702.   case 'd': /* delimiter */
  2703. map_p->regex_delim = ++p;
  2704. break;
  2705.   case 'a': /* map append */
  2706. map->map_app = ++p;
  2707. break;
  2708.   case 'm': /* matchonly */
  2709. map->map_mflags |= MF_MATCHONLY;
  2710. break;
  2711.   case 'S':
  2712. map->map_spacesub = *++p;
  2713. break;
  2714.   case 'D':
  2715. map->map_mflags |= MF_DEFER;
  2716. break;
  2717. }
  2718. while (*p != '' && !(isascii(*p) && isspace(*p)))
  2719. p++;
  2720. if (*p != '')
  2721. *p++ = '';
  2722. }
  2723. if (tTd(38, 3))
  2724. dprintf("regex_map_init: compile '%s' 0x%xn", p, pflags);
  2725. if ((regerr = regcomp(&(map_p->regex_pattern_buf), p, pflags)) != 0)
  2726. {
  2727. /* Errorhandling */
  2728. char errbuf[ERRBUF_SIZE];
  2729. (void) regerror(regerr, &(map_p->regex_pattern_buf),
  2730.  errbuf, ERRBUF_SIZE);
  2731. syserr("pattern-compile-error: %sn", errbuf);
  2732. free(map_p);
  2733. return FALSE;
  2734. }
  2735. if (map->map_app != NULL)
  2736. map->map_app = newstr(map->map_app);
  2737. if (map_p->regex_delim != NULL)
  2738. map_p->regex_delim = newstr(map_p->regex_delim);
  2739. else
  2740. map_p->regex_delim = defdstr;
  2741. if (!bitset(REG_NOSUB, pflags))
  2742. {
  2743. /* substring matching */
  2744. int substrings;
  2745. int *fields = (int *) xalloc(sizeof(int) * (MAX_MATCH + 1));
  2746. substrings = map_p->regex_pattern_buf.re_nsub + 1;
  2747. if (tTd(38, 3))
  2748. dprintf("regex_map_init: nr of substrings %dn",
  2749. substrings);
  2750. if (substrings >= MAX_MATCH)
  2751. {
  2752. syserr("too many substrings, %d maxn", MAX_MATCH);
  2753. free(map_p);
  2754. return FALSE;
  2755. }
  2756. if (sub_param != NULL && sub_param[0] != '')
  2757. {
  2758. /* optional parameter -sfields */
  2759. if (parse_fields(sub_param, fields,
  2760.  MAX_MATCH + 1, substrings) == -1)
  2761. return FALSE;
  2762. }
  2763. else
  2764. {
  2765. /* set default fields */
  2766. int i;
  2767. for (i = 0; i < substrings; i++)
  2768. fields[i] = i;
  2769. fields[i] = END_OF_FIELDS;
  2770. }
  2771. map_p->regex_subfields = fields;
  2772. if (tTd(38, 3))
  2773. {
  2774. int *ip;
  2775. dprintf("regex_map_init: subfields");
  2776. for (ip = fields; *ip != END_OF_FIELDS; ip++)
  2777. dprintf(" %d", *ip);
  2778. dprintf("n");
  2779. }
  2780. }
  2781. map->map_db1 = (ARBPTR_T)map_p; /* dirty hack */
  2782. return TRUE;
  2783. }
  2784. static char *
  2785. regex_map_rewrite(map, s, slen, av)
  2786. MAP *map;
  2787. const char *s;
  2788. size_t slen;
  2789. char **av;
  2790. {
  2791. if (bitset(MF_MATCHONLY, map->map_mflags))
  2792. return map_rewrite(map, av[0], strlen(av[0]), NULL);
  2793. else
  2794. return map_rewrite(map, s, slen, NULL);
  2795. }
  2796. char *
  2797. regex_map_lookup(map, name, av, statp)
  2798. MAP *map;
  2799. char *name;
  2800. char **av;
  2801. int *statp;
  2802. {
  2803. int reg_res;
  2804. struct regex_map *map_p;
  2805. regmatch_t pmatch[MAX_MATCH];
  2806. if (tTd(38, 20))
  2807. {
  2808. char **cpp;
  2809. dprintf("regex_map_lookup: key '%s'n", name);
  2810. for (cpp = av; cpp != NULL && *cpp != NULL; cpp++)
  2811. dprintf("regex_map_lookup: arg '%s'n", *cpp);
  2812. }
  2813. map_p = (struct regex_map *)(map->map_db1);
  2814. reg_res = regexec(&(map_p->regex_pattern_buf),
  2815.   name, MAX_MATCH, pmatch, 0);
  2816. if (bitset(MF_REGEX_NOT, map->map_mflags))
  2817. {
  2818. /* option -n */
  2819. if (reg_res == REG_NOMATCH)
  2820. return regex_map_rewrite(map, "", (size_t)0, av);
  2821. else
  2822. return NULL;
  2823. }
  2824. if (reg_res == REG_NOMATCH)
  2825. return NULL;
  2826. if (map_p->regex_subfields != NULL)
  2827. {
  2828. /* option -s */
  2829. static char retbuf[MAXNAME];
  2830. int fields[MAX_MATCH + 1];
  2831. bool first = TRUE;
  2832. int anglecnt = 0, cmntcnt = 0, spacecnt = 0;
  2833. bool quotemode = FALSE, bslashmode = FALSE;
  2834. register char *dp, *sp;
  2835. char *endp, *ldp;
  2836. int *ip;
  2837. dp = retbuf;
  2838. ldp = retbuf + sizeof(retbuf) - 1;
  2839. if (av[1] != NULL)
  2840. {
  2841. if (parse_fields(av[1], fields, MAX_MATCH + 1,
  2842.  (int) map_p->regex_pattern_buf.re_nsub + 1) == -1)
  2843. {
  2844. *statp = EX_CONFIG;
  2845. return NULL;
  2846. }
  2847. ip = fields;
  2848. }
  2849. else
  2850. ip = map_p->regex_subfields;
  2851. for ( ; *ip != END_OF_FIELDS; ip++)
  2852. {
  2853. if (!first)
  2854. {
  2855. for (sp = map_p->regex_delim; *sp; sp++)
  2856. {
  2857. if (dp < ldp)
  2858. *dp++ = *sp;
  2859. }
  2860. }
  2861. else
  2862. first = FALSE;
  2863. if (pmatch[*ip].rm_so < 0 || pmatch[*ip].rm_eo < 0)
  2864. continue;
  2865. sp = name + pmatch[*ip].rm_so;
  2866. endp = name + pmatch[*ip].rm_eo;
  2867. for (; endp > sp; sp++)
  2868. {
  2869. if (dp < ldp)
  2870. {
  2871. if (bslashmode)
  2872. {
  2873. *dp++ = *sp;
  2874. bslashmode = FALSE;
  2875. }
  2876. else if (quotemode && *sp != '"' &&
  2877. *sp != '\')
  2878. {
  2879. *dp++ = *sp;
  2880. }
  2881. else switch(*dp++ = *sp)
  2882. {
  2883. case '\':
  2884. bslashmode = TRUE;
  2885. break;
  2886. case '(':
  2887. cmntcnt++;
  2888. break;
  2889. case ')':
  2890. cmntcnt--;
  2891. break;
  2892. case '<':
  2893. anglecnt++;
  2894. break;
  2895. case '>':
  2896. anglecnt--;
  2897. break;
  2898. case ' ':
  2899. spacecnt++;
  2900. break;
  2901. case '"':
  2902. quotemode = !quotemode;
  2903. break;
  2904. }
  2905. }
  2906. }
  2907. }
  2908. if (anglecnt != 0 || cmntcnt != 0 || quotemode ||
  2909.     bslashmode || spacecnt != 0)
  2910. {
  2911. sm_syslog(LOG_WARNING, NOQID,
  2912.   "Warning: regex may cause prescan() failure map=%s lookup=%s",
  2913.   map->map_mname, name);
  2914. return NULL;
  2915. }
  2916. *dp = '';
  2917. return regex_map_rewrite(map, retbuf, strlen(retbuf), av);
  2918. }
  2919. return regex_map_rewrite(map, "", (size_t)0, av);
  2920. }
  2921. #endif /* MAP_REGEX */
  2922. /*
  2923. **  NSD modules
  2924. */
  2925. #ifdef MAP_NSD
  2926. # include <ndbm.h>
  2927. # define _DATUM_DEFINED
  2928. # include <ns_api.h>
  2929. typedef struct ns_map_list
  2930. {
  2931. ns_map_t *map;
  2932. char *mapname;
  2933. struct ns_map_list *next;
  2934. } ns_map_list_t;
  2935. static ns_map_t *
  2936. ns_map_t_find(mapname)
  2937. char *mapname;
  2938. {
  2939. static ns_map_list_t *ns_maps = NULL;
  2940. ns_map_list_t *ns_map;
  2941. /* walk the list of maps looking for the correctly named map */
  2942. for (ns_map = ns_maps; ns_map != NULL; ns_map = ns_map->next)
  2943. {
  2944. if (strcmp(ns_map->mapname, mapname) == 0)
  2945. break;
  2946. }
  2947. /* if we are looking at a NULL ns_map_list_t, then create a new one */
  2948. if (ns_map == NULL)
  2949. {
  2950. ns_map = (ns_map_list_t *) xalloc(sizeof *ns_map);
  2951. ns_map->mapname = newstr(mapname);
  2952. ns_map->map = (ns_map_t *) xalloc(sizeof *ns_map->map);
  2953. ns_map->next = ns_maps;
  2954. ns_maps = ns_map;
  2955. }
  2956. return ns_map->map;
  2957. }
  2958. char *
  2959. nsd_map_lookup(map, name, av, statp)
  2960. MAP *map;
  2961. char *name;
  2962. char **av;
  2963. int *statp;
  2964. {
  2965. int buflen;
  2966. char *p;
  2967. ns_map_t *ns_map;
  2968. char keybuf[MAXNAME + 1];
  2969. char buf[MAXLINE];
  2970. if (tTd(38, 20))
  2971. dprintf("nsd_map_lookup(%s, %s)n", map->map_mname, name);
  2972. buflen = strlen(name);
  2973. if (buflen > sizeof keybuf - 1)
  2974. buflen = sizeof keybuf - 1;
  2975. memmove(keybuf, name, buflen);
  2976. keybuf[buflen] = '';
  2977. if (!bitset(MF_NOFOLDCASE, map->map_mflags))
  2978. makelower(keybuf);
  2979. ns_map = ns_map_t_find(map->map_file);
  2980. if (ns_map == NULL)
  2981. {
  2982. if (tTd(38, 20))
  2983. dprintf("nsd_map_t_find failedn");
  2984. return NULL;
  2985. }
  2986. if (ns_lookup(ns_map, NULL, map->map_file,
  2987.       keybuf, NULL, buf, MAXLINE) == NULL)
  2988. return NULL;
  2989. /* Null out trailing n */
  2990. if ((p = strchr(buf, 'n')) != NULL)
  2991. *p = '';
  2992. return map_rewrite(map, buf, strlen(buf), av);
  2993. }
  2994. #endif /* MAP_NSD */
  2995. char *
  2996. arith_map_lookup(map, name, av, statp)
  2997. MAP *map;
  2998. char *name;
  2999. char **av;
  3000. int *statp;
  3001. {
  3002. int r, v[2];
  3003. bool boolres;
  3004. static char result[16];
  3005. char **cpp;
  3006. if (tTd(38, 2))
  3007. {
  3008. dprintf("arith_map_lookup: key '%s'n", name);
  3009. for (cpp = av; cpp != NULL && *cpp != NULL; cpp++)
  3010. dprintf("arith_map_lookup: arg '%s'n", *cpp);
  3011. }
  3012. r = 0;
  3013. boolres = FALSE;
  3014. cpp = av;
  3015. *statp = EX_OK;
  3016. /*
  3017. **  read arguments for arith map
  3018. **  - no check is made whether they are really numbers
  3019. **  - just ignores args after the second
  3020. */
  3021. for (++cpp; cpp != NULL && *cpp != NULL && r < 2; cpp++)
  3022. v[r++] = atoi(*cpp);
  3023. /* operator and (at least) two operands given? */
  3024. if (name != NULL && r == 2)
  3025. {
  3026. switch(*name)
  3027. {
  3028.   case '+':
  3029. r = v[0] + v[1];
  3030. break;
  3031.   case '-':
  3032. r = v[0] - v[1];
  3033. break;
  3034.   case '*':
  3035. r = v[0] * v[1];
  3036. break;
  3037.   case '/':
  3038. if (v[1] == 0)
  3039. return NULL;
  3040. r = v[0] / v[1];
  3041. break;
  3042.   case 'l':
  3043. r = v[0] < v[1];
  3044. boolres = TRUE;
  3045. break;
  3046.   case '=':
  3047. r = v[0] == v[1];
  3048. boolres = TRUE;
  3049. break;
  3050.   default:
  3051. /* XXX */
  3052. *statp = EX_CONFIG;
  3053. if (LogLevel > 10)
  3054. sm_syslog(LOG_WARNING, NOQID,
  3055.   "arith_map: unknown operator %c",
  3056.   isprint(*name) ? *name : '?');
  3057. return NULL;
  3058. }
  3059. if (boolres)
  3060. snprintf(result, sizeof result, r ? "TRUE" : "FALSE");
  3061. else
  3062. snprintf(result, sizeof result, "%d", r);
  3063. return result;
  3064. }
  3065. *statp = EX_CONFIG;
  3066. return NULL;
  3067. }