home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.sbin / sendmail / src / alias.c next >
Encoding:
C/C++ Source or Header  |  1991-04-20  |  12.6 KB  |  598 lines

  1. /*
  2.  * Copyright (c) 1983 Eric P. Allman
  3.  * Copyright (c) 1988 Regents of the University of California.
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms, with or without
  7.  * modification, are permitted provided that the following conditions
  8.  * are met:
  9.  * 1. Redistributions of source code must retain the above copyright
  10.  *    notice, this list of conditions and the following disclaimer.
  11.  * 2. Redistributions in binary form must reproduce the above copyright
  12.  *    notice, this list of conditions and the following disclaimer in the
  13.  *    documentation and/or other materials provided with the distribution.
  14.  * 3. All advertising materials mentioning features or use of this software
  15.  *    must display the following acknowledgement:
  16.  *    This product includes software developed by the University of
  17.  *    California, Berkeley and its contributors.
  18.  * 4. Neither the name of the University nor the names of its contributors
  19.  *    may be used to endorse or promote products derived from this software
  20.  *    without specific prior written permission.
  21.  *
  22.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  23.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  26.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  27.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  28.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  29.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  31.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  32.  * SUCH DAMAGE.
  33.  */
  34.  
  35. #ifndef lint
  36. #ifdef DBM
  37. static char sccsid[] = "@(#)alias.c    5.22 (Berkeley) 3/2/91 (with DBM)";
  38. #else
  39. static char sccsid[] = "@(#)alias.c    5.22 (Berkeley) 3/2/91 (without DBM)";
  40. #endif
  41. #endif /* not lint */
  42.  
  43. # include <sys/types.h>
  44. # include <sys/stat.h>
  45. # include <signal.h>
  46. # include <errno.h>
  47. # include "sendmail.h"
  48. # include <sys/file.h>
  49. # include <pwd.h>
  50.  
  51. /*
  52. **  ALIAS -- Compute aliases.
  53. **
  54. **    Scans the alias file for an alias for the given address.
  55. **    If found, it arranges to deliver to the alias list instead.
  56. **    Uses libdbm database if -DDBM.
  57. **
  58. **    Parameters:
  59. **        a -- address to alias.
  60. **        sendq -- a pointer to the head of the send queue
  61. **            to put the aliases in.
  62. **
  63. **    Returns:
  64. **        none
  65. **
  66. **    Side Effects:
  67. **        Aliases found are expanded.
  68. **
  69. **    Notes:
  70. **        If NoAlias (the "-n" flag) is set, no aliasing is
  71. **            done.
  72. **
  73. **    Deficiencies:
  74. **        It should complain about names that are aliased to
  75. **            nothing.
  76. */
  77.  
  78.  
  79. #ifdef DBM
  80. typedef struct
  81. {
  82.     char    *dptr;
  83.     int    dsize;
  84. } DATUM;
  85. extern DATUM fetch();
  86. #endif DBM
  87.  
  88. alias(a, sendq)
  89.     register ADDRESS *a;
  90.     ADDRESS **sendq;
  91. {
  92.     register char *p;
  93.     extern char *aliaslookup();
  94.  
  95.     if (tTd(27, 1))
  96.         printf("alias(%s)\n", a->q_paddr);
  97.  
  98.     /* don't realias already aliased names */
  99.     if (bitset(QDONTSEND, a->q_flags))
  100.         return;
  101.  
  102.     CurEnv->e_to = a->q_paddr;
  103.  
  104.     /*
  105.     **  Look up this name
  106.     */
  107.  
  108.     if (NoAlias)
  109.         p = NULL;
  110.     else
  111.         p = aliaslookup(a->q_user);
  112.     if (p == NULL)
  113.         return;
  114.  
  115.     /*
  116.     **  Match on Alias.
  117.     **    Deliver to the target list.
  118.     */
  119.  
  120.     if (tTd(27, 1))
  121.         printf("%s (%s, %s) aliased to %s\n",
  122.             a->q_paddr, a->q_host, a->q_user, p);
  123.     message(Arpa_Info, "aliased to %s", p);
  124.     AliasLevel++;
  125.     sendtolist(p, a, sendq);
  126.     AliasLevel--;
  127. }
  128. /*
  129. **  ALIASLOOKUP -- look up a name in the alias file.
  130. **
  131. **    Parameters:
  132. **        name -- the name to look up.
  133. **
  134. **    Returns:
  135. **        the value of name.
  136. **        NULL if unknown.
  137. **
  138. **    Side Effects:
  139. **        none.
  140. **
  141. **    Warnings:
  142. **        The return value will be trashed across calls.
  143. */
  144.  
  145. char *
  146. aliaslookup(name)
  147.     char *name;
  148. {
  149. # ifdef DBM
  150.     DATUM rhs, lhs;
  151.  
  152.     /* create a key for fetch */
  153.     lhs.dptr = name;
  154.     lhs.dsize = strlen(name) + 1;
  155.     rhs = fetch(lhs);
  156.     return (rhs.dptr);
  157. # else DBM
  158.     register STAB *s;
  159.  
  160.     s = stab(name, ST_ALIAS, ST_FIND);
  161.     if (s == NULL)
  162.         return (NULL);
  163.     return (s->s_alias);
  164. # endif DBM
  165. }
  166. /*
  167. **  INITALIASES -- initialize for aliasing
  168. **
  169. **    Very different depending on whether we are running DBM or not.
  170. **
  171. **    Parameters:
  172. **        aliasfile -- location of aliases.
  173. **        init -- if set and if DBM, initialize the DBM files.
  174. **
  175. **    Returns:
  176. **        none.
  177. **
  178. **    Side Effects:
  179. **        initializes aliases:
  180. **        if DBM:  opens the database.
  181. **        if ~DBM: reads the aliases into the symbol table.
  182. */
  183.  
  184. # define DBMMODE    0644
  185.  
  186. initaliases(aliasfile, init)
  187.     char *aliasfile;
  188.     bool init;
  189. {
  190. #ifdef DBM
  191.     int atcnt;
  192.     time_t modtime;
  193.     bool automatic = FALSE;
  194.     char buf[MAXNAME];
  195. #endif DBM
  196.     struct stat stb;
  197.     static bool initialized = FALSE;
  198.     static int readaliases();
  199.  
  200.     if (initialized)
  201.         return;
  202.     initialized = TRUE;
  203.  
  204.     if (aliasfile == NULL || stat(aliasfile, &stb) < 0)
  205.     {
  206.         if (aliasfile != NULL && init)
  207.             syserr("Cannot open %s", aliasfile);
  208.         NoAlias = TRUE;
  209.         errno = 0;
  210.         return;
  211.     }
  212.  
  213. # ifdef DBM
  214.     /*
  215.     **  Check to see that the alias file is complete.
  216.     **    If not, we will assume that someone died, and it is up
  217.     **    to us to rebuild it.
  218.     */
  219.  
  220.     if (!init)
  221.         dbminit(aliasfile);
  222.     atcnt = SafeAlias * 2;
  223.     if (atcnt > 0)
  224.     {
  225.         while (!init && atcnt-- >= 0 && aliaslookup("@") == NULL)
  226.         {
  227.             /*
  228.             **  Reinitialize alias file in case the new
  229.             **  one is mv'ed in instead of cp'ed in.
  230.             **
  231.             **    Only works with new DBM -- old one will
  232.             **    just consume file descriptors forever.
  233.             **    If you have a dbmclose() it can be
  234.             **    added before the sleep(30).
  235.             */
  236.  
  237.             sleep(30);
  238. # ifdef NDBM
  239.             dbminit(aliasfile);
  240. # endif NDBM
  241.         }
  242.     }
  243.     else
  244.         atcnt = 1;
  245.  
  246.     /*
  247.     **  See if the DBM version of the file is out of date with
  248.     **  the text version.  If so, go into 'init' mode automatically.
  249.     **    This only happens if our effective userid owns the DBM.
  250.     **    Note the unpalatable hack to see if the stat succeeded.
  251.     */
  252.  
  253.     modtime = stb.st_mtime;
  254.     (void) strcpy(buf, aliasfile);
  255.     (void) strcat(buf, ".pag");
  256.     stb.st_ino = 0;
  257.     if (!init && (stat(buf, &stb) < 0 || stb.st_mtime < modtime || atcnt < 0))
  258.     {
  259.         errno = 0;
  260.         if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid())
  261.         {
  262.             init = TRUE;
  263.             automatic = TRUE;
  264.             message(Arpa_Info, "rebuilding alias database");
  265. #ifdef LOG
  266.             if (LogLevel >= 7)
  267.                 syslog(LOG_INFO, "rebuilding alias database");
  268. #endif LOG
  269.         }
  270.         else
  271.         {
  272. #ifdef LOG
  273.             if (LogLevel >= 7)
  274.                 syslog(LOG_INFO, "alias database out of date");
  275. #endif LOG
  276.             message(Arpa_Info, "Warning: alias database out of date");
  277.         }
  278.     }
  279.  
  280.  
  281.     /*
  282.     **  If necessary, load the DBM file.
  283.     **    If running without DBM, load the symbol table.
  284.     */
  285.  
  286.     if (init)
  287.     {
  288. #ifdef LOG
  289.         if (LogLevel >= 6)
  290.         {
  291.             extern char *username();
  292.  
  293.             syslog(LOG_NOTICE, "alias database %srebuilt by %s",
  294.                 automatic ? "auto" : "", username());
  295.         }
  296. #endif LOG
  297.         readaliases(aliasfile, TRUE);
  298.     }
  299. # else DBM
  300.     readaliases(aliasfile, init);
  301. # endif DBM
  302. }
  303. /*
  304. **  READALIASES -- read and process the alias file.
  305. **
  306. **    This routine implements the part of initaliases that occurs
  307. **    when we are not going to use the DBM stuff.
  308. **
  309. **    Parameters:
  310. **        aliasfile -- the pathname of the alias file master.
  311. **        init -- if set, initialize the DBM stuff.
  312. **
  313. **    Returns:
  314. **        none.
  315. **
  316. **    Side Effects:
  317. **        Reads aliasfile into the symbol table.
  318. **        Optionally, builds the .dir & .pag files.
  319. */
  320.  
  321. static
  322. readaliases(aliasfile, init)
  323.     char *aliasfile;
  324.     bool init;
  325. {
  326.     register char *p;
  327.     char *rhs;
  328.     bool skipping;
  329.     int naliases, bytes, longest;
  330.     FILE *af;
  331.     void (*oldsigint)();
  332.     ADDRESS al, bl;
  333.     register STAB *s;
  334.     char line[BUFSIZ];
  335.  
  336.     if ((af = fopen(aliasfile, "r")) == NULL)
  337.     {
  338.         if (tTd(27, 1))
  339.             printf("Can't open %s\n", aliasfile);
  340.         errno = 0;
  341.         NoAlias++;
  342.         return;
  343.     }
  344.  
  345. # ifdef DBM
  346.     /* see if someone else is rebuilding the alias file already */
  347.     if (flock(fileno(af), LOCK_EX | LOCK_NB) < 0 && errno == EWOULDBLOCK)
  348.     {
  349.         /* yes, they are -- wait until done and then return */
  350.         message(Arpa_Info, "Alias file is already being rebuilt");
  351.         if (OpMode != MD_INITALIAS)
  352.         {
  353.             /* wait for other rebuild to complete */
  354.             (void) flock(fileno(af), LOCK_EX);
  355.         }
  356.         (void) fclose(af);
  357.         errno = 0;
  358.         return;
  359.     }
  360. # endif DBM
  361.  
  362.     /*
  363.     **  If initializing, create the new DBM files.
  364.     */
  365.  
  366.     if (init)
  367.     {
  368.         oldsigint = signal(SIGINT, SIG_IGN);
  369.         (void) strcpy(line, aliasfile);
  370.         (void) strcat(line, ".dir");
  371.         if (close(creat(line, DBMMODE)) < 0)
  372.         {
  373.             syserr("cannot make %s", line);
  374.             (void) signal(SIGINT, oldsigint);
  375.             return;
  376.         }
  377.         (void) strcpy(line, aliasfile);
  378.         (void) strcat(line, ".pag");
  379.         if (close(creat(line, DBMMODE)) < 0)
  380.         {
  381.             syserr("cannot make %s", line);
  382.             (void) signal(SIGINT, oldsigint);
  383.             return;
  384.         }
  385.         dbminit(aliasfile);
  386.     }
  387.  
  388.     /*
  389.     **  Read and interpret lines
  390.     */
  391.  
  392.     FileName = aliasfile;
  393.     LineNumber = 0;
  394.     naliases = bytes = longest = 0;
  395.     skipping = FALSE;
  396.     while (fgets(line, sizeof (line), af) != NULL)
  397.     {
  398.         int lhssize, rhssize;
  399.  
  400.         LineNumber++;
  401.         p = index(line, '\n');
  402.         if (p != NULL)
  403.             *p = '\0';
  404.         switch (line[0])
  405.         {
  406.           case '#':
  407.           case '\0':
  408.             skipping = FALSE;
  409.             continue;
  410.  
  411.           case ' ':
  412.           case '\t':
  413.             if (!skipping)
  414.                 syserr("Non-continuation line starts with space");
  415.             skipping = TRUE;
  416.             continue;
  417.         }
  418.         skipping = FALSE;
  419.  
  420.         /*
  421.         **  Process the LHS
  422.         **    Find the final colon, and parse the address.
  423.         **    It should resolve to a local name -- this will
  424.         **    be checked later (we want to optionally do
  425.         **    parsing of the RHS first to maximize error
  426.         **    detection).
  427.         */
  428.  
  429.         for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
  430.             continue;
  431.         if (*p++ != ':')
  432.         {
  433.             syserr("missing colon");
  434.             continue;
  435.         }
  436.         if (parseaddr(line, &al, 1, ':') == NULL)
  437.         {
  438.             syserr("illegal alias name");
  439.             continue;
  440.         }
  441.         loweraddr(&al);
  442.  
  443.         /*
  444.         **  Process the RHS.
  445.         **    'al' is the internal form of the LHS address.
  446.         **    'p' points to the text of the RHS.
  447.         */
  448.  
  449.         rhs = p;
  450.         for (;;)
  451.         {
  452.             register char c;
  453.  
  454.             if (init && CheckAliases)
  455.             {
  456.                 /* do parsing & compression of addresses */
  457.                 while (*p != '\0')
  458.                 {
  459.                     extern char *DelimChar;
  460.  
  461.                     while (isspace(*p) || *p == ',')
  462.                         p++;
  463.                     if (*p == '\0')
  464.                         break;
  465.                     if (parseaddr(p, &bl, -1, ',') == NULL)
  466.                         usrerr("%s... bad address", p);
  467.                     p = DelimChar;
  468.                 }
  469.             }
  470.             else
  471.             {
  472.                 p = &p[strlen(p)];
  473.                 if (p[-1] == '\n')
  474.                     *--p = '\0';
  475.             }
  476.  
  477.             /* see if there should be a continuation line */
  478.             c = fgetc(af);
  479.             if (!feof(af))
  480.                 (void) ungetc(c, af);
  481.             if (c != ' ' && c != '\t')
  482.                 break;
  483.  
  484.             /* read continuation line */
  485.             if (fgets(p, sizeof line - (p - line), af) == NULL)
  486.                 break;
  487.             LineNumber++;
  488.         }
  489.         if (al.q_mailer != LocalMailer)
  490.         {
  491.             syserr("cannot alias non-local names");
  492.             continue;
  493.         }
  494.  
  495.         /*
  496.         **  Insert alias into symbol table or DBM file
  497.         */
  498.  
  499.         lhssize = strlen(al.q_user) + 1;
  500.         rhssize = strlen(rhs) + 1;
  501.  
  502. # ifdef DBM
  503.         if (init)
  504.         {
  505.             DATUM key, content;
  506.  
  507.             key.dsize = lhssize;
  508.             key.dptr = al.q_user;
  509.             content.dsize = rhssize;
  510.             content.dptr = rhs;
  511.             store(key, content);
  512.         }
  513.         else
  514. # endif DBM
  515.         {
  516.             s = stab(al.q_user, ST_ALIAS, ST_ENTER);
  517.             s->s_alias = newstr(rhs);
  518.         }
  519.  
  520.         /* statistics */
  521.         naliases++;
  522.         bytes += lhssize + rhssize;
  523.         if (rhssize > longest)
  524.             longest = rhssize;
  525.     }
  526.  
  527. # ifdef DBM
  528.     if (init)
  529.     {
  530.         /* add the distinquished alias "@" */
  531.         DATUM key;
  532.  
  533.         key.dsize = 2;
  534.         key.dptr = "@";
  535.         store(key, key);
  536.  
  537.         /* restore the old signal */
  538.         (void) signal(SIGINT, oldsigint);
  539.     }
  540. # endif DBM
  541.  
  542.     /* closing the alias file drops the lock */
  543.     (void) fclose(af);
  544.     CurEnv->e_to = NULL;
  545.     FileName = NULL;
  546.     message(Arpa_Info, "%d aliases, longest %d bytes, %d bytes total",
  547.             naliases, longest, bytes);
  548. # ifdef LOG
  549.     if (LogLevel >= 8)
  550.         syslog(LOG_INFO, "%d aliases, longest %d bytes, %d bytes total",
  551.             naliases, longest, bytes);
  552. # endif LOG
  553. }
  554. /*
  555. **  FORWARD -- Try to forward mail
  556. **
  557. **    This is similar but not identical to aliasing.
  558. **
  559. **    Parameters:
  560. **        user -- the name of the user who's mail we would like
  561. **            to forward to.  It must have been verified --
  562. **            i.e., the q_home field must have been filled
  563. **            in.
  564. **        sendq -- a pointer to the head of the send queue to
  565. **            put this user's aliases in.
  566. **
  567. **    Returns:
  568. **        none.
  569. **
  570. **    Side Effects:
  571. **        New names are added to send queues.
  572. */
  573.  
  574. forward(user, sendq)
  575.     ADDRESS *user;
  576.     ADDRESS **sendq;
  577. {
  578.     char buf[60];
  579.     extern bool safefile();
  580.  
  581.     if (tTd(27, 1))
  582.         printf("forward(%s)\n", user->q_paddr);
  583.  
  584.     if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags))
  585.         return;
  586.     if (user->q_home == NULL)
  587.         syserr("forward: no home");
  588.  
  589.     /* good address -- look for .forward file in home */
  590.     define('z', user->q_home, CurEnv);
  591.     expand("\001z/.forward", buf, &buf[sizeof buf - 1], CurEnv);
  592.     if (!safefile(buf, user->q_uid, S_IREAD))
  593.         return;
  594.  
  595.     /* we do have an address to forward to -- do it */
  596.     include(buf, "forwarding", user, sendq);
  597. }
  598.