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