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