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