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