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
getctladdr defined in line 580; used 5 times
include defined in line 474; used 2 times
sendtoargv defined in line 539; used 1 times
writable defined in line 424; used 2 times

Defined variables

SccsId defined in line 12; never used

Defined macros

MAXRCRSN defined in line 41; used 1 times
Last modified: 1995-03-08
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4493
Valid CSS Valid XHTML 1.0 Strict