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