# 2.11BSD#431 - /usr/src/usr.sbin/sendmail/src/recipient.c

##### Functions

    finduser          X
    getctladdr        X
    include           X
    recipient         X
    sendtoargv        X
    sendtolist        X
    writable          X

##### Macros

    MAXRCRSN          X

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

#### Defined functions

finduser defined in line 361; used 2 times

- in line 309-312(2)

getctladdr defined in line 580; used 5 times

- in line 166, 492
- in /usr/src/usr.sbin/sendmail/src/deliver.c line 63, 218, 289

include defined in line 474; used 2 times

- in line 269
- in /usr/src/usr.sbin/sendmail/src/alias.c line 598

recipient defined in line 155; used 6 times

- in line 122-125(2)
- in /usr/src/usr.sbin/sendmail/src/deliver.c line 1328-1331(2)
- in /usr/src/usr.sbin/sendmail/src/srvrsmtp.c line 114, 273

sendtoargv defined in line 539; used 1 times

- in /usr/src/usr.sbin/sendmail/src/main.c line 685

sendtolist defined in line 43; used 14 times

- in line 517, 562
- in /usr/src/usr.sbin/sendmail/src/alias.c line 108
- in /usr/src/usr.sbin/sendmail/src/deliver.c line 1443, 1450
- in /usr/src/usr.sbin/sendmail/src/envelope.c line 118
- in /usr/src/usr.sbin/sendmail/src/headers.c line 305, 351
- in /usr/src/usr.sbin/sendmail/src/queue.c line 701-705(2)
- in /usr/src/usr.sbin/sendmail/src/savemail.c line 214, 220, 283
- in /usr/src/usr.sbin/sendmail/src/srvrsmtp.c line 373

writable defined in line 424; used 2 times

- in line 287, 299

#### Defined variables

SccsId defined in line 12; never used

#### Defined macros

MAXRCRSN defined in line 41; used 1 times

- in line 181

Last modified: 1995-03-08 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 2204 |