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