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
getctladdr defined in line 571; used 5 times
include defined in line 466; used 2 times
sendtoargv defined in line 531; used 1 times
writable defined in line 416; used 2 times

Defined variables

sccsid defined in line 18; never used

Defined macros

MAXRCRSN defined in line 47; used 1 times
Last modified: 1988-09-14
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 277
Valid CSS Valid XHTML 1.0 Strict