1 /* 2 * Copyright (c) 1983, 1995 Eric P. Allman 3 * Copyright (c) 1988, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 # include "sendmail.h" 10 11 #ifndef lint 12 #ifdef QUEUE 13 static char sccsid[] = "@(#)queue.c 8.88 (Berkeley) 06/16/95 (with queueing)"; 14 #else 15 static char sccsid[] = "@(#)queue.c 8.88 (Berkeley) 06/16/95 (without queueing)"; 16 #endif 17 #endif /* not lint */ 18 19 # include <errno.h> 20 # include <dirent.h> 21 22 # ifdef QUEUE 23 24 /* 25 ** Work queue. 26 */ 27 28 struct work 29 { 30 char *w_name; /* name of control file */ 31 char *w_host; /* name of recipient host */ 32 bool w_lock; /* is message locked? */ 33 long w_pri; /* priority of message, see below */ 34 time_t w_ctime; /* creation time of message */ 35 struct work *w_next; /* next in queue */ 36 }; 37 38 typedef struct work WORK; 39 40 WORK *WorkQ; /* queue of things to be done */ 41 42 #define QF_VERSION 1 /* version number of this queue format */ 43 /* 44 ** QUEUEUP -- queue a message up for future transmission. 45 ** 46 ** Parameters: 47 ** e -- the envelope to queue up. 48 ** queueall -- if TRUE, queue all addresses, rather than 49 ** just those with the QQUEUEUP flag set. 50 ** announce -- if TRUE, tell when you are queueing up. 51 ** 52 ** Returns: 53 ** none. 54 ** 55 ** Side Effects: 56 ** The current request are saved in a control file. 57 ** The queue file is left locked. 58 */ 59 60 void 61 queueup(e, queueall, announce) 62 register ENVELOPE *e; 63 bool queueall; 64 bool announce; 65 { 66 char *qf; 67 register FILE *tfp; 68 register HDR *h; 69 register ADDRESS *q; 70 int fd; 71 int i; 72 bool newid; 73 register char *p; 74 MAILER nullmailer; 75 MCI mcibuf; 76 char buf[MAXLINE], tf[MAXLINE]; 77 extern void printctladdr __P((ADDRESS *, FILE *)); 78 79 /* 80 ** Create control file. 81 */ 82 83 newid = (e->e_id == NULL) || !bitset(EF_INQUEUE, e->e_flags); 84 85 /* if newid, queuename will create a locked qf file in e->lockfp */ 86 strcpy(tf, queuename(e, 't')); 87 tfp = e->e_lockfp; 88 if (tfp == NULL) 89 newid = FALSE; 90 91 /* if newid, just write the qf file directly (instead of tf file) */ 92 if (!newid) 93 { 94 /* get a locked tf file */ 95 for (i = 0; i < 128; i++) 96 { 97 fd = open(tf, O_CREAT|O_WRONLY|O_EXCL, FileMode); 98 if (fd < 0) 99 { 100 if (errno != EEXIST) 101 break; 102 #ifdef LOG 103 if (LogLevel > 0 && (i % 32) == 0) 104 syslog(LOG_ALERT, "queueup: cannot create %s, uid=%d: %s", 105 tf, geteuid(), errstring(errno)); 106 #endif 107 } 108 else 109 { 110 if (lockfile(fd, tf, NULL, LOCK_EX|LOCK_NB)) 111 break; 112 #ifdef LOG 113 else if (LogLevel > 0 && (i % 32) == 0) 114 syslog(LOG_ALERT, "queueup: cannot lock %s: %s", 115 tf, errstring(errno)); 116 #endif 117 close(fd); 118 } 119 120 if ((i % 32) == 31) 121 { 122 /* save the old temp file away */ 123 (void) rename(tf, queuename(e, 'T')); 124 } 125 else 126 sleep(i % 32); 127 } 128 if (fd < 0 || (tfp = fdopen(fd, "w")) == NULL) 129 { 130 printopenfds(TRUE); 131 syserr("!queueup: cannot create queue temp file %s, uid=%d", 132 tf, geteuid()); 133 } 134 } 135 136 if (tTd(40, 1)) 137 printf("\n>>>>> queueing %s%s queueall=%d >>>>>\n", e->e_id, 138 newid ? " (new id)" : "", queueall); 139 if (tTd(40, 3)) 140 { 141 extern void printenvflags(); 142 143 printf(" e_flags="); 144 printenvflags(e); 145 } 146 if (tTd(40, 32)) 147 { 148 printf(" sendq="); 149 printaddr(e->e_sendqueue, TRUE); 150 } 151 if (tTd(40, 9)) 152 { 153 printf(" tfp="); 154 dumpfd(fileno(tfp), TRUE, FALSE); 155 printf(" lockfp="); 156 if (e->e_lockfp == NULL) 157 printf("NULL\n"); 158 else 159 dumpfd(fileno(e->e_lockfp), TRUE, FALSE); 160 } 161 162 /* 163 ** If there is no data file yet, create one. 164 */ 165 166 if (!bitset(EF_HAS_DF, e->e_flags)) 167 { 168 register FILE *dfp; 169 char dfname[20]; 170 struct stat stbuf; 171 172 strcpy(dfname, queuename(e, 'd')); 173 fd = open(dfname, O_WRONLY|O_CREAT|O_TRUNC, FileMode); 174 if (fd < 0 || (dfp = fdopen(fd, "w")) == NULL) 175 syserr("!queueup: cannot create data temp file %s, uid=%d", 176 dfname, geteuid()); 177 if (fstat(fd, &stbuf) < 0) 178 e->e_dfino = -1; 179 else 180 { 181 e->e_dfdev = stbuf.st_dev; 182 e->e_dfino = stbuf.st_ino; 183 } 184 e->e_flags |= EF_HAS_DF; 185 bzero(&mcibuf, sizeof mcibuf); 186 mcibuf.mci_out = dfp; 187 mcibuf.mci_mailer = FileMailer; 188 (*e->e_putbody)(&mcibuf, e, NULL); 189 (void) xfclose(dfp, "queueup dfp", e->e_id); 190 e->e_putbody = putbody; 191 } 192 193 /* 194 ** Output future work requests. 195 ** Priority and creation time should be first, since 196 ** they are required by orderq. 197 */ 198 199 /* output queue version number (must be first!) */ 200 fprintf(tfp, "V%d\n", QF_VERSION); 201 202 /* output message priority */ 203 fprintf(tfp, "P%ld\n", e->e_msgpriority); 204 205 /* output creation time */ 206 fprintf(tfp, "T%ld\n", e->e_ctime); 207 208 /* output last delivery time */ 209 fprintf(tfp, "K%ld\n", e->e_dtime); 210 211 /* output number of delivery attempts */ 212 fprintf(tfp, "N%d\n", e->e_ntries); 213 214 /* output inode number of data file */ 215 /* XXX should probably include device major/minor too */ 216 if (e->e_dfino != -1) 217 fprintf(tfp, "I%d/%d/%ld\n", 218 major(e->e_dfdev), minor(e->e_dfdev), e->e_dfino); 219 220 /* output body type */ 221 if (e->e_bodytype != NULL) 222 fprintf(tfp, "B%s\n", e->e_bodytype); 223 224 /* message from envelope, if it exists */ 225 if (e->e_message != NULL) 226 fprintf(tfp, "M%s\n", denlstring(e->e_message, TRUE, FALSE)); 227 228 /* send various flag bits through */ 229 p = buf; 230 if (bitset(EF_WARNING, e->e_flags)) 231 *p++ = 'w'; 232 if (bitset(EF_RESPONSE, e->e_flags)) 233 *p++ = 'r'; 234 if (bitset(EF_HAS8BIT, e->e_flags)) 235 *p++ = '8'; 236 *p++ = '\0'; 237 if (buf[0] != '\0') 238 fprintf(tfp, "F%s\n", buf); 239 240 /* $r and $s and $_ macro values */ 241 if ((p = macvalue('r', e)) != NULL) 242 fprintf(tfp, "$r%s\n", denlstring(p, TRUE, FALSE)); 243 if ((p = macvalue('s', e)) != NULL) 244 fprintf(tfp, "$s%s\n", denlstring(p, TRUE, FALSE)); 245 if ((p = macvalue('_', e)) != NULL) 246 fprintf(tfp, "$_%s\n", denlstring(p, TRUE, FALSE)); 247 248 /* output name of sender */ 249 if (bitnset(M_UDBENVELOPE, e->e_from.q_mailer->m_flags)) 250 p = e->e_sender; 251 else 252 p = e->e_from.q_paddr; 253 fprintf(tfp, "S%s\n", denlstring(p, TRUE, FALSE)); 254 255 /* output ESMTP-supplied "original" information */ 256 if (e->e_envid != NULL) 257 fprintf(tfp, "Z%s\n", denlstring(e->e_envid, TRUE, FALSE)); 258 259 /* output list of recipient addresses */ 260 printctladdr(NULL, NULL); 261 for (q = e->e_sendqueue; q != NULL; q = q->q_next) 262 { 263 if (bitset(QQUEUEUP, q->q_flags) || 264 (queueall && !bitset(QDONTSEND|QBADADDR|QSENT, q->q_flags))) 265 { 266 printctladdr(q, tfp); 267 if (q->q_orcpt != NULL) 268 fprintf(tfp, "Q%s\n", 269 denlstring(q->q_orcpt, TRUE, FALSE)); 270 putc('R', tfp); 271 if (bitset(QPRIMARY, q->q_flags)) 272 putc('P', tfp); 273 if (bitset(QPINGONSUCCESS, q->q_flags)) 274 putc('S', tfp); 275 if (bitset(QPINGONFAILURE, q->q_flags)) 276 putc('F', tfp); 277 if (bitset(QPINGONDELAY, q->q_flags)) 278 putc('D', tfp); 279 putc(':', tfp); 280 fprintf(tfp, "%s\n", denlstring(q->q_paddr, TRUE, FALSE)); 281 if (announce) 282 { 283 e->e_to = q->q_paddr; 284 message("queued"); 285 if (LogLevel > 8) 286 logdelivery(NULL, NULL, "queued", 287 NULL, (time_t) 0, e); 288 e->e_to = NULL; 289 } 290 if (tTd(40, 1)) 291 { 292 printf("queueing "); 293 printaddr(q, FALSE); 294 } 295 } 296 } 297 298 /* 299 ** Output headers for this message. 300 ** Expand macros completely here. Queue run will deal with 301 ** everything as absolute headers. 302 ** All headers that must be relative to the recipient 303 ** can be cracked later. 304 ** We set up a "null mailer" -- i.e., a mailer that will have 305 ** no effect on the addresses as they are output. 306 */ 307 308 bzero((char *) &nullmailer, sizeof nullmailer); 309 nullmailer.m_re_rwset = nullmailer.m_rh_rwset = 310 nullmailer.m_se_rwset = nullmailer.m_sh_rwset = -1; 311 nullmailer.m_eol = "\n"; 312 bzero(&mcibuf, sizeof mcibuf); 313 mcibuf.mci_mailer = &nullmailer; 314 mcibuf.mci_out = tfp; 315 316 define('g', "\201f", e); 317 for (h = e->e_header; h != NULL; h = h->h_link) 318 { 319 extern bool bitzerop(); 320 321 /* don't output null headers */ 322 if (h->h_value == NULL || h->h_value[0] == '\0') 323 continue; 324 325 /* don't output resent headers on non-resent messages */ 326 if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags)) 327 continue; 328 329 /* expand macros; if null, don't output header at all */ 330 if (bitset(H_DEFAULT, h->h_flags)) 331 { 332 (void) expand(h->h_value, buf, sizeof buf, e); 333 if (buf[0] == '\0') 334 continue; 335 } 336 337 /* output this header */ 338 fprintf(tfp, "H"); 339 340 /* if conditional, output the set of conditions */ 341 if (!bitzerop(h->h_mflags) && bitset(H_CHECK|H_ACHECK, h->h_flags)) 342 { 343 int j; 344 345 (void) putc('?', tfp); 346 for (j = '\0'; j <= '\177'; j++) 347 if (bitnset(j, h->h_mflags)) 348 (void) putc(j, tfp); 349 (void) putc('?', tfp); 350 } 351 352 /* output the header: expand macros, convert addresses */ 353 if (bitset(H_DEFAULT, h->h_flags)) 354 { 355 fprintf(tfp, "%s: %s\n", h->h_field, buf); 356 } 357 else if (bitset(H_FROM|H_RCPT, h->h_flags)) 358 { 359 bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags); 360 FILE *savetrace = TrafficLogFile; 361 362 TrafficLogFile = NULL; 363 364 if (bitset(H_FROM, h->h_flags)) 365 oldstyle = FALSE; 366 367 commaize(h, h->h_value, oldstyle, &mcibuf, e); 368 369 TrafficLogFile = savetrace; 370 } 371 else 372 fprintf(tfp, "%s: %s\n", h->h_field, h->h_value); 373 } 374 375 /* 376 ** Clean up. 377 ** 378 ** Write a terminator record -- this is to prevent 379 ** scurrilous crackers from appending any data. 380 */ 381 382 fprintf(tfp, ".\n"); 383 384 if (fflush(tfp) < 0 || fsync(fileno(tfp)) < 0 || ferror(tfp)) 385 { 386 if (newid) 387 syserr("!552 Error writing control file %s", tf); 388 else 389 syserr("!452 Error writing control file %s", tf); 390 } 391 392 if (!newid) 393 { 394 /* rename (locked) tf to be (locked) qf */ 395 qf = queuename(e, 'q'); 396 if (rename(tf, qf) < 0) 397 syserr("cannot rename(%s, %s), uid=%d", 398 tf, qf, geteuid()); 399 400 /* close and unlock old (locked) qf */ 401 if (e->e_lockfp != NULL) 402 (void) xfclose(e->e_lockfp, "queueup lockfp", e->e_id); 403 e->e_lockfp = tfp; 404 } 405 else 406 qf = tf; 407 errno = 0; 408 e->e_flags |= EF_INQUEUE; 409 410 # ifdef LOG 411 /* save log info */ 412 if (LogLevel > 79) 413 syslog(LOG_DEBUG, "%s: queueup, qf=%s", e->e_id, qf); 414 # endif /* LOG */ 415 416 if (tTd(40, 1)) 417 printf("<<<<< done queueing %s <<<<<\n\n", e->e_id); 418 return; 419 } 420 421 void 422 printctladdr(a, tfp) 423 register ADDRESS *a; 424 FILE *tfp; 425 { 426 char *uname; 427 register struct passwd *pw; 428 register ADDRESS *q; 429 uid_t uid; 430 static ADDRESS *lastctladdr; 431 static uid_t lastuid; 432 433 /* initialization */ 434 if (a == NULL || a->q_alias == NULL || tfp == NULL) 435 { 436 if (lastctladdr != NULL && tfp != NULL) 437 fprintf(tfp, "C\n"); 438 lastctladdr = NULL; 439 lastuid = 0; 440 return; 441 } 442 443 /* find the active uid */ 444 q = getctladdr(a); 445 if (q == NULL) 446 uid = 0; 447 else 448 uid = q->q_uid; 449 a = a->q_alias; 450 451 /* check to see if this is the same as last time */ 452 if (lastctladdr != NULL && uid == lastuid && 453 strcmp(lastctladdr->q_paddr, a->q_paddr) == 0) 454 return; 455 lastuid = uid; 456 lastctladdr = a; 457 458 if (uid == 0 || (pw = sm_getpwuid(uid)) == NULL) 459 uname = ""; 460 else 461 uname = pw->pw_name; 462 463 fprintf(tfp, "C%s:%s\n", uname, denlstring(a->q_paddr, TRUE, FALSE)); 464 } 465 /* 466 ** RUNQUEUE -- run the jobs in the queue. 467 ** 468 ** Gets the stuff out of the queue in some presumably logical 469 ** order and processes them. 470 ** 471 ** Parameters: 472 ** forkflag -- TRUE if the queue scanning should be done in 473 ** a child process. We double-fork so it is not our 474 ** child and we don't have to clean up after it. 475 ** 476 ** Returns: 477 ** none. 478 ** 479 ** Side Effects: 480 ** runs things in the mail queue. 481 */ 482 483 ENVELOPE QueueEnvelope; /* the queue run envelope */ 484 485 void 486 runqueue(forkflag) 487 bool forkflag; 488 { 489 register ENVELOPE *e; 490 int njobs; 491 int sequenceno = 0; 492 extern ENVELOPE BlankEnvelope; 493 494 /* 495 ** If no work will ever be selected, don't even bother reading 496 ** the queue. 497 */ 498 499 CurrentLA = getla(); /* get load average */ 500 501 if (shouldqueue(0L, curtime())) 502 { 503 char *msg = "Skipping queue run -- load average too high"; 504 505 if (Verbose) 506 printf("%s\n", msg); 507 #ifdef LOG 508 if (LogLevel > 8) 509 syslog(LOG_INFO, "runqueue: %s", msg); 510 #endif 511 if (forkflag && QueueIntvl != 0) 512 (void) setevent(QueueIntvl, runqueue, TRUE); 513 return; 514 } 515 516 /* 517 ** See if we want to go off and do other useful work. 518 */ 519 520 if (forkflag) 521 { 522 int pid; 523 #ifdef SIGCHLD 524 extern void reapchild(); 525 526 (void) setsignal(SIGCHLD, reapchild); 527 #endif 528 529 pid = dofork(); 530 if (pid != 0) 531 { 532 /* parent -- pick up intermediate zombie */ 533 #ifndef SIGCHLD 534 (void) waitfor(pid); 535 #else 536 CurChildren++; 537 #endif /* SIGCHLD */ 538 if (QueueIntvl != 0) 539 (void) setevent(QueueIntvl, runqueue, TRUE); 540 return; 541 } 542 /* child -- double fork */ 543 #ifndef SIGCHLD 544 if (fork() != 0) 545 exit(EX_OK); 546 #else /* SIGCHLD */ 547 (void) setsignal(SIGCHLD, SIG_DFL); 548 #endif /* SIGCHLD */ 549 } 550 551 setproctitle("running queue: %s", QueueDir); 552 553 # ifdef LOG 554 if (LogLevel > 69) 555 syslog(LOG_DEBUG, "runqueue %s, pid=%d, forkflag=%d", 556 QueueDir, getpid(), forkflag); 557 # endif /* LOG */ 558 559 /* 560 ** Release any resources used by the daemon code. 561 */ 562 563 # ifdef DAEMON 564 clrdaemon(); 565 # endif /* DAEMON */ 566 567 /* force it to run expensive jobs */ 568 NoConnect = FALSE; 569 570 /* 571 ** Create ourselves an envelope 572 */ 573 574 CurEnv = &QueueEnvelope; 575 e = newenvelope(&QueueEnvelope, CurEnv); 576 e->e_flags = BlankEnvelope.e_flags; 577 578 /* 579 ** Make sure the alias database is open. 580 */ 581 582 initmaps(FALSE, e); 583 584 /* 585 ** Start making passes through the queue. 586 ** First, read and sort the entire queue. 587 ** Then, process the work in that order. 588 ** But if you take too long, start over. 589 */ 590 591 /* order the existing work requests */ 592 njobs = orderq(FALSE); 593 594 /* process them once at a time */ 595 while (WorkQ != NULL) 596 { 597 WORK *w = WorkQ; 598 599 WorkQ = WorkQ->w_next; 600 601 /* 602 ** Ignore jobs that are too expensive for the moment. 603 */ 604 605 sequenceno++; 606 if (shouldqueue(w->w_pri, w->w_ctime)) 607 { 608 if (Verbose) 609 printf("\nSkipping %s (sequence %d of %d)\n", 610 w->w_name + 2, sequenceno, njobs); 611 } 612 else 613 { 614 pid_t pid; 615 extern pid_t dowork(); 616 617 if (Verbose) 618 printf("\nRunning %s (sequence %d of %d)\n", 619 w->w_name + 2, sequenceno, njobs); 620 pid = dowork(w->w_name + 2, ForkQueueRuns, FALSE, e); 621 errno = 0; 622 if (pid != 0) 623 (void) waitfor(pid); 624 } 625 free(w->w_name); 626 if (w->w_host) 627 free(w->w_host); 628 free((char *) w); 629 } 630 631 /* exit without the usual cleanup */ 632 e->e_id = NULL; 633 finis(); 634 } 635 /* 636 ** ORDERQ -- order the work queue. 637 ** 638 ** Parameters: 639 ** doall -- if set, include everything in the queue (even 640 ** the jobs that cannot be run because the load 641 ** average is too high). Otherwise, exclude those 642 ** jobs. 643 ** 644 ** Returns: 645 ** The number of request in the queue (not necessarily 646 ** the number of requests in WorkQ however). 647 ** 648 ** Side Effects: 649 ** Sets WorkQ to the queue of available work, in order. 650 */ 651 652 # define NEED_P 001 653 # define NEED_T 002 654 # define NEED_R 004 655 # define NEED_S 010 656 657 static WORK *WorkList = NULL; 658 static int WorkListSize = 0; 659 660 int 661 orderq(doall) 662 bool doall; 663 { 664 register struct dirent *d; 665 register WORK *w; 666 DIR *f; 667 register int i; 668 int wn = -1; 669 int wc; 670 671 if (tTd(41, 1)) 672 { 673 printf("orderq:\n"); 674 if (QueueLimitId != NULL) 675 printf("\tQueueLimitId = %s\n", QueueLimitId); 676 if (QueueLimitSender != NULL) 677 printf("\tQueueLimitSender = %s\n", QueueLimitSender); 678 if (QueueLimitRecipient != NULL) 679 printf("\tQueueLimitRecipient = %s\n", QueueLimitRecipient); 680 } 681 682 /* clear out old WorkQ */ 683 for (w = WorkQ; w != NULL; ) 684 { 685 register WORK *nw = w->w_next; 686 687 WorkQ = nw; 688 free(w->w_name); 689 if (w->w_host) 690 free(w->w_host); 691 free((char *) w); 692 w = nw; 693 } 694 695 /* open the queue directory */ 696 f = opendir("."); 697 if (f == NULL) 698 { 699 syserr("orderq: cannot open \"%s\" as \".\"", QueueDir); 700 return (0); 701 } 702 703 /* 704 ** Read the work directory. 705 */ 706 707 while ((d = readdir(f)) != NULL) 708 { 709 FILE *cf; 710 register char *p; 711 char lbuf[MAXNAME + 1]; 712 extern bool strcontainedin(); 713 714 /* is this an interesting entry? */ 715 if (d->d_name[0] != 'q' || d->d_name[1] != 'f') 716 continue; 717 718 if (QueueLimitId != NULL && 719 !strcontainedin(QueueLimitId, d->d_name)) 720 continue; 721 722 #ifdef PICKY_QF_NAME_CHECK 723 /* 724 ** Check queue name for plausibility. This handles 725 ** both old and new type ids. 726 */ 727 728 p = d->d_name + 2; 729 if (isupper(p[0]) && isupper(p[2])) 730 p += 3; 731 else if (isupper(p[1])) 732 p += 2; 733 else 734 p = d->d_name; 735 for (i = 0; isdigit(*p); p++) 736 i++; 737 if (i < 5 || *p != '\0') 738 { 739 if (Verbose) 740 printf("orderq: bogus qf name %s\n", d->d_name); 741 # ifdef LOG 742 if (LogLevel > 0) 743 syslog(LOG_ALERT, "orderq: bogus qf name %s", 744 d->d_name); 745 # endif 746 if (strlen(d->d_name) > (SIZE_T) MAXNAME) 747 d->d_name[MAXNAME] = '\0'; 748 strcpy(lbuf, d->d_name); 749 lbuf[0] = 'Q'; 750 (void) rename(d->d_name, lbuf); 751 continue; 752 } 753 #endif 754 755 /* open control file (if not too many files) */ 756 if (++wn > MaxQueueRun && MaxQueueRun > 0) 757 { 758 # ifdef LOG 759 if (wn == MaxQueueRun + 1 && LogLevel > 0) 760 syslog(LOG_ALERT, "WorkList for %s maxed out at %d", 761 QueueDir, MaxQueueRun); 762 # endif 763 continue; 764 } 765 if (wn >= WorkListSize) 766 { 767 extern void grow_wlist __P((void)); 768 769 grow_wlist(); 770 if (wn >= WorkListSize) 771 continue; 772 } 773 774 cf = fopen(d->d_name, "r"); 775 if (cf == NULL) 776 { 777 /* this may be some random person sending hir msgs */ 778 /* syserr("orderq: cannot open %s", cbuf); */ 779 if (tTd(41, 2)) 780 printf("orderq: cannot open %s (%d)\n", 781 d->d_name, errno); 782 errno = 0; 783 wn--; 784 continue; 785 } 786 w = &WorkList[wn]; 787 w->w_name = newstr(d->d_name); 788 w->w_host = NULL; 789 w->w_lock = !lockfile(fileno(cf), w->w_name, NULL, LOCK_SH|LOCK_NB); 790 791 /* make sure jobs in creation don't clog queue */ 792 w->w_pri = 0x7fffffff; 793 w->w_ctime = 0; 794 795 /* extract useful information */ 796 i = NEED_P | NEED_T; 797 if (QueueLimitSender != NULL) 798 i |= NEED_S; 799 if (QueueSortOrder == QS_BYHOST || QueueLimitRecipient != NULL) 800 i |= NEED_R; 801 while (i != 0 && fgets(lbuf, sizeof lbuf, cf) != NULL) 802 { 803 extern bool strcontainedin(); 804 805 switch (lbuf[0]) 806 { 807 case 'P': 808 w->w_pri = atol(&lbuf[1]); 809 i &= ~NEED_P; 810 break; 811 812 case 'T': 813 w->w_ctime = atol(&lbuf[1]); 814 i &= ~NEED_T; 815 break; 816 817 case 'R': 818 if (w->w_host == NULL && 819 (p = strrchr(&lbuf[1], '@')) != NULL) 820 w->w_host = newstr(&p[1]); 821 if (QueueLimitRecipient == NULL || 822 strcontainedin(QueueLimitRecipient, &lbuf[1])) 823 i &= ~NEED_R; 824 break; 825 826 case 'S': 827 if (QueueLimitSender != NULL && 828 strcontainedin(QueueLimitSender, &lbuf[1])) 829 i &= ~NEED_S; 830 break; 831 } 832 } 833 (void) fclose(cf); 834 835 if ((!doall && shouldqueue(w->w_pri, w->w_ctime)) || 836 bitset(NEED_R|NEED_S, i)) 837 { 838 /* don't even bother sorting this job in */ 839 free(w->w_name); 840 if (w->w_host) 841 free(w->w_host); 842 wn--; 843 } 844 } 845 (void) closedir(f); 846 wn++; 847 848 wc = min(wn, WorkListSize); 849 850 if (QueueSortOrder == QS_BYHOST) 851 { 852 extern workcmpf1(); 853 extern workcmpf2(); 854 855 /* 856 ** Sort the work directory for the first time, 857 ** based on host name, lock status, and priority. 858 */ 859 860 qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf1); 861 862 /* 863 ** If one message to host is locked, "lock" all messages 864 ** to that host. 865 */ 866 867 i = 0; 868 while (i < wc) 869 { 870 if (!WorkList[i].w_lock) 871 { 872 i++; 873 continue; 874 } 875 w = &WorkList[i]; 876 while (++i < wc) 877 { 878 if (WorkList[i].w_host == NULL && 879 w->w_host == NULL) 880 WorkList[i].w_lock = TRUE; 881 else if (WorkList[i].w_host != NULL && 882 w->w_host != NULL && 883 strcmp(WorkList[i].w_host, w->w_host) == 0) 884 WorkList[i].w_lock = TRUE; 885 else 886 break; 887 } 888 } 889 890 /* 891 ** Sort the work directory for the second time, 892 ** based on lock status, host name, and priority. 893 */ 894 895 qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf2); 896 } 897 else 898 { 899 extern workcmpf0(); 900 901 /* 902 ** Simple sort based on queue priority only. 903 */ 904 905 qsort((char *) WorkList, wc, sizeof *WorkList, workcmpf0); 906 } 907 908 /* 909 ** Convert the work list into canonical form. 910 ** Should be turning it into a list of envelopes here perhaps. 911 */ 912 913 WorkQ = NULL; 914 for (i = wc; --i >= 0; ) 915 { 916 w = (WORK *) xalloc(sizeof *w); 917 w->w_name = WorkList[i].w_name; 918 w->w_host = WorkList[i].w_host; 919 w->w_lock = WorkList[i].w_lock; 920 w->w_pri = WorkList[i].w_pri; 921 w->w_ctime = WorkList[i].w_ctime; 922 w->w_next = WorkQ; 923 WorkQ = w; 924 } 925 free(WorkList); 926 WorkList = NULL; 927 928 if (tTd(40, 1)) 929 { 930 for (w = WorkQ; w != NULL; w = w->w_next) 931 printf("%32s: pri=%ld\n", w->w_name, w->w_pri); 932 } 933 934 return (wn); 935 } 936 /* 937 ** GROW_WLIST -- make the work list larger 938 ** 939 ** Parameters: 940 ** none. 941 ** 942 ** Returns: 943 ** none. 944 ** 945 ** Side Effects: 946 ** Adds another QUEUESEGSIZE entries to WorkList if possible. 947 ** It can fail if there isn't enough memory, so WorkListSize 948 ** should be checked again upon return. 949 */ 950 951 void 952 grow_wlist() 953 { 954 if (tTd(41, 1)) 955 printf("grow_wlist: WorkListSize=%d\n", WorkListSize); 956 if (WorkList == NULL) 957 { 958 WorkList = (WORK *) xalloc(sizeof(WORK) * (QUEUESEGSIZE + 1)); 959 WorkListSize = QUEUESEGSIZE; 960 } 961 else 962 { 963 int newsize = WorkListSize + QUEUESEGSIZE; 964 WORK *newlist = (WORK *) realloc((char *)WorkList, 965 (unsigned)sizeof(WORK) * (newsize + 1)); 966 967 if (newlist != NULL) 968 { 969 WorkListSize = newsize; 970 WorkList = newlist; 971 # ifdef LOG 972 if (LogLevel > 1) 973 { 974 syslog(LOG_NOTICE, "grew WorkList for %s to %d", 975 QueueDir, WorkListSize); 976 } 977 } 978 else if (LogLevel > 0) 979 { 980 syslog(LOG_ALERT, "FAILED to grow WorkList for %s to %d", 981 QueueDir, newsize); 982 # endif 983 } 984 } 985 if (tTd(41, 1)) 986 printf("grow_wlist: WorkListSize now %d\n", WorkListSize); 987 } 988 /* 989 ** WORKCMPF0 -- simple priority-only compare function. 990 ** 991 ** Parameters: 992 ** a -- the first argument. 993 ** b -- the second argument. 994 ** 995 ** Returns: 996 ** -1 if a < b 997 ** 0 if a == b 998 ** +1 if a > b 999 ** 1000 ** Side Effects: 1001 ** none. 1002 */ 1003 1004 int 1005 workcmpf0(a, b) 1006 register WORK *a; 1007 register WORK *b; 1008 { 1009 long pa = a->w_pri; 1010 long pb = b->w_pri; 1011 1012 if (pa == pb) 1013 return 0; 1014 else if (pa > pb) 1015 return 1; 1016 else 1017 return -1; 1018 } 1019 /* 1020 ** WORKCMPF1 -- first compare function for ordering work based on host name. 1021 ** 1022 ** Sorts on host name, lock status, and priority in that order. 1023 ** 1024 ** Parameters: 1025 ** a -- the first argument. 1026 ** b -- the second argument. 1027 ** 1028 ** Returns: 1029 ** <0 if a < b 1030 ** 0 if a == b 1031 ** >0 if a > b 1032 ** 1033 ** Side Effects: 1034 ** none. 1035 */ 1036 1037 int 1038 workcmpf1(a, b) 1039 register WORK *a; 1040 register WORK *b; 1041 { 1042 int i; 1043 1044 /* host name */ 1045 if (a->w_host != NULL && b->w_host == NULL) 1046 return 1; 1047 else if (a->w_host == NULL && b->w_host != NULL) 1048 return -1; 1049 if (a->w_host != NULL && b->w_host != NULL && 1050 (i = strcmp(a->w_host, b->w_host))) 1051 return i; 1052 1053 /* lock status */ 1054 if (a->w_lock != b->w_lock) 1055 return b->w_lock - a->w_lock; 1056 1057 /* job priority */ 1058 return a->w_pri - b->w_pri; 1059 } 1060 /* 1061 ** WORKCMPF2 -- second compare function for ordering work based on host name. 1062 ** 1063 ** Sorts on lock status, host name, and priority in that order. 1064 ** 1065 ** Parameters: 1066 ** a -- the first argument. 1067 ** b -- the second argument. 1068 ** 1069 ** Returns: 1070 ** <0 if a < b 1071 ** 0 if a == b 1072 ** >0 if a > b 1073 ** 1074 ** Side Effects: 1075 ** none. 1076 */ 1077 1078 int 1079 workcmpf2(a, b) 1080 register WORK *a; 1081 register WORK *b; 1082 { 1083 int i; 1084 1085 /* lock status */ 1086 if (a->w_lock != b->w_lock) 1087 return a->w_lock - b->w_lock; 1088 1089 /* host name */ 1090 if (a->w_host != NULL && b->w_host == NULL) 1091 return 1; 1092 else if (a->w_host == NULL && b->w_host != NULL) 1093 return -1; 1094 if (a->w_host != NULL && b->w_host != NULL && 1095 (i = strcmp(a->w_host, b->w_host))) 1096 return i; 1097 1098 /* job priority */ 1099 return a->w_pri - b->w_pri; 1100 } 1101 /* 1102 ** DOWORK -- do a work request. 1103 ** 1104 ** Parameters: 1105 ** id -- the ID of the job to run. 1106 ** forkflag -- if set, run this in background. 1107 ** requeueflag -- if set, reinstantiate the queue quickly. 1108 ** This is used when expanding aliases in the queue. 1109 ** If forkflag is also set, it doesn't wait for the 1110 ** child. 1111 ** e - the envelope in which to run it. 1112 ** 1113 ** Returns: 1114 ** process id of process that is running the queue job. 1115 ** 1116 ** Side Effects: 1117 ** The work request is satisfied if possible. 1118 */ 1119 1120 pid_t 1121 dowork(id, forkflag, requeueflag, e) 1122 char *id; 1123 bool forkflag; 1124 bool requeueflag; 1125 register ENVELOPE *e; 1126 { 1127 register pid_t pid; 1128 extern bool readqf(); 1129 1130 if (tTd(40, 1)) 1131 printf("dowork(%s)\n", id); 1132 1133 /* 1134 ** Fork for work. 1135 */ 1136 1137 if (forkflag) 1138 { 1139 pid = fork(); 1140 if (pid < 0) 1141 { 1142 syserr("dowork: cannot fork"); 1143 return 0; 1144 } 1145 else if (pid > 0) 1146 { 1147 /* parent -- clean out connection cache */ 1148 mci_flush(FALSE, NULL); 1149 } 1150 } 1151 else 1152 { 1153 pid = 0; 1154 } 1155 1156 if (pid == 0) 1157 { 1158 /* 1159 ** CHILD 1160 ** Lock the control file to avoid duplicate deliveries. 1161 ** Then run the file as though we had just read it. 1162 ** We save an idea of the temporary name so we 1163 ** can recover on interrupt. 1164 */ 1165 1166 /* set basic modes, etc. */ 1167 (void) alarm(0); 1168 clearenvelope(e, FALSE); 1169 e->e_flags |= EF_QUEUERUN|EF_GLOBALERRS; 1170 e->e_errormode = EM_MAIL; 1171 e->e_id = id; 1172 GrabTo = UseErrorsTo = FALSE; 1173 ExitStat = EX_OK; 1174 if (forkflag) 1175 { 1176 disconnect(1, e); 1177 OpMode = MD_DELIVER; 1178 } 1179 # ifdef LOG 1180 if (LogLevel > 76) 1181 syslog(LOG_DEBUG, "%s: dowork, pid=%d", e->e_id, 1182 getpid()); 1183 # endif /* LOG */ 1184 1185 /* don't use the headers from sendmail.cf... */ 1186 e->e_header = NULL; 1187 1188 /* read the queue control file -- return if locked */ 1189 if (!readqf(e)) 1190 { 1191 if (tTd(40, 4)) 1192 printf("readqf(%s) failed\n", e->e_id); 1193 if (forkflag) 1194 exit(EX_OK); 1195 else 1196 return 0; 1197 } 1198 1199 e->e_flags |= EF_INQUEUE; 1200 1201 /* if this has been tried recently, let it be */ 1202 if (e->e_ntries > 0 && (curtime() - e->e_dtime) < MinQueueAge) 1203 { 1204 char *howlong = pintvl(curtime() - e->e_dtime, TRUE); 1205 1206 e->e_flags |= EF_KEEPQUEUE; 1207 if (Verbose || tTd(40, 8)) 1208 printf("%s: too young (%s)\n", 1209 e->e_id, howlong); 1210 #ifdef LOG 1211 if (LogLevel > 19) 1212 syslog(LOG_DEBUG, "%s: too young (%s)", 1213 e->e_id, howlong); 1214 #endif 1215 } 1216 else 1217 { 1218 eatheader(e, requeueflag); 1219 1220 if (requeueflag) 1221 queueup(e, TRUE, FALSE); 1222 1223 /* do the delivery */ 1224 sendall(e, SM_DELIVER); 1225 } 1226 1227 /* finish up and exit */ 1228 if (forkflag) 1229 finis(); 1230 else 1231 dropenvelope(e); 1232 } 1233 e->e_id = NULL; 1234 return pid; 1235 } 1236 /* 1237 ** READQF -- read queue file and set up environment. 1238 ** 1239 ** Parameters: 1240 ** e -- the envelope of the job to run. 1241 ** 1242 ** Returns: 1243 ** TRUE if it successfully read the queue file. 1244 ** FALSE otherwise. 1245 ** 1246 ** Side Effects: 1247 ** The queue file is returned locked. 1248 */ 1249 1250 bool 1251 readqf(e) 1252 register ENVELOPE *e; 1253 { 1254 register FILE *qfp; 1255 ADDRESS *ctladdr; 1256 struct stat st; 1257 char *bp; 1258 int qfver = 0; 1259 register char *p; 1260 char *orcpt = NULL; 1261 bool nomore = FALSE; 1262 char qf[20]; 1263 char buf[MAXLINE]; 1264 extern ADDRESS *setctluser(); 1265 extern void loseqfile(); 1266 1267 /* 1268 ** Read and process the file. 1269 */ 1270 1271 strcpy(qf, queuename(e, 'q')); 1272 qfp = fopen(qf, "r+"); 1273 if (qfp == NULL) 1274 { 1275 if (tTd(40, 8)) 1276 printf("readqf(%s): fopen failure (%s)\n", 1277 qf, errstring(errno)); 1278 if (errno != ENOENT) 1279 syserr("readqf: no control file %s", qf); 1280 return FALSE; 1281 } 1282 1283 if (!lockfile(fileno(qfp), qf, NULL, LOCK_EX|LOCK_NB)) 1284 { 1285 /* being processed by another queuer */ 1286 if (Verbose || tTd(40, 8)) 1287 printf("%s: locked\n", e->e_id); 1288 # ifdef LOG 1289 if (LogLevel > 19) 1290 syslog(LOG_DEBUG, "%s: locked", e->e_id); 1291 # endif /* LOG */ 1292 (void) fclose(qfp); 1293 return FALSE; 1294 } 1295 1296 /* 1297 ** Check the queue file for plausibility to avoid attacks. 1298 */ 1299 1300 if (fstat(fileno(qfp), &st) < 0) 1301 { 1302 /* must have been being processed by someone else */ 1303 if (tTd(40, 8)) 1304 printf("readqf(%s): fstat failure (%s)\n", 1305 qf, errstring(errno)); 1306 fclose(qfp); 1307 return FALSE; 1308 } 1309 1310 if (st.st_uid != geteuid() || bitset(S_IWOTH|S_IWGRP, st.st_mode)) 1311 { 1312 # ifdef LOG 1313 if (LogLevel > 0) 1314 { 1315 syslog(LOG_ALERT, "%s: bogus queue file, uid=%d, mode=%o", 1316 e->e_id, st.st_uid, st.st_mode); 1317 } 1318 # endif /* LOG */ 1319 if (tTd(40, 8)) 1320 printf("readqf(%s): bogus file\n", qf); 1321 loseqfile(e, "bogus file uid in mqueue"); 1322 fclose(qfp); 1323 return FALSE; 1324 } 1325 1326 if (st.st_size == 0) 1327 { 1328 /* must be a bogus file -- just remove it */ 1329 (void) unlink(qf); 1330 fclose(qfp); 1331 return FALSE; 1332 } 1333 1334 if (st.st_nlink == 0) 1335 { 1336 /* 1337 ** Race condition -- we got a file just as it was being 1338 ** unlinked. Just assume it is zero length. 1339 */ 1340 1341 fclose(qfp); 1342 return FALSE; 1343 } 1344 1345 /* good file -- save this lock */ 1346 e->e_lockfp = qfp; 1347 1348 /* do basic system initialization */ 1349 initsys(e); 1350 define('i', e->e_id, e); 1351 1352 LineNumber = 0; 1353 e->e_flags |= EF_GLOBALERRS; 1354 OpMode = MD_DELIVER; 1355 ctladdr = NULL; 1356 e->e_dfino = -1; 1357 e->e_msgsize = -1; 1358 while ((bp = fgetfolded(buf, sizeof buf, qfp)) != NULL) 1359 { 1360 register char *p; 1361 u_long qflags; 1362 ADDRESS *q; 1363 1364 if (tTd(40, 4)) 1365 printf("+++++ %s\n", bp); 1366 if (nomore) 1367 { 1368 /* hack attack */ 1369 syserr("SECURITY ALERT: extra data in qf: %s", bp); 1370 fclose(qfp); 1371 loseqfile(e, "bogus queue line"); 1372 return FALSE; 1373 } 1374 switch (bp[0]) 1375 { 1376 case 'V': /* queue file version number */ 1377 qfver = atoi(&bp[1]); 1378 if (qfver > QF_VERSION) 1379 { 1380 syserr("Version number in qf (%d) greater than max (%d)", 1381 qfver, QF_VERSION); 1382 } 1383 break; 1384 1385 case 'C': /* specify controlling user */ 1386 ctladdr = setctluser(&bp[1]); 1387 break; 1388 1389 case 'Q': /* original recipient */ 1390 orcpt = newstr(&bp[1]); 1391 break; 1392 1393 case 'R': /* specify recipient */ 1394 p = bp; 1395 qflags = 0; 1396 if (qfver >= 1) 1397 { 1398 /* get flag bits */ 1399 while (*++p != '\0' && *p != ':') 1400 { 1401 switch (*p) 1402 { 1403 case 'S': 1404 qflags |= QPINGONSUCCESS; 1405 break; 1406 1407 case 'F': 1408 qflags |= QPINGONFAILURE; 1409 break; 1410 1411 case 'D': 1412 qflags |= QPINGONDELAY; 1413 break; 1414 1415 case 'P': 1416 qflags |= QPRIMARY; 1417 break; 1418 } 1419 } 1420 } 1421 else 1422 qflags |= QPRIMARY; 1423 q = parseaddr(++p, NULLADDR, RF_COPYALL, '\0', NULL, e); 1424 if (q != NULL) 1425 { 1426 q->q_alias = ctladdr; 1427 q->q_flags |= qflags; 1428 q->q_orcpt = orcpt; 1429 (void) recipient(q, &e->e_sendqueue, 0, e); 1430 } 1431 orcpt = NULL; 1432 break; 1433 1434 case 'E': /* specify error recipient */ 1435 /* no longer used */ 1436 break; 1437 1438 case 'H': /* header */ 1439 (void) chompheader(&bp[1], FALSE, NULL, e); 1440 break; 1441 1442 case 'M': /* message */ 1443 /* ignore this; we want a new message next time */ 1444 break; 1445 1446 case 'S': /* sender */ 1447 setsender(newstr(&bp[1]), e, NULL, TRUE); 1448 break; 1449 1450 case 'B': /* body type */ 1451 e->e_bodytype = newstr(&bp[1]); 1452 break; 1453 1454 case 'D': /* data file name */ 1455 /* obsolete -- ignore */ 1456 break; 1457 1458 case 'T': /* init time */ 1459 e->e_ctime = atol(&bp[1]); 1460 break; 1461 1462 case 'I': /* data file's inode number */ 1463 if (e->e_dfino == -1) 1464 e->e_dfino = atol(&buf[1]); 1465 break; 1466 1467 case 'K': /* time of last deliver attempt */ 1468 e->e_dtime = atol(&buf[1]); 1469 break; 1470 1471 case 'N': /* number of delivery attempts */ 1472 e->e_ntries = atoi(&buf[1]); 1473 break; 1474 1475 case 'P': /* message priority */ 1476 e->e_msgpriority = atol(&bp[1]) + WkTimeFact; 1477 break; 1478 1479 case 'F': /* flag bits */ 1480 if (strncmp(bp, "From ", 5) == 0) 1481 { 1482 /* we are being spoofed! */ 1483 syserr("SECURITY ALERT: bogus qf line %s", bp); 1484 fclose(qfp); 1485 loseqfile(e, "bogus queue line"); 1486 return FALSE; 1487 } 1488 for (p = &bp[1]; *p != '\0'; p++) 1489 { 1490 switch (*p) 1491 { 1492 case 'w': /* warning sent */ 1493 e->e_flags |= EF_WARNING; 1494 break; 1495 1496 case 'r': /* response */ 1497 e->e_flags |= EF_RESPONSE; 1498 break; 1499 1500 case '8': /* has 8 bit data */ 1501 e->e_flags |= EF_HAS8BIT; 1502 break; 1503 } 1504 } 1505 break; 1506 1507 case 'Z': /* original envelope id from ESMTP */ 1508 e->e_envid = newstr(&bp[1]); 1509 break; 1510 1511 case '$': /* define macro */ 1512 define(bp[1], newstr(&bp[2]), e); 1513 break; 1514 1515 case '.': /* terminate file */ 1516 nomore = TRUE; 1517 break; 1518 1519 default: 1520 syserr("readqf: %s: line %d: bad line \"%s\"", 1521 qf, LineNumber, bp); 1522 fclose(qfp); 1523 loseqfile(e, "unrecognized line"); 1524 return FALSE; 1525 } 1526 1527 if (bp != buf) 1528 free(bp); 1529 } 1530 1531 /* 1532 ** If we haven't read any lines, this queue file is empty. 1533 ** Arrange to remove it without referencing any null pointers. 1534 */ 1535 1536 if (LineNumber == 0) 1537 { 1538 errno = 0; 1539 e->e_flags |= EF_CLRQUEUE | EF_FATALERRS | EF_RESPONSE; 1540 } 1541 else 1542 { 1543 /* 1544 ** Arrange to read the data file. 1545 */ 1546 1547 p = queuename(e, 'd'); 1548 e->e_dfp = fopen(p, "r"); 1549 if (e->e_dfp == NULL) 1550 { 1551 syserr("readqf: cannot open %s", p); 1552 } 1553 else 1554 { 1555 e->e_flags |= EF_HAS_DF; 1556 if (fstat(fileno(e->e_dfp), &st) >= 0) 1557 { 1558 e->e_msgsize = st.st_size; 1559 e->e_dfdev = st.st_dev; 1560 e->e_dfino = st.st_ino; 1561 } 1562 } 1563 } 1564 1565 return TRUE; 1566 } 1567 /* 1568 ** PRINTQUEUE -- print out a representation of the mail queue 1569 ** 1570 ** Parameters: 1571 ** none. 1572 ** 1573 ** Returns: 1574 ** none. 1575 ** 1576 ** Side Effects: 1577 ** Prints a listing of the mail queue on the standard output. 1578 */ 1579 1580 void 1581 printqueue() 1582 { 1583 register WORK *w; 1584 FILE *f; 1585 int nrequests; 1586 char buf[MAXLINE]; 1587 1588 /* 1589 ** Check for permission to print the queue 1590 */ 1591 1592 if (bitset(PRIV_RESTRICTMAILQ, PrivacyFlags) && RealUid != 0) 1593 { 1594 struct stat st; 1595 # ifdef NGROUPS 1596 int n; 1597 GIDSET_T gidset[NGROUPS]; 1598 # endif 1599 1600 if (stat(QueueDir, &st) < 0) 1601 { 1602 syserr("Cannot stat %s", QueueDir); 1603 return; 1604 } 1605 # ifdef NGROUPS 1606 n = getgroups(NGROUPS, gidset); 1607 while (--n >= 0) 1608 { 1609 if (gidset[n] == st.st_gid) 1610 break; 1611 } 1612 if (n < 0 && RealGid != st.st_gid) 1613 # else 1614 if (RealGid != st.st_gid) 1615 # endif 1616 { 1617 usrerr("510 You are not permitted to see the queue"); 1618 setstat(EX_NOPERM); 1619 return; 1620 } 1621 } 1622 1623 /* 1624 ** Read and order the queue. 1625 */ 1626 1627 nrequests = orderq(TRUE); 1628 1629 /* 1630 ** Print the work list that we have read. 1631 */ 1632 1633 /* first see if there is anything */ 1634 if (nrequests <= 0) 1635 { 1636 printf("Mail queue is empty\n"); 1637 return; 1638 } 1639 1640 CurrentLA = getla(); /* get load average */ 1641 1642 printf("\t\tMail Queue (%d request%s", nrequests, nrequests == 1 ? "" : "s"); 1643 if (nrequests > WorkListSize) 1644 printf(", only %d printed", WorkListSize); 1645 if (Verbose) 1646 printf(")\n--Q-ID-- --Size-- -Priority- ---Q-Time--- -----------Sender/Recipient-----------\n"); 1647 else 1648 printf(")\n--Q-ID-- --Size-- -----Q-Time----- ------------Sender/Recipient------------\n"); 1649 for (w = WorkQ; w != NULL; w = w->w_next) 1650 { 1651 struct stat st; 1652 auto time_t submittime = 0; 1653 long dfsize; 1654 int flags = 0; 1655 int qfver; 1656 char statmsg[MAXLINE]; 1657 char bodytype[MAXNAME + 1]; 1658 1659 printf("%8s", w->w_name + 2); 1660 f = fopen(w->w_name, "r"); 1661 if (f == NULL) 1662 { 1663 printf(" (job completed)\n"); 1664 errno = 0; 1665 continue; 1666 } 1667 w->w_name[0] = 'd'; 1668 if (stat(w->w_name, &st) >= 0) 1669 dfsize = st.st_size; 1670 else 1671 dfsize = -1; 1672 if (w->w_lock) 1673 printf("*"); 1674 else if (shouldqueue(w->w_pri, w->w_ctime)) 1675 printf("X"); 1676 else 1677 printf(" "); 1678 errno = 0; 1679 1680 statmsg[0] = bodytype[0] = '\0'; 1681 qfver = 0; 1682 while (fgets(buf, sizeof buf, f) != NULL) 1683 { 1684 register int i; 1685 register char *p; 1686 1687 fixcrlf(buf, TRUE); 1688 switch (buf[0]) 1689 { 1690 case 'V': /* queue file version */ 1691 qfver = atoi(&buf[1]); 1692 break; 1693 1694 case 'M': /* error message */ 1695 if ((i = strlen(&buf[1])) >= sizeof statmsg) 1696 i = sizeof statmsg - 1; 1697 bcopy(&buf[1], statmsg, i); 1698 statmsg[i] = '\0'; 1699 break; 1700 1701 case 'B': /* body type */ 1702 if ((i = strlen(&buf[1])) >= sizeof bodytype) 1703 i = sizeof bodytype - 1; 1704 bcopy(&buf[1], bodytype, i); 1705 bodytype[i] = '\0'; 1706 break; 1707 1708 case 'S': /* sender name */ 1709 if (Verbose) 1710 printf("%8ld %10ld%c%.12s %.38s", 1711 dfsize, 1712 w->w_pri, 1713 bitset(EF_WARNING, flags) ? '+' : ' ', 1714 ctime(&submittime) + 4, 1715 &buf[1]); 1716 else 1717 printf("%8ld %.16s %.45s", dfsize, 1718 ctime(&submittime), &buf[1]); 1719 if (statmsg[0] != '\0' || bodytype[0] != '\0') 1720 { 1721 printf("\n %10.10s", bodytype); 1722 if (statmsg[0] != '\0') 1723 printf(" (%.60s)", statmsg); 1724 } 1725 break; 1726 1727 case 'C': /* controlling user */ 1728 if (Verbose) 1729 printf("\n\t\t\t\t (---%.34s---)", 1730 &buf[1]); 1731 break; 1732 1733 case 'R': /* recipient name */ 1734 p = &buf[1]; 1735 if (qfver >= 1) 1736 { 1737 p = strchr(p, ':'); 1738 if (p == NULL) 1739 break; 1740 p++; 1741 } 1742 if (Verbose) 1743 printf("\n\t\t\t\t\t %.38s", p); 1744 else 1745 printf("\n\t\t\t\t %.45s", p); 1746 break; 1747 1748 case 'T': /* creation time */ 1749 submittime = atol(&buf[1]); 1750 break; 1751 1752 case 'F': /* flag bits */ 1753 for (p = &buf[1]; *p != '\0'; p++) 1754 { 1755 switch (*p) 1756 { 1757 case 'w': 1758 flags |= EF_WARNING; 1759 break; 1760 } 1761 } 1762 } 1763 } 1764 if (submittime == (time_t) 0) 1765 printf(" (no control file)"); 1766 printf("\n"); 1767 (void) fclose(f); 1768 } 1769 } 1770 1771 # endif /* QUEUE */ 1772 /* 1773 ** QUEUENAME -- build a file name in the queue directory for this envelope. 1774 ** 1775 ** Assigns an id code if one does not already exist. 1776 ** This code is very careful to avoid trashing existing files 1777 ** under any circumstances. 1778 ** 1779 ** Parameters: 1780 ** e -- envelope to build it in/from. 1781 ** type -- the file type, used as the first character 1782 ** of the file name. 1783 ** 1784 ** Returns: 1785 ** a pointer to the new file name (in a static buffer). 1786 ** 1787 ** Side Effects: 1788 ** If no id code is already assigned, queuename will 1789 ** assign an id code, create a qf file, and leave a 1790 ** locked, open-for-write file pointer in the envelope. 1791 */ 1792 1793 char * 1794 queuename(e, type) 1795 register ENVELOPE *e; 1796 int type; 1797 { 1798 static int pid = -1; 1799 static char c0; 1800 static char c1; 1801 static char c2; 1802 time_t now; 1803 struct tm *tm; 1804 static char buf[MAXNAME + 1]; 1805 1806 if (e->e_id == NULL) 1807 { 1808 char qf[20]; 1809 1810 /* find a unique id */ 1811 if (pid != getpid()) 1812 { 1813 /* new process -- start back at "AA" */ 1814 pid = getpid(); 1815 now = curtime(); 1816 tm = localtime(&now); 1817 c0 = 'A' + tm->tm_hour; 1818 c1 = 'A'; 1819 c2 = 'A' - 1; 1820 } 1821 (void) sprintf(qf, "qf%cAA%05d", c0, pid); 1822 1823 while (c1 < '~' || c2 < 'Z') 1824 { 1825 int i; 1826 1827 if (c2 >= 'Z') 1828 { 1829 c1++; 1830 c2 = 'A' - 1; 1831 } 1832 qf[3] = c1; 1833 qf[4] = ++c2; 1834 if (tTd(7, 20)) 1835 printf("queuename: trying \"%s\"\n", qf); 1836 1837 i = open(qf, O_WRONLY|O_CREAT|O_EXCL, FileMode); 1838 if (i < 0) 1839 { 1840 if (errno == EEXIST) 1841 continue; 1842 syserr("queuename: Cannot create \"%s\" in \"%s\" (euid=%d)", 1843 qf, QueueDir, geteuid()); 1844 exit(EX_UNAVAILABLE); 1845 } 1846 if (lockfile(i, qf, NULL, LOCK_EX|LOCK_NB)) 1847 { 1848 e->e_lockfp = fdopen(i, "w"); 1849 break; 1850 } 1851 1852 /* a reader got the file; abandon it and try again */ 1853 (void) close(i); 1854 } 1855 if (c1 >= '~' && c2 >= 'Z') 1856 { 1857 syserr("queuename: Cannot create \"%s\" in \"%s\" (euid=%d)", 1858 qf, QueueDir, geteuid()); 1859 exit(EX_OSERR); 1860 } 1861 e->e_id = newstr(&qf[2]); 1862 define('i', e->e_id, e); 1863 if (tTd(7, 1)) 1864 printf("queuename: assigned id %s, env=%x\n", e->e_id, e); 1865 if (tTd(7, 9)) 1866 { 1867 printf(" lockfd="); 1868 dumpfd(fileno(e->e_lockfp), TRUE, FALSE); 1869 } 1870 # ifdef LOG 1871 if (LogLevel > 93) 1872 syslog(LOG_DEBUG, "%s: assigned id", e->e_id); 1873 # endif /* LOG */ 1874 } 1875 1876 if (type == '\0') 1877 return (NULL); 1878 (void) sprintf(buf, "%cf%s", type, e->e_id); 1879 if (tTd(7, 2)) 1880 printf("queuename: %s\n", buf); 1881 return (buf); 1882 } 1883 /* 1884 ** UNLOCKQUEUE -- unlock the queue entry for a specified envelope 1885 ** 1886 ** Parameters: 1887 ** e -- the envelope to unlock. 1888 ** 1889 ** Returns: 1890 ** none 1891 ** 1892 ** Side Effects: 1893 ** unlocks the queue for `e'. 1894 */ 1895 1896 void 1897 unlockqueue(e) 1898 ENVELOPE *e; 1899 { 1900 if (tTd(51, 4)) 1901 printf("unlockqueue(%s)\n", e->e_id); 1902 1903 /* if there is a lock file in the envelope, close it */ 1904 if (e->e_lockfp != NULL) 1905 xfclose(e->e_lockfp, "unlockqueue", e->e_id); 1906 e->e_lockfp = NULL; 1907 1908 /* don't create a queue id if we don't already have one */ 1909 if (e->e_id == NULL) 1910 return; 1911 1912 /* remove the transcript */ 1913 # ifdef LOG 1914 if (LogLevel > 87) 1915 syslog(LOG_DEBUG, "%s: unlock", e->e_id); 1916 # endif /* LOG */ 1917 if (!tTd(51, 104)) 1918 xunlink(queuename(e, 'x')); 1919 1920 } 1921 /* 1922 ** SETCTLUSER -- create a controlling address 1923 ** 1924 ** Create a fake "address" given only a local login name; this is 1925 ** used as a "controlling user" for future recipient addresses. 1926 ** 1927 ** Parameters: 1928 ** user -- the user name of the controlling user. 1929 ** 1930 ** Returns: 1931 ** An address descriptor for the controlling user. 1932 ** 1933 ** Side Effects: 1934 ** none. 1935 */ 1936 1937 ADDRESS * 1938 setctluser(user) 1939 char *user; 1940 { 1941 register ADDRESS *a; 1942 struct passwd *pw; 1943 char *p; 1944 1945 /* 1946 ** See if this clears our concept of controlling user. 1947 */ 1948 1949 if (user == NULL || *user == '\0') 1950 return NULL; 1951 1952 /* 1953 ** Set up addr fields for controlling user. 1954 */ 1955 1956 a = (ADDRESS *) xalloc(sizeof *a); 1957 bzero((char *) a, sizeof *a); 1958 1959 p = strchr(user, ':'); 1960 if (p != NULL) 1961 *p++ = '\0'; 1962 if (*user != '\0' && (pw = sm_getpwnam(user)) != NULL) 1963 { 1964 if (strcmp(pw->pw_dir, "/") == 0) 1965 a->q_home = ""; 1966 else 1967 a->q_home = newstr(pw->pw_dir); 1968 a->q_uid = pw->pw_uid; 1969 a->q_gid = pw->pw_gid; 1970 a->q_flags |= QGOODUID; 1971 } 1972 1973 if (*user != '\0') 1974 a->q_user = newstr(user); 1975 else if (p != NULL) 1976 a->q_user = newstr(p); 1977 else 1978 a->q_user = newstr(DefUser); 1979 1980 a->q_flags |= QPRIMARY; /* flag as a "ctladdr" */ 1981 a->q_mailer = LocalMailer; 1982 if (p == NULL) 1983 a->q_paddr = a->q_user; 1984 else 1985 a->q_paddr = newstr(p); 1986 return a; 1987 } 1988 /* 1989 ** LOSEQFILE -- save the qf as Qf and try to let someone know 1990 ** 1991 ** Parameters: 1992 ** e -- the envelope (e->e_id will be used). 1993 ** why -- reported to whomever can hear. 1994 ** 1995 ** Returns: 1996 ** none. 1997 */ 1998 1999 void 2000 loseqfile(e, why) 2001 register ENVELOPE *e; 2002 char *why; 2003 { 2004 char *p; 2005 char buf[40]; 2006 2007 if (e == NULL || e->e_id == NULL) 2008 return; 2009 if (strlen(e->e_id) > sizeof buf - 4) 2010 return; 2011 strcpy(buf, queuename(e, 'q')); 2012 p = queuename(e, 'Q'); 2013 if (rename(buf, p) < 0) 2014 syserr("cannot rename(%s, %s), uid=%d", buf, p, geteuid()); 2015 #ifdef LOG 2016 else if (LogLevel > 0) 2017 syslog(LOG_ALERT, "Losing %s: %s", buf, why); 2018 #endif 2019 } 2020