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