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[] = "@(#)envelope.c 5.19 (Berkeley) 02/27/89"; 21 #endif /* not lint */ 22 23 #include <sys/types.h> 24 #include <sys/time.h> 25 #include <sys/stat.h> 26 #include <pwd.h> 27 #include "sendmail.h" 28 29 /* 30 ** NEWENVELOPE -- allocate a new envelope 31 ** 32 ** Supports inheritance. 33 ** 34 ** Parameters: 35 ** e -- the new envelope to fill in. 36 ** 37 ** Returns: 38 ** e. 39 ** 40 ** Side Effects: 41 ** none. 42 */ 43 44 ENVELOPE * 45 newenvelope(e) 46 register ENVELOPE *e; 47 { 48 register ENVELOPE *parent; 49 extern putheader(), putbody(); 50 extern ENVELOPE BlankEnvelope; 51 52 parent = CurEnv; 53 if (e == CurEnv) 54 parent = e->e_parent; 55 clearenvelope(e, TRUE); 56 if (e == CurEnv) 57 bcopy((char *) &NullAddress, (char *) &e->e_from, sizeof e->e_from); 58 else 59 bcopy((char *) &CurEnv->e_from, (char *) &e->e_from, sizeof e->e_from); 60 e->e_parent = parent; 61 e->e_ctime = curtime(); 62 e->e_msgpriority = parent->e_msgsize; 63 e->e_puthdr = putheader; 64 e->e_putbody = putbody; 65 if (CurEnv->e_xfp != NULL) 66 (void) fflush(CurEnv->e_xfp); 67 68 return (e); 69 } 70 /* 71 ** DROPENVELOPE -- deallocate an envelope. 72 ** 73 ** Parameters: 74 ** e -- the envelope to deallocate. 75 ** 76 ** Returns: 77 ** none. 78 ** 79 ** Side Effects: 80 ** housekeeping necessary to dispose of an envelope. 81 ** Unlocks this queue file. 82 */ 83 84 dropenvelope(e) 85 register ENVELOPE *e; 86 { 87 bool queueit = FALSE; 88 register ADDRESS *q; 89 90 if (tTd(50, 1)) 91 { 92 printf("dropenvelope %x id=", e); 93 xputs(e->e_id); 94 printf(" flags=%o\n", e->e_flags); 95 } 96 #ifdef LOG 97 if (LogLevel > 10) 98 syslog(LOG_DEBUG, "dropenvelope, id=%s, flags=%o, pid=%d", 99 e->e_id == NULL ? "(none)" : e->e_id, 100 e->e_flags, getpid()); 101 #endif LOG 102 103 /* we must have an id to remove disk files */ 104 if (e->e_id == NULL) 105 return; 106 107 /* 108 ** Extract state information from dregs of send list. 109 */ 110 111 for (q = e->e_sendqueue; q != NULL; q = q->q_next) 112 { 113 if (bitset(QQUEUEUP, q->q_flags)) 114 queueit = TRUE; 115 } 116 117 /* 118 ** Send back return receipts as requested. 119 */ 120 121 if (e->e_receiptto != NULL && bitset(EF_SENDRECEIPT, e->e_flags)) 122 { 123 auto ADDRESS *rlist = NULL; 124 125 sendtolist(CurEnv->e_receiptto, (ADDRESS *) NULL, &rlist); 126 (void) returntosender("Return receipt", rlist, FALSE); 127 } 128 129 /* 130 ** Arrange to send error messages if there are fatal errors. 131 */ 132 133 if (bitset(EF_FATALERRS|EF_TIMEOUT, e->e_flags) && ErrorMode != EM_QUIET) 134 savemail(e); 135 136 /* 137 ** Instantiate or deinstantiate the queue. 138 */ 139 140 if ((!queueit && !bitset(EF_KEEPQUEUE, e->e_flags)) || 141 bitset(EF_CLRQUEUE, e->e_flags)) 142 { 143 if (e->e_df != NULL) 144 xunlink(e->e_df); 145 xunlink(queuename(e, 'q')); 146 } 147 else if (queueit || !bitset(EF_INQUEUE, e->e_flags)) 148 { 149 #ifdef QUEUE 150 queueup(e, FALSE, FALSE); 151 #else QUEUE 152 syserr("dropenvelope: queueup"); 153 #endif QUEUE 154 } 155 156 /* now unlock the job */ 157 closexscript(e); 158 unlockqueue(e); 159 160 /* make sure that this envelope is marked unused */ 161 e->e_id = e->e_df = NULL; 162 if (e->e_dfp != NULL) 163 (void) fclose(e->e_dfp); 164 e->e_dfp = NULL; 165 } 166 /* 167 ** CLEARENVELOPE -- clear an envelope without unlocking 168 ** 169 ** This is normally used by a child process to get a clean 170 ** envelope without disturbing the parent. 171 ** 172 ** Parameters: 173 ** e -- the envelope to clear. 174 ** fullclear - if set, the current envelope is total 175 ** garbage and should be ignored; otherwise, 176 ** release any resources it may indicate. 177 ** 178 ** Returns: 179 ** none. 180 ** 181 ** Side Effects: 182 ** Closes files associated with the envelope. 183 ** Marks the envelope as unallocated. 184 */ 185 186 clearenvelope(e, fullclear) 187 register ENVELOPE *e; 188 bool fullclear; 189 { 190 register HDR *bh; 191 register HDR **nhp; 192 extern ENVELOPE BlankEnvelope; 193 194 if (!fullclear) 195 { 196 /* clear out any file information */ 197 if (e->e_xfp != NULL) 198 (void) fclose(e->e_xfp); 199 if (e->e_dfp != NULL) 200 (void) fclose(e->e_dfp); 201 } 202 203 /* now clear out the data */ 204 STRUCTCOPY(BlankEnvelope, *e); 205 bh = BlankEnvelope.e_header; 206 nhp = &e->e_header; 207 while (bh != NULL) 208 { 209 *nhp = (HDR *) xalloc(sizeof *bh); 210 bcopy((char *) bh, (char *) *nhp, sizeof *bh); 211 bh = bh->h_link; 212 nhp = &(*nhp)->h_link; 213 } 214 } 215 /* 216 ** INITSYS -- initialize instantiation of system 217 ** 218 ** In Daemon mode, this is done in the child. 219 ** 220 ** Parameters: 221 ** none. 222 ** 223 ** Returns: 224 ** none. 225 ** 226 ** Side Effects: 227 ** Initializes the system macros, some global variables, 228 ** etc. In particular, the current time in various 229 ** forms is set. 230 */ 231 232 initsys() 233 { 234 static char cbuf[5]; /* holds hop count */ 235 static char pbuf[10]; /* holds pid */ 236 #ifdef TTYNAME 237 static char ybuf[10]; /* holds tty id */ 238 register char *p; 239 #endif TTYNAME 240 extern char *ttyname(); 241 extern char *macvalue(); 242 extern char Version[]; 243 244 /* 245 ** Give this envelope a reality. 246 ** I.e., an id, a transcript, and a creation time. 247 */ 248 249 openxscript(CurEnv); 250 CurEnv->e_ctime = curtime(); 251 252 /* 253 ** Set OutChannel to something useful if stdout isn't it. 254 ** This arranges that any extra stuff the mailer produces 255 ** gets sent back to the user on error (because it is 256 ** tucked away in the transcript). 257 */ 258 259 if (OpMode == MD_DAEMON && QueueRun) 260 OutChannel = CurEnv->e_xfp; 261 262 /* 263 ** Set up some basic system macros. 264 */ 265 266 /* process id */ 267 (void) sprintf(pbuf, "%d", getpid()); 268 define('p', pbuf, CurEnv); 269 270 /* hop count */ 271 (void) sprintf(cbuf, "%d", CurEnv->e_hopcount); 272 define('c', cbuf, CurEnv); 273 274 /* time as integer, unix time, arpa time */ 275 settime(); 276 277 #ifdef TTYNAME 278 /* tty name */ 279 if (macvalue('y', CurEnv) == NULL) 280 { 281 p = ttyname(2); 282 if (p != NULL) 283 { 284 if (rindex(p, '/') != NULL) 285 p = rindex(p, '/') + 1; 286 (void) strcpy(ybuf, p); 287 define('y', ybuf, CurEnv); 288 } 289 } 290 #endif TTYNAME 291 } 292 /* 293 ** SETTIME -- set the current time. 294 ** 295 ** Parameters: 296 ** none. 297 ** 298 ** Returns: 299 ** none. 300 ** 301 ** Side Effects: 302 ** Sets the various time macros -- $a, $b, $d, $t. 303 */ 304 305 settime() 306 { 307 register char *p; 308 auto time_t now; 309 static char tbuf[20]; /* holds "current" time */ 310 static char dbuf[30]; /* holds ctime(tbuf) */ 311 register struct tm *tm; 312 extern char *arpadate(); 313 extern struct tm *gmtime(); 314 extern char *macvalue(); 315 316 now = curtime(); 317 tm = gmtime(&now); 318 (void) sprintf(tbuf, "%02d%02d%02d%02d%02d", tm->tm_year, tm->tm_mon+1, 319 tm->tm_mday, tm->tm_hour, tm->tm_min); 320 define('t', tbuf, CurEnv); 321 (void) strcpy(dbuf, ctime(&now)); 322 *index(dbuf, '\n') = '\0'; 323 if (macvalue('d', CurEnv) == NULL) 324 define('d', dbuf, CurEnv); 325 p = newstr(arpadate(dbuf)); 326 if (macvalue('a', CurEnv) == NULL) 327 define('a', p, CurEnv); 328 define('b', p, CurEnv); 329 } 330 /* 331 ** OPENXSCRIPT -- Open transcript file 332 ** 333 ** Creates a transcript file for possible eventual mailing or 334 ** sending back. 335 ** 336 ** Parameters: 337 ** e -- the envelope to create the transcript in/for. 338 ** 339 ** Returns: 340 ** none 341 ** 342 ** Side Effects: 343 ** Creates the transcript file. 344 */ 345 346 openxscript(e) 347 register ENVELOPE *e; 348 { 349 register char *p; 350 351 # ifdef LOG 352 if (LogLevel > 19) 353 syslog(LOG_DEBUG, "%s: openx%s", e->e_id, e->e_xfp == NULL ? "" : " (no)"); 354 # endif LOG 355 if (e->e_xfp != NULL) 356 return; 357 p = queuename(e, 'x'); 358 e->e_xfp = fopen(p, "w"); 359 if (e->e_xfp == NULL) 360 syserr("Can't create %s", p); 361 else 362 (void) chmod(p, 0644); 363 } 364 /* 365 ** CLOSEXSCRIPT -- close the transcript file. 366 ** 367 ** Parameters: 368 ** e -- the envelope containing the transcript to close. 369 ** 370 ** Returns: 371 ** none. 372 ** 373 ** Side Effects: 374 ** none. 375 */ 376 377 closexscript(e) 378 register ENVELOPE *e; 379 { 380 if (e->e_xfp == NULL) 381 return; 382 (void) fclose(e->e_xfp); 383 e->e_xfp = NULL; 384 } 385 /* 386 ** SETSENDER -- set the person who this message is from 387 ** 388 ** Under certain circumstances allow the user to say who 389 ** s/he is (using -f or -r). These are: 390 ** 1. The user's uid is zero (root). 391 ** 2. The user's login name is in an approved list (typically 392 ** from a network server). 393 ** 3. The address the user is trying to claim has a 394 ** "!" character in it (since #2 doesn't do it for 395 ** us if we are dialing out for UUCP). 396 ** A better check to replace #3 would be if the 397 ** effective uid is "UUCP" -- this would require me 398 ** to rewrite getpwent to "grab" uucp as it went by, 399 ** make getname more nasty, do another passwd file 400 ** scan, or compile the UID of "UUCP" into the code, 401 ** all of which are reprehensible. 402 ** 403 ** Assuming all of these fail, we figure out something 404 ** ourselves. 405 ** 406 ** Parameters: 407 ** from -- the person we would like to believe this message 408 ** is from, as specified on the command line. 409 ** 410 ** Returns: 411 ** none. 412 ** 413 ** Side Effects: 414 ** sets sendmail's notion of who the from person is. 415 */ 416 417 setsender(from) 418 char *from; 419 { 420 register char **pvp; 421 char *realname = NULL; 422 register struct passwd *pw; 423 char buf[MAXNAME]; 424 char pvpbuf[PSBUFSIZE]; 425 extern struct passwd *getpwnam(); 426 extern char *macvalue(); 427 extern char **prescan(); 428 extern bool safefile(); 429 extern char *FullName; 430 431 if (tTd(45, 1)) 432 printf("setsender(%s)\n", from == NULL ? "" : from); 433 434 /* 435 ** Figure out the real user executing us. 436 ** Username can return errno != 0 on non-errors. 437 */ 438 439 if (QueueRun || OpMode == MD_SMTP || OpMode == MD_ARPAFTP) 440 realname = from; 441 if (realname == NULL || realname[0] == '\0') 442 { 443 extern char *username(); 444 445 realname = username(); 446 } 447 448 /* 449 ** Determine if this real person is allowed to alias themselves. 450 */ 451 452 if (from != NULL) 453 { 454 extern bool trusteduser(); 455 456 if (!trusteduser(realname) && getuid() != geteuid() && 457 index(from, '!') == NULL && getuid() != 0) 458 { 459 /* network sends -r regardless (why why why?) */ 460 /* syserr("%s, you cannot use the -f flag", realname); */ 461 from = NULL; 462 } 463 } 464 465 SuprErrs = TRUE; 466 if (from == NULL || parseaddr(from, &CurEnv->e_from, 1, '\0') == NULL) 467 { 468 /* log garbage addresses for traceback */ 469 if (from != NULL) 470 { 471 # ifdef LOG 472 if (LogLevel >= 1) 473 if (realname == from && RealHostName != NULL) 474 syslog(LOG_NOTICE, 475 "from=%s unparseable, received from %s", 476 from, RealHostName); 477 else 478 syslog(LOG_NOTICE, 479 "Unparseable username %s wants from=%s", 480 realname, from); 481 # endif LOG 482 } 483 from = newstr(realname); 484 if (parseaddr(from, &CurEnv->e_from, 1, '\0') == NULL && 485 parseaddr("postmaster", &CurEnv->e_from, 1, '\0') == NULL) 486 { 487 syserr("setsender: can't even parse postmaster!"); 488 } 489 } 490 else 491 FromFlag = TRUE; 492 CurEnv->e_from.q_flags |= QDONTSEND; 493 loweraddr(&CurEnv->e_from); 494 SuprErrs = FALSE; 495 496 if (CurEnv->e_from.q_mailer == LocalMailer && 497 (pw = getpwnam(CurEnv->e_from.q_user)) != NULL) 498 { 499 /* 500 ** Process passwd file entry. 501 */ 502 503 504 /* extract home directory */ 505 CurEnv->e_from.q_home = newstr(pw->pw_dir); 506 define('z', CurEnv->e_from.q_home, CurEnv); 507 508 /* extract user and group id */ 509 CurEnv->e_from.q_uid = pw->pw_uid; 510 CurEnv->e_from.q_gid = pw->pw_gid; 511 512 /* if the user has given fullname already, don't redefine */ 513 if (FullName == NULL) 514 FullName = macvalue('x', CurEnv); 515 if (FullName != NULL && FullName[0] == '\0') 516 FullName = NULL; 517 518 /* extract full name from passwd file */ 519 if (FullName == NULL && pw->pw_gecos != NULL && 520 strcmp(pw->pw_name, CurEnv->e_from.q_user) == 0) 521 { 522 buildfname(pw->pw_gecos, CurEnv->e_from.q_user, buf); 523 if (buf[0] != '\0') 524 FullName = newstr(buf); 525 } 526 if (FullName != NULL) 527 define('x', FullName, CurEnv); 528 } 529 else 530 { 531 if (CurEnv->e_from.q_home == NULL) 532 CurEnv->e_from.q_home = getenv("HOME"); 533 CurEnv->e_from.q_uid = getuid(); 534 CurEnv->e_from.q_gid = getgid(); 535 } 536 537 if (CurEnv->e_from.q_uid != 0) 538 { 539 DefUid = CurEnv->e_from.q_uid; 540 DefGid = CurEnv->e_from.q_gid; 541 } 542 543 /* 544 ** Rewrite the from person to dispose of possible implicit 545 ** links in the net. 546 */ 547 548 pvp = prescan(from, '\0', pvpbuf); 549 if (pvp == NULL) 550 { 551 # ifdef LOG 552 if (LogLevel >= 1) 553 syslog(LOG_NOTICE, "cannot prescan from (%s)", from); 554 # endif 555 usrerr("cannot prescan from (%s)", from); 556 finis(); 557 } 558 rewrite(pvp, 3); 559 rewrite(pvp, 1); 560 rewrite(pvp, 4); 561 cataddr(pvp, buf, sizeof buf); 562 define('f', newstr(buf), CurEnv); 563 564 /* save the domain spec if this mailer wants it */ 565 if (CurEnv->e_from.q_mailer != NULL && 566 bitnset(M_CANONICAL, CurEnv->e_from.q_mailer->m_flags)) 567 { 568 extern char **copyplist(); 569 570 while (*pvp != NULL && strcmp(*pvp, "@") != 0) 571 pvp++; 572 if (*pvp != NULL) 573 CurEnv->e_fromdomain = copyplist(pvp, TRUE); 574 } 575 } 576 /* 577 ** TRUSTEDUSER -- tell us if this user is to be trusted. 578 ** 579 ** Parameters: 580 ** user -- the user to be checked. 581 ** 582 ** Returns: 583 ** TRUE if the user is in an approved list. 584 ** FALSE otherwise. 585 ** 586 ** Side Effects: 587 ** none. 588 */ 589 590 bool 591 trusteduser(user) 592 char *user; 593 { 594 register char **ulist; 595 extern char *TrustedUsers[]; 596 597 for (ulist = TrustedUsers; *ulist != NULL; ulist++) 598 if (strcmp(*ulist, user) == 0) 599 return (TRUE); 600 return (FALSE); 601 } 602