14174Seric # include <pwd.h> 24329Seric # include <sys/types.h> 34329Seric # include <sys/stat.h> 44174Seric # include "sendmail.h" 54174Seric 6*4423Seric static char SccsId[] = "@(#)recipient.c 3.23 09/22/81"; 74174Seric 84174Seric /* 94174Seric ** SENDTO -- Designate a send list. 104174Seric ** 114174Seric ** The parameter is a comma-separated list of people to send to. 124174Seric ** This routine arranges to send to all of them. 134174Seric ** 144174Seric ** Parameters: 154174Seric ** list -- the send list. 164174Seric ** copyf -- the copy flag; passed to parse. 174399Seric ** ctladdr -- the address template for the person to 184399Seric ** send to -- effective uid/gid are important. 194174Seric ** 204174Seric ** Returns: 214174Seric ** none 224174Seric ** 234174Seric ** Side Effects: 244174Seric ** none. 254174Seric */ 264174Seric 274174Seric # define MAXRCRSN 10 284174Seric 294399Seric sendto(list, copyf, ctladdr) 304174Seric char *list; 314174Seric int copyf; 324399Seric ADDRESS *ctladdr; 334174Seric { 344174Seric register char *p; 354319Seric bool more; /* set if more addresses to send to */ 364324Seric ADDRESS *al; /* list of addresses to send to */ 37*4423Seric bool firstone; /* set on first address sent */ 384174Seric 394324Seric # ifdef DEBUG 404324Seric if (Debug > 1) 414324Seric printf("sendto: %s\n", list); 424324Seric # endif DEBUG 434324Seric 444174Seric more = TRUE; 45*4423Seric firstone = TRUE; 464324Seric al = NULL; 474174Seric for (p = list; more; ) 484174Seric { 494319Seric register char *q; 504319Seric register char c; 514319Seric ADDRESS *a; 524319Seric 534174Seric /* find the end of this address */ 544174Seric while (*p == ' ' || *p == '\t') 554174Seric p++; 564174Seric q = p; 574174Seric while ((c = *p++) != '\0' && c != ',' && c != '\n') 584174Seric continue; 594174Seric more = c != '\0'; 604174Seric *--p = '\0'; 614174Seric if (more) 624174Seric p++; 634324Seric if (*q == '\0') 644324Seric continue; 654174Seric 664174Seric /* parse the address */ 674174Seric if ((a = parse(q, (ADDRESS *) NULL, copyf)) == NULL) 684174Seric continue; 694174Seric 704324Seric /* put it on the local send list */ 714324Seric a->q_next = al; 724399Seric a->q_alias = ctladdr; 73*4423Seric if (ctladdr == NULL || 74*4423Seric (firstone && !more && bitset(QPRIMARY, ctladdr->q_flags))) 75*4423Seric a->q_flags |= QPRIMARY; 764324Seric al = a; 77*4423Seric firstone = FALSE; 784324Seric } 794324Seric 804324Seric /* arrange to send to everyone on the local send list */ 814324Seric while (al != NULL) 824324Seric { 834324Seric register ADDRESS *a = al; 844324Seric 854324Seric al = a->q_next; 864174Seric recipient(a); 874174Seric } 884324Seric 894174Seric To = NULL; 904174Seric } 914174Seric /* 924174Seric ** RECIPIENT -- Designate a message recipient 934174Seric ** 944174Seric ** Saves the named person for future mailing. 954174Seric ** 964174Seric ** Parameters: 974174Seric ** a -- the (preparsed) address header for the recipient. 984174Seric ** 994174Seric ** Returns: 1004174Seric ** none. 1014174Seric ** 1024174Seric ** Side Effects: 1034174Seric ** none. 1044174Seric */ 1054174Seric 1064174Seric recipient(a) 1074174Seric register ADDRESS *a; 1084174Seric { 1094174Seric register ADDRESS *q; 1104319Seric ADDRESS **pq; 1114174Seric register struct mailer *m; 1124399Seric extern ADDRESS *getctladdr(); 1134174Seric 1144174Seric To = a->q_paddr; 1154174Seric m = Mailer[a->q_mailer]; 1164174Seric errno = 0; 1174174Seric # ifdef DEBUG 1184174Seric if (Debug) 1194174Seric printf("recipient(%s)\n", To); 1204174Seric # endif DEBUG 1214174Seric 1224174Seric /* break aliasing loops */ 1234174Seric if (AliasLevel > MAXRCRSN) 1244174Seric { 1254174Seric usrerr("aliasing/forwarding loop broken"); 1264174Seric return; 1274174Seric } 1284174Seric 1294174Seric /* 1304174Seric ** Do sickly crude mapping for program mailing, etc. 1314174Seric */ 1324174Seric 1334197Seric if (a->q_mailer == MN_LOCAL) 1344174Seric { 1354174Seric if (a->q_user[0] == '|') 1364174Seric { 1374197Seric a->q_mailer = MN_PROG; 1384197Seric m = Mailer[MN_PROG]; 1394174Seric a->q_user++; 1404406Seric if (a->q_alias == NULL && Debug == 0) 1414217Seric { 1424217Seric usrerr("Cannot mail directly to programs"); 1434217Seric a->q_flags |= QDONTSEND; 1444217Seric } 1454174Seric } 1464174Seric } 1474174Seric 1484174Seric /* 1494419Seric ** Look up this person in the recipient list. 1504419Seric ** If they are there already, return, otherwise continue. 1514419Seric ** If the list is empty, just add it. Notice the cute 1524419Seric ** hack to make from addresses suppress things correctly: 1534419Seric ** the QDONTSEND bit will be set in the send list. 1544419Seric ** [Please note: the emphasis is on "hack."] 1554174Seric */ 1564174Seric 1574319Seric for (pq = &m->m_sendq; (q = *pq) != NULL; pq = &q->q_next) 1584174Seric { 1594319Seric if (!ForceMail && sameaddr(q, a, FALSE)) 1604174Seric { 1614174Seric # ifdef DEBUG 1624319Seric if (Debug) 1634319Seric printf("(%s in sendq)\n", a->q_paddr); 1644174Seric # endif DEBUG 1654319Seric if (Verbose && !bitset(QDONTSEND, a->q_flags)) 1664324Seric message(Arpa_Info, "duplicate suppressed"); 167*4423Seric if (!bitset(QPRIMARY, q->q_flags)) 168*4423Seric q->q_flags |= a->q_flags; 1694319Seric return; 1704174Seric } 1714319Seric } 1724174Seric 1734319Seric /* add address on list */ 1744319Seric *pq = a; 1754174Seric a->q_next = NULL; 1764247Seric if (DontSend) 1774247Seric a->q_flags |= QDONTSEND; 1784174Seric 1794174Seric /* 1804174Seric ** Alias the name and handle :include: specs. 1814174Seric */ 1824174Seric 1834197Seric if (a->q_mailer == MN_LOCAL) 1844174Seric { 1854174Seric if (strncmp(a->q_user, ":include:", 9) == 0) 1864174Seric { 1874174Seric a->q_flags |= QDONTSEND; 1884406Seric if (a->q_alias == NULL && Debug == 0) 1894399Seric usrerr("Cannot mail directly to :include:s"); 1904399Seric else 1914399Seric { 1924399Seric if (Verbose) 1934399Seric message(Arpa_Info, "including file %s", &a->q_user[9]); 1944399Seric include(&a->q_user[9], " sending", a); 1954399Seric } 1964174Seric } 1974174Seric else 1984174Seric alias(a); 1994174Seric } 2004174Seric 2014174Seric /* 2024174Seric ** If the user is local and still being sent, verify that 2034174Seric ** the address is good. If it is, try to forward. 2044174Seric ** If the address is already good, we have a forwarding 2054174Seric ** loop. This can be broken by just sending directly to 2064174Seric ** the user (which is probably correct anyway). 2074174Seric */ 2084174Seric 2094197Seric if (!bitset(QDONTSEND, a->q_flags) && a->q_mailer == MN_LOCAL) 2104174Seric { 2114174Seric char buf[MAXNAME]; 2124201Seric register char *p; 2134329Seric struct stat stb; 2144329Seric extern bool writable(); 2154399Seric bool quoted = FALSE; 2164174Seric 2174174Seric strcpy(buf, a->q_user); 2184399Seric for (p = buf; *p != '\0' && !quoted; p++) 2194399Seric { 2204399Seric if (!isascii(*p)) 2214399Seric quoted = TRUE; 2224399Seric } 2234174Seric stripquotes(buf, TRUE); 2244174Seric 2254174Seric /* see if this is to a file */ 2264201Seric if ((p = rindex(buf, '/')) != NULL) 2274174Seric { 2284201Seric /* check if writable or creatable */ 2294406Seric if (a->q_alias == NULL && Debug == 0) 2304399Seric { 2314399Seric usrerr("Cannot mail directly to files"); 2324399Seric a->q_flags |= QDONTSEND; 2334399Seric } 2344399Seric else if ((stat(buf, &stb) >= 0) ? (!writable(&stb)) : 2354201Seric (*p = '\0', access(buf, 3) < 0)) 2364174Seric { 2374174Seric a->q_flags |= QBADADDR; 2384174Seric giveresponse(EX_CANTCREAT, TRUE, m); 2394174Seric } 2404174Seric } 2414174Seric else 2424174Seric { 2434174Seric register struct passwd *pw; 2444373Seric extern struct passwd *finduser(); 2454373Seric 2464407Seric /* warning -- finduser may trash buf */ 2474373Seric pw = finduser(buf); 2484174Seric if (pw == NULL) 2494174Seric { 2504174Seric a->q_flags |= QBADADDR; 2514174Seric giveresponse(EX_NOUSER, TRUE, m); 2524174Seric } 2534174Seric else 2544174Seric { 2554376Seric if (strcmp(a->q_user, pw->pw_name) != 0) 2564376Seric { 2574376Seric a->q_user = newstr(pw->pw_name); 2584376Seric strcpy(buf, pw->pw_name); 2594376Seric } 2604174Seric a->q_home = newstr(pw->pw_dir); 2614213Seric a->q_uid = pw->pw_uid; 2624399Seric a->q_gid = pw->pw_gid; 2634404Seric a->q_flags |= QGOODUID; 2644399Seric if (!quoted) 2654174Seric forward(a); 2664174Seric } 2674174Seric } 2684174Seric } 2694174Seric } 2704174Seric /* 2714373Seric ** FINDUSER -- find the password entry for a user. 2724373Seric ** 2734373Seric ** This looks a lot like getpwnam, except that it may want to 2744373Seric ** do some fancier pattern matching in /etc/passwd. 2754373Seric ** 2764373Seric ** Parameters: 2774373Seric ** name -- the name to match against. 2784373Seric ** 2794373Seric ** Returns: 2804373Seric ** A pointer to a pw struct. 2814373Seric ** NULL if name is unknown or ambiguous. 2824373Seric ** 2834373Seric ** Side Effects: 2844407Seric ** may modify name. 2854373Seric */ 2864373Seric 2874373Seric struct passwd * 2884373Seric finduser(name) 2894373Seric char *name; 2904373Seric { 2914376Seric extern struct passwd *getpwent(); 2924376Seric register struct passwd *pw; 2934407Seric register char *p; 2944373Seric 2954407Seric /* 2964407Seric ** Make name canonical. 2974407Seric */ 2984407Seric 2994407Seric for (p = name; *p != '\0'; p++) 3004407Seric { 3014407Seric if (*p == (SPACESUB & 0177) || *p == '_') 3024407Seric *p = ' '; 3034407Seric } 3044407Seric 3054376Seric setpwent(); 3064376Seric while ((pw = getpwent()) != NULL) 3074376Seric { 3084376Seric char buf[MAXNAME]; 3094376Seric extern bool sameword(); 3104376Seric 3114376Seric if (strcmp(pw->pw_name, name) == 0) 3124376Seric return (pw); 3134376Seric buildfname(pw->pw_gecos, pw->pw_name, buf); 3144407Seric if (index(buf, ' ') != NULL && sameword(buf, name)) 3154381Seric { 3164377Seric if (Verbose) 3174381Seric message(Arpa_Info, "sending to login name %s", 3184381Seric pw->pw_name); 3194376Seric return (pw); 3204377Seric } 3214376Seric } 3224376Seric return (NULL); 3234373Seric } 3244373Seric /* 3254329Seric ** WRITABLE -- predicate returning if the file is writable. 3264329Seric ** 3274329Seric ** This routine must duplicate the algorithm in sys/fio.c. 3284329Seric ** Unfortunately, we cannot use the access call since we 3294329Seric ** won't necessarily be the real uid when we try to 3304329Seric ** actually open the file. 3314329Seric ** 3324329Seric ** Notice that ANY file with ANY execute bit is automatically 3334329Seric ** not writable. This is also enforced by mailfile. 3344329Seric ** 3354329Seric ** Parameters: 3364329Seric ** s -- pointer to a stat struct for the file. 3374329Seric ** 3384329Seric ** Returns: 3394329Seric ** TRUE -- if we will be able to write this file. 3404329Seric ** FALSE -- if we cannot write this file. 3414329Seric ** 3424329Seric ** Side Effects: 3434329Seric ** none. 3444329Seric */ 3454329Seric 3464329Seric bool 3474329Seric writable(s) 3484329Seric register struct stat *s; 3494329Seric { 3504329Seric int euid, egid; 3514329Seric int bits; 3524329Seric 3534329Seric if (bitset(0111, s->st_mode)) 3544329Seric return (FALSE); 3554329Seric euid = getruid(); 3564329Seric egid = getrgid(); 3574329Seric if (geteuid() == 0) 3584329Seric { 3594329Seric if (bitset(S_ISUID, s->st_mode)) 3604329Seric euid = s->st_uid; 3614329Seric if (bitset(S_ISGID, s->st_mode)) 3624329Seric egid = s->st_gid; 3634329Seric } 3644329Seric 3654329Seric if (euid == 0) 3664329Seric return (TRUE); 3674329Seric bits = S_IWRITE; 3684329Seric if (euid != s->st_uid) 3694329Seric { 3704329Seric bits >>= 3; 3714329Seric if (egid != s->st_gid) 3724329Seric bits >>= 3; 3734329Seric } 3744329Seric return ((s->st_mode & bits) != 0); 3754329Seric } 3764329Seric /* 3774174Seric ** INCLUDE -- handle :include: specification. 3784174Seric ** 3794174Seric ** Parameters: 3804174Seric ** fname -- filename to include. 3814176Seric ** msg -- message to print in verbose mode. 3824399Seric ** ctladdr -- address template to use to fill in these 3834399Seric ** addresses -- effective user/group id are 3844399Seric ** the important things. 3854174Seric ** 3864174Seric ** Returns: 3874174Seric ** none. 3884174Seric ** 3894174Seric ** Side Effects: 3904174Seric ** reads the :include: file and sends to everyone 3914174Seric ** listed in that file. 3924174Seric */ 3934174Seric 3944399Seric include(fname, msg, ctladdr) 3954174Seric char *fname; 3964176Seric char *msg; 3974399Seric ADDRESS *ctladdr; 3984174Seric { 3994174Seric char buf[MAXLINE]; 4004174Seric register FILE *fp; 4014178Seric char *oldto = To; 4024174Seric 4034174Seric fp = fopen(fname, "r"); 4044174Seric if (fp == NULL) 4054174Seric { 4064174Seric usrerr("Cannot open %s", fname); 4074174Seric return; 4084174Seric } 4094406Seric if (getctladdr(ctladdr) == NULL) 4104406Seric { 4114406Seric struct stat st; 4124174Seric 4134406Seric if (fstat(fileno(fp), &st) < 0) 4144406Seric syserr("Cannot fstat %s!", fname); 4154406Seric ctladdr->q_uid = st.st_uid; 4164406Seric ctladdr->q_gid = st.st_gid; 4174406Seric ctladdr->q_flags |= QGOODUID; 4184406Seric } 4194406Seric 4204174Seric /* read the file -- each line is a comma-separated list. */ 4214174Seric while (fgets(buf, sizeof buf, fp) != NULL) 4224174Seric { 4234174Seric register char *p = index(buf, '\n'); 4244174Seric 4254174Seric if (p != NULL) 4264174Seric *p = '\0'; 4274174Seric if (buf[0] == '\0') 4284174Seric continue; 4294178Seric To = oldto; 4304174Seric if (Verbose) 4314176Seric message(Arpa_Info, "%s to %s", msg, buf); 4324176Seric AliasLevel++; 4334399Seric sendto(buf, 1, ctladdr); 4344176Seric AliasLevel--; 4354174Seric } 4364174Seric 4374319Seric (void) fclose(fp); 4384174Seric } 4394324Seric /* 4404324Seric ** SENDTOARGV -- send to an argument vector. 4414324Seric ** 4424324Seric ** Parameters: 4434324Seric ** argv -- argument vector to send to. 4444324Seric ** 4454324Seric ** Returns: 4464324Seric ** none. 4474324Seric ** 4484324Seric ** Side Effects: 4494324Seric ** puts all addresses on the argument vector onto the 4504324Seric ** send queue. 4514324Seric */ 4524324Seric 4534324Seric sendtoargv(argv) 4544324Seric register char **argv; 4554324Seric { 4564324Seric register char *p; 4574324Seric extern bool sameword(); 4584324Seric 4594324Seric while ((p = *argv++) != NULL) 4604324Seric { 4614324Seric if (argv[0] != NULL && argv[1] != NULL && sameword(argv[0], "at")) 4624324Seric { 4634324Seric char nbuf[MAXNAME]; 4644324Seric 4654324Seric if (strlen(p) + strlen(argv[1]) + 2 > sizeof nbuf) 4664324Seric usrerr("address overflow"); 4674324Seric else 4684324Seric { 4694324Seric (void) strcpy(nbuf, p); 4704324Seric (void) strcat(nbuf, "@"); 4714324Seric (void) strcat(nbuf, argv[1]); 4724324Seric p = newstr(nbuf); 4734324Seric argv += 2; 4744324Seric } 4754324Seric } 4764402Seric sendto(p, 0, NULL); 4774324Seric } 4784324Seric } 4794399Seric /* 4804399Seric ** GETCTLADDR -- get controlling address from an address header. 4814399Seric ** 4824399Seric ** If none, get one corresponding to the effective userid. 4834399Seric ** 4844399Seric ** Parameters: 4854399Seric ** a -- the address to find the controller of. 4864399Seric ** 4874399Seric ** Returns: 4884399Seric ** the controlling address. 4894399Seric ** 4904399Seric ** Side Effects: 4914399Seric ** none. 4924399Seric */ 4934399Seric 4944399Seric ADDRESS * 4954399Seric getctladdr(a) 4964399Seric register ADDRESS *a; 4974399Seric { 4984404Seric while (a != NULL && !bitset(QGOODUID, a->q_flags)) 4994399Seric a = a->q_alias; 5004399Seric return (a); 5014399Seric } 502