14174Seric # include <pwd.h> 24329Seric # include <sys/types.h> 34329Seric # include <sys/stat.h> 44174Seric # include "sendmail.h" 54174Seric 6*4419Seric static char SccsId[] = "@(#)recipient.c 3.22 09/21/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 */ 374174Seric 384324Seric # ifdef DEBUG 394324Seric if (Debug > 1) 404324Seric printf("sendto: %s\n", list); 414324Seric # endif DEBUG 424324Seric 434174Seric more = TRUE; 444324Seric al = NULL; 454174Seric for (p = list; more; ) 464174Seric { 474319Seric register char *q; 484319Seric register char c; 494319Seric ADDRESS *a; 504319Seric 514174Seric /* find the end of this address */ 524174Seric while (*p == ' ' || *p == '\t') 534174Seric p++; 544174Seric q = p; 554174Seric while ((c = *p++) != '\0' && c != ',' && c != '\n') 564174Seric continue; 574174Seric more = c != '\0'; 584174Seric *--p = '\0'; 594174Seric if (more) 604174Seric p++; 614324Seric if (*q == '\0') 624324Seric continue; 634174Seric 644174Seric /* parse the address */ 654174Seric if ((a = parse(q, (ADDRESS *) NULL, copyf)) == NULL) 664174Seric continue; 674174Seric 684324Seric /* put it on the local send list */ 694324Seric a->q_next = al; 704399Seric a->q_alias = ctladdr; 714324Seric al = a; 724324Seric } 734324Seric 744324Seric /* arrange to send to everyone on the local send list */ 754324Seric while (al != NULL) 764324Seric { 774324Seric register ADDRESS *a = al; 784324Seric 794324Seric al = a->q_next; 804174Seric recipient(a); 814174Seric } 824324Seric 834174Seric To = NULL; 844174Seric } 854174Seric /* 864174Seric ** RECIPIENT -- Designate a message recipient 874174Seric ** 884174Seric ** Saves the named person for future mailing. 894174Seric ** 904174Seric ** Parameters: 914174Seric ** a -- the (preparsed) address header for the recipient. 924174Seric ** 934174Seric ** Returns: 944174Seric ** none. 954174Seric ** 964174Seric ** Side Effects: 974174Seric ** none. 984174Seric */ 994174Seric 1004174Seric recipient(a) 1014174Seric register ADDRESS *a; 1024174Seric { 1034174Seric register ADDRESS *q; 1044319Seric ADDRESS **pq; 1054174Seric register struct mailer *m; 1064399Seric extern ADDRESS *getctladdr(); 1074174Seric 1084174Seric To = a->q_paddr; 1094174Seric m = Mailer[a->q_mailer]; 1104174Seric errno = 0; 1114174Seric # ifdef DEBUG 1124174Seric if (Debug) 1134174Seric printf("recipient(%s)\n", To); 1144174Seric # endif DEBUG 1154174Seric 1164174Seric /* break aliasing loops */ 1174174Seric if (AliasLevel > MAXRCRSN) 1184174Seric { 1194174Seric usrerr("aliasing/forwarding loop broken"); 1204174Seric return; 1214174Seric } 1224174Seric 1234174Seric /* 1244174Seric ** Do sickly crude mapping for program mailing, etc. 1254174Seric */ 1264174Seric 1274197Seric if (a->q_mailer == MN_LOCAL) 1284174Seric { 1294174Seric if (a->q_user[0] == '|') 1304174Seric { 1314197Seric a->q_mailer = MN_PROG; 1324197Seric m = Mailer[MN_PROG]; 1334174Seric a->q_user++; 1344406Seric if (a->q_alias == NULL && Debug == 0) 1354217Seric { 1364217Seric usrerr("Cannot mail directly to programs"); 1374217Seric a->q_flags |= QDONTSEND; 1384217Seric } 1394174Seric } 1404174Seric } 1414174Seric 1424174Seric /* 143*4419Seric ** Look up this person in the recipient list. 144*4419Seric ** If they are there already, return, otherwise continue. 145*4419Seric ** If the list is empty, just add it. Notice the cute 146*4419Seric ** hack to make from addresses suppress things correctly: 147*4419Seric ** the QDONTSEND bit will be set in the send list. 148*4419Seric ** [Please note: the emphasis is on "hack."] 1494174Seric */ 1504174Seric 1514319Seric for (pq = &m->m_sendq; (q = *pq) != NULL; pq = &q->q_next) 1524174Seric { 1534319Seric if (!ForceMail && sameaddr(q, a, FALSE)) 1544174Seric { 1554174Seric # ifdef DEBUG 1564319Seric if (Debug) 1574319Seric printf("(%s in sendq)\n", a->q_paddr); 1584174Seric # endif DEBUG 1594319Seric if (Verbose && !bitset(QDONTSEND, a->q_flags)) 1604324Seric message(Arpa_Info, "duplicate suppressed"); 161*4419Seric q->q_flags |= a->q_flags; 1624319Seric return; 1634174Seric } 1644319Seric } 1654174Seric 1664319Seric /* add address on list */ 1674319Seric *pq = a; 1684174Seric a->q_next = NULL; 1694247Seric if (DontSend) 1704247Seric a->q_flags |= QDONTSEND; 1714174Seric 1724174Seric /* 1734174Seric ** Alias the name and handle :include: specs. 1744174Seric */ 1754174Seric 1764197Seric if (a->q_mailer == MN_LOCAL) 1774174Seric { 1784174Seric if (strncmp(a->q_user, ":include:", 9) == 0) 1794174Seric { 1804174Seric a->q_flags |= QDONTSEND; 1814406Seric if (a->q_alias == NULL && Debug == 0) 1824399Seric usrerr("Cannot mail directly to :include:s"); 1834399Seric else 1844399Seric { 1854399Seric if (Verbose) 1864399Seric message(Arpa_Info, "including file %s", &a->q_user[9]); 1874399Seric include(&a->q_user[9], " sending", a); 1884399Seric } 1894174Seric } 1904174Seric else 1914174Seric alias(a); 1924174Seric } 1934174Seric 1944174Seric /* 1954174Seric ** If the user is local and still being sent, verify that 1964174Seric ** the address is good. If it is, try to forward. 1974174Seric ** If the address is already good, we have a forwarding 1984174Seric ** loop. This can be broken by just sending directly to 1994174Seric ** the user (which is probably correct anyway). 2004174Seric */ 2014174Seric 2024197Seric if (!bitset(QDONTSEND, a->q_flags) && a->q_mailer == MN_LOCAL) 2034174Seric { 2044174Seric char buf[MAXNAME]; 2054201Seric register char *p; 2064329Seric struct stat stb; 2074329Seric extern bool writable(); 2084399Seric bool quoted = FALSE; 2094174Seric 2104174Seric strcpy(buf, a->q_user); 2114399Seric for (p = buf; *p != '\0' && !quoted; p++) 2124399Seric { 2134399Seric if (!isascii(*p)) 2144399Seric quoted = TRUE; 2154399Seric } 2164174Seric stripquotes(buf, TRUE); 2174174Seric 2184174Seric /* see if this is to a file */ 2194201Seric if ((p = rindex(buf, '/')) != NULL) 2204174Seric { 2214201Seric /* check if writable or creatable */ 2224406Seric if (a->q_alias == NULL && Debug == 0) 2234399Seric { 2244399Seric usrerr("Cannot mail directly to files"); 2254399Seric a->q_flags |= QDONTSEND; 2264399Seric } 2274399Seric else if ((stat(buf, &stb) >= 0) ? (!writable(&stb)) : 2284201Seric (*p = '\0', access(buf, 3) < 0)) 2294174Seric { 2304174Seric a->q_flags |= QBADADDR; 2314174Seric giveresponse(EX_CANTCREAT, TRUE, m); 2324174Seric } 2334174Seric } 2344174Seric else 2354174Seric { 2364174Seric register struct passwd *pw; 2374373Seric extern struct passwd *finduser(); 2384373Seric 2394407Seric /* warning -- finduser may trash buf */ 2404373Seric pw = finduser(buf); 2414174Seric if (pw == NULL) 2424174Seric { 2434174Seric a->q_flags |= QBADADDR; 2444174Seric giveresponse(EX_NOUSER, TRUE, m); 2454174Seric } 2464174Seric else 2474174Seric { 2484376Seric if (strcmp(a->q_user, pw->pw_name) != 0) 2494376Seric { 2504376Seric a->q_user = newstr(pw->pw_name); 2514376Seric strcpy(buf, pw->pw_name); 2524376Seric } 2534174Seric a->q_home = newstr(pw->pw_dir); 2544213Seric a->q_uid = pw->pw_uid; 2554399Seric a->q_gid = pw->pw_gid; 2564404Seric a->q_flags |= QGOODUID; 2574399Seric if (!quoted) 2584174Seric forward(a); 2594174Seric } 2604174Seric } 2614174Seric } 2624174Seric } 2634174Seric /* 2644373Seric ** FINDUSER -- find the password entry for a user. 2654373Seric ** 2664373Seric ** This looks a lot like getpwnam, except that it may want to 2674373Seric ** do some fancier pattern matching in /etc/passwd. 2684373Seric ** 2694373Seric ** Parameters: 2704373Seric ** name -- the name to match against. 2714373Seric ** 2724373Seric ** Returns: 2734373Seric ** A pointer to a pw struct. 2744373Seric ** NULL if name is unknown or ambiguous. 2754373Seric ** 2764373Seric ** Side Effects: 2774407Seric ** may modify name. 2784373Seric */ 2794373Seric 2804373Seric struct passwd * 2814373Seric finduser(name) 2824373Seric char *name; 2834373Seric { 2844376Seric extern struct passwd *getpwent(); 2854376Seric register struct passwd *pw; 2864407Seric register char *p; 2874373Seric 2884407Seric /* 2894407Seric ** Make name canonical. 2904407Seric */ 2914407Seric 2924407Seric for (p = name; *p != '\0'; p++) 2934407Seric { 2944407Seric if (*p == (SPACESUB & 0177) || *p == '_') 2954407Seric *p = ' '; 2964407Seric } 2974407Seric 2984376Seric setpwent(); 2994376Seric while ((pw = getpwent()) != NULL) 3004376Seric { 3014376Seric char buf[MAXNAME]; 3024376Seric extern bool sameword(); 3034376Seric 3044376Seric if (strcmp(pw->pw_name, name) == 0) 3054376Seric return (pw); 3064376Seric buildfname(pw->pw_gecos, pw->pw_name, buf); 3074407Seric if (index(buf, ' ') != NULL && sameword(buf, name)) 3084381Seric { 3094377Seric if (Verbose) 3104381Seric message(Arpa_Info, "sending to login name %s", 3114381Seric pw->pw_name); 3124376Seric return (pw); 3134377Seric } 3144376Seric } 3154376Seric return (NULL); 3164373Seric } 3174373Seric /* 3184329Seric ** WRITABLE -- predicate returning if the file is writable. 3194329Seric ** 3204329Seric ** This routine must duplicate the algorithm in sys/fio.c. 3214329Seric ** Unfortunately, we cannot use the access call since we 3224329Seric ** won't necessarily be the real uid when we try to 3234329Seric ** actually open the file. 3244329Seric ** 3254329Seric ** Notice that ANY file with ANY execute bit is automatically 3264329Seric ** not writable. This is also enforced by mailfile. 3274329Seric ** 3284329Seric ** Parameters: 3294329Seric ** s -- pointer to a stat struct for the file. 3304329Seric ** 3314329Seric ** Returns: 3324329Seric ** TRUE -- if we will be able to write this file. 3334329Seric ** FALSE -- if we cannot write this file. 3344329Seric ** 3354329Seric ** Side Effects: 3364329Seric ** none. 3374329Seric */ 3384329Seric 3394329Seric bool 3404329Seric writable(s) 3414329Seric register struct stat *s; 3424329Seric { 3434329Seric int euid, egid; 3444329Seric int bits; 3454329Seric 3464329Seric if (bitset(0111, s->st_mode)) 3474329Seric return (FALSE); 3484329Seric euid = getruid(); 3494329Seric egid = getrgid(); 3504329Seric if (geteuid() == 0) 3514329Seric { 3524329Seric if (bitset(S_ISUID, s->st_mode)) 3534329Seric euid = s->st_uid; 3544329Seric if (bitset(S_ISGID, s->st_mode)) 3554329Seric egid = s->st_gid; 3564329Seric } 3574329Seric 3584329Seric if (euid == 0) 3594329Seric return (TRUE); 3604329Seric bits = S_IWRITE; 3614329Seric if (euid != s->st_uid) 3624329Seric { 3634329Seric bits >>= 3; 3644329Seric if (egid != s->st_gid) 3654329Seric bits >>= 3; 3664329Seric } 3674329Seric return ((s->st_mode & bits) != 0); 3684329Seric } 3694329Seric /* 3704174Seric ** INCLUDE -- handle :include: specification. 3714174Seric ** 3724174Seric ** Parameters: 3734174Seric ** fname -- filename to include. 3744176Seric ** msg -- message to print in verbose mode. 3754399Seric ** ctladdr -- address template to use to fill in these 3764399Seric ** addresses -- effective user/group id are 3774399Seric ** the important things. 3784174Seric ** 3794174Seric ** Returns: 3804174Seric ** none. 3814174Seric ** 3824174Seric ** Side Effects: 3834174Seric ** reads the :include: file and sends to everyone 3844174Seric ** listed in that file. 3854174Seric */ 3864174Seric 3874399Seric include(fname, msg, ctladdr) 3884174Seric char *fname; 3894176Seric char *msg; 3904399Seric ADDRESS *ctladdr; 3914174Seric { 3924174Seric char buf[MAXLINE]; 3934174Seric register FILE *fp; 3944178Seric char *oldto = To; 3954174Seric 3964174Seric fp = fopen(fname, "r"); 3974174Seric if (fp == NULL) 3984174Seric { 3994174Seric usrerr("Cannot open %s", fname); 4004174Seric return; 4014174Seric } 4024406Seric if (getctladdr(ctladdr) == NULL) 4034406Seric { 4044406Seric struct stat st; 4054174Seric 4064406Seric if (fstat(fileno(fp), &st) < 0) 4074406Seric syserr("Cannot fstat %s!", fname); 4084406Seric ctladdr->q_uid = st.st_uid; 4094406Seric ctladdr->q_gid = st.st_gid; 4104406Seric ctladdr->q_flags |= QGOODUID; 4114406Seric } 4124406Seric 4134174Seric /* read the file -- each line is a comma-separated list. */ 4144174Seric while (fgets(buf, sizeof buf, fp) != NULL) 4154174Seric { 4164174Seric register char *p = index(buf, '\n'); 4174174Seric 4184174Seric if (p != NULL) 4194174Seric *p = '\0'; 4204174Seric if (buf[0] == '\0') 4214174Seric continue; 4224178Seric To = oldto; 4234174Seric if (Verbose) 4244176Seric message(Arpa_Info, "%s to %s", msg, buf); 4254176Seric AliasLevel++; 4264399Seric sendto(buf, 1, ctladdr); 4274176Seric AliasLevel--; 4284174Seric } 4294174Seric 4304319Seric (void) fclose(fp); 4314174Seric } 4324324Seric /* 4334324Seric ** SENDTOARGV -- send to an argument vector. 4344324Seric ** 4354324Seric ** Parameters: 4364324Seric ** argv -- argument vector to send to. 4374324Seric ** 4384324Seric ** Returns: 4394324Seric ** none. 4404324Seric ** 4414324Seric ** Side Effects: 4424324Seric ** puts all addresses on the argument vector onto the 4434324Seric ** send queue. 4444324Seric */ 4454324Seric 4464324Seric sendtoargv(argv) 4474324Seric register char **argv; 4484324Seric { 4494324Seric register char *p; 4504324Seric extern bool sameword(); 4514324Seric 4524324Seric while ((p = *argv++) != NULL) 4534324Seric { 4544324Seric if (argv[0] != NULL && argv[1] != NULL && sameword(argv[0], "at")) 4554324Seric { 4564324Seric char nbuf[MAXNAME]; 4574324Seric 4584324Seric if (strlen(p) + strlen(argv[1]) + 2 > sizeof nbuf) 4594324Seric usrerr("address overflow"); 4604324Seric else 4614324Seric { 4624324Seric (void) strcpy(nbuf, p); 4634324Seric (void) strcat(nbuf, "@"); 4644324Seric (void) strcat(nbuf, argv[1]); 4654324Seric p = newstr(nbuf); 4664324Seric argv += 2; 4674324Seric } 4684324Seric } 4694402Seric sendto(p, 0, NULL); 4704324Seric } 4714324Seric } 4724399Seric /* 4734399Seric ** GETCTLADDR -- get controlling address from an address header. 4744399Seric ** 4754399Seric ** If none, get one corresponding to the effective userid. 4764399Seric ** 4774399Seric ** Parameters: 4784399Seric ** a -- the address to find the controller of. 4794399Seric ** 4804399Seric ** Returns: 4814399Seric ** the controlling address. 4824399Seric ** 4834399Seric ** Side Effects: 4844399Seric ** none. 4854399Seric */ 4864399Seric 4874399Seric ADDRESS * 4884399Seric getctladdr(a) 4894399Seric register ADDRESS *a; 4904399Seric { 4914404Seric while (a != NULL && !bitset(QGOODUID, a->q_flags)) 4924399Seric a = a->q_alias; 4934399Seric return (a); 4944399Seric } 495