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

Defined functions

finduser defined in line 326; used 2 times
getctladdr defined in line 544; used 5 times
include defined in line 438; used 2 times
recipient defined in line 130; used 6 times
sendtoargv defined in line 503; never used
sendtolist defined in line 31; never used
writable defined in line 388; used 2 times

Defined macros

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