14174Seric # include <pwd.h> 24329Seric # include <sys/types.h> 34329Seric # include <sys/stat.h> 44174Seric # include "sendmail.h" 54174Seric 6*4381Seric static char SccsId[] = "@(#)recipient.c 3.16 09/12/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. 174174Seric ** 184174Seric ** Returns: 194174Seric ** none 204174Seric ** 214174Seric ** Side Effects: 224174Seric ** none. 234174Seric */ 244174Seric 254174Seric # define MAXRCRSN 10 264174Seric 274174Seric sendto(list, copyf) 284174Seric char *list; 294174Seric int copyf; 304174Seric { 314174Seric register char *p; 324319Seric bool more; /* set if more addresses to send to */ 334324Seric ADDRESS *al; /* list of addresses to send to */ 344174Seric 354324Seric # ifdef DEBUG 364324Seric if (Debug > 1) 374324Seric printf("sendto: %s\n", list); 384324Seric # endif DEBUG 394324Seric 404174Seric more = TRUE; 414324Seric al = NULL; 424174Seric for (p = list; more; ) 434174Seric { 444319Seric register char *q; 454319Seric register char c; 464319Seric ADDRESS *a; 474319Seric 484174Seric /* find the end of this address */ 494174Seric while (*p == ' ' || *p == '\t') 504174Seric p++; 514174Seric q = p; 524174Seric while ((c = *p++) != '\0' && c != ',' && c != '\n') 534174Seric continue; 544174Seric more = c != '\0'; 554174Seric *--p = '\0'; 564174Seric if (more) 574174Seric p++; 584324Seric if (*q == '\0') 594324Seric continue; 604174Seric 614174Seric /* parse the address */ 624174Seric if ((a = parse(q, (ADDRESS *) NULL, copyf)) == NULL) 634174Seric continue; 644174Seric 654324Seric /* put it on the local send list */ 664324Seric a->q_next = al; 674324Seric al = a; 684324Seric } 694324Seric 704324Seric /* arrange to send to everyone on the local send list */ 714324Seric while (al != NULL) 724324Seric { 734324Seric register ADDRESS *a = al; 744324Seric 754324Seric al = a->q_next; 764174Seric recipient(a); 774174Seric } 784324Seric 794174Seric To = NULL; 804174Seric } 814174Seric /* 824174Seric ** RECIPIENT -- Designate a message recipient 834174Seric ** 844174Seric ** Saves the named person for future mailing. 854174Seric ** 864174Seric ** Parameters: 874174Seric ** a -- the (preparsed) address header for the recipient. 884174Seric ** 894174Seric ** Returns: 904174Seric ** none. 914174Seric ** 924174Seric ** Side Effects: 934174Seric ** none. 944174Seric */ 954174Seric 964174Seric recipient(a) 974174Seric register ADDRESS *a; 984174Seric { 994174Seric register ADDRESS *q; 1004319Seric ADDRESS **pq; 1014174Seric register struct mailer *m; 1024174Seric 1034174Seric To = a->q_paddr; 1044174Seric m = Mailer[a->q_mailer]; 1054174Seric errno = 0; 1064174Seric # ifdef DEBUG 1074174Seric if (Debug) 1084174Seric printf("recipient(%s)\n", To); 1094174Seric # endif DEBUG 1104174Seric 1114174Seric /* break aliasing loops */ 1124174Seric if (AliasLevel > MAXRCRSN) 1134174Seric { 1144174Seric usrerr("aliasing/forwarding loop broken"); 1154174Seric return; 1164174Seric } 1174174Seric 1184174Seric /* 1194174Seric ** Do sickly crude mapping for program mailing, etc. 1204174Seric */ 1214174Seric 1224197Seric if (a->q_mailer == MN_LOCAL) 1234174Seric { 1244174Seric if (a->q_user[0] == '|') 1254174Seric { 1264197Seric a->q_mailer = MN_PROG; 1274197Seric m = Mailer[MN_PROG]; 1284174Seric a->q_user++; 1294217Seric # ifdef PARANOID 1304217Seric if (AliasLevel <= 0) 1314217Seric { 1324217Seric usrerr("Cannot mail directly to programs"); 1334217Seric a->q_flags |= QDONTSEND; 1344217Seric } 1354217Seric # endif PARANOID 1364174Seric } 1374174Seric } 1384174Seric 1394174Seric /* 1404174Seric ** Look up this person in the recipient list. If they 1414174Seric ** are there already, return, otherwise continue. 1424174Seric ** If the list is empty, just add it. 1434174Seric */ 1444174Seric 1454319Seric for (pq = &m->m_sendq; (q = *pq) != NULL; pq = &q->q_next) 1464174Seric { 1474319Seric if (!ForceMail && sameaddr(q, a, FALSE)) 1484174Seric { 1494174Seric # ifdef DEBUG 1504319Seric if (Debug) 1514319Seric printf("(%s in sendq)\n", a->q_paddr); 1524174Seric # endif DEBUG 1534319Seric if (Verbose && !bitset(QDONTSEND, a->q_flags)) 1544324Seric message(Arpa_Info, "duplicate suppressed"); 1554319Seric return; 1564174Seric } 1574319Seric } 1584174Seric 1594319Seric /* add address on list */ 1604319Seric *pq = a; 1614174Seric a->q_next = NULL; 1624247Seric if (DontSend) 1634247Seric a->q_flags |= QDONTSEND; 1644174Seric 1654174Seric /* 1664174Seric ** Alias the name and handle :include: specs. 1674174Seric */ 1684174Seric 1694197Seric if (a->q_mailer == MN_LOCAL) 1704174Seric { 1714174Seric if (strncmp(a->q_user, ":include:", 9) == 0) 1724174Seric { 1734174Seric a->q_flags |= QDONTSEND; 1744176Seric if (Verbose) 1754176Seric message(Arpa_Info, "including file %s", &a->q_user[9]); 1764176Seric include(&a->q_user[9], " sending"); 1774174Seric } 1784174Seric else 1794174Seric alias(a); 1804174Seric } 1814174Seric 1824174Seric /* 1834174Seric ** If the user is local and still being sent, verify that 1844174Seric ** the address is good. If it is, try to forward. 1854174Seric ** If the address is already good, we have a forwarding 1864174Seric ** loop. This can be broken by just sending directly to 1874174Seric ** the user (which is probably correct anyway). 1884174Seric */ 1894174Seric 1904197Seric if (!bitset(QDONTSEND, a->q_flags) && a->q_mailer == MN_LOCAL) 1914174Seric { 1924174Seric char buf[MAXNAME]; 1934201Seric register char *p; 1944329Seric struct stat stb; 1954329Seric extern bool writable(); 1964174Seric 1974174Seric strcpy(buf, a->q_user); 1984174Seric stripquotes(buf, TRUE); 1994174Seric 2004174Seric /* see if this is to a file */ 2014201Seric if ((p = rindex(buf, '/')) != NULL) 2024174Seric { 2034201Seric /* check if writable or creatable */ 2044329Seric if ((stat(buf, &stb) >= 0) ? (!writable(&stb)) : 2054201Seric (*p = '\0', access(buf, 3) < 0)) 2064174Seric { 2074174Seric a->q_flags |= QBADADDR; 2084174Seric giveresponse(EX_CANTCREAT, TRUE, m); 2094174Seric } 2104174Seric } 2114174Seric else 2124174Seric { 2134174Seric register struct passwd *pw; 2144373Seric extern struct passwd *finduser(); 2154373Seric 2164373Seric pw = finduser(buf); 2174174Seric if (pw == NULL) 2184174Seric { 2194174Seric a->q_flags |= QBADADDR; 2204174Seric giveresponse(EX_NOUSER, TRUE, m); 2214174Seric } 2224174Seric else 2234174Seric { 2244376Seric if (strcmp(a->q_user, pw->pw_name) != 0) 2254376Seric { 2264376Seric a->q_user = newstr(pw->pw_name); 2274376Seric strcpy(buf, pw->pw_name); 2284376Seric } 2294174Seric a->q_home = newstr(pw->pw_dir); 2304213Seric a->q_uid = pw->pw_uid; 2314174Seric if (strcmp(buf, a->q_user) == 0) 2324174Seric forward(a); 2334174Seric } 2344174Seric } 2354174Seric } 2364174Seric } 2374174Seric /* 2384373Seric ** FINDUSER -- find the password entry for a user. 2394373Seric ** 2404373Seric ** This looks a lot like getpwnam, except that it may want to 2414373Seric ** do some fancier pattern matching in /etc/passwd. 2424373Seric ** 2434373Seric ** Parameters: 2444373Seric ** name -- the name to match against. 2454373Seric ** 2464373Seric ** Returns: 2474373Seric ** A pointer to a pw struct. 2484373Seric ** NULL if name is unknown or ambiguous. 2494373Seric ** 2504373Seric ** Side Effects: 2514373Seric ** none. 2524373Seric */ 2534373Seric 2544373Seric struct passwd * 2554373Seric finduser(name) 2564373Seric char *name; 2574373Seric { 2584376Seric extern struct passwd *getpwent(); 2594376Seric register struct passwd *pw; 2604373Seric 2614376Seric setpwent(); 2624376Seric while ((pw = getpwent()) != NULL) 2634376Seric { 2644376Seric char buf[MAXNAME]; 2654376Seric register char *p; 2664376Seric extern bool sameword(); 267*4381Seric bool gotaspace; 2684376Seric 2694376Seric if (strcmp(pw->pw_name, name) == 0) 2704376Seric return (pw); 2714376Seric buildfname(pw->pw_gecos, pw->pw_name, buf); 272*4381Seric gotaspace = FALSE; 2734376Seric for (p = buf; (p = index(p, ' ')) != NULL; ) 274*4381Seric { 2754376Seric *p++ = SPACESUB & 0177; 276*4381Seric gotaspace = TRUE; 277*4381Seric } 278*4381Seric if (gotaspace && sameword(buf, name)) 2794377Seric { 2804377Seric if (Verbose) 281*4381Seric message(Arpa_Info, "sending to login name %s", 282*4381Seric pw->pw_name); 2834376Seric return (pw); 2844377Seric } 2854376Seric } 2864376Seric return (NULL); 2874373Seric } 2884373Seric /* 2894329Seric ** WRITABLE -- predicate returning if the file is writable. 2904329Seric ** 2914329Seric ** This routine must duplicate the algorithm in sys/fio.c. 2924329Seric ** Unfortunately, we cannot use the access call since we 2934329Seric ** won't necessarily be the real uid when we try to 2944329Seric ** actually open the file. 2954329Seric ** 2964329Seric ** Notice that ANY file with ANY execute bit is automatically 2974329Seric ** not writable. This is also enforced by mailfile. 2984329Seric ** 2994329Seric ** Parameters: 3004329Seric ** s -- pointer to a stat struct for the file. 3014329Seric ** 3024329Seric ** Returns: 3034329Seric ** TRUE -- if we will be able to write this file. 3044329Seric ** FALSE -- if we cannot write this file. 3054329Seric ** 3064329Seric ** Side Effects: 3074329Seric ** none. 3084329Seric */ 3094329Seric 3104329Seric bool 3114329Seric writable(s) 3124329Seric register struct stat *s; 3134329Seric { 3144329Seric int euid, egid; 3154329Seric int bits; 3164329Seric 3174329Seric if (bitset(0111, s->st_mode)) 3184329Seric return (FALSE); 3194329Seric euid = getruid(); 3204329Seric egid = getrgid(); 3214329Seric if (geteuid() == 0) 3224329Seric { 3234329Seric if (bitset(S_ISUID, s->st_mode)) 3244329Seric euid = s->st_uid; 3254329Seric if (bitset(S_ISGID, s->st_mode)) 3264329Seric egid = s->st_gid; 3274329Seric } 3284329Seric 3294329Seric if (euid == 0) 3304329Seric return (TRUE); 3314329Seric bits = S_IWRITE; 3324329Seric if (euid != s->st_uid) 3334329Seric { 3344329Seric bits >>= 3; 3354329Seric if (egid != s->st_gid) 3364329Seric bits >>= 3; 3374329Seric } 3384329Seric return ((s->st_mode & bits) != 0); 3394329Seric } 3404329Seric /* 3414174Seric ** INCLUDE -- handle :include: specification. 3424174Seric ** 3434174Seric ** Parameters: 3444174Seric ** fname -- filename to include. 3454176Seric ** msg -- message to print in verbose mode. 3464174Seric ** 3474174Seric ** Returns: 3484174Seric ** none. 3494174Seric ** 3504174Seric ** Side Effects: 3514174Seric ** reads the :include: file and sends to everyone 3524174Seric ** listed in that file. 3534174Seric */ 3544174Seric 3554176Seric include(fname, msg) 3564174Seric char *fname; 3574176Seric char *msg; 3584174Seric { 3594174Seric char buf[MAXLINE]; 3604174Seric register FILE *fp; 3614178Seric char *oldto = To; 3624174Seric 3634174Seric fp = fopen(fname, "r"); 3644174Seric if (fp == NULL) 3654174Seric { 3664174Seric usrerr("Cannot open %s", fname); 3674174Seric return; 3684174Seric } 3694174Seric 3704174Seric /* read the file -- each line is a comma-separated list. */ 3714174Seric while (fgets(buf, sizeof buf, fp) != NULL) 3724174Seric { 3734174Seric register char *p = index(buf, '\n'); 3744174Seric 3754174Seric if (p != NULL) 3764174Seric *p = '\0'; 3774174Seric if (buf[0] == '\0') 3784174Seric continue; 3794178Seric To = oldto; 3804174Seric if (Verbose) 3814176Seric message(Arpa_Info, "%s to %s", msg, buf); 3824176Seric AliasLevel++; 3834174Seric sendto(buf, 1); 3844176Seric AliasLevel--; 3854174Seric } 3864174Seric 3874319Seric (void) fclose(fp); 3884174Seric } 3894324Seric /* 3904324Seric ** SENDTOARGV -- send to an argument vector. 3914324Seric ** 3924324Seric ** Parameters: 3934324Seric ** argv -- argument vector to send to. 3944324Seric ** 3954324Seric ** Returns: 3964324Seric ** none. 3974324Seric ** 3984324Seric ** Side Effects: 3994324Seric ** puts all addresses on the argument vector onto the 4004324Seric ** send queue. 4014324Seric */ 4024324Seric 4034324Seric sendtoargv(argv) 4044324Seric register char **argv; 4054324Seric { 4064324Seric register char *p; 4074324Seric extern bool sameword(); 4084324Seric 4094324Seric while ((p = *argv++) != NULL) 4104324Seric { 4114324Seric if (argv[0] != NULL && argv[1] != NULL && sameword(argv[0], "at")) 4124324Seric { 4134324Seric char nbuf[MAXNAME]; 4144324Seric 4154324Seric if (strlen(p) + strlen(argv[1]) + 2 > sizeof nbuf) 4164324Seric usrerr("address overflow"); 4174324Seric else 4184324Seric { 4194324Seric (void) strcpy(nbuf, p); 4204324Seric (void) strcat(nbuf, "@"); 4214324Seric (void) strcat(nbuf, argv[1]); 4224324Seric p = newstr(nbuf); 4234324Seric argv += 2; 4244324Seric } 4254324Seric } 4264324Seric sendto(p, 0); 4274324Seric } 4284324Seric } 429