1 /* 2 * Copyright (c) 1983 Eric P. Allman 3 * Copyright (c) 1988 Regents of the University of California. 4 * All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 # include "sendmail.h" 10 11 #ifndef lint 12 #ifdef QUEUE 13 static char sccsid[] = "@(#)queue.c 5.37 (Berkeley) 12/14/91 (with queueing)"; 14 #else 15 static char sccsid[] = "@(#)queue.c 5.37 (Berkeley) 12/14/91 (without queueing)"; 16 #endif 17 #endif /* not lint */ 18 19 # include <sys/stat.h> 20 # include <sys/dir.h> 21 # include <sys/file.h> 22 # include <signal.h> 23 # include <errno.h> 24 # include <pwd.h> 25 # ifdef LOCKF 26 # include <fcntl.h> 27 # endif 28 29 # ifdef QUEUE 30 31 /* 32 ** Work queue. 33 */ 34 35 struct work 36 { 37 char *w_name; /* name of control file */ 38 long w_pri; /* priority of message, see below */ 39 time_t w_ctime; /* creation time of message */ 40 struct work *w_next; /* next in queue */ 41 }; 42 43 typedef struct work WORK; 44 45 WORK *WorkQ; /* queue of things to be done */ 46 /* 47 ** QUEUEUP -- queue a message up for future transmission. 48 ** 49 ** Parameters: 50 ** e -- the envelope to queue up. 51 ** queueall -- if TRUE, queue all addresses, rather than 52 ** just those with the QQUEUEUP flag set. 53 ** announce -- if TRUE, tell when you are queueing up. 54 ** 55 ** Returns: 56 ** none. 57 ** 58 ** Side Effects: 59 ** The current request are saved in a control file. 60 ** The queue file is left locked. 61 */ 62 63 queueup(e, queueall, announce) 64 register ENVELOPE *e; 65 bool queueall; 66 bool announce; 67 { 68 char *qf; 69 register FILE *tfp; 70 register HDR *h; 71 register ADDRESS *q; 72 int fd; 73 int i; 74 bool newid; 75 MAILER nullmailer; 76 char buf[MAXLINE], tf[MAXLINE]; 77 78 /* 79 ** Create control file. 80 */ 81 82 newid = (e->e_id == NULL); 83 strcpy(tf, queuename(e, 't')); 84 tfp = e->e_lockfp; 85 if (tfp == NULL) 86 newid = FALSE; 87 if (newid) 88 { 89 tfp = e->e_lockfp; 90 } 91 else 92 { 93 /* get a locked tf file */ 94 for (i = 100; --i >= 0; ) 95 { 96 # ifdef LOCKF 97 struct flock lfd; 98 # endif 99 100 fd = open(tf, O_CREAT|O_WRONLY|O_EXCL, FileMode); 101 if (fd < 0) 102 { 103 if (errno == EEXIST) 104 continue; 105 syserr("queueup: cannot create temp file %s", tf); 106 return; 107 } 108 # ifdef LOCKF 109 lfd.l_type = F_WRLCK; 110 lfd.l_whence = lfd.l_start = lfd.l_len = 0; 111 if (fcntl(fd, F_SETLK, &lfd) >= 0) 112 break; 113 if (errno != EACCES && errno != EAGAIN) 114 syserr("cannot lockf(%s)", tf); 115 # else 116 if (flock(fd, LOCK_EX|LOCK_NB) >= 0) 117 break; 118 if (errno != EWOULDBLOCK) 119 syserr("cannot flock(%s)", tf); 120 # endif 121 close(fd); 122 } 123 124 tfp = fdopen(fd, "w"); 125 } 126 127 if (tTd(40, 1)) 128 printf("queueing %s\n", e->e_id); 129 130 /* 131 ** If there is no data file yet, create one. 132 */ 133 134 if (e->e_df == NULL) 135 { 136 register FILE *dfp; 137 extern putbody(); 138 139 e->e_df = newstr(queuename(e, 'd')); 140 fd = open(e->e_df, O_WRONLY|O_CREAT, FileMode); 141 if (fd < 0) 142 { 143 syserr("queueup: cannot create %s", e->e_df); 144 if (!newid) 145 (void) fclose(tfp); 146 return; 147 } 148 dfp = fdopen(fd, "w"); 149 (*e->e_putbody)(dfp, ProgMailer, e); 150 (void) fclose(dfp); 151 e->e_putbody = putbody; 152 } 153 154 /* 155 ** Output future work requests. 156 ** Priority and creation time should be first, since 157 ** they are required by orderq. 158 */ 159 160 /* output message priority */ 161 fprintf(tfp, "P%ld\n", e->e_msgpriority); 162 163 /* output creation time */ 164 fprintf(tfp, "T%ld\n", e->e_ctime); 165 166 /* output name of data file */ 167 fprintf(tfp, "D%s\n", e->e_df); 168 169 /* message from envelope, if it exists */ 170 if (e->e_message != NULL) 171 fprintf(tfp, "M%s\n", e->e_message); 172 173 /* output name of sender */ 174 fprintf(tfp, "S%s\n", e->e_from.q_paddr); 175 176 /* output list of recipient addresses */ 177 for (q = e->e_sendqueue; q != NULL; q = q->q_next) 178 { 179 if (queueall ? !bitset(QDONTSEND|QSENT, q->q_flags) : 180 bitset(QQUEUEUP, q->q_flags)) 181 { 182 char *ctluser, *getctluser(); 183 184 if ((ctluser = getctluser(q)) != NULL) 185 fprintf(tfp, "C%s\n", ctluser); 186 fprintf(tfp, "R%s\n", q->q_paddr); 187 if (announce) 188 { 189 e->e_to = q->q_paddr; 190 message(Arpa_Info, "queued"); 191 if (LogLevel > 4) 192 logdelivery("queued"); 193 e->e_to = NULL; 194 } 195 if (tTd(40, 1)) 196 { 197 printf("queueing "); 198 printaddr(q, FALSE); 199 } 200 } 201 } 202 203 /* output list of error recipients */ 204 for (q = e->e_errorqueue; q != NULL; q = q->q_next) 205 { 206 if (!bitset(QDONTSEND, q->q_flags)) 207 { 208 char *ctluser, *getctluser(); 209 210 if ((ctluser = getctluser(q)) != NULL) 211 fprintf(tfp, "C%s\n", ctluser); 212 fprintf(tfp, "E%s\n", q->q_paddr); 213 } 214 } 215 216 /* 217 ** Output headers for this message. 218 ** Expand macros completely here. Queue run will deal with 219 ** everything as absolute headers. 220 ** All headers that must be relative to the recipient 221 ** can be cracked later. 222 ** We set up a "null mailer" -- i.e., a mailer that will have 223 ** no effect on the addresses as they are output. 224 */ 225 226 bzero((char *) &nullmailer, sizeof nullmailer); 227 nullmailer.m_r_rwset = nullmailer.m_s_rwset = -1; 228 nullmailer.m_eol = "\n"; 229 230 define('g', "\001f", e); 231 for (h = e->e_header; h != NULL; h = h->h_link) 232 { 233 extern bool bitzerop(); 234 235 /* don't output null headers */ 236 if (h->h_value == NULL || h->h_value[0] == '\0') 237 continue; 238 239 /* don't output resent headers on non-resent messages */ 240 if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags)) 241 continue; 242 243 /* output this header */ 244 fprintf(tfp, "H"); 245 246 /* if conditional, output the set of conditions */ 247 if (!bitzerop(h->h_mflags) && bitset(H_CHECK|H_ACHECK, h->h_flags)) 248 { 249 int j; 250 251 (void) putc('?', tfp); 252 for (j = '\0'; j <= '\177'; j++) 253 if (bitnset(j, h->h_mflags)) 254 (void) putc(j, tfp); 255 (void) putc('?', tfp); 256 } 257 258 /* output the header: expand macros, convert addresses */ 259 if (bitset(H_DEFAULT, h->h_flags)) 260 { 261 (void) expand(h->h_value, buf, &buf[sizeof buf], e); 262 fprintf(tfp, "%s: %s\n", h->h_field, buf); 263 } 264 else if (bitset(H_FROM|H_RCPT, h->h_flags)) 265 { 266 commaize(h, h->h_value, tfp, bitset(EF_OLDSTYLE, e->e_flags), 267 &nullmailer); 268 } 269 else 270 fprintf(tfp, "%s: %s\n", h->h_field, h->h_value); 271 } 272 273 /* 274 ** Clean up. 275 */ 276 277 if (!newid) 278 { 279 qf = queuename(e, 'q'); 280 if (rename(tf, qf) < 0) 281 syserr("cannot rename(%s, %s), df=%s", tf, qf, e->e_df); 282 if (e->e_lockfp != NULL) 283 (void) fclose(e->e_lockfp); 284 e->e_lockfp = tfp; 285 } 286 else 287 qf = tf; 288 errno = 0; 289 290 # ifdef LOG 291 /* save log info */ 292 if (LogLevel > 15) 293 syslog(LOG_DEBUG, "%s: queueup, qf=%s, df=%s\n", e->e_id, qf, e->e_df); 294 # endif LOG 295 fflush(tfp); 296 return; 297 } 298 /* 299 ** RUNQUEUE -- run the jobs in the queue. 300 ** 301 ** Gets the stuff out of the queue in some presumably logical 302 ** order and processes them. 303 ** 304 ** Parameters: 305 ** forkflag -- TRUE if the queue scanning should be done in 306 ** a child process. We double-fork so it is not our 307 ** child and we don't have to clean up after it. 308 ** 309 ** Returns: 310 ** none. 311 ** 312 ** Side Effects: 313 ** runs things in the mail queue. 314 */ 315 316 runqueue(forkflag) 317 bool forkflag; 318 { 319 extern bool shouldqueue(); 320 321 /* 322 ** If no work will ever be selected, don't even bother reading 323 ** the queue. 324 */ 325 326 CurrentLA = getla(); /* get load average */ 327 328 if (shouldqueue(-100000000L)) 329 { 330 if (Verbose) 331 printf("Skipping queue run -- load average too high\n"); 332 333 if (forkflag) 334 return; 335 finis(); 336 } 337 338 /* 339 ** See if we want to go off and do other useful work. 340 */ 341 342 if (forkflag) 343 { 344 int pid; 345 346 pid = dofork(); 347 if (pid != 0) 348 { 349 extern void reapchild(); 350 351 /* parent -- pick up intermediate zombie */ 352 #ifndef SIGCHLD 353 (void) waitfor(pid); 354 #else SIGCHLD 355 (void) signal(SIGCHLD, reapchild); 356 #endif SIGCHLD 357 if (QueueIntvl != 0) 358 (void) setevent(QueueIntvl, runqueue, TRUE); 359 return; 360 } 361 /* child -- double fork */ 362 #ifndef SIGCHLD 363 if (fork() != 0) 364 exit(EX_OK); 365 #else SIGCHLD 366 (void) signal(SIGCHLD, SIG_DFL); 367 #endif SIGCHLD 368 } 369 370 setproctitle("running queue: %s", QueueDir); 371 372 # ifdef LOG 373 if (LogLevel > 11) 374 syslog(LOG_DEBUG, "runqueue %s, pid=%d", QueueDir, getpid()); 375 # endif LOG 376 377 /* 378 ** Release any resources used by the daemon code. 379 */ 380 381 # ifdef DAEMON 382 clrdaemon(); 383 # endif DAEMON 384 385 /* 386 ** Make sure the alias database is open. 387 */ 388 389 initaliases(AliasFile, FALSE); 390 391 /* 392 ** Start making passes through the queue. 393 ** First, read and sort the entire queue. 394 ** Then, process the work in that order. 395 ** But if you take too long, start over. 396 */ 397 398 /* order the existing work requests */ 399 (void) orderq(FALSE); 400 401 /* process them once at a time */ 402 while (WorkQ != NULL) 403 { 404 WORK *w = WorkQ; 405 406 WorkQ = WorkQ->w_next; 407 dowork(w); 408 free(w->w_name); 409 free((char *) w); 410 } 411 412 /* exit without the usual cleanup */ 413 exit(ExitStat); 414 } 415 /* 416 ** ORDERQ -- order the work queue. 417 ** 418 ** Parameters: 419 ** doall -- if set, include everything in the queue (even 420 ** the jobs that cannot be run because the load 421 ** average is too high). Otherwise, exclude those 422 ** jobs. 423 ** 424 ** Returns: 425 ** The number of request in the queue (not necessarily 426 ** the number of requests in WorkQ however). 427 ** 428 ** Side Effects: 429 ** Sets WorkQ to the queue of available work, in order. 430 */ 431 432 # define NEED_P 001 433 # define NEED_T 002 434 435 orderq(doall) 436 bool doall; 437 { 438 register struct direct *d; 439 register WORK *w; 440 DIR *f; 441 register int i; 442 WORK wlist[QUEUESIZE+1]; 443 int wn = -1; 444 extern workcmpf(); 445 446 /* clear out old WorkQ */ 447 for (w = WorkQ; w != NULL; ) 448 { 449 register WORK *nw = w->w_next; 450 451 WorkQ = nw; 452 free(w->w_name); 453 free((char *) w); 454 w = nw; 455 } 456 457 /* open the queue directory */ 458 f = opendir("."); 459 if (f == NULL) 460 { 461 syserr("orderq: cannot open \"%s\" as \".\"", QueueDir); 462 return (0); 463 } 464 465 /* 466 ** Read the work directory. 467 */ 468 469 while ((d = readdir(f)) != NULL) 470 { 471 FILE *cf; 472 char lbuf[MAXNAME]; 473 474 /* is this an interesting entry? */ 475 if (d->d_name[0] != 'q' || d->d_name[1] != 'f') 476 continue; 477 478 /* yes -- open control file (if not too many files) */ 479 if (++wn >= QUEUESIZE) 480 continue; 481 cf = fopen(d->d_name, "r"); 482 if (cf == NULL) 483 { 484 /* this may be some random person sending hir msgs */ 485 /* syserr("orderq: cannot open %s", cbuf); */ 486 if (tTd(41, 2)) 487 printf("orderq: cannot open %s (%d)\n", 488 d->d_name, errno); 489 errno = 0; 490 wn--; 491 continue; 492 } 493 w = &wlist[wn]; 494 w->w_name = newstr(d->d_name); 495 496 /* make sure jobs in creation don't clog queue */ 497 w->w_pri = 0x7fffffff; 498 w->w_ctime = 0; 499 500 /* extract useful information */ 501 i = NEED_P | NEED_T; 502 while (i != 0 && fgets(lbuf, sizeof lbuf, cf) != NULL) 503 { 504 extern long atol(); 505 506 switch (lbuf[0]) 507 { 508 case 'P': 509 w->w_pri = atol(&lbuf[1]); 510 i &= ~NEED_P; 511 break; 512 513 case 'T': 514 w->w_ctime = atol(&lbuf[1]); 515 i &= ~NEED_T; 516 break; 517 } 518 } 519 (void) fclose(cf); 520 521 if (!doall && shouldqueue(w->w_pri)) 522 { 523 /* don't even bother sorting this job in */ 524 wn--; 525 } 526 } 527 (void) closedir(f); 528 wn++; 529 530 /* 531 ** Sort the work directory. 532 */ 533 534 qsort((char *) wlist, min(wn, QUEUESIZE), sizeof *wlist, workcmpf); 535 536 /* 537 ** Convert the work list into canonical form. 538 ** Should be turning it into a list of envelopes here perhaps. 539 */ 540 541 WorkQ = NULL; 542 for (i = min(wn, QUEUESIZE); --i >= 0; ) 543 { 544 w = (WORK *) xalloc(sizeof *w); 545 w->w_name = wlist[i].w_name; 546 w->w_pri = wlist[i].w_pri; 547 w->w_ctime = wlist[i].w_ctime; 548 w->w_next = WorkQ; 549 WorkQ = w; 550 } 551 552 if (tTd(40, 1)) 553 { 554 for (w = WorkQ; w != NULL; w = w->w_next) 555 printf("%32s: pri=%ld\n", w->w_name, w->w_pri); 556 } 557 558 return (wn); 559 } 560 /* 561 ** WORKCMPF -- compare function for ordering work. 562 ** 563 ** Parameters: 564 ** a -- the first argument. 565 ** b -- the second argument. 566 ** 567 ** Returns: 568 ** -1 if a < b 569 ** 0 if a == b 570 ** +1 if a > b 571 ** 572 ** Side Effects: 573 ** none. 574 */ 575 576 workcmpf(a, b) 577 register WORK *a; 578 register WORK *b; 579 { 580 long pa = a->w_pri + a->w_ctime; 581 long pb = b->w_pri + b->w_ctime; 582 583 if (pa == pb) 584 return (0); 585 else if (pa > pb) 586 return (1); 587 else 588 return (-1); 589 } 590 /* 591 ** DOWORK -- do a work request. 592 ** 593 ** Parameters: 594 ** w -- the work request to be satisfied. 595 ** 596 ** Returns: 597 ** none. 598 ** 599 ** Side Effects: 600 ** The work request is satisfied if possible. 601 */ 602 603 dowork(w) 604 register WORK *w; 605 { 606 register int i; 607 extern bool shouldqueue(); 608 extern bool readqf(); 609 610 if (tTd(40, 1)) 611 printf("dowork: %s pri %ld\n", w->w_name, w->w_pri); 612 613 /* 614 ** Ignore jobs that are too expensive for the moment. 615 */ 616 617 if (shouldqueue(w->w_pri)) 618 { 619 if (Verbose) 620 printf("\nSkipping %s\n", w->w_name + 2); 621 return; 622 } 623 624 /* 625 ** Fork for work. 626 */ 627 628 if (ForkQueueRuns) 629 { 630 i = fork(); 631 if (i < 0) 632 { 633 syserr("dowork: cannot fork"); 634 return; 635 } 636 } 637 else 638 { 639 i = 0; 640 } 641 642 if (i == 0) 643 { 644 /* 645 ** CHILD 646 ** Lock the control file to avoid duplicate deliveries. 647 ** Then run the file as though we had just read it. 648 ** We save an idea of the temporary name so we 649 ** can recover on interrupt. 650 */ 651 652 /* set basic modes, etc. */ 653 (void) alarm(0); 654 clearenvelope(CurEnv, FALSE); 655 QueueRun = TRUE; 656 ErrorMode = EM_MAIL; 657 CurEnv->e_id = &w->w_name[2]; 658 # ifdef LOG 659 if (LogLevel > 11) 660 syslog(LOG_DEBUG, "%s: dowork, pid=%d", CurEnv->e_id, 661 getpid()); 662 # endif LOG 663 664 /* don't use the headers from sendmail.cf... */ 665 CurEnv->e_header = NULL; 666 667 /* read the queue control file -- return if locked */ 668 if (!readqf(CurEnv)) 669 { 670 if (ForkQueueRuns) 671 exit(EX_OK); 672 else 673 return; 674 } 675 676 CurEnv->e_flags |= EF_INQUEUE; 677 eatheader(CurEnv); 678 679 /* do the delivery */ 680 if (!bitset(EF_FATALERRS, CurEnv->e_flags)) 681 sendall(CurEnv, SM_DELIVER); 682 683 /* finish up and exit */ 684 if (ForkQueueRuns) 685 finis(); 686 else 687 dropenvelope(CurEnv); 688 } 689 else 690 { 691 /* 692 ** Parent -- pick up results. 693 */ 694 695 errno = 0; 696 (void) waitfor(i); 697 } 698 } 699 /* 700 ** READQF -- read queue file and set up environment. 701 ** 702 ** Parameters: 703 ** e -- the envelope of the job to run. 704 ** 705 ** Returns: 706 ** TRUE if it successfully read the queue file. 707 ** FALSE otherwise. 708 ** 709 ** Side Effects: 710 ** The queue file is returned locked. 711 */ 712 713 bool 714 readqf(e) 715 register ENVELOPE *e; 716 { 717 char *qf; 718 register FILE *qfp; 719 char buf[MAXFIELD]; 720 extern char *fgetfolded(); 721 extern long atol(); 722 int gotctluser = 0; 723 int fd; 724 # ifdef LOCKF 725 struct flock lfd; 726 # endif 727 728 /* 729 ** Read and process the file. 730 */ 731 732 qf = queuename(e, 'q'); 733 qfp = fopen(qf, "r+"); 734 if (qfp == NULL) 735 { 736 if (errno != ENOENT) 737 syserr("readqf: no control file %s", qf); 738 return FALSE; 739 } 740 741 # ifdef LOCKF 742 lfd.l_type = F_WRLCK; 743 lfd.l_whence = lfd.l_start = lfd.l_len = 0; 744 if (fcntl(fileno(qfp), F_SETLK, &lfd) < 0) 745 # else 746 if (flock(fileno(qfp), LOCK_EX|LOCK_NB) < 0) 747 # endif 748 { 749 /* being processed by another queuer */ 750 if (Verbose) 751 printf("%s: locked\n", CurEnv->e_id); 752 # ifdef LOG 753 if (LogLevel > 9) 754 syslog(LOG_DEBUG, "%s: locked", CurEnv->e_id); 755 # endif LOG 756 (void) fclose(qfp); 757 return FALSE; 758 } 759 760 /* save this lock */ 761 e->e_lockfp = qfp; 762 763 /* do basic system initialization */ 764 initsys(); 765 766 FileName = qf; 767 LineNumber = 0; 768 if (Verbose) 769 printf("\nRunning %s\n", e->e_id); 770 while (fgetfolded(buf, sizeof buf, qfp) != NULL) 771 { 772 if (tTd(40, 4)) 773 printf("+++++ %s\n", buf); 774 switch (buf[0]) 775 { 776 case 'C': /* specify controlling user */ 777 setctluser(&buf[1]); 778 gotctluser = 1; 779 break; 780 781 case 'R': /* specify recipient */ 782 sendtolist(&buf[1], (ADDRESS *) NULL, &e->e_sendqueue); 783 break; 784 785 case 'E': /* specify error recipient */ 786 sendtolist(&buf[1], (ADDRESS *) NULL, &e->e_errorqueue); 787 break; 788 789 case 'H': /* header */ 790 (void) chompheader(&buf[1], FALSE); 791 break; 792 793 case 'M': /* message */ 794 e->e_message = newstr(&buf[1]); 795 break; 796 797 case 'S': /* sender */ 798 setsender(newstr(&buf[1])); 799 break; 800 801 case 'D': /* data file name */ 802 e->e_df = newstr(&buf[1]); 803 e->e_dfp = fopen(e->e_df, "r"); 804 if (e->e_dfp == NULL) 805 syserr("readqf: cannot open %s", e->e_df); 806 break; 807 808 case 'T': /* init time */ 809 e->e_ctime = atol(&buf[1]); 810 break; 811 812 case 'P': /* message priority */ 813 e->e_msgpriority = atol(&buf[1]) + WkTimeFact; 814 break; 815 816 case '\0': /* blank line; ignore */ 817 break; 818 819 default: 820 syserr("readqf(%s:%d): bad line \"%s\"", e->e_id, 821 LineNumber, buf); 822 break; 823 } 824 /* 825 ** The `C' queue file command operates on the next line, 826 ** so we use "gotctluser" to maintain state as follows: 827 ** 0 - no controlling user, 828 ** 1 - controlling user has been set but not used, 829 ** 2 - controlling user must be used on next iteration. 830 */ 831 if (gotctluser == 1) 832 gotctluser++; 833 else if (gotctluser == 2) 834 { 835 clrctluser(); 836 gotctluser = 0; 837 } 838 } 839 840 /* clear controlling user in case we break out prematurely */ 841 clrctluser(); 842 843 FileName = NULL; 844 845 /* 846 ** If we haven't read any lines, this queue file is empty. 847 ** Arrange to remove it without referencing any null pointers. 848 */ 849 850 if (LineNumber == 0) 851 { 852 errno = 0; 853 e->e_flags |= EF_CLRQUEUE | EF_FATALERRS | EF_RESPONSE; 854 } 855 return TRUE; 856 } 857 /* 858 ** PRINTQUEUE -- print out a representation of the mail queue 859 ** 860 ** Parameters: 861 ** none. 862 ** 863 ** Returns: 864 ** none. 865 ** 866 ** Side Effects: 867 ** Prints a listing of the mail queue on the standard output. 868 */ 869 870 printqueue() 871 { 872 register WORK *w; 873 FILE *f; 874 int nrequests; 875 char buf[MAXLINE]; 876 char cbuf[MAXLINE]; 877 878 /* 879 ** Read and order the queue. 880 */ 881 882 nrequests = orderq(TRUE); 883 884 /* 885 ** Print the work list that we have read. 886 */ 887 888 /* first see if there is anything */ 889 if (nrequests <= 0) 890 { 891 printf("Mail queue is empty\n"); 892 return; 893 } 894 895 CurrentLA = getla(); /* get load average */ 896 897 printf("\t\tMail Queue (%d request%s", nrequests, nrequests == 1 ? "" : "s"); 898 if (nrequests > QUEUESIZE) 899 printf(", only %d printed", QUEUESIZE); 900 if (Verbose) 901 printf(")\n--QID-- --Size-- -Priority- ---Q-Time--- -----------Sender/Recipient-----------\n"); 902 else 903 printf(")\n--QID-- --Size-- -----Q-Time----- ------------Sender/Recipient------------\n"); 904 for (w = WorkQ; w != NULL; w = w->w_next) 905 { 906 struct stat st; 907 auto time_t submittime = 0; 908 long dfsize = -1; 909 char message[MAXLINE]; 910 # ifdef LOCKF 911 struct flock lfd; 912 # endif 913 extern bool shouldqueue(); 914 915 f = fopen(w->w_name, "r"); 916 if (f == NULL) 917 { 918 errno = 0; 919 continue; 920 } 921 printf("%7s", w->w_name + 2); 922 # ifdef LOCKF 923 lfd.l_type = F_RDLCK; 924 lfd.l_whence = lfd.l_start = lfd.l_len = 0; 925 if (fcntl(fileno(f), F_GETLK, &lfd) < 0 || lfd.l_type != F_UNLCK) 926 # else 927 if (flock(fileno(f), LOCK_SH|LOCK_NB) < 0) 928 # endif 929 printf("*"); 930 else if (shouldqueue(w->w_pri)) 931 printf("X"); 932 else 933 printf(" "); 934 errno = 0; 935 936 message[0] = '\0'; 937 cbuf[0] = '\0'; 938 while (fgets(buf, sizeof buf, f) != NULL) 939 { 940 fixcrlf(buf, TRUE); 941 switch (buf[0]) 942 { 943 case 'M': /* error message */ 944 (void) strcpy(message, &buf[1]); 945 break; 946 947 case 'S': /* sender name */ 948 if (Verbose) 949 printf("%8ld %10ld %.12s %.38s", dfsize, 950 w->w_pri, ctime(&submittime) + 4, 951 &buf[1]); 952 else 953 printf("%8ld %.16s %.45s", dfsize, 954 ctime(&submittime), &buf[1]); 955 if (message[0] != '\0') 956 printf("\n\t\t (%.60s)", message); 957 break; 958 959 case 'C': /* controlling user */ 960 if (strlen(buf) < MAXLINE-3) /* sanity */ 961 (void) strcat(buf, ") "); 962 cbuf[0] = cbuf[1] = '('; 963 (void) strncpy(&cbuf[2], &buf[1], MAXLINE-1); 964 cbuf[MAXLINE-1] = '\0'; 965 break; 966 967 case 'R': /* recipient name */ 968 if (cbuf[0] != '\0') { 969 /* prepend controlling user to `buf' */ 970 (void) strncat(cbuf, &buf[1], 971 MAXLINE-strlen(cbuf)); 972 cbuf[MAXLINE-1] = '\0'; 973 (void) strcpy(buf, cbuf); 974 cbuf[0] = '\0'; 975 } 976 if (Verbose) 977 printf("\n\t\t\t\t\t %.38s", &buf[1]); 978 else 979 printf("\n\t\t\t\t %.45s", &buf[1]); 980 break; 981 982 case 'T': /* creation time */ 983 submittime = atol(&buf[1]); 984 break; 985 986 case 'D': /* data file name */ 987 if (stat(&buf[1], &st) >= 0) 988 dfsize = st.st_size; 989 break; 990 } 991 } 992 if (submittime == (time_t) 0) 993 printf(" (no control file)"); 994 printf("\n"); 995 (void) fclose(f); 996 } 997 } 998 999 # endif QUEUE 1000 /* 1001 ** QUEUENAME -- build a file name in the queue directory for this envelope. 1002 ** 1003 ** Assigns an id code if one does not already exist. 1004 ** This code is very careful to avoid trashing existing files 1005 ** under any circumstances. 1006 ** 1007 ** Parameters: 1008 ** e -- envelope to build it in/from. 1009 ** type -- the file type, used as the first character 1010 ** of the file name. 1011 ** 1012 ** Returns: 1013 ** a pointer to the new file name (in a static buffer). 1014 ** 1015 ** Side Effects: 1016 ** If no id code is already assigned, queuename will 1017 ** assign an id code, create a qf file, and leave a 1018 ** locked, open-for-write file pointer in the envelope. 1019 */ 1020 1021 char * 1022 queuename(e, type) 1023 register ENVELOPE *e; 1024 char type; 1025 { 1026 static char buf[MAXNAME]; 1027 static int pid = -1; 1028 char c1 = 'A'; 1029 char c2 = 'A'; 1030 1031 if (e->e_id == NULL) 1032 { 1033 char qf[20]; 1034 1035 /* find a unique id */ 1036 if (pid != getpid()) 1037 { 1038 /* new process -- start back at "AA" */ 1039 pid = getpid(); 1040 c1 = 'A'; 1041 c2 = 'A' - 1; 1042 } 1043 (void) sprintf(qf, "qfAA%05d", pid); 1044 1045 while (c1 < '~' || c2 < 'Z') 1046 { 1047 int i; 1048 # ifdef LOCKF 1049 struct flock lfd; 1050 # endif 1051 1052 if (c2 >= 'Z') 1053 { 1054 c1++; 1055 c2 = 'A' - 1; 1056 } 1057 qf[2] = c1; 1058 qf[3] = ++c2; 1059 if (tTd(7, 20)) 1060 printf("queuename: trying \"%s\"\n", qf); 1061 1062 i = open(qf, O_WRONLY|O_CREAT|O_EXCL, FileMode); 1063 if (i < 0) 1064 { 1065 if (errno == EEXIST) 1066 continue; 1067 syserr("queuename: Cannot create \"%s\" in \"%s\"", 1068 qf, QueueDir); 1069 exit(EX_UNAVAILABLE); 1070 } 1071 # ifdef LOCKF 1072 lfd.l_type = F_WRLCK; 1073 lfd.l_whence = lfd.l_start = lfd.l_len = 0; 1074 if (fcntl(i, F_SETLK, &lfd) >= 0) 1075 # else 1076 if (flock(i, LOCK_EX|LOCK_NB) >= 0) 1077 # endif 1078 { 1079 e->e_lockfp = fdopen(i, "w"); 1080 break; 1081 } 1082 1083 /* a reader got the file; abandon it and try again */ 1084 (void) close(i); 1085 } 1086 if (c1 >= '~' && c2 >= 'Z') 1087 { 1088 syserr("queuename: Cannot create \"%s\" in \"%s\"", 1089 qf, QueueDir); 1090 exit(EX_OSERR); 1091 } 1092 e->e_id = newstr(&qf[2]); 1093 define('i', e->e_id, e); 1094 if (tTd(7, 1)) 1095 printf("queuename: assigned id %s, env=%x\n", e->e_id, e); 1096 # ifdef LOG 1097 if (LogLevel > 16) 1098 syslog(LOG_DEBUG, "%s: assigned id", e->e_id); 1099 # endif LOG 1100 } 1101 1102 if (type == '\0') 1103 return (NULL); 1104 (void) sprintf(buf, "%cf%s", type, e->e_id); 1105 if (tTd(7, 2)) 1106 printf("queuename: %s\n", buf); 1107 return (buf); 1108 } 1109 /* 1110 ** UNLOCKQUEUE -- unlock the queue entry for a specified envelope 1111 ** 1112 ** Parameters: 1113 ** e -- the envelope to unlock. 1114 ** 1115 ** Returns: 1116 ** none 1117 ** 1118 ** Side Effects: 1119 ** unlocks the queue for `e'. 1120 */ 1121 1122 unlockqueue(e) 1123 ENVELOPE *e; 1124 { 1125 /* if there is a lock file in the envelope, close it */ 1126 if (e->e_lockfp != NULL) 1127 fclose(e->e_lockfp); 1128 e->e_lockfp = NULL; 1129 1130 /* remove the transcript */ 1131 # ifdef LOG 1132 if (LogLevel > 19) 1133 syslog(LOG_DEBUG, "%s: unlock", e->e_id); 1134 # endif LOG 1135 if (!tTd(51, 4)) 1136 xunlink(queuename(e, 'x')); 1137 1138 } 1139 /* 1140 ** GETCTLUSER -- return controlling user if mailing to prog or file 1141 ** 1142 ** Check for a "|" or "/" at the beginning of the address. If 1143 ** found, return a controlling username. 1144 ** 1145 ** Parameters: 1146 ** a - the address to check out 1147 ** 1148 ** Returns: 1149 ** Either NULL, if we werent mailing to a program or file, 1150 ** or a controlling user name (possibly in getpwuid's 1151 ** static buffer). 1152 ** 1153 ** Side Effects: 1154 ** none. 1155 */ 1156 1157 char * 1158 getctluser(a) 1159 ADDRESS *a; 1160 { 1161 extern ADDRESS *getctladdr(); 1162 struct passwd *pw; 1163 char *retstr; 1164 1165 /* 1166 ** Get unquoted user for file, program or user.name check. 1167 ** N.B. remove this code block to always emit controlling 1168 ** addresses (at the expense of backward compatibility). 1169 */ 1170 1171 { 1172 char buf[MAXNAME]; 1173 (void) strncpy(buf, a->q_paddr, MAXNAME); 1174 buf[MAXNAME-1] = '\0'; 1175 stripquotes(buf, TRUE); 1176 1177 if (buf[0] != '|' && buf[0] != '/') 1178 return((char *)NULL); 1179 } 1180 1181 a = getctladdr(a); /* find controlling address */ 1182 1183 if (a != NULL && a->q_uid != 0 && (pw = getpwuid(a->q_uid)) != NULL) 1184 retstr = pw->pw_name; 1185 else /* use default user */ 1186 retstr = DefUser; 1187 1188 if (tTd(40, 5)) 1189 printf("Set controlling user for `%s' to `%s'\n", 1190 (a == NULL)? "<null>": a->q_paddr, retstr); 1191 1192 return(retstr); 1193 } 1194 /* 1195 ** SETCTLUSER - sets `CtlUser' to controlling user 1196 ** CLRCTLUSER - clears controlling user (no params, nothing returned) 1197 ** 1198 ** These routines manipulate `CtlUser'. 1199 ** 1200 ** Parameters: 1201 ** str - controlling user as passed to setctluser() 1202 ** 1203 ** Returns: 1204 ** None. 1205 ** 1206 ** Side Effects: 1207 ** `CtlUser' is changed. 1208 */ 1209 1210 static char CtlUser[MAXNAME]; 1211 1212 setctluser(str) 1213 register char *str; 1214 { 1215 (void) strncpy(CtlUser, str, MAXNAME); 1216 CtlUser[MAXNAME-1] = '\0'; 1217 } 1218 1219 clrctluser() 1220 { 1221 CtlUser[0] = '\0'; 1222 } 1223 1224 /* 1225 ** SETCTLADDR -- create a controlling address 1226 ** 1227 ** If global variable `CtlUser' is set and we are given a valid 1228 ** address, make that address a controlling address; change the 1229 ** `q_uid', `q_gid', and `q_ruser' fields and set QGOODUID. 1230 ** 1231 ** Parameters: 1232 ** a - address for which control uid/gid info may apply 1233 ** 1234 ** Returns: 1235 ** None. 1236 ** 1237 ** Side Effects: 1238 ** Fills in uid/gid fields in address and sets QGOODUID 1239 ** flag if appropriate. 1240 */ 1241 1242 setctladdr(a) 1243 ADDRESS *a; 1244 { 1245 struct passwd *pw; 1246 1247 /* 1248 ** If there is no current controlling user, or we were passed a 1249 ** NULL addr ptr or we already have a controlling user, return. 1250 */ 1251 1252 if (CtlUser[0] == '\0' || a == NULL || a->q_ruser) 1253 return; 1254 1255 /* 1256 ** Set up addr fields for controlling user. If `CtlUser' is no 1257 ** longer valid, use the default user/group. 1258 */ 1259 1260 if ((pw = getpwnam(CtlUser)) != NULL) 1261 { 1262 if (a->q_home) 1263 free(a->q_home); 1264 a->q_home = newstr(pw->pw_dir); 1265 a->q_uid = pw->pw_uid; 1266 a->q_gid = pw->pw_gid; 1267 a->q_ruser = newstr(CtlUser); 1268 } 1269 else 1270 { 1271 a->q_uid = DefUid; 1272 a->q_gid = DefGid; 1273 a->q_ruser = newstr(DefUser); 1274 } 1275 1276 a->q_flags |= QGOODUID; /* flag as a "ctladdr" */ 1277 1278 if (tTd(40, 5)) 1279 printf("Restored controlling user for `%s' to `%s'\n", 1280 a->q_paddr, a->q_ruser); 1281 } 1282