122708Sdist /* 234921Sbostic * Copyright (c) 1983 Eric P. Allman 362528Sbostic * Copyright (c) 1988, 1993 462528Sbostic * The Regents of the University of California. All rights reserved. 533731Sbostic * 642829Sbostic * %sccs.include.redist.c% 733731Sbostic */ 822708Sdist 933731Sbostic # include "sendmail.h" 1022708Sdist 1133731Sbostic #ifndef lint 1233731Sbostic #ifdef QUEUE 13*64070Seric static char sccsid[] = "@(#)queue.c 8.8 (Berkeley) 07/27/93 (with queueing)"; 1433731Sbostic #else 15*64070Seric static char sccsid[] = "@(#)queue.c 8.8 (Berkeley) 07/27/93 (without queueing)"; 1633731Sbostic #endif 1733731Sbostic #endif /* not lint */ 1833731Sbostic 194632Seric # include <errno.h> 2040973Sbostic # include <pwd.h> 2157736Seric # include <dirent.h> 224632Seric 2333731Sbostic # ifdef QUEUE 244632Seric 254632Seric /* 269377Seric ** Work queue. 279377Seric */ 289377Seric 299377Seric struct work 309377Seric { 319377Seric char *w_name; /* name of control file */ 329377Seric long w_pri; /* priority of message, see below */ 3325013Seric time_t w_ctime; /* creation time of message */ 349377Seric struct work *w_next; /* next in queue */ 359377Seric }; 369377Seric 379377Seric typedef struct work WORK; 389377Seric 399377Seric WORK *WorkQ; /* queue of things to be done */ 409377Seric /* 414632Seric ** QUEUEUP -- queue a message up for future transmission. 424632Seric ** 434632Seric ** Parameters: 446980Seric ** e -- the envelope to queue up. 456999Seric ** queueall -- if TRUE, queue all addresses, rather than 466999Seric ** just those with the QQUEUEUP flag set. 479377Seric ** announce -- if TRUE, tell when you are queueing up. 484632Seric ** 494632Seric ** Returns: 5051920Seric ** none. 514632Seric ** 524632Seric ** Side Effects: 539377Seric ** The current request are saved in a control file. 5451920Seric ** The queue file is left locked. 554632Seric */ 564632Seric 579377Seric queueup(e, queueall, announce) 586980Seric register ENVELOPE *e; 596999Seric bool queueall; 609377Seric bool announce; 614632Seric { 627812Seric char *qf; 637812Seric register FILE *tfp; 644632Seric register HDR *h; 655007Seric register ADDRESS *q; 6651920Seric int fd; 6751920Seric int i; 6851920Seric bool newid; 6953400Seric register char *p; 7010173Seric MAILER nullmailer; 7151920Seric char buf[MAXLINE], tf[MAXLINE]; 724632Seric 735037Seric /* 7417477Seric ** Create control file. 755037Seric */ 764632Seric 7751920Seric newid = (e->e_id == NULL); 7851920Seric strcpy(tf, queuename(e, 't')); 7951920Seric tfp = e->e_lockfp; 8051920Seric if (tfp == NULL) 8151920Seric newid = FALSE; 8251920Seric if (newid) 8351835Seric { 8451920Seric tfp = e->e_lockfp; 8551920Seric } 8651920Seric else 8751920Seric { 8851920Seric /* get a locked tf file */ 89*64070Seric for (i = 0; i < 128; i++) 9051835Seric { 9151920Seric fd = open(tf, O_CREAT|O_WRONLY|O_EXCL, FileMode); 9251920Seric if (fd < 0) 9351835Seric { 94*64070Seric if (errno != EEXIST) 95*64070Seric break; 96*64070Seric #ifdef LOG 97*64070Seric if (LogLevel > 0 && (i % 32) == 0) 98*64070Seric syslog(LOG_ALERT, "queueup: cannot create %s: %s", 99*64070Seric tf, errstring(errno)); 100*64070Seric #endif 101*64070Seric continue; 10241636Srick } 10358689Seric 10458689Seric if (lockfile(fd, tf, LOCK_EX|LOCK_NB)) 10551920Seric break; 106*64070Seric #ifdef LOG 107*64070Seric else if (LogLevel > 0 && (i % 32) == 0) 108*64070Seric syslog(LOG_ALERT, "queueup: cannot lock %s: %s", 109*64070Seric tf, errstring(errno)); 110*64070Seric #endif 11158689Seric 11251920Seric close(fd); 113*64070Seric 114*64070Seric if ((i % 32) == 31) 115*64070Seric { 116*64070Seric /* save the old temp file away */ 117*64070Seric (void) rename(tf, queuename(e, 'T')); 118*64070Seric } 119*64070Seric else 120*64070Seric sleep(i % 32); 12141636Srick } 12258801Seric if (fd < 0) 123*64070Seric syserr("!queueup: cannot create temp file %s", tf); 12441636Srick 12551920Seric tfp = fdopen(fd, "w"); 12651920Seric } 1274632Seric 1287677Seric if (tTd(40, 1)) 12917468Seric printf("queueing %s\n", e->e_id); 1304632Seric 1314632Seric /* 1326980Seric ** If there is no data file yet, create one. 1336980Seric */ 1346980Seric 1356980Seric if (e->e_df == NULL) 1366980Seric { 1376980Seric register FILE *dfp; 1389389Seric extern putbody(); 1396980Seric 1407812Seric e->e_df = newstr(queuename(e, 'd')); 14140934Srick fd = open(e->e_df, O_WRONLY|O_CREAT, FileMode); 14240934Srick if (fd < 0) 14358690Seric syserr("!queueup: cannot create %s", e->e_df); 14440934Srick dfp = fdopen(fd, "w"); 14559730Seric (*e->e_putbody)(dfp, FileMailer, e, NULL); 14658680Seric (void) xfclose(dfp, "queueup dfp", e->e_id); 1479389Seric e->e_putbody = putbody; 1486980Seric } 1496980Seric 1506980Seric /* 1514632Seric ** Output future work requests. 15225687Seric ** Priority and creation time should be first, since 15325687Seric ** they are required by orderq. 1544632Seric */ 1554632Seric 1569377Seric /* output message priority */ 1579377Seric fprintf(tfp, "P%ld\n", e->e_msgpriority); 1589377Seric 1599630Seric /* output creation time */ 1609630Seric fprintf(tfp, "T%ld\n", e->e_ctime); 1619630Seric 16259093Seric /* output type and name of data file */ 16359093Seric if (e->e_bodytype != NULL) 16459093Seric fprintf(tfp, "B%s\n", e->e_bodytype); 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 17158737Seric /* send various flag bits through */ 17258737Seric p = buf; 17358737Seric if (bitset(EF_WARNING, e->e_flags)) 17458737Seric *p++ = 'w'; 17558737Seric if (bitset(EF_RESPONSE, e->e_flags)) 17658737Seric *p++ = 'r'; 17758737Seric *p++ = '\0'; 17858737Seric if (buf[0] != '\0') 17958737Seric fprintf(tfp, "F%s\n", buf); 18058737Seric 18158957Seric /* $r and $s and $_ macro values */ 18253400Seric if ((p = macvalue('r', e)) != NULL) 18353400Seric fprintf(tfp, "$r%s\n", p); 18453400Seric if ((p = macvalue('s', e)) != NULL) 18553400Seric fprintf(tfp, "$s%s\n", p); 18658957Seric if ((p = macvalue('_', e)) != NULL) 18758957Seric fprintf(tfp, "$_%s\n", p); 18853400Seric 1894632Seric /* output name of sender */ 1907812Seric fprintf(tfp, "S%s\n", e->e_from.q_paddr); 1914632Seric 19255360Seric /* output list of error recipients */ 19359670Seric printctladdr(NULL, NULL); 19455360Seric for (q = e->e_errorqueue; q != NULL; q = q->q_next) 19555360Seric { 19658680Seric if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 19755360Seric { 19859113Seric printctladdr(q, tfp); 19955360Seric fprintf(tfp, "E%s\n", q->q_paddr); 20055360Seric } 20155360Seric } 20255360Seric 2034632Seric /* output list of recipient addresses */ 2046980Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 2054632Seric { 20658250Seric if (bitset(QQUEUEUP, q->q_flags) || 20758680Seric (queueall && !bitset(QDONTSEND|QBADADDR|QSENT, q->q_flags))) 2088245Seric { 20959113Seric printctladdr(q, tfp); 2107812Seric fprintf(tfp, "R%s\n", q->q_paddr); 2119377Seric if (announce) 2129377Seric { 2139377Seric e->e_to = q->q_paddr; 21458151Seric message("queued"); 21558020Seric if (LogLevel > 8) 21658337Seric logdelivery(NULL, NULL, "queued", e); 2179377Seric e->e_to = NULL; 2189377Seric } 2199387Seric if (tTd(40, 1)) 2209387Seric { 2219387Seric printf("queueing "); 2229387Seric printaddr(q, FALSE); 2239387Seric } 2248245Seric } 2254632Seric } 2264632Seric 2279377Seric /* 2289377Seric ** Output headers for this message. 2299377Seric ** Expand macros completely here. Queue run will deal with 2309377Seric ** everything as absolute headers. 2319377Seric ** All headers that must be relative to the recipient 2329377Seric ** can be cracked later. 23310173Seric ** We set up a "null mailer" -- i.e., a mailer that will have 23410173Seric ** no effect on the addresses as they are output. 2359377Seric */ 2369377Seric 23710686Seric bzero((char *) &nullmailer, sizeof nullmailer); 23858020Seric nullmailer.m_re_rwset = nullmailer.m_rh_rwset = 23958020Seric nullmailer.m_se_rwset = nullmailer.m_sh_rwset = -1; 24010349Seric nullmailer.m_eol = "\n"; 24110173Seric 24258050Seric define('g', "\201f", e); 2436980Seric for (h = e->e_header; h != NULL; h = h->h_link) 2444632Seric { 24510686Seric extern bool bitzerop(); 24610686Seric 24712015Seric /* don't output null headers */ 2484632Seric if (h->h_value == NULL || h->h_value[0] == '\0') 2494632Seric continue; 25012015Seric 25112015Seric /* don't output resent headers on non-resent messages */ 25212015Seric if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags)) 25312015Seric continue; 25412015Seric 25512015Seric /* output this header */ 2567812Seric fprintf(tfp, "H"); 25712015Seric 25812015Seric /* if conditional, output the set of conditions */ 25910686Seric if (!bitzerop(h->h_mflags) && bitset(H_CHECK|H_ACHECK, h->h_flags)) 26010686Seric { 26110686Seric int j; 26210686Seric 26323098Seric (void) putc('?', tfp); 26410686Seric for (j = '\0'; j <= '\177'; j++) 26510686Seric if (bitnset(j, h->h_mflags)) 26623098Seric (void) putc(j, tfp); 26723098Seric (void) putc('?', tfp); 26810686Seric } 26912015Seric 27012015Seric /* output the header: expand macros, convert addresses */ 2717763Seric if (bitset(H_DEFAULT, h->h_flags)) 2727763Seric { 2737763Seric (void) expand(h->h_value, buf, &buf[sizeof buf], e); 2748236Seric fprintf(tfp, "%s: %s\n", h->h_field, buf); 2757763Seric } 2768245Seric else if (bitset(H_FROM|H_RCPT, h->h_flags)) 2779348Seric { 27858737Seric bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags); 27963753Seric FILE *savetrace = TrafficLogFile; 28058737Seric 28163753Seric TrafficLogFile = NULL; 28263753Seric 28358737Seric if (bitset(H_FROM, h->h_flags)) 28458737Seric oldstyle = FALSE; 28558737Seric 28658737Seric commaize(h, h->h_value, tfp, oldstyle, 28755012Seric &nullmailer, e); 28863753Seric 28963753Seric TrafficLogFile = savetrace; 2909348Seric } 2917763Seric else 2928245Seric fprintf(tfp, "%s: %s\n", h->h_field, h->h_value); 2934632Seric } 2944632Seric 2954632Seric /* 2964632Seric ** Clean up. 2974632Seric */ 2984632Seric 29958732Seric fflush(tfp); 30060603Seric fsync(fileno(tfp)); 30158732Seric if (ferror(tfp)) 30258732Seric { 30358732Seric if (newid) 30458732Seric syserr("!552 Error writing control file %s", tf); 30558732Seric else 30658732Seric syserr("!452 Error writing control file %s", tf); 30758732Seric } 30858732Seric 30951920Seric if (!newid) 31051920Seric { 31151920Seric qf = queuename(e, 'q'); 31251920Seric if (rename(tf, qf) < 0) 31351920Seric syserr("cannot rename(%s, %s), df=%s", tf, qf, e->e_df); 31451920Seric if (e->e_lockfp != NULL) 31558680Seric (void) xfclose(e->e_lockfp, "queueup lockfp", e->e_id); 31651920Seric e->e_lockfp = tfp; 31751920Seric } 31851920Seric else 31951920Seric qf = tf; 32041636Srick errno = 0; 3217391Seric 3227677Seric # ifdef LOG 3237677Seric /* save log info */ 32458020Seric if (LogLevel > 79) 3257878Seric syslog(LOG_DEBUG, "%s: queueup, qf=%s, df=%s\n", e->e_id, qf, e->e_df); 32656795Seric # endif /* LOG */ 32751920Seric return; 3284632Seric } 32954974Seric 33054974Seric printctladdr(a, tfp) 33159113Seric register ADDRESS *a; 33254974Seric FILE *tfp; 33354974Seric { 33459113Seric char *uname; 33559113Seric register struct passwd *pw; 33659113Seric register ADDRESS *q; 33759113Seric uid_t uid; 33859113Seric static ADDRESS *lastctladdr; 33959113Seric static uid_t lastuid; 34054974Seric 34159113Seric /* initialization */ 34263850Seric if (a == NULL || a->q_alias == NULL || tfp == NULL) 34354974Seric { 34459670Seric if (lastctladdr != NULL && tfp != NULL) 34559113Seric fprintf(tfp, "C\n"); 34659113Seric lastctladdr = NULL; 34759113Seric lastuid = 0; 34854974Seric return; 34954974Seric } 35059113Seric 35159113Seric /* find the active uid */ 35259113Seric q = getctladdr(a); 35359113Seric if (q == NULL) 35459113Seric uid = 0; 35554974Seric else 35659113Seric uid = q->q_uid; 35763850Seric a = a->q_alias; 35859113Seric 35959113Seric /* check to see if this is the same as last time */ 36059113Seric if (lastctladdr != NULL && uid == lastuid && 36159113Seric strcmp(lastctladdr->q_paddr, a->q_paddr) == 0) 36259113Seric return; 36359113Seric lastuid = uid; 36459113Seric lastctladdr = a; 36559113Seric 36659113Seric if (uid == 0 || (pw = getpwuid(uid)) == NULL) 36759270Seric uname = ""; 36859113Seric else 36959113Seric uname = pw->pw_name; 37059113Seric 37159113Seric fprintf(tfp, "C%s:%s\n", uname, a->q_paddr); 37254974Seric } 37354974Seric 3744632Seric /* 3754632Seric ** RUNQUEUE -- run the jobs in the queue. 3764632Seric ** 3774632Seric ** Gets the stuff out of the queue in some presumably logical 3784632Seric ** order and processes them. 3794632Seric ** 3804632Seric ** Parameters: 38124941Seric ** forkflag -- TRUE if the queue scanning should be done in 38224941Seric ** a child process. We double-fork so it is not our 38324941Seric ** child and we don't have to clean up after it. 3844632Seric ** 3854632Seric ** Returns: 3864632Seric ** none. 3874632Seric ** 3884632Seric ** Side Effects: 3894632Seric ** runs things in the mail queue. 3904632Seric */ 3914632Seric 39255360Seric ENVELOPE QueueEnvelope; /* the queue run envelope */ 39355360Seric 39455360Seric runqueue(forkflag) 3954639Seric bool forkflag; 3964632Seric { 39755360Seric register ENVELOPE *e; 39855360Seric extern ENVELOPE BlankEnvelope; 39924953Seric 4007466Seric /* 40124953Seric ** If no work will ever be selected, don't even bother reading 40224953Seric ** the queue. 40324953Seric */ 40424953Seric 40551920Seric CurrentLA = getla(); /* get load average */ 40640934Srick 40758132Seric if (shouldqueue(0L, curtime())) 40824953Seric { 40924953Seric if (Verbose) 41024953Seric printf("Skipping queue run -- load average too high\n"); 41158107Seric if (forkflag && QueueIntvl != 0) 41258107Seric (void) setevent(QueueIntvl, runqueue, TRUE); 41355360Seric return; 41424953Seric } 41524953Seric 41624953Seric /* 4177466Seric ** See if we want to go off and do other useful work. 4187466Seric */ 4194639Seric 4204639Seric if (forkflag) 4214639Seric { 4227943Seric int pid; 4237943Seric 4247943Seric pid = dofork(); 4257943Seric if (pid != 0) 4264639Seric { 42746928Sbostic extern void reapchild(); 42825184Seric 4297943Seric /* parent -- pick up intermediate zombie */ 43025184Seric #ifndef SIGCHLD 4319377Seric (void) waitfor(pid); 43256795Seric #else /* SIGCHLD */ 43364035Seric (void) setsignal(SIGCHLD, reapchild); 43456795Seric #endif /* SIGCHLD */ 4357690Seric if (QueueIntvl != 0) 4369348Seric (void) setevent(QueueIntvl, runqueue, TRUE); 4374639Seric return; 4384639Seric } 4397943Seric /* child -- double fork */ 44025184Seric #ifndef SIGCHLD 4417943Seric if (fork() != 0) 4427943Seric exit(EX_OK); 44356795Seric #else /* SIGCHLD */ 44464035Seric (void) setsignal(SIGCHLD, SIG_DFL); 44556795Seric #endif /* SIGCHLD */ 4464639Seric } 44724941Seric 44840934Srick setproctitle("running queue: %s", QueueDir); 44924941Seric 4507876Seric # ifdef LOG 45158020Seric if (LogLevel > 69) 45255360Seric syslog(LOG_DEBUG, "runqueue %s, pid=%d, forkflag=%d", 45355360Seric QueueDir, getpid(), forkflag); 45456795Seric # endif /* LOG */ 4554639Seric 4567466Seric /* 45710205Seric ** Release any resources used by the daemon code. 45810205Seric */ 45910205Seric 46010205Seric # ifdef DAEMON 46110205Seric clrdaemon(); 46256795Seric # endif /* DAEMON */ 46310205Seric 46410205Seric /* 46555360Seric ** Create ourselves an envelope 46655360Seric */ 46755360Seric 46855360Seric CurEnv = &QueueEnvelope; 46958179Seric e = newenvelope(&QueueEnvelope, CurEnv); 47055360Seric e->e_flags = BlankEnvelope.e_flags; 47155360Seric 47255360Seric /* 47327175Seric ** Make sure the alias database is open. 47427175Seric */ 47527175Seric 47660537Seric initmaps(FALSE, e); 47727175Seric 47827175Seric /* 4797466Seric ** Start making passes through the queue. 4807466Seric ** First, read and sort the entire queue. 4817466Seric ** Then, process the work in that order. 4827466Seric ** But if you take too long, start over. 4837466Seric */ 4847466Seric 4857943Seric /* order the existing work requests */ 48624954Seric (void) orderq(FALSE); 4877690Seric 4887943Seric /* process them once at a time */ 4897943Seric while (WorkQ != NULL) 4904639Seric { 4917943Seric WORK *w = WorkQ; 4927881Seric 4937943Seric WorkQ = WorkQ->w_next; 49458884Seric 49558884Seric /* 49658884Seric ** Ignore jobs that are too expensive for the moment. 49758884Seric */ 49858884Seric 49958884Seric if (shouldqueue(w->w_pri, w->w_ctime)) 50058884Seric { 50158884Seric if (Verbose) 50258884Seric printf("\nSkipping %s\n", w->w_name + 2); 50358884Seric } 50458930Seric else 50558930Seric { 50658930Seric dowork(w->w_name + 2, ForkQueueRuns, FALSE, e); 50758930Seric } 5087943Seric free(w->w_name); 5097943Seric free((char *) w); 5104639Seric } 51129866Seric 51229866Seric /* exit without the usual cleanup */ 51355467Seric e->e_id = NULL; 51455467Seric finis(); 5154634Seric } 5164634Seric /* 5174632Seric ** ORDERQ -- order the work queue. 5184632Seric ** 5194632Seric ** Parameters: 52024941Seric ** doall -- if set, include everything in the queue (even 52124941Seric ** the jobs that cannot be run because the load 52224941Seric ** average is too high). Otherwise, exclude those 52324941Seric ** jobs. 5244632Seric ** 5254632Seric ** Returns: 52610121Seric ** The number of request in the queue (not necessarily 52710121Seric ** the number of requests in WorkQ however). 5284632Seric ** 5294632Seric ** Side Effects: 5304632Seric ** Sets WorkQ to the queue of available work, in order. 5314632Seric */ 5324632Seric 53325687Seric # define NEED_P 001 53425687Seric # define NEED_T 002 53558318Seric # define NEED_R 004 53658318Seric # define NEED_S 010 5374632Seric 53824941Seric orderq(doall) 53924941Seric bool doall; 5404632Seric { 54160219Seric register struct dirent *d; 5424632Seric register WORK *w; 5436625Sglickman DIR *f; 5444632Seric register int i; 54525687Seric WORK wlist[QUEUESIZE+1]; 54610070Seric int wn = -1; 5474632Seric extern workcmpf(); 5484632Seric 54958318Seric if (tTd(41, 1)) 55058318Seric { 55158318Seric printf("orderq:\n"); 55258318Seric if (QueueLimitId != NULL) 55358318Seric printf("\tQueueLimitId = %s\n", QueueLimitId); 55458318Seric if (QueueLimitSender != NULL) 55558318Seric printf("\tQueueLimitSender = %s\n", QueueLimitSender); 55658318Seric if (QueueLimitRecipient != NULL) 55758318Seric printf("\tQueueLimitRecipient = %s\n", QueueLimitRecipient); 55858318Seric } 55958318Seric 5604632Seric /* clear out old WorkQ */ 5614632Seric for (w = WorkQ; w != NULL; ) 5624632Seric { 5634632Seric register WORK *nw = w->w_next; 5644632Seric 5654632Seric WorkQ = nw; 5664632Seric free(w->w_name); 5674632Seric free((char *) w); 5684632Seric w = nw; 5694632Seric } 5704632Seric 5714632Seric /* open the queue directory */ 5728148Seric f = opendir("."); 5734632Seric if (f == NULL) 5744632Seric { 5758148Seric syserr("orderq: cannot open \"%s\" as \".\"", QueueDir); 57610070Seric return (0); 5774632Seric } 5784632Seric 5794632Seric /* 5804632Seric ** Read the work directory. 5814632Seric */ 5824632Seric 58310070Seric while ((d = readdir(f)) != NULL) 5844632Seric { 5859377Seric FILE *cf; 5864632Seric char lbuf[MAXNAME]; 58758318Seric extern bool strcontainedin(); 5884632Seric 5894632Seric /* is this an interesting entry? */ 5907812Seric if (d->d_name[0] != 'q' || d->d_name[1] != 'f') 5914632Seric continue; 5924632Seric 59358318Seric if (QueueLimitId != NULL && 59458318Seric !strcontainedin(QueueLimitId, d->d_name)) 59558318Seric continue; 59658318Seric 59758722Seric /* 59858722Seric ** Check queue name for plausibility. This handles 59958722Seric ** both old and new type ids. 60058722Seric */ 60158722Seric 60258722Seric i = strlen(d->d_name); 60358722Seric if (i != 9 && i != 10) 60458020Seric { 60558020Seric if (Verbose) 60658020Seric printf("orderq: bogus qf name %s\n", d->d_name); 60758020Seric #ifdef LOG 60858020Seric if (LogLevel > 3) 60959615Seric syslog(LOG_CRIT, "orderq: bogus qf name %s", 61058020Seric d->d_name); 61158020Seric #endif 61258020Seric if (strlen(d->d_name) >= MAXNAME) 61358020Seric d->d_name[MAXNAME - 1] = '\0'; 61458020Seric strcpy(lbuf, d->d_name); 61558020Seric lbuf[0] = 'Q'; 61658020Seric (void) rename(d->d_name, lbuf); 61758020Seric continue; 61858020Seric } 61958020Seric 62010070Seric /* yes -- open control file (if not too many files) */ 62125687Seric if (++wn >= QUEUESIZE) 62210070Seric continue; 62358318Seric 6248148Seric cf = fopen(d->d_name, "r"); 6254632Seric if (cf == NULL) 6264632Seric { 6277055Seric /* this may be some random person sending hir msgs */ 6287055Seric /* syserr("orderq: cannot open %s", cbuf); */ 62910090Seric if (tTd(41, 2)) 63010090Seric printf("orderq: cannot open %s (%d)\n", 63110090Seric d->d_name, errno); 6327055Seric errno = 0; 63310090Seric wn--; 6344632Seric continue; 6354632Seric } 63625687Seric w = &wlist[wn]; 63725687Seric w->w_name = newstr(d->d_name); 6384632Seric 63925027Seric /* make sure jobs in creation don't clog queue */ 64025687Seric w->w_pri = 0x7fffffff; 64125687Seric w->w_ctime = 0; 64225027Seric 6434632Seric /* extract useful information */ 64425687Seric i = NEED_P | NEED_T; 64558318Seric if (QueueLimitSender != NULL) 64658318Seric i |= NEED_S; 64758318Seric if (QueueLimitRecipient != NULL) 64858318Seric i |= NEED_R; 64925687Seric while (i != 0 && fgets(lbuf, sizeof lbuf, cf) != NULL) 6504632Seric { 65124954Seric extern long atol(); 65258318Seric extern bool strcontainedin(); 65324954Seric 65424941Seric switch (lbuf[0]) 6554632Seric { 65624941Seric case 'P': 65725687Seric w->w_pri = atol(&lbuf[1]); 65825687Seric i &= ~NEED_P; 6594632Seric break; 66025013Seric 66125013Seric case 'T': 66225687Seric w->w_ctime = atol(&lbuf[1]); 66325687Seric i &= ~NEED_T; 66425013Seric break; 66558318Seric 66658318Seric case 'R': 66758318Seric if (QueueLimitRecipient != NULL && 66858318Seric strcontainedin(QueueLimitRecipient, &lbuf[1])) 66958318Seric i &= ~NEED_R; 67058318Seric break; 67158318Seric 67258318Seric case 'S': 67358318Seric if (QueueLimitSender != NULL && 67458318Seric strcontainedin(QueueLimitSender, &lbuf[1])) 67558318Seric i &= ~NEED_S; 67658318Seric break; 6774632Seric } 6784632Seric } 6794632Seric (void) fclose(cf); 68024953Seric 68158318Seric if ((!doall && shouldqueue(w->w_pri, w->w_ctime)) || 68258318Seric bitset(NEED_R|NEED_S, i)) 68324953Seric { 68424953Seric /* don't even bother sorting this job in */ 68524953Seric wn--; 68624953Seric } 6874632Seric } 6886625Sglickman (void) closedir(f); 68910090Seric wn++; 6904632Seric 6914632Seric /* 6924632Seric ** Sort the work directory. 6934632Seric */ 6944632Seric 69525687Seric qsort((char *) wlist, min(wn, QUEUESIZE), sizeof *wlist, workcmpf); 6964632Seric 6974632Seric /* 6984632Seric ** Convert the work list into canonical form. 6999377Seric ** Should be turning it into a list of envelopes here perhaps. 7004632Seric */ 7014632Seric 70224981Seric WorkQ = NULL; 70325687Seric for (i = min(wn, QUEUESIZE); --i >= 0; ) 7044632Seric { 7054632Seric w = (WORK *) xalloc(sizeof *w); 7064632Seric w->w_name = wlist[i].w_name; 7074632Seric w->w_pri = wlist[i].w_pri; 70825013Seric w->w_ctime = wlist[i].w_ctime; 70924981Seric w->w_next = WorkQ; 71024981Seric WorkQ = w; 7114632Seric } 7124632Seric 7137677Seric if (tTd(40, 1)) 7144632Seric { 7154632Seric for (w = WorkQ; w != NULL; w = w->w_next) 7165037Seric printf("%32s: pri=%ld\n", w->w_name, w->w_pri); 7174632Seric } 71810070Seric 71910090Seric return (wn); 7204632Seric } 7214632Seric /* 7227677Seric ** WORKCMPF -- compare function for ordering work. 7234632Seric ** 7244632Seric ** Parameters: 7254632Seric ** a -- the first argument. 7264632Seric ** b -- the second argument. 7274632Seric ** 7284632Seric ** Returns: 72924981Seric ** -1 if a < b 73024981Seric ** 0 if a == b 73124981Seric ** +1 if a > b 7324632Seric ** 7334632Seric ** Side Effects: 7344632Seric ** none. 7354632Seric */ 7364632Seric 7374632Seric workcmpf(a, b) 7385037Seric register WORK *a; 7395037Seric register WORK *b; 7404632Seric { 74157438Seric long pa = a->w_pri; 74257438Seric long pb = b->w_pri; 74324941Seric 74424941Seric if (pa == pb) 7454632Seric return (0); 74624941Seric else if (pa > pb) 74724981Seric return (1); 74824981Seric else 74910121Seric return (-1); 7504632Seric } 7514632Seric /* 7524632Seric ** DOWORK -- do a work request. 7534632Seric ** 7544632Seric ** Parameters: 75558884Seric ** id -- the ID of the job to run. 75658884Seric ** forkflag -- if set, run this in background. 75758924Seric ** requeueflag -- if set, reinstantiate the queue quickly. 75858924Seric ** This is used when expanding aliases in the queue. 75961094Seric ** If forkflag is also set, it doesn't wait for the 76061094Seric ** child. 76158884Seric ** e - the envelope in which to run it. 7624632Seric ** 7634632Seric ** Returns: 7644632Seric ** none. 7654632Seric ** 7664632Seric ** Side Effects: 7674632Seric ** The work request is satisfied if possible. 7684632Seric */ 7694632Seric 77058924Seric dowork(id, forkflag, requeueflag, e) 77158884Seric char *id; 77258884Seric bool forkflag; 77358924Seric bool requeueflag; 77455012Seric register ENVELOPE *e; 7754632Seric { 7764632Seric register int i; 77751920Seric extern bool readqf(); 7784632Seric 7797677Seric if (tTd(40, 1)) 78058884Seric printf("dowork(%s)\n", id); 7814632Seric 7824632Seric /* 78324941Seric ** Fork for work. 78424941Seric */ 78524941Seric 78658884Seric if (forkflag) 78724941Seric { 78824941Seric i = fork(); 78924941Seric if (i < 0) 79024941Seric { 79124941Seric syserr("dowork: cannot fork"); 79224941Seric return; 79324941Seric } 79424941Seric } 79524941Seric else 79624941Seric { 79724941Seric i = 0; 79824941Seric } 79924941Seric 8004632Seric if (i == 0) 8014632Seric { 8024632Seric /* 8034632Seric ** CHILD 8048148Seric ** Lock the control file to avoid duplicate deliveries. 8058148Seric ** Then run the file as though we had just read it. 8067350Seric ** We save an idea of the temporary name so we 8077350Seric ** can recover on interrupt. 8084632Seric */ 8094632Seric 8107763Seric /* set basic modes, etc. */ 8117356Seric (void) alarm(0); 81255012Seric clearenvelope(e, FALSE); 81358737Seric e->e_flags |= EF_QUEUERUN; 81458734Seric e->e_errormode = EM_MAIL; 81558884Seric e->e_id = id; 81663846Seric if (forkflag) 81763846Seric disconnect(0, e); 8187876Seric # ifdef LOG 81958020Seric if (LogLevel > 76) 82055012Seric syslog(LOG_DEBUG, "%s: dowork, pid=%d", e->e_id, 8217881Seric getpid()); 82256795Seric # endif /* LOG */ 8237763Seric 8247763Seric /* don't use the headers from sendmail.cf... */ 82555012Seric e->e_header = NULL; 8267763Seric 82751920Seric /* read the queue control file -- return if locked */ 82863850Seric if (!readqf(e, !requeueflag)) 8296980Seric { 83058884Seric if (tTd(40, 4)) 83158884Seric printf("readqf(%s) failed\n", e->e_id); 83258884Seric if (forkflag) 83324941Seric exit(EX_OK); 83424941Seric else 83524941Seric return; 8366980Seric } 8376980Seric 83855012Seric e->e_flags |= EF_INQUEUE; 83958929Seric eatheader(e, requeueflag); 8406980Seric 84158924Seric if (requeueflag) 84258924Seric queueup(e, TRUE, FALSE); 84358924Seric 8446980Seric /* do the delivery */ 84558915Seric sendall(e, SM_DELIVER); 8466980Seric 8476980Seric /* finish up and exit */ 84858884Seric if (forkflag) 84924941Seric finis(); 85024941Seric else 85155012Seric dropenvelope(e); 8524632Seric } 85361094Seric else if (!requeueflag) 85424941Seric { 85524941Seric /* 85624941Seric ** Parent -- pick up results. 85724941Seric */ 8584632Seric 85924941Seric errno = 0; 86024941Seric (void) waitfor(i); 86124941Seric } 8624632Seric } 8634632Seric /* 8644632Seric ** READQF -- read queue file and set up environment. 8654632Seric ** 8664632Seric ** Parameters: 8679377Seric ** e -- the envelope of the job to run. 86863850Seric ** announcefile -- if set, announce the name of the queue 86963850Seric ** file in error messages. 8704632Seric ** 8714632Seric ** Returns: 87251920Seric ** TRUE if it successfully read the queue file. 87351920Seric ** FALSE otherwise. 8744632Seric ** 8754632Seric ** Side Effects: 87651920Seric ** The queue file is returned locked. 8774632Seric */ 8784632Seric 87951920Seric bool 88063850Seric readqf(e, announcefile) 8819377Seric register ENVELOPE *e; 88263850Seric bool announcefile; 8834632Seric { 88417477Seric register FILE *qfp; 88554974Seric ADDRESS *ctladdr; 88656400Seric struct stat st; 88757135Seric char *bp; 88858915Seric char qf[20]; 88957135Seric char buf[MAXLINE]; 89024954Seric extern long atol(); 89154974Seric extern ADDRESS *setctluser(); 8924632Seric 8934632Seric /* 89417468Seric ** Read and process the file. 8954632Seric */ 8964632Seric 89758915Seric strcpy(qf, queuename(e, 'q')); 89851937Seric qfp = fopen(qf, "r+"); 89917477Seric if (qfp == NULL) 90017477Seric { 90158884Seric if (tTd(40, 8)) 90258884Seric printf("readqf(%s): fopen failure (%s)\n", 90358884Seric qf, errstring(errno)); 90440934Srick if (errno != ENOENT) 90540934Srick syserr("readqf: no control file %s", qf); 90651920Seric return FALSE; 90717477Seric } 90840934Srick 90956400Seric /* 91056400Seric ** Check the queue file for plausibility to avoid attacks. 91156400Seric */ 91256400Seric 91356400Seric if (fstat(fileno(qfp), &st) < 0) 91456400Seric { 91556400Seric /* must have been being processed by someone else */ 91658884Seric if (tTd(40, 8)) 91758884Seric printf("readqf(%s): fstat failure (%s)\n", 91858884Seric qf, errstring(errno)); 91956400Seric fclose(qfp); 92056400Seric return FALSE; 92156400Seric } 92256400Seric 92357135Seric if (st.st_uid != geteuid() || (st.st_mode & 07777) != FileMode) 92456400Seric { 92556400Seric # ifdef LOG 92656400Seric if (LogLevel > 0) 92756400Seric { 92856400Seric syslog(LOG_ALERT, "%s: bogus queue file, uid=%d, mode=%o", 92956400Seric e->e_id, st.st_uid, st.st_mode); 93056400Seric } 93156795Seric # endif /* LOG */ 93258884Seric if (tTd(40, 8)) 93358884Seric printf("readqf(%s): bogus file\n", qf); 93456400Seric fclose(qfp); 93563753Seric rename(qf, queuename(e, 'Q')); 93656400Seric return FALSE; 93756400Seric } 93856400Seric 93958689Seric if (!lockfile(fileno(qfp), qf, LOCK_EX|LOCK_NB)) 94040934Srick { 94158689Seric /* being processed by another queuer */ 94258884Seric if (tTd(40, 8)) 94358884Seric printf("readqf(%s): locked\n", qf); 94458689Seric if (Verbose) 94558689Seric printf("%s: locked\n", e->e_id); 94651920Seric # ifdef LOG 94758689Seric if (LogLevel > 19) 94858689Seric syslog(LOG_DEBUG, "%s: locked", e->e_id); 94956795Seric # endif /* LOG */ 95040934Srick (void) fclose(qfp); 95151920Seric return FALSE; 95240934Srick } 95340934Srick 95459101Seric if (st.st_size == 0) 95559101Seric { 95659101Seric /* must be a bogus file -- just remove it */ 95759101Seric (void) unlink(qf); 95859101Seric fclose(qfp); 95959101Seric return FALSE; 96059101Seric } 96159101Seric 96251920Seric /* save this lock */ 96351920Seric e->e_lockfp = qfp; 96451920Seric 96540934Srick /* do basic system initialization */ 96655012Seric initsys(e); 96740934Srick 96863850Seric if (announcefile) 96963850Seric FileName = qf; 9709377Seric LineNumber = 0; 97163850Seric e->e_flags |= EF_GLOBALERRS; 97263850Seric OpMode = MD_DELIVER; 97351920Seric if (Verbose) 9749377Seric printf("\nRunning %s\n", e->e_id); 97554974Seric ctladdr = NULL; 97657135Seric while ((bp = fgetfolded(buf, sizeof buf, qfp)) != NULL) 9774632Seric { 97858737Seric register char *p; 97957529Seric struct stat st; 98057529Seric 98126504Seric if (tTd(40, 4)) 98257135Seric printf("+++++ %s\n", bp); 98357135Seric switch (bp[0]) 9844632Seric { 98540973Sbostic case 'C': /* specify controlling user */ 98657135Seric ctladdr = setctluser(&bp[1]); 98740973Sbostic break; 98840973Sbostic 9894632Seric case 'R': /* specify recipient */ 99058082Seric (void) sendtolist(&bp[1], ctladdr, &e->e_sendqueue, e); 9914632Seric break; 9924632Seric 99325687Seric case 'E': /* specify error recipient */ 99458082Seric (void) sendtolist(&bp[1], ctladdr, &e->e_errorqueue, e); 99525687Seric break; 99625687Seric 9974632Seric case 'H': /* header */ 99857135Seric (void) chompheader(&bp[1], FALSE, e); 9994632Seric break; 10004632Seric 100110108Seric case 'M': /* message */ 100257135Seric e->e_message = newstr(&bp[1]); 100310108Seric break; 100410108Seric 10054632Seric case 'S': /* sender */ 100658704Seric setsender(newstr(&bp[1]), e, NULL, TRUE); 10074632Seric break; 10084632Seric 100959093Seric case 'B': /* body type */ 101059093Seric e->e_bodytype = newstr(&bp[1]); 101159093Seric break; 101259093Seric 10134632Seric case 'D': /* data file name */ 101457135Seric e->e_df = newstr(&bp[1]); 10159544Seric e->e_dfp = fopen(e->e_df, "r"); 10169544Seric if (e->e_dfp == NULL) 101758020Seric { 10189377Seric syserr("readqf: cannot open %s", e->e_df); 101958020Seric e->e_msgsize = -1; 102058020Seric } 102158020Seric else if (fstat(fileno(e->e_dfp), &st) >= 0) 102257529Seric e->e_msgsize = st.st_size; 10234632Seric break; 10244632Seric 10257860Seric case 'T': /* init time */ 102657135Seric e->e_ctime = atol(&bp[1]); 10274632Seric break; 10284632Seric 10294634Seric case 'P': /* message priority */ 103057135Seric e->e_msgpriority = atol(&bp[1]) + WkTimeFact; 10314634Seric break; 10324634Seric 103358737Seric case 'F': /* flag bits */ 103458737Seric for (p = &bp[1]; *p != '\0'; p++) 103558737Seric { 103658737Seric switch (*p) 103758737Seric { 103858737Seric case 'w': /* warning sent */ 103958737Seric e->e_flags |= EF_WARNING; 104058737Seric break; 104158737Seric 104258737Seric case 'r': /* response */ 104358737Seric e->e_flags |= EF_RESPONSE; 104458737Seric break; 104558737Seric } 104658737Seric } 104758737Seric break; 104858737Seric 104953400Seric case '$': /* define macro */ 105057135Seric define(bp[1], newstr(&bp[2]), e); 105153400Seric break; 105253400Seric 105324941Seric case '\0': /* blank line; ignore */ 105424941Seric break; 105524941Seric 10564632Seric default: 105759700Seric syserr("readqf: bad line \"%s\"", e->e_id, 105857135Seric LineNumber, bp); 105963753Seric fclose(qfp); 106063753Seric rename(qf, queuename(e, 'Q')); 106163753Seric return FALSE; 10624632Seric } 106357135Seric 106457135Seric if (bp != buf) 106557135Seric free(bp); 10664632Seric } 10679377Seric 10689377Seric FileName = NULL; 106924941Seric 107024941Seric /* 107124941Seric ** If we haven't read any lines, this queue file is empty. 107224941Seric ** Arrange to remove it without referencing any null pointers. 107324941Seric */ 107424941Seric 107524941Seric if (LineNumber == 0) 107624941Seric { 107724941Seric errno = 0; 107824941Seric e->e_flags |= EF_CLRQUEUE | EF_FATALERRS | EF_RESPONSE; 107924941Seric } 108051920Seric return TRUE; 10814632Seric } 10824632Seric /* 10839630Seric ** PRINTQUEUE -- print out a representation of the mail queue 10849630Seric ** 10859630Seric ** Parameters: 10869630Seric ** none. 10879630Seric ** 10889630Seric ** Returns: 10899630Seric ** none. 10909630Seric ** 10919630Seric ** Side Effects: 10929630Seric ** Prints a listing of the mail queue on the standard output. 10939630Seric */ 10945182Seric 10959630Seric printqueue() 10969630Seric { 10979630Seric register WORK *w; 10989630Seric FILE *f; 109910070Seric int nrequests; 11009630Seric char buf[MAXLINE]; 11019630Seric 11029630Seric /* 110358250Seric ** Check for permission to print the queue 110458250Seric */ 110558250Seric 110663787Seric if (bitset(PRIV_RESTRMAILQ, PrivacyFlags) && RealUid != 0) 110758250Seric { 110858250Seric struct stat st; 110958523Seric # ifdef NGROUPS 111058523Seric int n; 111163937Seric GIDSET_T gidset[NGROUPS]; 111258523Seric # endif 111358250Seric 111458517Seric if (stat(QueueDir, &st) < 0) 111558250Seric { 111658250Seric syserr("Cannot stat %s", QueueDir); 111758250Seric return; 111858250Seric } 111958523Seric # ifdef NGROUPS 112058523Seric n = getgroups(NGROUPS, gidset); 112158523Seric while (--n >= 0) 112258523Seric { 112358523Seric if (gidset[n] == st.st_gid) 112458523Seric break; 112558523Seric } 112658523Seric if (n < 0) 112758523Seric # else 112863787Seric if (RealGid != st.st_gid) 112958523Seric # endif 113058250Seric { 113158250Seric usrerr("510 You are not permitted to see the queue"); 113258250Seric setstat(EX_NOPERM); 113358250Seric return; 113458250Seric } 113558250Seric } 113658250Seric 113758250Seric /* 11389630Seric ** Read and order the queue. 11399630Seric */ 11409630Seric 114124941Seric nrequests = orderq(TRUE); 11429630Seric 11439630Seric /* 11449630Seric ** Print the work list that we have read. 11459630Seric */ 11469630Seric 11479630Seric /* first see if there is anything */ 114810070Seric if (nrequests <= 0) 11499630Seric { 115010070Seric printf("Mail queue is empty\n"); 11519630Seric return; 11529630Seric } 11539630Seric 115451920Seric CurrentLA = getla(); /* get load average */ 115540934Srick 115610096Seric printf("\t\tMail Queue (%d request%s", nrequests, nrequests == 1 ? "" : "s"); 115725687Seric if (nrequests > QUEUESIZE) 115825687Seric printf(", only %d printed", QUEUESIZE); 115924979Seric if (Verbose) 116058716Seric printf(")\n--Q-ID-- --Size-- -Priority- ---Q-Time--- -----------Sender/Recipient-----------\n"); 116124979Seric else 116258716Seric printf(")\n--Q-ID-- --Size-- -----Q-Time----- ------------Sender/Recipient------------\n"); 11639630Seric for (w = WorkQ; w != NULL; w = w->w_next) 11649630Seric { 11659630Seric struct stat st; 116610070Seric auto time_t submittime = 0; 116710070Seric long dfsize = -1; 116858737Seric int flags = 0; 116910108Seric char message[MAXLINE]; 117059093Seric char bodytype[MAXNAME]; 11719630Seric 117217468Seric f = fopen(w->w_name, "r"); 117317468Seric if (f == NULL) 117417468Seric { 117517468Seric errno = 0; 117617468Seric continue; 117717468Seric } 117858724Seric printf("%8s", w->w_name + 2); 117958689Seric if (!lockfile(fileno(f), w->w_name, LOCK_SH|LOCK_NB)) 118010070Seric printf("*"); 118157438Seric else if (shouldqueue(w->w_pri, w->w_ctime)) 118224941Seric printf("X"); 118310070Seric else 118410070Seric printf(" "); 118510070Seric errno = 0; 118617468Seric 118759093Seric message[0] = bodytype[0] = '\0'; 11889630Seric while (fgets(buf, sizeof buf, f) != NULL) 11899630Seric { 119053400Seric register int i; 119158737Seric register char *p; 119253400Seric 11939630Seric fixcrlf(buf, TRUE); 11949630Seric switch (buf[0]) 11959630Seric { 119610108Seric case 'M': /* error message */ 119753400Seric if ((i = strlen(&buf[1])) >= sizeof message) 119858737Seric i = sizeof message - 1; 119953400Seric bcopy(&buf[1], message, i); 120053400Seric message[i] = '\0'; 120110108Seric break; 120210108Seric 120359093Seric case 'B': /* body type */ 120459093Seric if ((i = strlen(&buf[1])) >= sizeof bodytype) 120559093Seric i = sizeof bodytype - 1; 120659093Seric bcopy(&buf[1], bodytype, i); 120759093Seric bodytype[i] = '\0'; 120859093Seric break; 120959093Seric 12109630Seric case 'S': /* sender name */ 121124979Seric if (Verbose) 121258737Seric printf("%8ld %10ld%c%.12s %.38s", 121358737Seric dfsize, 121458737Seric w->w_pri, 121558737Seric bitset(EF_WARNING, flags) ? '+' : ' ', 121658737Seric ctime(&submittime) + 4, 121724979Seric &buf[1]); 121824979Seric else 121924979Seric printf("%8ld %.16s %.45s", dfsize, 122024979Seric ctime(&submittime), &buf[1]); 122159093Seric if (message[0] != '\0' || bodytype[0] != '\0') 122259093Seric { 122359093Seric printf("\n %10.10s", bodytype); 122459093Seric if (message[0] != '\0') 122559093Seric printf(" (%.60s)", message); 122659093Seric } 12279630Seric break; 122851920Seric 122940973Sbostic case 'C': /* controlling user */ 123054974Seric if (Verbose) 123158716Seric printf("\n\t\t\t\t (---%.34s---)", 123258716Seric &buf[1]); 123340973Sbostic break; 12349630Seric 12359630Seric case 'R': /* recipient name */ 123624979Seric if (Verbose) 123758716Seric printf("\n\t\t\t\t\t %.38s", &buf[1]); 123824979Seric else 123958716Seric printf("\n\t\t\t\t %.45s", &buf[1]); 12409630Seric break; 12419630Seric 12429630Seric case 'T': /* creation time */ 124324941Seric submittime = atol(&buf[1]); 12449630Seric break; 124510070Seric 124610070Seric case 'D': /* data file name */ 124710070Seric if (stat(&buf[1], &st) >= 0) 124810070Seric dfsize = st.st_size; 124910070Seric break; 125058737Seric 125158737Seric case 'F': /* flag bits */ 125258737Seric for (p = &buf[1]; *p != '\0'; p++) 125358737Seric { 125458737Seric switch (*p) 125558737Seric { 125658737Seric case 'w': 125758737Seric flags |= EF_WARNING; 125858737Seric break; 125958737Seric } 126058737Seric } 12619630Seric } 12629630Seric } 126310070Seric if (submittime == (time_t) 0) 126410070Seric printf(" (no control file)"); 12659630Seric printf("\n"); 126623098Seric (void) fclose(f); 12679630Seric } 12689630Seric } 12699630Seric 127056795Seric # endif /* QUEUE */ 127117468Seric /* 127217468Seric ** QUEUENAME -- build a file name in the queue directory for this envelope. 127317468Seric ** 127417468Seric ** Assigns an id code if one does not already exist. 127517468Seric ** This code is very careful to avoid trashing existing files 127617468Seric ** under any circumstances. 127717468Seric ** 127817468Seric ** Parameters: 127917468Seric ** e -- envelope to build it in/from. 128017468Seric ** type -- the file type, used as the first character 128117468Seric ** of the file name. 128217468Seric ** 128317468Seric ** Returns: 128417468Seric ** a pointer to the new file name (in a static buffer). 128517468Seric ** 128617468Seric ** Side Effects: 128751920Seric ** If no id code is already assigned, queuename will 128851920Seric ** assign an id code, create a qf file, and leave a 128951920Seric ** locked, open-for-write file pointer in the envelope. 129017468Seric */ 129117468Seric 129217468Seric char * 129317468Seric queuename(e, type) 129417468Seric register ENVELOPE *e; 129559700Seric int type; 129617468Seric { 129717468Seric static int pid = -1; 129858741Seric static char c0; 129958741Seric static char c1; 130058741Seric static char c2; 130158716Seric time_t now; 130258716Seric struct tm *tm; 130358689Seric static char buf[MAXNAME]; 130417468Seric 130517468Seric if (e->e_id == NULL) 130617468Seric { 130717468Seric char qf[20]; 130817468Seric 130917468Seric /* find a unique id */ 131017468Seric if (pid != getpid()) 131117468Seric { 131217468Seric /* new process -- start back at "AA" */ 131317468Seric pid = getpid(); 131458716Seric now = curtime(); 131558716Seric tm = localtime(&now); 131658716Seric c0 = 'A' + tm->tm_hour; 131717468Seric c1 = 'A'; 131817468Seric c2 = 'A' - 1; 131917468Seric } 132058716Seric (void) sprintf(qf, "qf%cAA%05d", c0, pid); 132117468Seric 132217468Seric while (c1 < '~' || c2 < 'Z') 132317468Seric { 132417468Seric int i; 132517468Seric 132617468Seric if (c2 >= 'Z') 132717468Seric { 132817468Seric c1++; 132917468Seric c2 = 'A' - 1; 133017468Seric } 133158716Seric qf[3] = c1; 133258716Seric qf[4] = ++c2; 133317468Seric if (tTd(7, 20)) 133440934Srick printf("queuename: trying \"%s\"\n", qf); 133517468Seric 133640934Srick i = open(qf, O_WRONLY|O_CREAT|O_EXCL, FileMode); 133751920Seric if (i < 0) 133851920Seric { 133951920Seric if (errno == EEXIST) 134051920Seric continue; 134151920Seric syserr("queuename: Cannot create \"%s\" in \"%s\"", 134251920Seric qf, QueueDir); 134351920Seric exit(EX_UNAVAILABLE); 134451920Seric } 134558689Seric if (lockfile(i, qf, LOCK_EX|LOCK_NB)) 134651920Seric { 134751920Seric e->e_lockfp = fdopen(i, "w"); 134840934Srick break; 134917468Seric } 135051920Seric 135151920Seric /* a reader got the file; abandon it and try again */ 135251920Seric (void) close(i); 135317468Seric } 135417468Seric if (c1 >= '~' && c2 >= 'Z') 135517468Seric { 135617468Seric syserr("queuename: Cannot create \"%s\" in \"%s\"", 135717468Seric qf, QueueDir); 135817468Seric exit(EX_OSERR); 135917468Seric } 136017468Seric e->e_id = newstr(&qf[2]); 136117468Seric define('i', e->e_id, e); 136217468Seric if (tTd(7, 1)) 136317468Seric printf("queuename: assigned id %s, env=%x\n", e->e_id, e); 136417468Seric # ifdef LOG 136558020Seric if (LogLevel > 93) 136617468Seric syslog(LOG_DEBUG, "%s: assigned id", e->e_id); 136756795Seric # endif /* LOG */ 136817468Seric } 136917468Seric 137017468Seric if (type == '\0') 137117468Seric return (NULL); 137217468Seric (void) sprintf(buf, "%cf%s", type, e->e_id); 137317468Seric if (tTd(7, 2)) 137417468Seric printf("queuename: %s\n", buf); 137517468Seric return (buf); 137617468Seric } 137717468Seric /* 137817468Seric ** UNLOCKQUEUE -- unlock the queue entry for a specified envelope 137917468Seric ** 138017468Seric ** Parameters: 138117468Seric ** e -- the envelope to unlock. 138217468Seric ** 138317468Seric ** Returns: 138417468Seric ** none 138517468Seric ** 138617468Seric ** Side Effects: 138717468Seric ** unlocks the queue for `e'. 138817468Seric */ 138917468Seric 139017468Seric unlockqueue(e) 139117468Seric ENVELOPE *e; 139217468Seric { 139358680Seric if (tTd(51, 4)) 139458680Seric printf("unlockqueue(%s)\n", e->e_id); 139558680Seric 139651920Seric /* if there is a lock file in the envelope, close it */ 139751920Seric if (e->e_lockfp != NULL) 139858680Seric xfclose(e->e_lockfp, "unlockqueue", e->e_id); 139951920Seric e->e_lockfp = NULL; 140051920Seric 140158728Seric /* don't create a queue id if we don't already have one */ 140258728Seric if (e->e_id == NULL) 140358728Seric return; 140458728Seric 140517468Seric /* remove the transcript */ 140617468Seric # ifdef LOG 140758020Seric if (LogLevel > 87) 140817468Seric syslog(LOG_DEBUG, "%s: unlock", e->e_id); 140956795Seric # endif /* LOG */ 141058680Seric if (!tTd(51, 104)) 141117468Seric xunlink(queuename(e, 'x')); 141217468Seric 141317468Seric } 141440973Sbostic /* 141554974Seric ** SETCTLUSER -- create a controlling address 141640973Sbostic ** 141754974Seric ** Create a fake "address" given only a local login name; this is 141854974Seric ** used as a "controlling user" for future recipient addresses. 141940973Sbostic ** 142040973Sbostic ** Parameters: 142154974Seric ** user -- the user name of the controlling user. 142240973Sbostic ** 142340973Sbostic ** Returns: 142454974Seric ** An address descriptor for the controlling user. 142540973Sbostic ** 142640973Sbostic ** Side Effects: 142740973Sbostic ** none. 142840973Sbostic */ 142940973Sbostic 143054974Seric ADDRESS * 143154974Seric setctluser(user) 143254974Seric char *user; 143340973Sbostic { 143454974Seric register ADDRESS *a; 143540973Sbostic struct passwd *pw; 143659113Seric char *p; 143740973Sbostic 143840973Sbostic /* 143954974Seric ** See if this clears our concept of controlling user. 144040973Sbostic */ 144140973Sbostic 144263850Seric if (user == NULL || *user == '\0') 144363850Seric return NULL; 144440973Sbostic 144540973Sbostic /* 144654974Seric ** Set up addr fields for controlling user. 144740973Sbostic */ 144840973Sbostic 144954974Seric a = (ADDRESS *) xalloc(sizeof *a); 145054974Seric bzero((char *) a, sizeof *a); 145159113Seric 145259113Seric p = strchr(user, ':'); 145359113Seric if (p != NULL) 145459113Seric *p++ = '\0'; 145559270Seric if (*user != '\0' && (pw = getpwnam(user)) != NULL) 145640973Sbostic { 145740973Sbostic a->q_home = newstr(pw->pw_dir); 145840973Sbostic a->q_uid = pw->pw_uid; 145940973Sbostic a->q_gid = pw->pw_gid; 146057642Seric a->q_user = newstr(user); 146159270Seric a->q_flags |= QGOODUID; 146240973Sbostic } 146340973Sbostic else 146440973Sbostic { 146557642Seric a->q_user = newstr(DefUser); 146640973Sbostic } 146740973Sbostic 146859270Seric a->q_flags |= QPRIMARY; /* flag as a "ctladdr" */ 146956328Seric a->q_mailer = LocalMailer; 147059113Seric if (p == NULL) 147159113Seric a->q_paddr = a->q_user; 147259113Seric else 147359113Seric a->q_paddr = newstr(p); 147454974Seric return a; 147540973Sbostic } 1476