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.15 (Berkeley) 02/27/89"; 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 a = recipient(a, sendq); 122 123 /* arrange to inherit full name */ 124 if (a->q_fullname == NULL && ctladdr != NULL) 125 a->q_fullname = ctladdr->q_fullname; 126 } 127 128 CurEnv->e_to = NULL; 129 } 130 /* 131 ** RECIPIENT -- Designate a message recipient 132 ** 133 ** Saves the named person for future mailing. 134 ** 135 ** Parameters: 136 ** a -- the (preparsed) address header for the recipient. 137 ** sendq -- a pointer to the head of a queue to put the 138 ** recipient in. Duplicate supression is done 139 ** in this queue. 140 ** 141 ** Returns: 142 ** The actual address in the queue. This will be "a" if 143 ** the address is not a duplicate, else the original address. 144 ** 145 ** Side Effects: 146 ** none. 147 */ 148 149 ADDRESS * 150 recipient(a, sendq) 151 register ADDRESS *a; 152 register ADDRESS **sendq; 153 { 154 register ADDRESS *q; 155 ADDRESS **pq; 156 register struct mailer *m; 157 register char *p; 158 bool quoted = FALSE; /* set if the addr has a quote bit */ 159 char buf[MAXNAME]; /* unquoted image of the user name */ 160 extern ADDRESS *getctladdr(); 161 extern bool safefile(); 162 163 CurEnv->e_to = a->q_paddr; 164 m = a->q_mailer; 165 errno = 0; 166 if (tTd(26, 1)) 167 { 168 printf("\nrecipient: "); 169 printaddr(a, FALSE); 170 } 171 172 /* break aliasing loops */ 173 if (AliasLevel > MAXRCRSN) 174 { 175 usrerr("aliasing/forwarding loop broken"); 176 return (a); 177 } 178 179 /* 180 ** Finish setting up address structure. 181 */ 182 183 /* set the queue timeout */ 184 a->q_timeout = TimeOut; 185 186 /* map user & host to lower case if requested on non-aliases */ 187 if (a->q_alias == NULL) 188 loweraddr(a); 189 190 /* get unquoted user for file, program or user.name check */ 191 (void) strcpy(buf, a->q_user); 192 for (p = buf; *p != '\0' && !quoted; p++) 193 { 194 if (!isascii(*p) && (*p & 0377) != (SpaceSub & 0377)) 195 quoted = TRUE; 196 } 197 stripquotes(buf, TRUE); 198 199 /* do sickly crude mapping for program mailing, etc. */ 200 if (m == LocalMailer && buf[0] == '|') 201 { 202 a->q_mailer = m = ProgMailer; 203 a->q_user++; 204 if (a->q_alias == NULL && !QueueRun && !ForceMail) 205 { 206 a->q_flags |= QDONTSEND|QBADADDR; 207 usrerr("Cannot mail directly to programs"); 208 } 209 } 210 211 /* 212 ** Look up this person in the recipient list. 213 ** If they are there already, return, otherwise continue. 214 ** If the list is empty, just add it. Notice the cute 215 ** hack to make from addresses suppress things correctly: 216 ** the QDONTSEND bit will be set in the send list. 217 ** [Please note: the emphasis is on "hack."] 218 */ 219 220 for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next) 221 { 222 if (!ForceMail && sameaddr(q, a)) 223 { 224 if (tTd(26, 1)) 225 { 226 printf("%s in sendq: ", a->q_paddr); 227 printaddr(q, FALSE); 228 } 229 if (!bitset(QDONTSEND, a->q_flags)) 230 message(Arpa_Info, "duplicate suppressed"); 231 if (!bitset(QPRIMARY, q->q_flags)) 232 q->q_flags |= a->q_flags; 233 return (q); 234 } 235 } 236 237 /* add address on list */ 238 *pq = a; 239 a->q_next = NULL; 240 CurEnv->e_nrcpts++; 241 242 /* 243 ** Alias the name and handle :include: specs. 244 */ 245 246 if (m == LocalMailer && !bitset(QDONTSEND, a->q_flags)) 247 { 248 if (strncmp(a->q_user, ":include:", 9) == 0) 249 { 250 a->q_flags |= QDONTSEND; 251 if (a->q_alias == NULL && !QueueRun && !ForceMail) 252 { 253 a->q_flags |= QBADADDR; 254 usrerr("Cannot mail directly to :include:s"); 255 } 256 else 257 { 258 message(Arpa_Info, "including file %s", &a->q_user[9]); 259 include(&a->q_user[9], " sending", a, sendq); 260 } 261 } 262 else 263 alias(a, sendq); 264 } 265 266 /* 267 ** If the user is local and still being sent, verify that 268 ** the address is good. If it is, try to forward. 269 ** If the address is already good, we have a forwarding 270 ** loop. This can be broken by just sending directly to 271 ** the user (which is probably correct anyway). 272 */ 273 274 if (!bitset(QDONTSEND, a->q_flags) && m == LocalMailer) 275 { 276 struct stat stb; 277 extern bool writable(); 278 279 /* see if this is to a file */ 280 if (buf[0] == '/') 281 { 282 p = rindex(buf, '/'); 283 /* check if writable or creatable */ 284 if (a->q_alias == NULL && !QueueRun && !ForceMail) 285 { 286 a->q_flags |= QDONTSEND|QBADADDR; 287 usrerr("Cannot mail directly to files"); 288 } 289 else if ((stat(buf, &stb) >= 0) ? (!writable(&stb)) : 290 (*p = '\0', !safefile(buf, getruid(), S_IWRITE|S_IEXEC))) 291 { 292 a->q_flags |= QBADADDR; 293 giveresponse(EX_CANTCREAT, m, CurEnv); 294 } 295 } 296 else 297 { 298 register struct passwd *pw; 299 extern struct passwd *finduser(); 300 301 /* warning -- finduser may trash buf */ 302 pw = finduser(buf); 303 if (pw == NULL) 304 { 305 a->q_flags |= QBADADDR; 306 giveresponse(EX_NOUSER, m, CurEnv); 307 } 308 else 309 { 310 char nbuf[MAXNAME]; 311 312 if (strcmp(a->q_user, pw->pw_name) != 0) 313 { 314 a->q_user = newstr(pw->pw_name); 315 (void) strcpy(buf, pw->pw_name); 316 } 317 a->q_home = newstr(pw->pw_dir); 318 a->q_uid = pw->pw_uid; 319 a->q_gid = pw->pw_gid; 320 a->q_flags |= QGOODUID; 321 buildfname(pw->pw_gecos, pw->pw_name, nbuf); 322 if (nbuf[0] != '\0') 323 a->q_fullname = newstr(nbuf); 324 if (!quoted) 325 forward(a, sendq); 326 } 327 } 328 } 329 return (a); 330 } 331 /* 332 ** FINDUSER -- find the password entry for a user. 333 ** 334 ** This looks a lot like getpwnam, except that it may want to 335 ** do some fancier pattern matching in /etc/passwd. 336 ** 337 ** This routine contains most of the time of many sendmail runs. 338 ** It deserves to be optimized. 339 ** 340 ** Parameters: 341 ** name -- the name to match against. 342 ** 343 ** Returns: 344 ** A pointer to a pw struct. 345 ** NULL if name is unknown or ambiguous. 346 ** 347 ** Side Effects: 348 ** may modify name. 349 */ 350 351 struct passwd * 352 finduser(name) 353 char *name; 354 { 355 register struct passwd *pw; 356 register char *p; 357 extern struct passwd *getpwent(); 358 extern struct passwd *getpwnam(); 359 360 /* map upper => lower case */ 361 for (p = name; *p != '\0'; p++) 362 { 363 if (isascii(*p) && isupper(*p)) 364 *p = tolower(*p); 365 } 366 367 /* look up this login name using fast path */ 368 if ((pw = getpwnam(name)) != NULL) 369 return (pw); 370 371 /* search for a matching full name instead */ 372 for (p = name; *p != '\0'; p++) 373 { 374 if (*p == (SpaceSub & 0177) || *p == '_') 375 *p = ' '; 376 } 377 (void) setpwent(); 378 while ((pw = getpwent()) != NULL) 379 { 380 char buf[MAXNAME]; 381 382 buildfname(pw->pw_gecos, pw->pw_name, buf); 383 if (index(buf, ' ') != NULL && !strcasecmp(buf, name)) 384 { 385 message(Arpa_Info, "sending to login name %s", pw->pw_name); 386 return (pw); 387 } 388 } 389 return (NULL); 390 } 391 /* 392 ** WRITABLE -- predicate returning if the file is writable. 393 ** 394 ** This routine must duplicate the algorithm in sys/fio.c. 395 ** Unfortunately, we cannot use the access call since we 396 ** won't necessarily be the real uid when we try to 397 ** actually open the file. 398 ** 399 ** Notice that ANY file with ANY execute bit is automatically 400 ** not writable. This is also enforced by mailfile. 401 ** 402 ** Parameters: 403 ** s -- pointer to a stat struct for the file. 404 ** 405 ** Returns: 406 ** TRUE -- if we will be able to write this file. 407 ** FALSE -- if we cannot write this file. 408 ** 409 ** Side Effects: 410 ** none. 411 */ 412 413 bool 414 writable(s) 415 register struct stat *s; 416 { 417 int euid, egid; 418 int bits; 419 420 if (bitset(0111, s->st_mode)) 421 return (FALSE); 422 euid = getruid(); 423 egid = getrgid(); 424 if (geteuid() == 0) 425 { 426 if (bitset(S_ISUID, s->st_mode)) 427 euid = s->st_uid; 428 if (bitset(S_ISGID, s->st_mode)) 429 egid = s->st_gid; 430 } 431 432 if (euid == 0) 433 return (TRUE); 434 bits = S_IWRITE; 435 if (euid != s->st_uid) 436 { 437 bits >>= 3; 438 if (egid != s->st_gid) 439 bits >>= 3; 440 } 441 return ((s->st_mode & bits) != 0); 442 } 443 /* 444 ** INCLUDE -- handle :include: specification. 445 ** 446 ** Parameters: 447 ** fname -- filename to include. 448 ** msg -- message to print in verbose mode. 449 ** ctladdr -- address template to use to fill in these 450 ** addresses -- effective user/group id are 451 ** the important things. 452 ** sendq -- a pointer to the head of the send queue 453 ** to put these addresses in. 454 ** 455 ** Returns: 456 ** none. 457 ** 458 ** Side Effects: 459 ** reads the :include: file and sends to everyone 460 ** listed in that file. 461 */ 462 463 include(fname, msg, ctladdr, sendq) 464 char *fname; 465 char *msg; 466 ADDRESS *ctladdr; 467 ADDRESS **sendq; 468 { 469 char buf[MAXLINE]; 470 register FILE *fp; 471 char *oldto = CurEnv->e_to; 472 char *oldfilename = FileName; 473 int oldlinenumber = LineNumber; 474 475 fp = fopen(fname, "r"); 476 if (fp == NULL) 477 { 478 usrerr("Cannot open %s", fname); 479 return; 480 } 481 if (getctladdr(ctladdr) == NULL) 482 { 483 struct stat st; 484 485 if (fstat(fileno(fp), &st) < 0) 486 syserr("Cannot fstat %s!", fname); 487 ctladdr->q_uid = st.st_uid; 488 ctladdr->q_gid = st.st_gid; 489 ctladdr->q_flags |= QGOODUID; 490 } 491 492 /* read the file -- each line is a comma-separated list. */ 493 FileName = fname; 494 LineNumber = 0; 495 while (fgets(buf, sizeof buf, fp) != NULL) 496 { 497 register char *p = index(buf, '\n'); 498 499 if (p != NULL) 500 *p = '\0'; 501 if (buf[0] == '\0') 502 continue; 503 CurEnv->e_to = oldto; 504 message(Arpa_Info, "%s to %s", msg, buf); 505 AliasLevel++; 506 sendtolist(buf, ctladdr, sendq); 507 AliasLevel--; 508 } 509 510 (void) fclose(fp); 511 FileName = oldfilename; 512 LineNumber = oldlinenumber; 513 } 514 /* 515 ** SENDTOARGV -- send to an argument vector. 516 ** 517 ** Parameters: 518 ** argv -- argument vector to send to. 519 ** 520 ** Returns: 521 ** none. 522 ** 523 ** Side Effects: 524 ** puts all addresses on the argument vector onto the 525 ** send queue. 526 */ 527 528 sendtoargv(argv) 529 register char **argv; 530 { 531 register char *p; 532 533 while ((p = *argv++) != NULL) 534 { 535 if (argv[0] != NULL && argv[1] != NULL && !strcasecmp(argv[0], "at")) 536 { 537 char nbuf[MAXNAME]; 538 539 if (strlen(p) + strlen(argv[1]) + 2 > sizeof nbuf) 540 usrerr("address overflow"); 541 else 542 { 543 (void) strcpy(nbuf, p); 544 (void) strcat(nbuf, "@"); 545 (void) strcat(nbuf, argv[1]); 546 p = newstr(nbuf); 547 argv += 2; 548 } 549 } 550 sendtolist(p, (ADDRESS *) NULL, &CurEnv->e_sendqueue); 551 } 552 } 553 /* 554 ** GETCTLADDR -- get controlling address from an address header. 555 ** 556 ** If none, get one corresponding to the effective userid. 557 ** 558 ** Parameters: 559 ** a -- the address to find the controller of. 560 ** 561 ** Returns: 562 ** the controlling address. 563 ** 564 ** Side Effects: 565 ** none. 566 */ 567 568 ADDRESS * 569 getctladdr(a) 570 register ADDRESS *a; 571 { 572 while (a != NULL && !bitset(QGOODUID, a->q_flags)) 573 a = a->q_alias; 574 return (a); 575 } 576