1 # include <pwd.h> 2 # include "sendmail.h" 3 # include <sys/stat.h> 4 5 SCCSID(@(#)recipient.c 3.38 06/07/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 CurEnv->e_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 CurEnv->e_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 (!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 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 (void) 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 (buf[0] == '/') 261 { 262 p = rindex(buf, '/'); 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 (void) 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 message(Arpa_Info, "sending to login name %s", pw->pw_name); 357 return (pw); 358 } 359 } 360 return (NULL); 361 } 362 /* 363 ** WRITABLE -- predicate returning if the file is writable. 364 ** 365 ** This routine must duplicate the algorithm in sys/fio.c. 366 ** Unfortunately, we cannot use the access call since we 367 ** won't necessarily be the real uid when we try to 368 ** actually open the file. 369 ** 370 ** Notice that ANY file with ANY execute bit is automatically 371 ** not writable. This is also enforced by mailfile. 372 ** 373 ** Parameters: 374 ** s -- pointer to a stat struct for the file. 375 ** 376 ** Returns: 377 ** TRUE -- if we will be able to write this file. 378 ** FALSE -- if we cannot write this file. 379 ** 380 ** Side Effects: 381 ** none. 382 */ 383 384 bool 385 writable(s) 386 register struct stat *s; 387 { 388 int euid, egid; 389 int bits; 390 391 if (bitset(0111, s->st_mode)) 392 return (FALSE); 393 euid = getruid(); 394 egid = getrgid(); 395 if (geteuid() == 0) 396 { 397 if (bitset(S_ISUID, s->st_mode)) 398 euid = s->st_uid; 399 if (bitset(S_ISGID, s->st_mode)) 400 egid = s->st_gid; 401 } 402 403 if (euid == 0) 404 return (TRUE); 405 bits = S_IWRITE; 406 if (euid != s->st_uid) 407 { 408 bits >>= 3; 409 if (egid != s->st_gid) 410 bits >>= 3; 411 } 412 return ((s->st_mode & bits) != 0); 413 } 414 /* 415 ** INCLUDE -- handle :include: specification. 416 ** 417 ** Parameters: 418 ** fname -- filename to include. 419 ** msg -- message to print in verbose mode. 420 ** ctladdr -- address template to use to fill in these 421 ** addresses -- effective user/group id are 422 ** the important things. 423 ** sendq -- a pointer to the head of the send queue 424 ** to put these addresses in. 425 ** 426 ** Returns: 427 ** none. 428 ** 429 ** Side Effects: 430 ** reads the :include: file and sends to everyone 431 ** listed in that file. 432 */ 433 434 include(fname, msg, ctladdr, sendq) 435 char *fname; 436 char *msg; 437 ADDRESS *ctladdr; 438 ADDRESS **sendq; 439 { 440 char buf[MAXLINE]; 441 register FILE *fp; 442 char *oldto = CurEnv->e_to; 443 444 fp = fopen(fname, "r"); 445 if (fp == NULL) 446 { 447 usrerr("Cannot open %s", fname); 448 return; 449 } 450 if (getctladdr(ctladdr) == NULL) 451 { 452 struct stat st; 453 454 if (fstat(fileno(fp), &st) < 0) 455 syserr("Cannot fstat %s!", fname); 456 ctladdr->q_uid = st.st_uid; 457 ctladdr->q_gid = st.st_gid; 458 ctladdr->q_flags |= QGOODUID; 459 } 460 461 /* read the file -- each line is a comma-separated list. */ 462 while (fgets(buf, sizeof buf, fp) != NULL) 463 { 464 register char *p = index(buf, '\n'); 465 466 if (p != NULL) 467 *p = '\0'; 468 if (buf[0] == '\0') 469 continue; 470 CurEnv->e_to = oldto; 471 message(Arpa_Info, "%s to %s", msg, buf); 472 AliasLevel++; 473 sendto(buf, 1, ctladdr, sendq); 474 AliasLevel--; 475 } 476 477 (void) fclose(fp); 478 } 479 /* 480 ** SENDTOARGV -- send to an argument vector. 481 ** 482 ** Parameters: 483 ** argv -- argument vector to send to. 484 ** 485 ** Returns: 486 ** none. 487 ** 488 ** Side Effects: 489 ** puts all addresses on the argument vector onto the 490 ** send queue. 491 */ 492 493 sendtoargv(argv) 494 register char **argv; 495 { 496 register char *p; 497 extern bool sameword(); 498 499 while ((p = *argv++) != NULL) 500 { 501 if (argv[0] != NULL && argv[1] != NULL && sameword(argv[0], "at")) 502 { 503 char nbuf[MAXNAME]; 504 505 if (strlen(p) + strlen(argv[1]) + 2 > sizeof nbuf) 506 usrerr("address overflow"); 507 else 508 { 509 (void) strcpy(nbuf, p); 510 (void) strcat(nbuf, "@"); 511 (void) strcat(nbuf, argv[1]); 512 p = newstr(nbuf); 513 argv += 2; 514 } 515 } 516 sendto(p, 0, (ADDRESS *) NULL, &CurEnv->e_sendqueue); 517 } 518 } 519 /* 520 ** GETCTLADDR -- get controlling address from an address header. 521 ** 522 ** If none, get one corresponding to the effective userid. 523 ** 524 ** Parameters: 525 ** a -- the address to find the controller of. 526 ** 527 ** Returns: 528 ** the controlling address. 529 ** 530 ** Side Effects: 531 ** none. 532 */ 533 534 ADDRESS * 535 getctladdr(a) 536 register ADDRESS *a; 537 { 538 while (a != NULL && !bitset(QGOODUID, a->q_flags)) 539 a = a->q_alias; 540 return (a); 541 } 542