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

##### Functions

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

##### Macros

    MAXRCRSN          X

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

#### Defined functions

finduser defined in line 354; used 2 times

- in line 302-305(2)

getctladdr defined in line 571; used 5 times

- in line 159, 484
- in /usr/src/usr.sbin/sendmail.MX/src/deliver.c line 77, 238, 309

include defined in line 466; used 2 times

- in line 262
- in /usr/src/usr.sbin/sendmail.MX/src/alias.c line 590

recipient defined in line 148; used 6 times

- in line 117-120(2)
- in /usr/src/usr.sbin/sendmail.MX/src/deliver.c line 1377-1380(2)
- in /usr/src/usr.sbin/sendmail.MX/src/srvrsmtp.c line 122, 283

sendtoargv defined in line 531; used 1 times

- in /usr/src/usr.sbin/sendmail.MX/src/main.c line 681

sendtolist defined in line 49; used 14 times

- in line 509, 553
- in /usr/src/usr.sbin/sendmail.MX/src/alias.c line 111
- in /usr/src/usr.sbin/sendmail.MX/src/deliver.c line 1492, 1499
- in /usr/src/usr.sbin/sendmail.MX/src/envelope.c line 124
- in /usr/src/usr.sbin/sendmail.MX/src/headers.c line 311, 357
- in /usr/src/usr.sbin/sendmail.MX/src/queue.c line 714-718(2)
- in /usr/src/usr.sbin/sendmail.MX/src/savemail.c line 220, 226, 289
- in /usr/src/usr.sbin/sendmail.MX/src/srvrsmtp.c line 383

writable defined in line 416; used 2 times

- in line 280, 292

#### Defined variables

sccsid defined in line 18; never used

#### Defined macros

MAXRCRSN defined in line 47; used 1 times

- in line 174

Last modified: 1988-09-14 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 1867 |