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