📄 queue.c
字号:
syslog(LOG_INFO, "%s: dowork, pid=%d", CurEnv->e_id, getpid());# endif LOG /* don't use the headers from sendmail.cf... */ CurEnv->e_header = NULL; /* lock the control file during processing */ if (link(w->w_name, queuename(CurEnv, 'l')) < 0) { /* being processed by another queuer */# ifdef LOG if (LogLevel > 4) syslog(LOG_INFO, "%s: locked", CurEnv->e_id);# endif LOG if (ForkQueueRuns) exit(EX_OK); else return; } /* do basic system initialization */ initsys(); /* read the queue control file */ readqf(CurEnv, TRUE); CurEnv->e_flags |= EF_INQUEUE; eatheader(CurEnv); /* do the delivery */ if (!bitset(EF_FATALERRS, CurEnv->e_flags)) sendall(CurEnv, SM_DELIVER); /* finish up and exit */ if (ForkQueueRuns) finis(); else dropenvelope(CurEnv); } else { /* ** Parent -- pick up results. */ errno = 0; (void) waitfor(i); }}/*** READQF -- read queue file and set up environment.**** Parameters:** e -- the envelope of the job to run.** full -- if set, read in all information. Otherwise just** read in info needed for a queue print.**** Returns:** none.**** Side Effects:** cf is read and created as the current job, as though** we had been invoked by argument.*/readqf(e, full) register ENVELOPE *e; bool full;{ char *qf; register FILE *qfp; char buf[MAXFIELD]; extern char *fgetfolded(), *setctluser(); extern long atol(); /* ** Read and process the file. */ qf = queuename(e, 'q'); qfp = fopen(qf, "r"); if (qfp == NULL) { syserr("readqf: no control file %s", qf); return; } FileName = qf; LineNumber = 0; if (Verbose && full) printf("\nRunning %s\n", e->e_id); while (fgetfolded(buf, sizeof buf, qfp) != NULL) {# ifdef DEBUG if (tTd(40, 4)) printf("+++++ %s\n", buf);# endif DEBUG switch (buf[0]) { case 'R': /* specify recipient */ sendtolist(setctluser(&buf[1]), (ADDRESS *) NULL, &e->e_sendqueue); clrctluser(); break; case 'E': /* specify error recipient */ sendtolist(setctluser(&buf[1]), (ADDRESS *) NULL, &e->e_errorqueue); clrctluser(); break; case 'H': /* header */ if (full) (void) chompheader(&buf[1], FALSE); break; case 'M': /* message */ e->e_message = newstr(&buf[1]); break; case 'S': /* sender */ setsender(newstr(&buf[1])); break; case 'D': /* data file name */ if (!full) break; e->e_df = newstr(&buf[1]); e->e_dfp = fopen(e->e_df, "r"); if (e->e_dfp == NULL) syserr("readqf: cannot open %s", e->e_df); break; case 'T': /* init time */ e->e_ctime = atol(&buf[1]); break; case 'P': /* message priority */ e->e_msgpriority = atol(&buf[1]) + WkTimeFact; break; case '\0': /* blank line; ignore */ break; default: syserr("readqf(%s:%d): bad line \"%s\"", e->e_id, LineNumber, buf); break; } } (void) fclose(qfp); FileName = NULL; /* ** If we haven't read any lines, this queue file is empty. ** Arrange to remove it without referencing any null pointers. */ if (LineNumber == 0) { errno = 0; e->e_flags |= EF_CLRQUEUE | EF_FATALERRS | EF_RESPONSE; }}/*** PRINTQUEUE -- print out a representation of the mail queue**** Parameters:** none.**** Returns:** none.**** Side Effects:** Prints a listing of the mail queue on the standard output.*/printqueue(){ register WORK *w; FILE *f; int nrequests; char buf[MAXLINE]; /* ** Read and order the queue. */ nrequests = orderq(TRUE); /* ** Print the work list that we have read. */ /* first see if there is anything */ if (nrequests <= 0) { printf("Mail queue is empty\n"); return; } printf("\t\tMail Queue (%d request%s", nrequests, nrequests == 1 ? "" : "s"); if (nrequests > QUEUESIZE) printf(", only %d printed", QUEUESIZE); if (Verbose) printf(")\n--QID-- --Size-- -Priority- ---Q-Time--- -----------Sender/Recipient-----------\n"); else printf(")\n--QID-- --Size-- -----Q-Time----- ------------Sender/Recipient------------\n"); for (w = WorkQ; w != NULL; w = w->w_next) { struct stat st; auto time_t submittime = 0; long dfsize = -1; char lf[20]; char message[MAXLINE]; extern bool shouldqueue(); f = fopen(w->w_name, "r"); if (f == NULL) { errno = 0; continue; } printf("%7s", w->w_name + 2); (void) strcpy(lf, w->w_name); lf[0] = 'l'; if (stat(lf, &st) >= 0) printf("*"); else if (shouldqueue(w->w_pri)) printf("X"); else printf(" "); errno = 0; message[0] = '\0'; while (fgets(buf, sizeof buf, f) != NULL) { fixcrlf(buf, TRUE); switch (buf[0]) { case 'M': /* error message */ (void) strcpy(message, &buf[1]); break; case 'S': /* sender name */ if (Verbose) printf("%8ld %10ld %.12s %.38s", dfsize, w->w_pri, ctime(&submittime) + 4, &buf[1]); else printf("%8ld %.16s %.45s", dfsize, ctime(&submittime), &buf[1]); if (message[0] != '\0') printf("\n\t\t (%.60s)", message); break; case 'R': /* recipient name */ if (Verbose) printf("\n\t\t\t\t\t %.38s", &buf[1]); else printf("\n\t\t\t\t %.45s", &buf[1]); break; case 'T': /* creation time */ submittime = atol(&buf[1]); break; case 'D': /* data file name */ if (stat(&buf[1], &st) >= 0) dfsize = st.st_size; break; } } if (submittime == (time_t) 0) printf(" (no control file)"); printf("\n"); (void) fclose(f); }}# endif QUEUE/*** QUEUENAME -- build a file name in the queue directory for this envelope.**** Assigns an id code if one does not already exist.** This code is very careful to avoid trashing existing files** under any circumstances.** We first create an nf file that is only used when** assigning an id. This file is always empty, so that** we can never accidently truncate an lf file.**** Parameters:** e -- envelope to build it in/from.** type -- the file type, used as the first character** of the file name.**** Returns:** a pointer to the new file name (in a static buffer).**** Side Effects:** Will create the lf and qf files if no id code is** already assigned. This will cause the envelope** to be modified.*/char *queuename(e, type) register ENVELOPE *e; char type;{ static char buf[MAXNAME]; static int pid = -1; char c1 = 'A'; char c2 = 'A'; if (e->e_id == NULL) { char qf[20]; char nf[20]; char lf[20]; /* find a unique id */ if (pid != getpid()) { /* new process -- start back at "AA" */ pid = getpid(); c1 = 'A'; c2 = 'A' - 1; } (void) sprintf(qf, "qfAA%05d", pid); (void) strcpy(lf, qf); lf[0] = 'l'; (void) strcpy(nf, qf); nf[0] = 'n'; while (c1 < '~' || c2 < 'Z') { int i; if (c2 >= 'Z') { c1++; c2 = 'A' - 1; } lf[2] = nf[2] = qf[2] = c1; lf[3] = nf[3] = qf[3] = ++c2;# ifdef DEBUG if (tTd(7, 20)) printf("queuename: trying \"%s\"\n", nf);# endif DEBUG# ifdef QUEUE if (access(lf, 0) >= 0 || access(qf, 0) >= 0) continue; errno = 0; i = creat(nf, FileMode); if (i < 0) { (void) unlink(nf); /* kernel bug */ continue; } (void) close(i); i = link(nf, lf); (void) unlink(nf); if (i < 0) continue; if (link(lf, qf) >= 0) break; (void) unlink(lf);# else QUEUE if (close(creat(qf, FileMode)) >= 0) break;# endif QUEUE } if (c1 >= '~' && c2 >= 'Z') { syserr("queuename: Cannot create \"%s\" in \"%s\"", qf, QueueDir); exit(EX_OSERR); } e->e_id = newstr(&qf[2]); define('i', e->e_id, e);# ifdef DEBUG if (tTd(7, 1)) printf("queuename: assigned id %s, env=%x\n", e->e_id, e);# ifdef LOG if (LogLevel > 16) syslog(LOG_INFO, "%s: assigned id", e->e_id);# endif LOG# endif DEBUG } if (type == '\0') return (NULL); (void) sprintf(buf, "%cf%s", type, e->e_id);# ifdef DEBUG if (tTd(7, 2)) printf("queuename: %s\n", buf);# endif DEBUG return (buf);}/*** UNLOCKQUEUE -- unlock the queue entry for a specified envelope**** Parameters:** e -- the envelope to unlock.**** Returns:** none**** Side Effects:** unlocks the queue for `e'.*/unlockqueue(e) ENVELOPE *e;{ /* remove the transcript */#ifdef DEBUG# ifdef LOG if (LogLevel > 19) syslog(LOG_INFO, "%s: unlock", e->e_id);# endif LOG if (!tTd(51, 4))#endif DEBUG xunlink(queuename(e, 'x'));# ifdef QUEUE /* last but not least, remove the lock */ xunlink(queuename(e, 'l'));# endif QUEUE}/*** GETCTLUSER -- return controlling user if mailing to prog or file**** Check for a "|" or "/" at the beginning of the address. If** found, return a controlling username.**** Parameters:** a - the address to check out**** Returns:** Either NULL, if we werent mailing to a program or file,** or a controlling user name (possibly in getpwuid's** static buffer).**** Side Effects:** none.**** Discussion:** Bugfix: Mail to a file or program is occasionally** delivered with an inappropriate uid/gid. Problem** arises usually because of a .forward file and the** fact the message got queued instead of immediately** delivered. The proper Control Address info (and it's** uid/gid info) is usually lost irretrievably when a** program or file recipient is written into the queuefile.**** It may be better to emit a controlling address in all** cases where a "ctladdr" can be found. The use of a** new "C" record was considered, but would result in** non-backward-compatible queue files.**** Larry Parmelee 9-Mar-89 Jeff Forys 25-Feb-90** parmelee@cs.cornell.edu forys@cs.utah.edu*/char *getctluser(a) ADDRESS *a;{ extern ADDRESS *getctladdr(); struct passwd *pw; char *retstr, buf[MAXNAME]; /* get unquoted user for file, program or user.name check */ (void) strncpy(buf, a->q_paddr, MAXNAME); buf[MAXNAME-1] = '\0'; stripquotes(buf, TRUE); if (buf[0] != '|' && buf[0] != '/') return((char *)NULL); a = getctladdr(a); /* find controlling address */ if (a != NULL && a->q_uid != 0 && (pw = getpwuid(a->q_uid)) != NULL) retstr = pw->pw_name; else /* use default user */ retstr = DefUser; if (tTd(40, 5)) printf("Set controlling user for `%s' to `%s'\n", (a == NULL)? "<null>": a->q_paddr, retstr); return(retstr);}static char CtlUser[MAXNAME];/*** SETCTLUSER - sets `CtlUser' to controlling user if appropriate** CLRCTLUSER - clears controlling user (no params, nothing returned)**** These routines manipulate `CtlUser'.**** Parameters:** str - string checked for a controlling user**** Returns:** If `str' is of the form "(user) anything", `CtlUser'** is set to "user", and "anything" is returned, otherwise** `str' is returned.**** Side Effects:** setctluser() may chop up `str' into two strings.** `CtlUser' is changed.**** Larry Parmelee 9-Mar-89 Jeff Forys 25-Feb-90** parmelee@cs.cornell.edu forys@cs.utah.edu*/char *setctluser(str)register char *str;{ register char *ectl; int depth = 0, bslash = 0; if (*str != '(') /* no controlling user */ return(str); /* ** Look thru the string for the matching right paren, ** being careful about nesting and backslash escapes. ** This is done to take care of any "weird" user names ** which could conceivably show up between our paren. */ for (ectl = str; *ectl; ectl++) { if (bslash == 0 && *ectl == '\\') { /* escape */ bslash = 1; continue; } if (bslash) { /* escaped char */ bslash = 0; continue; } if (*ectl == '(') /* left paren */ depth++; else if (*ectl == ')') { /* right paren */ if (--depth == 0) break; } } if (depth) /* no controlling user */ return(str); /* we have a controlling user */ *ectl++ = '\0'; (void) strncpy(CtlUser, ++str, MAXNAME); CtlUser[MAXNAME-1] = '\0'; return((*ectl == ' ')? ++ectl: ectl);}clrctluser(){ *CtlUser = '\0';}/*** SETCTLADDR -- create a controlling address**** If global variable `CtlUser' is set and we are given a valid** address, make that address a controlling address; change the** `q_uid', `q_gid', and `q_ruser' fields and set QGOODUID.**** Parameters:** a - address for which control uid/gid info may apply**** Returns:** None.**** Side Effects:** Fills in uid/gid fields in address and sets QGOODUID** flag if appropriate.**** Larry Parmelee 9-Mar-89 Jeff Forys 25-Feb-90** parmelee@cs.cornell.edu forys@cs.utah.edu*/setctladdr(a) ADDRESS *a;{ struct passwd *pw; if (*CtlUser == '\0' || a == NULL || a->q_ruser) return; if ((pw = getpwnam(CtlUser)) != NULL) { if (a->q_home) free(a->q_home); a->q_home = newstr(pw->pw_dir); a->q_uid = pw->pw_uid; a->q_gid = pw->pw_gid; a->q_ruser = newstr(CtlUser); } else { a->q_uid = DefUid; a->q_gid = DefGid; a->q_ruser = newstr(DefUser); } a->q_flags |= QGOODUID; /* flag as a "ctladdr" */ if (tTd(40, 5)) printf("Restored controlling user for `%s' to `%s'\n", (a == NULL)? "<null>": a->q_paddr, a->q_ruser);}/*** BADCTLADDR - ensure that an address does not look like "(user) xxx". EOL** This is only a sanity check and is probably unnecessary, however** being wrong could lead to another security hole so we do it!**** Parameters:** addr - address to be checked**** Returns:** 0 if the address is valid, 1 otherwise.**** Side Effects:** If `addr->q_paddr' looks like "(user) xxx", `addr->q_flags'** gets set to QBADADDR and `addr->q_paddr' gets chopped up.*/boolbadctladdr(addr)ADDRESS *addr;{ char *setctluser(); char *opaddr = addr->q_paddr; if (setctluser(addr->q_paddr) != opaddr) { usrerr("Bad format for qf command: %s %s", CtlUser, addr->q_paddr); clrctluser(); addr->q_flags |= QBADADDR; return(TRUE); } return(FALSE);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -