1 # include <pwd.h> 2 # include <sys/types.h> 3 # include <sys/stat.h> 4 # include "sendmail.h" 5 6 static char SccsId[] = "@(#)recipient.c 3.15 09/12/81"; 7 8 /* 9 ** SENDTO -- Designate a send list. 10 ** 11 ** The parameter is a comma-separated list of people to send to. 12 ** This routine arranges to send to all of them. 13 ** 14 ** Parameters: 15 ** list -- the send list. 16 ** copyf -- the copy flag; passed to parse. 17 ** 18 ** Returns: 19 ** none 20 ** 21 ** Side Effects: 22 ** none. 23 */ 24 25 # define MAXRCRSN 10 26 27 sendto(list, copyf) 28 char *list; 29 int copyf; 30 { 31 register char *p; 32 bool more; /* set if more addresses to send to */ 33 ADDRESS *al; /* list of addresses to send to */ 34 35 # ifdef DEBUG 36 if (Debug > 1) 37 printf("sendto: %s\n", list); 38 # endif DEBUG 39 40 more = TRUE; 41 al = NULL; 42 for (p = list; more; ) 43 { 44 register char *q; 45 register char c; 46 ADDRESS *a; 47 48 /* find the end of this address */ 49 while (*p == ' ' || *p == '\t') 50 p++; 51 q = p; 52 while ((c = *p++) != '\0' && c != ',' && c != '\n') 53 continue; 54 more = c != '\0'; 55 *--p = '\0'; 56 if (more) 57 p++; 58 if (*q == '\0') 59 continue; 60 61 /* parse the address */ 62 if ((a = parse(q, (ADDRESS *) NULL, copyf)) == NULL) 63 continue; 64 65 /* put it on the local send list */ 66 a->q_next = al; 67 al = a; 68 } 69 70 /* arrange to send to everyone on the local send list */ 71 while (al != NULL) 72 { 73 register ADDRESS *a = al; 74 75 al = a->q_next; 76 recipient(a); 77 } 78 79 To = NULL; 80 } 81 /* 82 ** RECIPIENT -- Designate a message recipient 83 ** 84 ** Saves the named person for future mailing. 85 ** 86 ** Parameters: 87 ** a -- the (preparsed) address header for the recipient. 88 ** 89 ** Returns: 90 ** none. 91 ** 92 ** Side Effects: 93 ** none. 94 */ 95 96 recipient(a) 97 register ADDRESS *a; 98 { 99 register ADDRESS *q; 100 ADDRESS **pq; 101 register struct mailer *m; 102 103 To = a->q_paddr; 104 m = Mailer[a->q_mailer]; 105 errno = 0; 106 # ifdef DEBUG 107 if (Debug) 108 printf("recipient(%s)\n", To); 109 # endif DEBUG 110 111 /* break aliasing loops */ 112 if (AliasLevel > MAXRCRSN) 113 { 114 usrerr("aliasing/forwarding loop broken"); 115 return; 116 } 117 118 /* 119 ** Do sickly crude mapping for program mailing, etc. 120 */ 121 122 if (a->q_mailer == MN_LOCAL) 123 { 124 if (a->q_user[0] == '|') 125 { 126 a->q_mailer = MN_PROG; 127 m = Mailer[MN_PROG]; 128 a->q_user++; 129 # ifdef PARANOID 130 if (AliasLevel <= 0) 131 { 132 usrerr("Cannot mail directly to programs"); 133 a->q_flags |= QDONTSEND; 134 } 135 # endif PARANOID 136 } 137 } 138 139 /* 140 ** Look up this person in the recipient list. If they 141 ** are there already, return, otherwise continue. 142 ** If the list is empty, just add it. 143 */ 144 145 for (pq = &m->m_sendq; (q = *pq) != NULL; pq = &q->q_next) 146 { 147 if (!ForceMail && sameaddr(q, a, FALSE)) 148 { 149 # ifdef DEBUG 150 if (Debug) 151 printf("(%s in sendq)\n", a->q_paddr); 152 # endif DEBUG 153 if (Verbose && !bitset(QDONTSEND, a->q_flags)) 154 message(Arpa_Info, "duplicate suppressed"); 155 return; 156 } 157 } 158 159 /* add address on list */ 160 *pq = a; 161 a->q_next = NULL; 162 if (DontSend) 163 a->q_flags |= QDONTSEND; 164 165 /* 166 ** Alias the name and handle :include: specs. 167 */ 168 169 if (a->q_mailer == MN_LOCAL) 170 { 171 if (strncmp(a->q_user, ":include:", 9) == 0) 172 { 173 a->q_flags |= QDONTSEND; 174 if (Verbose) 175 message(Arpa_Info, "including file %s", &a->q_user[9]); 176 include(&a->q_user[9], " sending"); 177 } 178 else 179 alias(a); 180 } 181 182 /* 183 ** If the user is local and still being sent, verify that 184 ** the address is good. If it is, try to forward. 185 ** If the address is already good, we have a forwarding 186 ** loop. This can be broken by just sending directly to 187 ** the user (which is probably correct anyway). 188 */ 189 190 if (!bitset(QDONTSEND, a->q_flags) && a->q_mailer == MN_LOCAL) 191 { 192 char buf[MAXNAME]; 193 register char *p; 194 struct stat stb; 195 extern bool writable(); 196 197 strcpy(buf, a->q_user); 198 stripquotes(buf, TRUE); 199 200 /* see if this is to a file */ 201 if ((p = rindex(buf, '/')) != NULL) 202 { 203 /* check if writable or creatable */ 204 if ((stat(buf, &stb) >= 0) ? (!writable(&stb)) : 205 (*p = '\0', access(buf, 3) < 0)) 206 { 207 a->q_flags |= QBADADDR; 208 giveresponse(EX_CANTCREAT, TRUE, m); 209 } 210 } 211 else 212 { 213 register struct passwd *pw; 214 extern struct passwd *finduser(); 215 216 pw = finduser(buf); 217 if (pw == NULL) 218 { 219 a->q_flags |= QBADADDR; 220 giveresponse(EX_NOUSER, TRUE, m); 221 } 222 else 223 { 224 if (strcmp(a->q_user, pw->pw_name) != 0) 225 { 226 a->q_user = newstr(pw->pw_name); 227 strcpy(buf, pw->pw_name); 228 } 229 a->q_home = newstr(pw->pw_dir); 230 a->q_uid = pw->pw_uid; 231 if (strcmp(buf, a->q_user) == 0) 232 forward(a); 233 } 234 } 235 } 236 } 237 /* 238 ** FINDUSER -- find the password entry for a user. 239 ** 240 ** This looks a lot like getpwnam, except that it may want to 241 ** do some fancier pattern matching in /etc/passwd. 242 ** 243 ** Parameters: 244 ** name -- the name to match against. 245 ** 246 ** Returns: 247 ** A pointer to a pw struct. 248 ** NULL if name is unknown or ambiguous. 249 ** 250 ** Side Effects: 251 ** none. 252 */ 253 254 struct passwd * 255 finduser(name) 256 char *name; 257 { 258 extern struct passwd *getpwent(); 259 register struct passwd *pw; 260 261 setpwent(); 262 while ((pw = getpwent()) != NULL) 263 { 264 char buf[MAXNAME]; 265 register char *p; 266 extern bool sameword(); 267 268 if (strcmp(pw->pw_name, name) == 0) 269 return (pw); 270 buildfname(pw->pw_gecos, pw->pw_name, buf); 271 for (p = buf; (p = index(p, ' ')) != NULL; ) 272 *p++ = SPACESUB & 0177; 273 if (sameword(buf, name)) 274 { 275 if (Verbose) 276 message(Arpa_Info, "sending to login name %s", pw->pw_name); 277 return (pw); 278 } 279 } 280 return (NULL); 281 } 282 /* 283 ** WRITABLE -- predicate returning if the file is writable. 284 ** 285 ** This routine must duplicate the algorithm in sys/fio.c. 286 ** Unfortunately, we cannot use the access call since we 287 ** won't necessarily be the real uid when we try to 288 ** actually open the file. 289 ** 290 ** Notice that ANY file with ANY execute bit is automatically 291 ** not writable. This is also enforced by mailfile. 292 ** 293 ** Parameters: 294 ** s -- pointer to a stat struct for the file. 295 ** 296 ** Returns: 297 ** TRUE -- if we will be able to write this file. 298 ** FALSE -- if we cannot write this file. 299 ** 300 ** Side Effects: 301 ** none. 302 */ 303 304 bool 305 writable(s) 306 register struct stat *s; 307 { 308 int euid, egid; 309 int bits; 310 311 if (bitset(0111, s->st_mode)) 312 return (FALSE); 313 euid = getruid(); 314 egid = getrgid(); 315 if (geteuid() == 0) 316 { 317 if (bitset(S_ISUID, s->st_mode)) 318 euid = s->st_uid; 319 if (bitset(S_ISGID, s->st_mode)) 320 egid = s->st_gid; 321 } 322 323 if (euid == 0) 324 return (TRUE); 325 bits = S_IWRITE; 326 if (euid != s->st_uid) 327 { 328 bits >>= 3; 329 if (egid != s->st_gid) 330 bits >>= 3; 331 } 332 return ((s->st_mode & bits) != 0); 333 } 334 /* 335 ** INCLUDE -- handle :include: specification. 336 ** 337 ** Parameters: 338 ** fname -- filename to include. 339 ** msg -- message to print in verbose mode. 340 ** 341 ** Returns: 342 ** none. 343 ** 344 ** Side Effects: 345 ** reads the :include: file and sends to everyone 346 ** listed in that file. 347 */ 348 349 include(fname, msg) 350 char *fname; 351 char *msg; 352 { 353 char buf[MAXLINE]; 354 register FILE *fp; 355 char *oldto = To; 356 357 fp = fopen(fname, "r"); 358 if (fp == NULL) 359 { 360 usrerr("Cannot open %s", fname); 361 return; 362 } 363 364 /* read the file -- each line is a comma-separated list. */ 365 while (fgets(buf, sizeof buf, fp) != NULL) 366 { 367 register char *p = index(buf, '\n'); 368 369 if (p != NULL) 370 *p = '\0'; 371 if (buf[0] == '\0') 372 continue; 373 To = oldto; 374 if (Verbose) 375 message(Arpa_Info, "%s to %s", msg, buf); 376 AliasLevel++; 377 sendto(buf, 1); 378 AliasLevel--; 379 } 380 381 (void) fclose(fp); 382 } 383 /* 384 ** SENDTOARGV -- send to an argument vector. 385 ** 386 ** Parameters: 387 ** argv -- argument vector to send to. 388 ** 389 ** Returns: 390 ** none. 391 ** 392 ** Side Effects: 393 ** puts all addresses on the argument vector onto the 394 ** send queue. 395 */ 396 397 sendtoargv(argv) 398 register char **argv; 399 { 400 register char *p; 401 extern bool sameword(); 402 403 while ((p = *argv++) != NULL) 404 { 405 if (argv[0] != NULL && argv[1] != NULL && sameword(argv[0], "at")) 406 { 407 char nbuf[MAXNAME]; 408 409 if (strlen(p) + strlen(argv[1]) + 2 > sizeof nbuf) 410 usrerr("address overflow"); 411 else 412 { 413 (void) strcpy(nbuf, p); 414 (void) strcat(nbuf, "@"); 415 (void) strcat(nbuf, argv[1]); 416 p = newstr(nbuf); 417 argv += 2; 418 } 419 } 420 sendto(p, 0); 421 } 422 } 423