122708Sdist /* 234921Sbostic * Copyright (c) 1983 Eric P. Allman 333731Sbostic * Copyright (c) 1988 Regents of the University of California. 433731Sbostic * All rights reserved. 533731Sbostic * 642829Sbostic * %sccs.include.redist.c% 733731Sbostic */ 822708Sdist 933731Sbostic # include "sendmail.h" 1022708Sdist 1133731Sbostic #ifndef lint 1233731Sbostic #ifdef QUEUE 13*58690Seric static char sccsid[] = "@(#)queue.c 6.28 (Berkeley) 03/17/93 (with queueing)"; 1433731Sbostic #else 15*58690Seric static char sccsid[] = "@(#)queue.c 6.28 (Berkeley) 03/17/93 (without queueing)"; 1633731Sbostic #endif 1733731Sbostic #endif /* not lint */ 1833731Sbostic 194632Seric # include <sys/stat.h> 2013707Ssam # include <sys/dir.h> 2157948Seric # include <sys/file.h> 224634Seric # include <signal.h> 234632Seric # include <errno.h> 2440973Sbostic # include <pwd.h> 2557977Seric # ifndef MAXNAMLEN 2657736Seric # include <dirent.h> 2757736Seric # endif 284632Seric 2933731Sbostic # ifdef QUEUE 304632Seric 314632Seric /* 329377Seric ** Work queue. 339377Seric */ 349377Seric 359377Seric struct work 369377Seric { 379377Seric char *w_name; /* name of control file */ 389377Seric long w_pri; /* priority of message, see below */ 3925013Seric time_t w_ctime; /* creation time of message */ 409377Seric struct work *w_next; /* next in queue */ 419377Seric }; 429377Seric 439377Seric typedef struct work WORK; 449377Seric 459377Seric WORK *WorkQ; /* queue of things to be done */ 469377Seric /* 474632Seric ** QUEUEUP -- queue a message up for future transmission. 484632Seric ** 494632Seric ** Parameters: 506980Seric ** e -- the envelope to queue up. 516999Seric ** queueall -- if TRUE, queue all addresses, rather than 526999Seric ** just those with the QQUEUEUP flag set. 539377Seric ** announce -- if TRUE, tell when you are queueing up. 544632Seric ** 554632Seric ** Returns: 5651920Seric ** none. 574632Seric ** 584632Seric ** Side Effects: 599377Seric ** The current request are saved in a control file. 6051920Seric ** The queue file is left locked. 614632Seric */ 624632Seric 639377Seric queueup(e, queueall, announce) 646980Seric register ENVELOPE *e; 656999Seric bool queueall; 669377Seric bool announce; 674632Seric { 687812Seric char *qf; 697812Seric register FILE *tfp; 704632Seric register HDR *h; 715007Seric register ADDRESS *q; 7251920Seric int fd; 7351920Seric int i; 7451920Seric bool newid; 7553400Seric register char *p; 7610173Seric MAILER nullmailer; 7754974Seric ADDRESS *lastctladdr; 7854975Seric static ADDRESS *nullctladdr = NULL; 7951920Seric char buf[MAXLINE], tf[MAXLINE]; 8053400Seric extern char *macvalue(); 8154974Seric extern ADDRESS *getctladdr(); 824632Seric 835037Seric /* 8454975Seric ** If we don't have nullctladdr, create one 8554975Seric */ 8654975Seric 8754975Seric if (nullctladdr == NULL) 8854975Seric { 8954975Seric nullctladdr = (ADDRESS *) xalloc(sizeof *nullctladdr); 9054975Seric bzero((char *) nullctladdr, sizeof nullctladdr); 9154975Seric } 9254975Seric 9354975Seric /* 9417477Seric ** Create control file. 955037Seric */ 964632Seric 9751920Seric newid = (e->e_id == NULL); 9851920Seric strcpy(tf, queuename(e, 't')); 9951920Seric tfp = e->e_lockfp; 10051920Seric if (tfp == NULL) 10151920Seric newid = FALSE; 10251920Seric if (newid) 10351835Seric { 10451920Seric tfp = e->e_lockfp; 10551920Seric } 10651920Seric else 10751920Seric { 10851920Seric /* get a locked tf file */ 10951920Seric for (i = 100; --i >= 0; ) 11051835Seric { 11158689Seric extern bool lockfile(); 11251937Seric 11351920Seric fd = open(tf, O_CREAT|O_WRONLY|O_EXCL, FileMode); 11451920Seric if (fd < 0) 11551835Seric { 11651920Seric if (errno == EEXIST) 11751920Seric continue; 118*58690Seric syserr("!queueup: cannot create temp file %s", tf); 11941636Srick } 12058689Seric 12158689Seric if (lockfile(fd, tf, LOCK_EX|LOCK_NB)) 12251920Seric break; 12358689Seric 12451920Seric close(fd); 12541636Srick } 12641636Srick 12751920Seric tfp = fdopen(fd, "w"); 12851920Seric } 1294632Seric 1307677Seric if (tTd(40, 1)) 13117468Seric printf("queueing %s\n", e->e_id); 1324632Seric 1334632Seric /* 1346980Seric ** If there is no data file yet, create one. 1356980Seric */ 1366980Seric 1376980Seric if (e->e_df == NULL) 1386980Seric { 1396980Seric register FILE *dfp; 1409389Seric extern putbody(); 1416980Seric 1427812Seric e->e_df = newstr(queuename(e, 'd')); 14340934Srick fd = open(e->e_df, O_WRONLY|O_CREAT, FileMode); 14440934Srick if (fd < 0) 145*58690Seric syserr("!queueup: cannot create %s", e->e_df); 14640934Srick dfp = fdopen(fd, "w"); 14710173Seric (*e->e_putbody)(dfp, ProgMailer, e); 14858680Seric (void) xfclose(dfp, "queueup dfp", e->e_id); 1499389Seric e->e_putbody = putbody; 1506980Seric } 1516980Seric 1526980Seric /* 1534632Seric ** Output future work requests. 15425687Seric ** Priority and creation time should be first, since 15525687Seric ** they are required by orderq. 1564632Seric */ 1574632Seric 1589377Seric /* output message priority */ 1599377Seric fprintf(tfp, "P%ld\n", e->e_msgpriority); 1609377Seric 1619630Seric /* output creation time */ 1629630Seric fprintf(tfp, "T%ld\n", e->e_ctime); 1639630Seric 1644632Seric /* output name of data file */ 1657812Seric fprintf(tfp, "D%s\n", e->e_df); 1664632Seric 16710108Seric /* message from envelope, if it exists */ 16810108Seric if (e->e_message != NULL) 16910108Seric fprintf(tfp, "M%s\n", e->e_message); 17010108Seric 17153400Seric /* $r and $s macro values */ 17253400Seric if ((p = macvalue('r', e)) != NULL) 17353400Seric fprintf(tfp, "$r%s\n", p); 17453400Seric if ((p = macvalue('s', e)) != NULL) 17553400Seric fprintf(tfp, "$s%s\n", p); 17653400Seric 1774632Seric /* output name of sender */ 1787812Seric fprintf(tfp, "S%s\n", e->e_from.q_paddr); 1794632Seric 18055360Seric /* output list of error recipients */ 18155360Seric lastctladdr = NULL; 18255360Seric for (q = e->e_errorqueue; q != NULL; q = q->q_next) 18355360Seric { 18458680Seric if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 18555360Seric { 18655360Seric ADDRESS *ctladdr; 18755360Seric 18855360Seric ctladdr = getctladdr(q); 18955360Seric if (ctladdr == NULL && q->q_alias != NULL) 19055360Seric ctladdr = nullctladdr; 19155360Seric if (ctladdr != lastctladdr) 19255360Seric { 19355360Seric printctladdr(ctladdr, tfp); 19455360Seric lastctladdr = ctladdr; 19555360Seric } 19655360Seric fprintf(tfp, "E%s\n", q->q_paddr); 19755360Seric } 19855360Seric } 19955360Seric 2004632Seric /* output list of recipient addresses */ 2016980Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 2024632Seric { 20358250Seric if (bitset(QQUEUEUP, q->q_flags) || 20458680Seric (queueall && !bitset(QDONTSEND|QBADADDR|QSENT, q->q_flags))) 2058245Seric { 20654974Seric ADDRESS *ctladdr; 20740973Sbostic 20854975Seric ctladdr = getctladdr(q); 20954975Seric if (ctladdr == NULL && q->q_alias != NULL) 21054975Seric ctladdr = nullctladdr; 21154975Seric if (ctladdr != lastctladdr) 21254974Seric { 21354974Seric printctladdr(ctladdr, tfp); 21454974Seric lastctladdr = ctladdr; 21554974Seric } 2167812Seric fprintf(tfp, "R%s\n", q->q_paddr); 2179377Seric if (announce) 2189377Seric { 2199377Seric e->e_to = q->q_paddr; 22058151Seric message("queued"); 22158020Seric if (LogLevel > 8) 22258337Seric logdelivery(NULL, NULL, "queued", e); 2239377Seric e->e_to = NULL; 2249377Seric } 2259387Seric if (tTd(40, 1)) 2269387Seric { 2279387Seric printf("queueing "); 2289387Seric printaddr(q, FALSE); 2299387Seric } 2308245Seric } 2314632Seric } 2324632Seric 2339377Seric /* 2349377Seric ** Output headers for this message. 2359377Seric ** Expand macros completely here. Queue run will deal with 2369377Seric ** everything as absolute headers. 2379377Seric ** All headers that must be relative to the recipient 2389377Seric ** can be cracked later. 23910173Seric ** We set up a "null mailer" -- i.e., a mailer that will have 24010173Seric ** no effect on the addresses as they are output. 2419377Seric */ 2429377Seric 24310686Seric bzero((char *) &nullmailer, sizeof nullmailer); 24458020Seric nullmailer.m_re_rwset = nullmailer.m_rh_rwset = 24558020Seric nullmailer.m_se_rwset = nullmailer.m_sh_rwset = -1; 24610349Seric nullmailer.m_eol = "\n"; 24710173Seric 24858050Seric define('g', "\201f", e); 2496980Seric for (h = e->e_header; h != NULL; h = h->h_link) 2504632Seric { 25110686Seric extern bool bitzerop(); 25210686Seric 25312015Seric /* don't output null headers */ 2544632Seric if (h->h_value == NULL || h->h_value[0] == '\0') 2554632Seric continue; 25612015Seric 25712015Seric /* don't output resent headers on non-resent messages */ 25812015Seric if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags)) 25912015Seric continue; 26012015Seric 26112015Seric /* output this header */ 2627812Seric fprintf(tfp, "H"); 26312015Seric 26412015Seric /* if conditional, output the set of conditions */ 26510686Seric if (!bitzerop(h->h_mflags) && bitset(H_CHECK|H_ACHECK, h->h_flags)) 26610686Seric { 26710686Seric int j; 26810686Seric 26923098Seric (void) putc('?', tfp); 27010686Seric for (j = '\0'; j <= '\177'; j++) 27110686Seric if (bitnset(j, h->h_mflags)) 27223098Seric (void) putc(j, tfp); 27323098Seric (void) putc('?', tfp); 27410686Seric } 27512015Seric 27612015Seric /* output the header: expand macros, convert addresses */ 2777763Seric if (bitset(H_DEFAULT, h->h_flags)) 2787763Seric { 2797763Seric (void) expand(h->h_value, buf, &buf[sizeof buf], e); 2808236Seric fprintf(tfp, "%s: %s\n", h->h_field, buf); 2817763Seric } 2828245Seric else if (bitset(H_FROM|H_RCPT, h->h_flags)) 2839348Seric { 28455012Seric commaize(h, h->h_value, tfp, 28555012Seric bitset(EF_OLDSTYLE, e->e_flags), 28655012Seric &nullmailer, e); 2879348Seric } 2887763Seric else 2898245Seric fprintf(tfp, "%s: %s\n", h->h_field, h->h_value); 2904632Seric } 2914632Seric 2924632Seric /* 2934632Seric ** Clean up. 2944632Seric */ 2954632Seric 29651920Seric if (!newid) 29751920Seric { 29851920Seric qf = queuename(e, 'q'); 29951920Seric if (rename(tf, qf) < 0) 30051920Seric syserr("cannot rename(%s, %s), df=%s", tf, qf, e->e_df); 30151920Seric if (e->e_lockfp != NULL) 30258680Seric (void) xfclose(e->e_lockfp, "queueup lockfp", e->e_id); 30351920Seric e->e_lockfp = tfp; 30451920Seric } 30551920Seric else 30651920Seric qf = tf; 30741636Srick errno = 0; 3087391Seric 3097677Seric # ifdef LOG 3107677Seric /* save log info */ 31158020Seric if (LogLevel > 79) 3127878Seric syslog(LOG_DEBUG, "%s: queueup, qf=%s, df=%s\n", e->e_id, qf, e->e_df); 31356795Seric # endif /* LOG */ 31440934Srick fflush(tfp); 31551920Seric return; 3164632Seric } 31754974Seric 31854974Seric printctladdr(a, tfp) 31954974Seric ADDRESS *a; 32054974Seric FILE *tfp; 32154974Seric { 32254974Seric char *u; 32354974Seric struct passwd *pw; 32454974Seric extern struct passwd *getpwuid(); 32554974Seric 32654974Seric if (a == NULL) 32754974Seric { 32854974Seric fprintf(tfp, "C\n"); 32954974Seric return; 33054974Seric } 33154974Seric if (a->q_uid == 0 || (pw = getpwuid(a->q_uid)) == NULL) 33254974Seric u = DefUser; 33354974Seric else 33454974Seric u = pw->pw_name; 33554974Seric fprintf(tfp, "C%s\n", u); 33654974Seric } 33754974Seric 3384632Seric /* 3394632Seric ** RUNQUEUE -- run the jobs in the queue. 3404632Seric ** 3414632Seric ** Gets the stuff out of the queue in some presumably logical 3424632Seric ** order and processes them. 3434632Seric ** 3444632Seric ** Parameters: 34524941Seric ** forkflag -- TRUE if the queue scanning should be done in 34624941Seric ** a child process. We double-fork so it is not our 34724941Seric ** child and we don't have to clean up after it. 3484632Seric ** 3494632Seric ** Returns: 3504632Seric ** none. 3514632Seric ** 3524632Seric ** Side Effects: 3534632Seric ** runs things in the mail queue. 3544632Seric */ 3554632Seric 35655360Seric ENVELOPE QueueEnvelope; /* the queue run envelope */ 35755360Seric 35855360Seric runqueue(forkflag) 3594639Seric bool forkflag; 3604632Seric { 36124953Seric extern bool shouldqueue(); 36255360Seric register ENVELOPE *e; 36355360Seric extern ENVELOPE BlankEnvelope; 36455360Seric extern ENVELOPE *newenvelope(); 36524953Seric 3667466Seric /* 36724953Seric ** If no work will ever be selected, don't even bother reading 36824953Seric ** the queue. 36924953Seric */ 37024953Seric 37151920Seric CurrentLA = getla(); /* get load average */ 37240934Srick 37358132Seric if (shouldqueue(0L, curtime())) 37424953Seric { 37524953Seric if (Verbose) 37624953Seric printf("Skipping queue run -- load average too high\n"); 37758107Seric if (forkflag && QueueIntvl != 0) 37858107Seric (void) setevent(QueueIntvl, runqueue, TRUE); 37955360Seric return; 38024953Seric } 38124953Seric 38224953Seric /* 3837466Seric ** See if we want to go off and do other useful work. 3847466Seric */ 3854639Seric 3864639Seric if (forkflag) 3874639Seric { 3887943Seric int pid; 3897943Seric 3907943Seric pid = dofork(); 3917943Seric if (pid != 0) 3924639Seric { 39346928Sbostic extern void reapchild(); 39425184Seric 3957943Seric /* parent -- pick up intermediate zombie */ 39625184Seric #ifndef SIGCHLD 3979377Seric (void) waitfor(pid); 39856795Seric #else /* SIGCHLD */ 39925184Seric (void) signal(SIGCHLD, reapchild); 40056795Seric #endif /* SIGCHLD */ 4017690Seric if (QueueIntvl != 0) 4029348Seric (void) setevent(QueueIntvl, runqueue, TRUE); 4034639Seric return; 4044639Seric } 4057943Seric /* child -- double fork */ 40625184Seric #ifndef SIGCHLD 4077943Seric if (fork() != 0) 4087943Seric exit(EX_OK); 40956795Seric #else /* SIGCHLD */ 41025184Seric (void) signal(SIGCHLD, SIG_DFL); 41156795Seric #endif /* SIGCHLD */ 4124639Seric } 41324941Seric 41440934Srick setproctitle("running queue: %s", QueueDir); 41524941Seric 4167876Seric # ifdef LOG 41758020Seric if (LogLevel > 69) 41855360Seric syslog(LOG_DEBUG, "runqueue %s, pid=%d, forkflag=%d", 41955360Seric QueueDir, getpid(), forkflag); 42056795Seric # endif /* LOG */ 4214639Seric 4227466Seric /* 42310205Seric ** Release any resources used by the daemon code. 42410205Seric */ 42510205Seric 42610205Seric # ifdef DAEMON 42710205Seric clrdaemon(); 42856795Seric # endif /* DAEMON */ 42910205Seric 43010205Seric /* 43155360Seric ** Create ourselves an envelope 43255360Seric */ 43355360Seric 43455360Seric CurEnv = &QueueEnvelope; 43558179Seric e = newenvelope(&QueueEnvelope, CurEnv); 43655360Seric e->e_flags = BlankEnvelope.e_flags; 43755360Seric 43855360Seric /* 43927175Seric ** Make sure the alias database is open. 44027175Seric */ 44127175Seric 44255012Seric initaliases(AliasFile, FALSE, e); 44327175Seric 44427175Seric /* 4457466Seric ** Start making passes through the queue. 4467466Seric ** First, read and sort the entire queue. 4477466Seric ** Then, process the work in that order. 4487466Seric ** But if you take too long, start over. 4497466Seric */ 4507466Seric 4517943Seric /* order the existing work requests */ 45224954Seric (void) orderq(FALSE); 4537690Seric 4547943Seric /* process them once at a time */ 4557943Seric while (WorkQ != NULL) 4564639Seric { 4577943Seric WORK *w = WorkQ; 4587881Seric 4597943Seric WorkQ = WorkQ->w_next; 46055012Seric dowork(w, e); 4617943Seric free(w->w_name); 4627943Seric free((char *) w); 4634639Seric } 46429866Seric 46529866Seric /* exit without the usual cleanup */ 46655467Seric e->e_id = NULL; 46755467Seric finis(); 4684634Seric } 4694634Seric /* 4704632Seric ** ORDERQ -- order the work queue. 4714632Seric ** 4724632Seric ** Parameters: 47324941Seric ** doall -- if set, include everything in the queue (even 47424941Seric ** the jobs that cannot be run because the load 47524941Seric ** average is too high). Otherwise, exclude those 47624941Seric ** jobs. 4774632Seric ** 4784632Seric ** Returns: 47910121Seric ** The number of request in the queue (not necessarily 48010121Seric ** the number of requests in WorkQ however). 4814632Seric ** 4824632Seric ** Side Effects: 4834632Seric ** Sets WorkQ to the queue of available work, in order. 4844632Seric */ 4854632Seric 48625687Seric # define NEED_P 001 48725687Seric # define NEED_T 002 48858318Seric # define NEED_R 004 48958318Seric # define NEED_S 010 4904632Seric 49124941Seric orderq(doall) 49224941Seric bool doall; 4934632Seric { 4946625Sglickman register struct direct *d; 4954632Seric register WORK *w; 4966625Sglickman DIR *f; 4974632Seric register int i; 49825687Seric WORK wlist[QUEUESIZE+1]; 49910070Seric int wn = -1; 5004632Seric extern workcmpf(); 5014632Seric 50258318Seric if (tTd(41, 1)) 50358318Seric { 50458318Seric printf("orderq:\n"); 50558318Seric if (QueueLimitId != NULL) 50658318Seric printf("\tQueueLimitId = %s\n", QueueLimitId); 50758318Seric if (QueueLimitSender != NULL) 50858318Seric printf("\tQueueLimitSender = %s\n", QueueLimitSender); 50958318Seric if (QueueLimitRecipient != NULL) 51058318Seric printf("\tQueueLimitRecipient = %s\n", QueueLimitRecipient); 51158318Seric } 51258318Seric 5134632Seric /* clear out old WorkQ */ 5144632Seric for (w = WorkQ; w != NULL; ) 5154632Seric { 5164632Seric register WORK *nw = w->w_next; 5174632Seric 5184632Seric WorkQ = nw; 5194632Seric free(w->w_name); 5204632Seric free((char *) w); 5214632Seric w = nw; 5224632Seric } 5234632Seric 5244632Seric /* open the queue directory */ 5258148Seric f = opendir("."); 5264632Seric if (f == NULL) 5274632Seric { 5288148Seric syserr("orderq: cannot open \"%s\" as \".\"", QueueDir); 52910070Seric return (0); 5304632Seric } 5314632Seric 5324632Seric /* 5334632Seric ** Read the work directory. 5344632Seric */ 5354632Seric 53610070Seric while ((d = readdir(f)) != NULL) 5374632Seric { 5389377Seric FILE *cf; 5394632Seric char lbuf[MAXNAME]; 54057642Seric extern bool shouldqueue(); 54158318Seric extern bool strcontainedin(); 5424632Seric 5434632Seric /* is this an interesting entry? */ 5447812Seric if (d->d_name[0] != 'q' || d->d_name[1] != 'f') 5454632Seric continue; 5464632Seric 54758318Seric if (QueueLimitId != NULL && 54858318Seric !strcontainedin(QueueLimitId, d->d_name)) 54958318Seric continue; 55058318Seric 55158020Seric if (strlen(d->d_name) != 9) 55258020Seric { 55358020Seric if (Verbose) 55458020Seric printf("orderq: bogus qf name %s\n", d->d_name); 55558020Seric #ifdef LOG 55658020Seric if (LogLevel > 3) 55758020Seric syslog(LOG_NOTICE, "orderq: bogus qf name %s", 55858020Seric d->d_name); 55958020Seric #endif 56058020Seric if (strlen(d->d_name) >= MAXNAME) 56158020Seric d->d_name[MAXNAME - 1] = '\0'; 56258020Seric strcpy(lbuf, d->d_name); 56358020Seric lbuf[0] = 'Q'; 56458020Seric (void) rename(d->d_name, lbuf); 56558020Seric continue; 56658020Seric } 56758020Seric 56810070Seric /* yes -- open control file (if not too many files) */ 56925687Seric if (++wn >= QUEUESIZE) 57010070Seric continue; 57158318Seric 5728148Seric cf = fopen(d->d_name, "r"); 5734632Seric if (cf == NULL) 5744632Seric { 5757055Seric /* this may be some random person sending hir msgs */ 5767055Seric /* syserr("orderq: cannot open %s", cbuf); */ 57710090Seric if (tTd(41, 2)) 57810090Seric printf("orderq: cannot open %s (%d)\n", 57910090Seric d->d_name, errno); 5807055Seric errno = 0; 58110090Seric wn--; 5824632Seric continue; 5834632Seric } 58425687Seric w = &wlist[wn]; 58525687Seric w->w_name = newstr(d->d_name); 5864632Seric 58725027Seric /* make sure jobs in creation don't clog queue */ 58825687Seric w->w_pri = 0x7fffffff; 58925687Seric w->w_ctime = 0; 59025027Seric 5914632Seric /* extract useful information */ 59225687Seric i = NEED_P | NEED_T; 59358318Seric if (QueueLimitSender != NULL) 59458318Seric i |= NEED_S; 59558318Seric if (QueueLimitRecipient != NULL) 59658318Seric i |= NEED_R; 59725687Seric while (i != 0 && fgets(lbuf, sizeof lbuf, cf) != NULL) 5984632Seric { 59924954Seric extern long atol(); 60058318Seric extern bool strcontainedin(); 60124954Seric 60224941Seric switch (lbuf[0]) 6034632Seric { 60424941Seric case 'P': 60525687Seric w->w_pri = atol(&lbuf[1]); 60625687Seric i &= ~NEED_P; 6074632Seric break; 60825013Seric 60925013Seric case 'T': 61025687Seric w->w_ctime = atol(&lbuf[1]); 61125687Seric i &= ~NEED_T; 61225013Seric break; 61358318Seric 61458318Seric case 'R': 61558318Seric if (QueueLimitRecipient != NULL && 61658318Seric strcontainedin(QueueLimitRecipient, &lbuf[1])) 61758318Seric i &= ~NEED_R; 61858318Seric break; 61958318Seric 62058318Seric case 'S': 62158318Seric if (QueueLimitSender != NULL && 62258318Seric strcontainedin(QueueLimitSender, &lbuf[1])) 62358318Seric i &= ~NEED_S; 62458318Seric break; 6254632Seric } 6264632Seric } 6274632Seric (void) fclose(cf); 62824953Seric 62958318Seric if ((!doall && shouldqueue(w->w_pri, w->w_ctime)) || 63058318Seric bitset(NEED_R|NEED_S, i)) 63124953Seric { 63224953Seric /* don't even bother sorting this job in */ 63324953Seric wn--; 63424953Seric } 6354632Seric } 6366625Sglickman (void) closedir(f); 63710090Seric wn++; 6384632Seric 6394632Seric /* 6404632Seric ** Sort the work directory. 6414632Seric */ 6424632Seric 64325687Seric qsort((char *) wlist, min(wn, QUEUESIZE), sizeof *wlist, workcmpf); 6444632Seric 6454632Seric /* 6464632Seric ** Convert the work list into canonical form. 6479377Seric ** Should be turning it into a list of envelopes here perhaps. 6484632Seric */ 6494632Seric 65024981Seric WorkQ = NULL; 65125687Seric for (i = min(wn, QUEUESIZE); --i >= 0; ) 6524632Seric { 6534632Seric w = (WORK *) xalloc(sizeof *w); 6544632Seric w->w_name = wlist[i].w_name; 6554632Seric w->w_pri = wlist[i].w_pri; 65625013Seric w->w_ctime = wlist[i].w_ctime; 65724981Seric w->w_next = WorkQ; 65824981Seric WorkQ = w; 6594632Seric } 6604632Seric 6617677Seric if (tTd(40, 1)) 6624632Seric { 6634632Seric for (w = WorkQ; w != NULL; w = w->w_next) 6645037Seric printf("%32s: pri=%ld\n", w->w_name, w->w_pri); 6654632Seric } 66610070Seric 66710090Seric return (wn); 6684632Seric } 6694632Seric /* 6707677Seric ** WORKCMPF -- compare function for ordering work. 6714632Seric ** 6724632Seric ** Parameters: 6734632Seric ** a -- the first argument. 6744632Seric ** b -- the second argument. 6754632Seric ** 6764632Seric ** Returns: 67724981Seric ** -1 if a < b 67824981Seric ** 0 if a == b 67924981Seric ** +1 if a > b 6804632Seric ** 6814632Seric ** Side Effects: 6824632Seric ** none. 6834632Seric */ 6844632Seric 6854632Seric workcmpf(a, b) 6865037Seric register WORK *a; 6875037Seric register WORK *b; 6884632Seric { 68957438Seric long pa = a->w_pri; 69057438Seric long pb = b->w_pri; 69124941Seric 69224941Seric if (pa == pb) 6934632Seric return (0); 69424941Seric else if (pa > pb) 69524981Seric return (1); 69624981Seric else 69710121Seric return (-1); 6984632Seric } 6994632Seric /* 7004632Seric ** DOWORK -- do a work request. 7014632Seric ** 7024632Seric ** Parameters: 7034632Seric ** w -- the work request to be satisfied. 7044632Seric ** 7054632Seric ** Returns: 7064632Seric ** none. 7074632Seric ** 7084632Seric ** Side Effects: 7094632Seric ** The work request is satisfied if possible. 7104632Seric */ 7114632Seric 71255012Seric dowork(w, e) 7134632Seric register WORK *w; 71455012Seric register ENVELOPE *e; 7154632Seric { 7164632Seric register int i; 71724941Seric extern bool shouldqueue(); 71851920Seric extern bool readqf(); 7194632Seric 7207677Seric if (tTd(40, 1)) 7215037Seric printf("dowork: %s pri %ld\n", w->w_name, w->w_pri); 7224632Seric 7234632Seric /* 72424941Seric ** Ignore jobs that are too expensive for the moment. 7254632Seric */ 7264632Seric 72757438Seric if (shouldqueue(w->w_pri, w->w_ctime)) 7284632Seric { 72924941Seric if (Verbose) 73024967Seric printf("\nSkipping %s\n", w->w_name + 2); 7314632Seric return; 7324632Seric } 7334632Seric 73424941Seric /* 73524941Seric ** Fork for work. 73624941Seric */ 73724941Seric 73824941Seric if (ForkQueueRuns) 73924941Seric { 74024941Seric i = fork(); 74124941Seric if (i < 0) 74224941Seric { 74324941Seric syserr("dowork: cannot fork"); 74424941Seric return; 74524941Seric } 74624941Seric } 74724941Seric else 74824941Seric { 74924941Seric i = 0; 75024941Seric } 75124941Seric 7524632Seric if (i == 0) 7534632Seric { 7544632Seric /* 7554632Seric ** CHILD 7568148Seric ** Lock the control file to avoid duplicate deliveries. 7578148Seric ** Then run the file as though we had just read it. 7587350Seric ** We save an idea of the temporary name so we 7597350Seric ** can recover on interrupt. 7604632Seric */ 7614632Seric 7627763Seric /* set basic modes, etc. */ 7637356Seric (void) alarm(0); 76455012Seric clearenvelope(e, FALSE); 7654632Seric QueueRun = TRUE; 7669377Seric ErrorMode = EM_MAIL; 76755012Seric e->e_id = &w->w_name[2]; 7687876Seric # ifdef LOG 76958020Seric if (LogLevel > 76) 77055012Seric syslog(LOG_DEBUG, "%s: dowork, pid=%d", e->e_id, 7717881Seric getpid()); 77256795Seric # endif /* LOG */ 7737763Seric 7747763Seric /* don't use the headers from sendmail.cf... */ 77555012Seric e->e_header = NULL; 7767763Seric 77751920Seric /* read the queue control file -- return if locked */ 77855012Seric if (!readqf(e)) 7796980Seric { 78024941Seric if (ForkQueueRuns) 78124941Seric exit(EX_OK); 78224941Seric else 78324941Seric return; 7846980Seric } 7856980Seric 78655012Seric e->e_flags |= EF_INQUEUE; 78757642Seric eatheader(e, TRUE); 7886980Seric 7896980Seric /* do the delivery */ 79055012Seric if (!bitset(EF_FATALERRS, e->e_flags)) 79155012Seric sendall(e, SM_DELIVER); 7926980Seric 7936980Seric /* finish up and exit */ 79424941Seric if (ForkQueueRuns) 79524941Seric finis(); 79624941Seric else 79755012Seric dropenvelope(e); 7984632Seric } 79924941Seric else 80024941Seric { 80124941Seric /* 80224941Seric ** Parent -- pick up results. 80324941Seric */ 8044632Seric 80524941Seric errno = 0; 80624941Seric (void) waitfor(i); 80724941Seric } 8084632Seric } 8094632Seric /* 8104632Seric ** READQF -- read queue file and set up environment. 8114632Seric ** 8124632Seric ** Parameters: 8139377Seric ** e -- the envelope of the job to run. 8144632Seric ** 8154632Seric ** Returns: 81651920Seric ** TRUE if it successfully read the queue file. 81751920Seric ** FALSE otherwise. 8184632Seric ** 8194632Seric ** Side Effects: 82051920Seric ** The queue file is returned locked. 8214632Seric */ 8224632Seric 82351920Seric bool 82451920Seric readqf(e) 8259377Seric register ENVELOPE *e; 8264632Seric { 82717477Seric char *qf; 82817477Seric register FILE *qfp; 82954974Seric ADDRESS *ctladdr; 83056400Seric struct stat st; 83157135Seric char *bp; 83257135Seric char buf[MAXLINE]; 8339348Seric extern char *fgetfolded(); 83424954Seric extern long atol(); 83554974Seric extern ADDRESS *setctluser(); 83658689Seric extern bool lockfile(); 8374632Seric 8384632Seric /* 83917468Seric ** Read and process the file. 8404632Seric */ 8414632Seric 84217477Seric qf = queuename(e, 'q'); 84351937Seric qfp = fopen(qf, "r+"); 84417477Seric if (qfp == NULL) 84517477Seric { 84640934Srick if (errno != ENOENT) 84740934Srick syserr("readqf: no control file %s", qf); 84851920Seric return FALSE; 84917477Seric } 85040934Srick 85156400Seric /* 85256400Seric ** Check the queue file for plausibility to avoid attacks. 85356400Seric */ 85456400Seric 85556400Seric if (fstat(fileno(qfp), &st) < 0) 85656400Seric { 85756400Seric /* must have been being processed by someone else */ 85856400Seric fclose(qfp); 85956400Seric return FALSE; 86056400Seric } 86156400Seric 86257135Seric if (st.st_uid != geteuid() || (st.st_mode & 07777) != FileMode) 86356400Seric { 86456400Seric # ifdef LOG 86556400Seric if (LogLevel > 0) 86656400Seric { 86756400Seric syslog(LOG_ALERT, "%s: bogus queue file, uid=%d, mode=%o", 86856400Seric e->e_id, st.st_uid, st.st_mode); 86956400Seric } 87056795Seric # endif /* LOG */ 87156400Seric fclose(qfp); 87256400Seric return FALSE; 87356400Seric } 87456400Seric 87558689Seric if (!lockfile(fileno(qfp), qf, LOCK_EX|LOCK_NB)) 87640934Srick { 87758689Seric /* being processed by another queuer */ 87858689Seric if (Verbose) 87958689Seric printf("%s: locked\n", e->e_id); 88051920Seric # ifdef LOG 88158689Seric if (LogLevel > 19) 88258689Seric syslog(LOG_DEBUG, "%s: locked", e->e_id); 88356795Seric # endif /* LOG */ 88440934Srick (void) fclose(qfp); 88551920Seric return FALSE; 88640934Srick } 88740934Srick 88851920Seric /* save this lock */ 88951920Seric e->e_lockfp = qfp; 89051920Seric 89140934Srick /* do basic system initialization */ 89255012Seric initsys(e); 89340934Srick 89417477Seric FileName = qf; 8959377Seric LineNumber = 0; 89651920Seric if (Verbose) 8979377Seric printf("\nRunning %s\n", e->e_id); 89854974Seric ctladdr = NULL; 89957135Seric while ((bp = fgetfolded(buf, sizeof buf, qfp)) != NULL) 9004632Seric { 90157529Seric struct stat st; 90257529Seric 90326504Seric if (tTd(40, 4)) 90457135Seric printf("+++++ %s\n", bp); 90557135Seric switch (bp[0]) 9064632Seric { 90740973Sbostic case 'C': /* specify controlling user */ 90857135Seric ctladdr = setctluser(&bp[1]); 90940973Sbostic break; 91040973Sbostic 9114632Seric case 'R': /* specify recipient */ 91258082Seric (void) sendtolist(&bp[1], ctladdr, &e->e_sendqueue, e); 9134632Seric break; 9144632Seric 91525687Seric case 'E': /* specify error recipient */ 91658082Seric (void) sendtolist(&bp[1], ctladdr, &e->e_errorqueue, e); 91725687Seric break; 91825687Seric 9194632Seric case 'H': /* header */ 92057135Seric (void) chompheader(&bp[1], FALSE, e); 9214632Seric break; 9224632Seric 92310108Seric case 'M': /* message */ 92457135Seric e->e_message = newstr(&bp[1]); 92510108Seric break; 92610108Seric 9274632Seric case 'S': /* sender */ 92858333Seric setsender(newstr(&bp[1]), e, NULL); 9294632Seric break; 9304632Seric 9314632Seric case 'D': /* data file name */ 93257135Seric e->e_df = newstr(&bp[1]); 9339544Seric e->e_dfp = fopen(e->e_df, "r"); 9349544Seric if (e->e_dfp == NULL) 93558020Seric { 9369377Seric syserr("readqf: cannot open %s", e->e_df); 93758020Seric e->e_msgsize = -1; 93858020Seric } 93958020Seric else if (fstat(fileno(e->e_dfp), &st) >= 0) 94057529Seric e->e_msgsize = st.st_size; 9414632Seric break; 9424632Seric 9437860Seric case 'T': /* init time */ 94457135Seric e->e_ctime = atol(&bp[1]); 9454632Seric break; 9464632Seric 9474634Seric case 'P': /* message priority */ 94857135Seric e->e_msgpriority = atol(&bp[1]) + WkTimeFact; 9494634Seric break; 9504634Seric 95153400Seric case '$': /* define macro */ 95257135Seric define(bp[1], newstr(&bp[2]), e); 95353400Seric break; 95453400Seric 95524941Seric case '\0': /* blank line; ignore */ 95624941Seric break; 95724941Seric 9584632Seric default: 95924941Seric syserr("readqf(%s:%d): bad line \"%s\"", e->e_id, 96057135Seric LineNumber, bp); 9614632Seric break; 9624632Seric } 96357135Seric 96457135Seric if (bp != buf) 96557135Seric free(bp); 9664632Seric } 9679377Seric 9689377Seric FileName = NULL; 96924941Seric 97024941Seric /* 97124941Seric ** If we haven't read any lines, this queue file is empty. 97224941Seric ** Arrange to remove it without referencing any null pointers. 97324941Seric */ 97424941Seric 97524941Seric if (LineNumber == 0) 97624941Seric { 97724941Seric errno = 0; 97824941Seric e->e_flags |= EF_CLRQUEUE | EF_FATALERRS | EF_RESPONSE; 97924941Seric } 98051920Seric return TRUE; 9814632Seric } 9824632Seric /* 9839630Seric ** PRINTQUEUE -- print out a representation of the mail queue 9849630Seric ** 9859630Seric ** Parameters: 9869630Seric ** none. 9879630Seric ** 9889630Seric ** Returns: 9899630Seric ** none. 9909630Seric ** 9919630Seric ** Side Effects: 9929630Seric ** Prints a listing of the mail queue on the standard output. 9939630Seric */ 9945182Seric 9959630Seric printqueue() 9969630Seric { 9979630Seric register WORK *w; 9989630Seric FILE *f; 99910070Seric int nrequests; 10009630Seric char buf[MAXLINE]; 10019630Seric 10029630Seric /* 100358250Seric ** Check for permission to print the queue 100458250Seric */ 100558250Seric 100658523Seric if (bitset(PRIV_RESTRMAILQ, PrivacyFlags) && getuid() != 0) 100758250Seric { 100858250Seric struct stat st; 100958523Seric # ifdef NGROUPS 101058523Seric int n; 101158523Seric int gidset[NGROUPS]; 101258523Seric # endif 101358250Seric 101458517Seric if (stat(QueueDir, &st) < 0) 101558250Seric { 101658250Seric syserr("Cannot stat %s", QueueDir); 101758250Seric return; 101858250Seric } 101958523Seric # ifdef NGROUPS 102058523Seric n = getgroups(NGROUPS, gidset); 102158523Seric while (--n >= 0) 102258523Seric { 102358523Seric if (gidset[n] == st.st_gid) 102458523Seric break; 102558523Seric } 102658523Seric if (n < 0) 102758523Seric # else 102858250Seric if (getgid() != st.st_gid) 102958523Seric # endif 103058250Seric { 103158250Seric usrerr("510 You are not permitted to see the queue"); 103258250Seric setstat(EX_NOPERM); 103358250Seric return; 103458250Seric } 103558250Seric } 103658250Seric 103758250Seric /* 10389630Seric ** Read and order the queue. 10399630Seric */ 10409630Seric 104124941Seric nrequests = orderq(TRUE); 10429630Seric 10439630Seric /* 10449630Seric ** Print the work list that we have read. 10459630Seric */ 10469630Seric 10479630Seric /* first see if there is anything */ 104810070Seric if (nrequests <= 0) 10499630Seric { 105010070Seric printf("Mail queue is empty\n"); 10519630Seric return; 10529630Seric } 10539630Seric 105451920Seric CurrentLA = getla(); /* get load average */ 105540934Srick 105610096Seric printf("\t\tMail Queue (%d request%s", nrequests, nrequests == 1 ? "" : "s"); 105725687Seric if (nrequests > QUEUESIZE) 105825687Seric printf(", only %d printed", QUEUESIZE); 105924979Seric if (Verbose) 106025032Seric printf(")\n--QID-- --Size-- -Priority- ---Q-Time--- -----------Sender/Recipient-----------\n"); 106124979Seric else 106224979Seric printf(")\n--QID-- --Size-- -----Q-Time----- ------------Sender/Recipient------------\n"); 10639630Seric for (w = WorkQ; w != NULL; w = w->w_next) 10649630Seric { 10659630Seric struct stat st; 106610070Seric auto time_t submittime = 0; 106710070Seric long dfsize = -1; 106810108Seric char message[MAXLINE]; 106924941Seric extern bool shouldqueue(); 107058689Seric extern bool lockfile(); 10719630Seric 107217468Seric f = fopen(w->w_name, "r"); 107317468Seric if (f == NULL) 107417468Seric { 107517468Seric errno = 0; 107617468Seric continue; 107717468Seric } 10789630Seric printf("%7s", w->w_name + 2); 107958689Seric if (!lockfile(fileno(f), w->w_name, LOCK_SH|LOCK_NB)) 108010070Seric printf("*"); 108157438Seric else if (shouldqueue(w->w_pri, w->w_ctime)) 108224941Seric printf("X"); 108310070Seric else 108410070Seric printf(" "); 108510070Seric errno = 0; 108617468Seric 108710108Seric message[0] = '\0'; 10889630Seric while (fgets(buf, sizeof buf, f) != NULL) 10899630Seric { 109053400Seric register int i; 109153400Seric 10929630Seric fixcrlf(buf, TRUE); 10939630Seric switch (buf[0]) 10949630Seric { 109510108Seric case 'M': /* error message */ 109653400Seric if ((i = strlen(&buf[1])) >= sizeof message) 109753400Seric i = sizeof message; 109853400Seric bcopy(&buf[1], message, i); 109953400Seric message[i] = '\0'; 110010108Seric break; 110110108Seric 11029630Seric case 'S': /* sender name */ 110324979Seric if (Verbose) 110425027Seric printf("%8ld %10ld %.12s %.38s", dfsize, 110525027Seric w->w_pri, ctime(&submittime) + 4, 110624979Seric &buf[1]); 110724979Seric else 110824979Seric printf("%8ld %.16s %.45s", dfsize, 110924979Seric ctime(&submittime), &buf[1]); 111010108Seric if (message[0] != '\0') 111125027Seric printf("\n\t\t (%.60s)", message); 11129630Seric break; 111351920Seric 111440973Sbostic case 'C': /* controlling user */ 111554974Seric if (Verbose) 111654975Seric printf("\n\t\t\t\t (---%.34s---)", &buf[1]); 111740973Sbostic break; 11189630Seric 11199630Seric case 'R': /* recipient name */ 112024979Seric if (Verbose) 112125027Seric printf("\n\t\t\t\t\t %.38s", &buf[1]); 112224979Seric else 112324979Seric printf("\n\t\t\t\t %.45s", &buf[1]); 11249630Seric break; 11259630Seric 11269630Seric case 'T': /* creation time */ 112724941Seric submittime = atol(&buf[1]); 11289630Seric break; 112910070Seric 113010070Seric case 'D': /* data file name */ 113110070Seric if (stat(&buf[1], &st) >= 0) 113210070Seric dfsize = st.st_size; 113310070Seric break; 11349630Seric } 11359630Seric } 113610070Seric if (submittime == (time_t) 0) 113710070Seric printf(" (no control file)"); 11389630Seric printf("\n"); 113923098Seric (void) fclose(f); 11409630Seric } 11419630Seric } 11429630Seric 114356795Seric # endif /* QUEUE */ 114417468Seric /* 114517468Seric ** QUEUENAME -- build a file name in the queue directory for this envelope. 114617468Seric ** 114717468Seric ** Assigns an id code if one does not already exist. 114817468Seric ** This code is very careful to avoid trashing existing files 114917468Seric ** under any circumstances. 115017468Seric ** 115117468Seric ** Parameters: 115217468Seric ** e -- envelope to build it in/from. 115317468Seric ** type -- the file type, used as the first character 115417468Seric ** of the file name. 115517468Seric ** 115617468Seric ** Returns: 115717468Seric ** a pointer to the new file name (in a static buffer). 115817468Seric ** 115917468Seric ** Side Effects: 116051920Seric ** If no id code is already assigned, queuename will 116151920Seric ** assign an id code, create a qf file, and leave a 116251920Seric ** locked, open-for-write file pointer in the envelope. 116317468Seric */ 116417468Seric 116517468Seric char * 116617468Seric queuename(e, type) 116717468Seric register ENVELOPE *e; 116817468Seric char type; 116917468Seric { 117017468Seric static int pid = -1; 117158680Seric static char c1 = 'A'; 117258680Seric static char c2 = 'A'; 117358689Seric static char buf[MAXNAME]; 117458689Seric extern bool lockfile(); 117517468Seric 117617468Seric if (e->e_id == NULL) 117717468Seric { 117817468Seric char qf[20]; 117917468Seric 118017468Seric /* find a unique id */ 118117468Seric if (pid != getpid()) 118217468Seric { 118317468Seric /* new process -- start back at "AA" */ 118417468Seric pid = getpid(); 118517468Seric c1 = 'A'; 118617468Seric c2 = 'A' - 1; 118717468Seric } 118817468Seric (void) sprintf(qf, "qfAA%05d", pid); 118917468Seric 119017468Seric while (c1 < '~' || c2 < 'Z') 119117468Seric { 119217468Seric int i; 119317468Seric 119417468Seric if (c2 >= 'Z') 119517468Seric { 119617468Seric c1++; 119717468Seric c2 = 'A' - 1; 119817468Seric } 119940934Srick qf[2] = c1; 120040934Srick qf[3] = ++c2; 120117468Seric if (tTd(7, 20)) 120240934Srick printf("queuename: trying \"%s\"\n", qf); 120317468Seric 120440934Srick i = open(qf, O_WRONLY|O_CREAT|O_EXCL, FileMode); 120551920Seric if (i < 0) 120651920Seric { 120751920Seric if (errno == EEXIST) 120851920Seric continue; 120951920Seric syserr("queuename: Cannot create \"%s\" in \"%s\"", 121051920Seric qf, QueueDir); 121151920Seric exit(EX_UNAVAILABLE); 121251920Seric } 121358689Seric if (lockfile(i, qf, LOCK_EX|LOCK_NB)) 121451920Seric { 121551920Seric e->e_lockfp = fdopen(i, "w"); 121640934Srick break; 121717468Seric } 121851920Seric 121951920Seric /* a reader got the file; abandon it and try again */ 122051920Seric (void) close(i); 122117468Seric } 122217468Seric if (c1 >= '~' && c2 >= 'Z') 122317468Seric { 122417468Seric syserr("queuename: Cannot create \"%s\" in \"%s\"", 122517468Seric qf, QueueDir); 122617468Seric exit(EX_OSERR); 122717468Seric } 122817468Seric e->e_id = newstr(&qf[2]); 122917468Seric define('i', e->e_id, e); 123017468Seric if (tTd(7, 1)) 123117468Seric printf("queuename: assigned id %s, env=%x\n", e->e_id, e); 123217468Seric # ifdef LOG 123358020Seric if (LogLevel > 93) 123417468Seric syslog(LOG_DEBUG, "%s: assigned id", e->e_id); 123556795Seric # endif /* LOG */ 123617468Seric } 123717468Seric 123817468Seric if (type == '\0') 123917468Seric return (NULL); 124017468Seric (void) sprintf(buf, "%cf%s", type, e->e_id); 124117468Seric if (tTd(7, 2)) 124217468Seric printf("queuename: %s\n", buf); 124317468Seric return (buf); 124417468Seric } 124517468Seric /* 124617468Seric ** UNLOCKQUEUE -- unlock the queue entry for a specified envelope 124717468Seric ** 124817468Seric ** Parameters: 124917468Seric ** e -- the envelope to unlock. 125017468Seric ** 125117468Seric ** Returns: 125217468Seric ** none 125317468Seric ** 125417468Seric ** Side Effects: 125517468Seric ** unlocks the queue for `e'. 125617468Seric */ 125717468Seric 125817468Seric unlockqueue(e) 125917468Seric ENVELOPE *e; 126017468Seric { 126158680Seric if (tTd(51, 4)) 126258680Seric printf("unlockqueue(%s)\n", e->e_id); 126358680Seric 126451920Seric /* if there is a lock file in the envelope, close it */ 126551920Seric if (e->e_lockfp != NULL) 126658680Seric xfclose(e->e_lockfp, "unlockqueue", e->e_id); 126751920Seric e->e_lockfp = NULL; 126851920Seric 126917468Seric /* remove the transcript */ 127017468Seric # ifdef LOG 127158020Seric if (LogLevel > 87) 127217468Seric syslog(LOG_DEBUG, "%s: unlock", e->e_id); 127356795Seric # endif /* LOG */ 127458680Seric if (!tTd(51, 104)) 127517468Seric xunlink(queuename(e, 'x')); 127617468Seric 127717468Seric } 127840973Sbostic /* 127954974Seric ** SETCTLUSER -- create a controlling address 128040973Sbostic ** 128154974Seric ** Create a fake "address" given only a local login name; this is 128254974Seric ** used as a "controlling user" for future recipient addresses. 128340973Sbostic ** 128440973Sbostic ** Parameters: 128554974Seric ** user -- the user name of the controlling user. 128640973Sbostic ** 128740973Sbostic ** Returns: 128854974Seric ** An address descriptor for the controlling user. 128940973Sbostic ** 129040973Sbostic ** Side Effects: 129140973Sbostic ** none. 129240973Sbostic */ 129340973Sbostic 129454974Seric ADDRESS * 129554974Seric setctluser(user) 129654974Seric char *user; 129740973Sbostic { 129854974Seric register ADDRESS *a; 129940973Sbostic struct passwd *pw; 130040973Sbostic 130140973Sbostic /* 130254974Seric ** See if this clears our concept of controlling user. 130340973Sbostic */ 130440973Sbostic 130554974Seric if (user == NULL || *user == '\0') 130654974Seric return NULL; 130740973Sbostic 130840973Sbostic /* 130954974Seric ** Set up addr fields for controlling user. 131040973Sbostic */ 131140973Sbostic 131254974Seric a = (ADDRESS *) xalloc(sizeof *a); 131354974Seric bzero((char *) a, sizeof *a); 131454974Seric if ((pw = getpwnam(user)) != NULL) 131540973Sbostic { 131640973Sbostic a->q_home = newstr(pw->pw_dir); 131740973Sbostic a->q_uid = pw->pw_uid; 131840973Sbostic a->q_gid = pw->pw_gid; 131957642Seric a->q_user = newstr(user); 132040973Sbostic } 132140973Sbostic else 132240973Sbostic { 132340973Sbostic a->q_uid = DefUid; 132440973Sbostic a->q_gid = DefGid; 132557642Seric a->q_user = newstr(DefUser); 132640973Sbostic } 132740973Sbostic 132858294Seric a->q_flags |= QGOODUID|QPRIMARY; /* flag as a "ctladdr" */ 132956328Seric a->q_mailer = LocalMailer; 133054974Seric return a; 133140973Sbostic } 1332