home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.sbin / sendmail / src / recipient.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-20  |  13.9 KB  |  595 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. static char sccsid[] = "@(#)recipient.c    5.19 (Berkeley) 3/2/91";
  37. #endif /* not lint */
  38.  
  39. # include <sys/types.h>
  40. # include <sys/stat.h>
  41. # include <pwd.h>
  42. # include "sendmail.h"
  43.  
  44. /*
  45. **  SENDTOLIST -- Designate a send list.
  46. **
  47. **    The parameter is a comma-separated list of people to send to.
  48. **    This routine arranges to send to all of them.
  49. **
  50. **    Parameters:
  51. **        list -- the send list.
  52. **        ctladdr -- the address template for the person to
  53. **            send to -- effective uid/gid are important.
  54. **            This is typically the alias that caused this
  55. **            expansion.
  56. **        sendq -- a pointer to the head of a queue to put
  57. **            these people into.
  58. **
  59. **    Returns:
  60. **        none
  61. **
  62. **    Side Effects:
  63. **        none.
  64. */
  65.  
  66. # define MAXRCRSN    10
  67.  
  68. sendtolist(list, ctladdr, sendq)
  69.     char *list;
  70.     ADDRESS *ctladdr;
  71.     ADDRESS **sendq;
  72. {
  73.     register char *p;
  74.     register ADDRESS *al;    /* list of addresses to send to */
  75.     bool firstone;        /* set on first address sent */
  76.     bool selfref;        /* set if this list includes ctladdr */
  77.     char delimiter;        /* the address delimiter */
  78.  
  79.     if (tTd(25, 1))
  80.     {
  81.         printf("sendto: %s\n   ctladdr=", list);
  82.         printaddr(ctladdr, FALSE);
  83.     }
  84.  
  85.     /* heuristic to determine old versus new style addresses */
  86.     if (ctladdr == NULL &&
  87.         (index(list, ',') != NULL || index(list, ';') != NULL ||
  88.          index(list, '<') != NULL || index(list, '(') != NULL))
  89.         CurEnv->e_flags &= ~EF_OLDSTYLE;
  90.     delimiter = ' ';
  91.     if (!bitset(EF_OLDSTYLE, CurEnv->e_flags) || ctladdr != NULL)
  92.         delimiter = ',';
  93.  
  94.     firstone = TRUE;
  95.     selfref = FALSE;
  96.     al = NULL;
  97.  
  98.     for (p = list; *p != '\0'; )
  99.     {
  100.         register ADDRESS *a;
  101.         extern char *DelimChar;        /* defined in prescan */
  102.  
  103.         /* parse the address */
  104.         while (isspace(*p) || *p == ',')
  105.             p++;
  106.         a = parseaddr(p, (ADDRESS *) NULL, 1, delimiter);
  107.         p = DelimChar;
  108.         if (a == NULL)
  109.             continue;
  110.         a->q_next = al;
  111.         a->q_alias = ctladdr;
  112.  
  113.         /* see if this should be marked as a primary address */
  114.         if (ctladdr == NULL ||
  115.             (firstone && *p == '\0' && bitset(QPRIMARY, ctladdr->q_flags)))
  116.             a->q_flags |= QPRIMARY;
  117.  
  118.         /* put on send queue or suppress self-reference */
  119.         if (ctladdr != NULL && sameaddr(ctladdr, a))
  120.             selfref = TRUE;
  121.         else
  122.             al = a;
  123.         firstone = FALSE;
  124.     }
  125.  
  126.     /* if this alias doesn't include itself, delete ctladdr */
  127.     if (!selfref && ctladdr != NULL)
  128.         ctladdr->q_flags |= QDONTSEND;
  129.  
  130.     /* arrange to send to everyone on the local send list */
  131.     while (al != NULL)
  132.     {
  133.         register ADDRESS *a = al;
  134.         extern ADDRESS *recipient();
  135.  
  136.         al = a->q_next;
  137.         setctladdr(a);
  138.         a = recipient(a, sendq);
  139.  
  140.         /* arrange to inherit full name */
  141.         if (a->q_fullname == NULL && ctladdr != NULL)
  142.             a->q_fullname = ctladdr->q_fullname;
  143.     }
  144.  
  145.     CurEnv->e_to = NULL;
  146. }
  147. /*
  148. **  RECIPIENT -- Designate a message recipient
  149. **
  150. **    Saves the named person for future mailing.
  151. **
  152. **    Parameters:
  153. **        a -- the (preparsed) address header for the recipient.
  154. **        sendq -- a pointer to the head of a queue to put the
  155. **            recipient in.  Duplicate supression is done
  156. **            in this queue.
  157. **
  158. **    Returns:
  159. **        The actual address in the queue.  This will be "a" if
  160. **        the address is not a duplicate, else the original address.
  161. **
  162. **    Side Effects:
  163. **        none.
  164. */
  165.  
  166. extern ADDRESS *getctladdr();
  167.  
  168. ADDRESS *
  169. recipient(a, sendq)
  170.     register ADDRESS *a;
  171.     register ADDRESS **sendq;
  172. {
  173.     register ADDRESS *q;
  174.     ADDRESS **pq;
  175.     register struct mailer *m;
  176.     register char *p;
  177.     bool quoted = FALSE;        /* set if the addr has a quote bit */
  178.     char buf[MAXNAME];        /* unquoted image of the user name */
  179.     extern bool safefile();
  180.  
  181.     CurEnv->e_to = a->q_paddr;
  182.     m = a->q_mailer;
  183.     errno = 0;
  184.     if (tTd(26, 1))
  185.     {
  186.         printf("\nrecipient: ");
  187.         printaddr(a, FALSE);
  188.     }
  189.  
  190.     /* break aliasing loops */
  191.     if (AliasLevel > MAXRCRSN)
  192.     {
  193.         usrerr("aliasing/forwarding loop broken");
  194.         return (a);
  195.     }
  196.  
  197.     /*
  198.     **  Finish setting up address structure.
  199.     */
  200.  
  201.     /* set the queue timeout */
  202.     a->q_timeout = TimeOut;
  203.  
  204.     /* map user & host to lower case if requested on non-aliases */
  205.     if (a->q_alias == NULL)
  206.         loweraddr(a);
  207.  
  208.     /* get unquoted user for file, program or user.name check */
  209.     (void) strcpy(buf, a->q_user);
  210.     for (p = buf; *p != '\0' && !quoted; p++)
  211.     {
  212.         if (!isascii(*p) && (*p & 0377) != (SpaceSub & 0377))
  213.             quoted = TRUE;
  214.     }
  215.     stripquotes(buf, TRUE);
  216.  
  217.     /* do sickly crude mapping for program mailing, etc. */
  218.     if (m == LocalMailer && buf[0] == '|')
  219.     {
  220.         a->q_mailer = m = ProgMailer;
  221.         a->q_user++;
  222.         if (a->q_alias == NULL && !QueueRun && !ForceMail)
  223.         {
  224.             a->q_flags |= QDONTSEND|QBADADDR;
  225.             usrerr("Cannot mail directly to programs");
  226.         }
  227.     }
  228.  
  229.     /*
  230.     **  Look up this person in the recipient list.
  231.     **    If they are there already, return, otherwise continue.
  232.     **    If the list is empty, just add it.  Notice the cute
  233.     **    hack to make from addresses suppress things correctly:
  234.     **    the QDONTSEND bit will be set in the send list.
  235.     **    [Please note: the emphasis is on "hack."]
  236.     */
  237.  
  238.     for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next)
  239.     {
  240.         if (!ForceMail && sameaddr(q, a))
  241.         {
  242.             if (tTd(26, 1))
  243.             {
  244.                 printf("%s in sendq: ", a->q_paddr);
  245.                 printaddr(q, FALSE);
  246.             }
  247.             if (!bitset(QDONTSEND, a->q_flags))
  248.                 message(Arpa_Info, "duplicate suppressed");
  249.             if (!bitset(QPRIMARY, q->q_flags))
  250.                 q->q_flags |= a->q_flags;
  251.             return (q);
  252.         }
  253.     }
  254.  
  255.     /* add address on list */
  256.     *pq = a;
  257.     a->q_next = NULL;
  258.     CurEnv->e_nrcpts++;
  259.  
  260.     /*
  261.     **  Alias the name and handle :include: specs.
  262.     */
  263.  
  264.     if (m == LocalMailer && !bitset(QDONTSEND, a->q_flags))
  265.     {
  266.         if (strncmp(a->q_user, ":include:", 9) == 0)
  267.         {
  268.             a->q_flags |= QDONTSEND;
  269.             if (a->q_alias == NULL && !QueueRun && !ForceMail)
  270.             {
  271.                 a->q_flags |= QBADADDR;
  272.                 usrerr("Cannot mail directly to :include:s");
  273.             }
  274.             else
  275.             {
  276.                 message(Arpa_Info, "including file %s", &a->q_user[9]);
  277.                 include(&a->q_user[9], " sending", a, sendq);
  278.             }
  279.         }
  280.         else
  281.             alias(a, sendq);
  282.     }
  283.  
  284.     /*
  285.     **  If the user is local and still being sent, verify that
  286.     **  the address is good.  If it is, try to forward.
  287.     **  If the address is already good, we have a forwarding
  288.     **  loop.  This can be broken by just sending directly to
  289.     **  the user (which is probably correct anyway).
  290.     */
  291.  
  292.     if (!bitset(QDONTSEND, a->q_flags) && m == LocalMailer)
  293.     {
  294.         struct stat stb;
  295.         extern bool writable();
  296.  
  297.         /* see if this is to a file */
  298.         if (buf[0] == '/')
  299.         {
  300.             p = rindex(buf, '/');
  301.             /* check if writable or creatable */
  302.             if (a->q_alias == NULL && !QueueRun && !ForceMail)
  303.             {
  304.                 a->q_flags |= QDONTSEND|QBADADDR;
  305.                 usrerr("Cannot mail directly to files");
  306.             }
  307.             else if ((stat(buf, &stb) >= 0) ? (!writable(&stb)) :
  308.                 (*p = '\0', !safefile(buf, getruid(), S_IWRITE|S_IEXEC)))
  309.             {
  310.                 a->q_flags |= QBADADDR;
  311.                 giveresponse(EX_CANTCREAT, m, CurEnv);
  312.             }
  313.         }
  314.         else
  315.         {
  316.             register struct passwd *pw;
  317.             extern struct passwd *finduser();
  318.  
  319.             /* warning -- finduser may trash buf */
  320.             pw = finduser(buf);
  321.             if (pw == NULL)
  322.             {
  323.                 a->q_flags |= QBADADDR;
  324.                 giveresponse(EX_NOUSER, m, CurEnv);
  325.             }
  326.             else
  327.             {
  328.                 char nbuf[MAXNAME];
  329.  
  330.                 if (strcmp(a->q_user, pw->pw_name) != 0)
  331.                 {
  332.                     a->q_user = newstr(pw->pw_name);
  333.                     (void) strcpy(buf, pw->pw_name);
  334.                 }
  335.                 a->q_home = newstr(pw->pw_dir);
  336.                 a->q_uid = pw->pw_uid;
  337.                 a->q_gid = pw->pw_gid;
  338.                 a->q_flags |= QGOODUID;
  339.                 buildfname(pw->pw_gecos, pw->pw_name, nbuf);
  340.                 if (nbuf[0] != '\0')
  341.                     a->q_fullname = newstr(nbuf);
  342.                 if (!quoted)
  343.                     forward(a, sendq);
  344.             }
  345.         }
  346.     }
  347.     return (a);
  348. }
  349. /*
  350. **  FINDUSER -- find the password entry for a user.
  351. **
  352. **    This looks a lot like getpwnam, except that it may want to
  353. **    do some fancier pattern matching in /etc/passwd.
  354. **
  355. **    This routine contains most of the time of many sendmail runs.
  356. **    It deserves to be optimized.
  357. **
  358. **    Parameters:
  359. **        name -- the name to match against.
  360. **
  361. **    Returns:
  362. **        A pointer to a pw struct.
  363. **        NULL if name is unknown or ambiguous.
  364. **
  365. **    Side Effects:
  366. **        may modify name.
  367. */
  368.  
  369. struct passwd *
  370. finduser(name)
  371.     char *name;
  372. {
  373.     register struct passwd *pw;
  374.     register char *p;
  375.     extern struct passwd *getpwent();
  376.     extern struct passwd *getpwnam();
  377.  
  378.     /* map upper => lower case */
  379.     for (p = name; *p != '\0'; p++)
  380.     {
  381.         if (isascii(*p) && isupper(*p))
  382.             *p = tolower(*p);
  383.     }
  384.  
  385.     /* look up this login name using fast path */
  386.     if ((pw = getpwnam(name)) != NULL)
  387.         return (pw);
  388.  
  389.     /* search for a matching full name instead */
  390.     for (p = name; *p != '\0'; p++)
  391.     {
  392.         if (*p == (SpaceSub & 0177) || *p == '_')
  393.             *p = ' ';
  394.     }
  395.     (void) setpwent();
  396.     while ((pw = getpwent()) != NULL)
  397.     {
  398.         char buf[MAXNAME];
  399.  
  400.         buildfname(pw->pw_gecos, pw->pw_name, buf);
  401.         if (index(buf, ' ') != NULL && !strcasecmp(buf, name))
  402.         {
  403.             message(Arpa_Info, "sending to login name %s", pw->pw_name);
  404.             return (pw);
  405.         }
  406.     }
  407.     return (NULL);
  408. }
  409. /*
  410. **  WRITABLE -- predicate returning if the file is writable.
  411. **
  412. **    This routine must duplicate the algorithm in sys/fio.c.
  413. **    Unfortunately, we cannot use the access call since we
  414. **    won't necessarily be the real uid when we try to
  415. **    actually open the file.
  416. **
  417. **    Notice that ANY file with ANY execute bit is automatically
  418. **    not writable.  This is also enforced by mailfile.
  419. **
  420. **    Parameters:
  421. **        s -- pointer to a stat struct for the file.
  422. **
  423. **    Returns:
  424. **        TRUE -- if we will be able to write this file.
  425. **        FALSE -- if we cannot write this file.
  426. **
  427. **    Side Effects:
  428. **        none.
  429. */
  430.  
  431. bool
  432. writable(s)
  433.     register struct stat *s;
  434. {
  435.     int euid, egid;
  436.     int bits;
  437.  
  438.     if (bitset(0111, s->st_mode))
  439.         return (FALSE);
  440.     euid = getruid();
  441.     egid = getrgid();
  442.     if (geteuid() == 0)
  443.     {
  444.         if (bitset(S_ISUID, s->st_mode))
  445.             euid = s->st_uid;
  446.         if (bitset(S_ISGID, s->st_mode))
  447.             egid = s->st_gid;
  448.     }
  449.  
  450.     if (euid == 0)
  451.         return (TRUE);
  452.     bits = S_IWRITE;
  453.     if (euid != s->st_uid)
  454.     {
  455.         bits >>= 3;
  456.         if (egid != s->st_gid)
  457.             bits >>= 3;
  458.     }
  459.     return ((s->st_mode & bits) != 0);
  460. }
  461. /*
  462. **  INCLUDE -- handle :include: specification.
  463. **
  464. **    Parameters:
  465. **        fname -- filename to include.
  466. **        msg -- message to print in verbose mode.
  467. **        ctladdr -- address template to use to fill in these
  468. **            addresses -- effective user/group id are
  469. **            the important things.
  470. **        sendq -- a pointer to the head of the send queue
  471. **            to put these addresses in.
  472. **
  473. **    Returns:
  474. **        none.
  475. **
  476. **    Side Effects:
  477. **        reads the :include: file and sends to everyone
  478. **        listed in that file.
  479. */
  480.  
  481. include(fname, msg, ctladdr, sendq)
  482.     char *fname;
  483.     char *msg;
  484.     ADDRESS *ctladdr;
  485.     ADDRESS **sendq;
  486. {
  487.     char buf[MAXLINE];
  488.     register FILE *fp;
  489.     char *oldto = CurEnv->e_to;
  490.     char *oldfilename = FileName;
  491.     int oldlinenumber = LineNumber;
  492.  
  493.     fp = fopen(fname, "r");
  494.     if (fp == NULL)
  495.     {
  496.         usrerr("Cannot open %s", fname);
  497.         return;
  498.     }
  499.     if (getctladdr(ctladdr) == NULL)
  500.     {
  501.         struct stat st;
  502.  
  503.         if (fstat(fileno(fp), &st) < 0)
  504.             syserr("Cannot fstat %s!", fname);
  505.         ctladdr->q_uid = st.st_uid;
  506.         ctladdr->q_gid = st.st_gid;
  507.         ctladdr->q_flags |= QGOODUID;
  508.     }
  509.  
  510.     /* read the file -- each line is a comma-separated list. */
  511.     FileName = fname;
  512.     LineNumber = 0;
  513.     while (fgets(buf, sizeof buf, fp) != NULL)
  514.     {
  515.         register char *p = index(buf, '\n');
  516.  
  517.         LineNumber++;
  518.         if (p != NULL)
  519.             *p = '\0';
  520.         if (buf[0] == '\0')
  521.             continue;
  522.         CurEnv->e_to = oldto;
  523.         message(Arpa_Info, "%s to %s", msg, buf);
  524.         AliasLevel++;
  525.         sendtolist(buf, ctladdr, sendq);
  526.         AliasLevel--;
  527.     }
  528.  
  529.     (void) fclose(fp);
  530.     FileName = oldfilename;
  531.     LineNumber = oldlinenumber;
  532. }
  533. /*
  534. **  SENDTOARGV -- send to an argument vector.
  535. **
  536. **    Parameters:
  537. **        argv -- argument vector to send to.
  538. **
  539. **    Returns:
  540. **        none.
  541. **
  542. **    Side Effects:
  543. **        puts all addresses on the argument vector onto the
  544. **            send queue.
  545. */
  546.  
  547. sendtoargv(argv)
  548.     register char **argv;
  549. {
  550.     register char *p;
  551.  
  552.     while ((p = *argv++) != NULL)
  553.     {
  554.         if (argv[0] != NULL && argv[1] != NULL && !strcasecmp(argv[0], "at"))
  555.         {
  556.             char nbuf[MAXNAME];
  557.  
  558.             if (strlen(p) + strlen(argv[1]) + 2 > sizeof nbuf)
  559.                 usrerr("address overflow");
  560.             else
  561.             {
  562.                 (void) strcpy(nbuf, p);
  563.                 (void) strcat(nbuf, "@");
  564.                 (void) strcat(nbuf, argv[1]);
  565.                 p = newstr(nbuf);
  566.                 argv += 2;
  567.             }
  568.         }
  569.         sendtolist(p, (ADDRESS *) NULL, &CurEnv->e_sendqueue);
  570.     }
  571. }
  572. /*
  573. **  GETCTLADDR -- get controlling address from an address header.
  574. **
  575. **    If none, get one corresponding to the effective userid.
  576. **
  577. **    Parameters:
  578. **        a -- the address to find the controller of.
  579. **
  580. **    Returns:
  581. **        the controlling address.
  582. **
  583. **    Side Effects:
  584. **        none.
  585. */
  586.  
  587. ADDRESS *
  588. getctladdr(a)
  589.     register ADDRESS *a;
  590. {
  591.     while (a != NULL && !bitset(QGOODUID, a->q_flags))
  592.         a = a->q_alias;
  593.     return (a);
  594. }
  595.