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