[Raw Msg Headers][Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Fixes to smtpserver and mailbox
>The patches below fix the following bugs in zmailer 2.2:
>
>transports/mailbox/mailbox.c:
> There's a race condition between the time zmailer checks
> a mailbox file and opens it for write.
> Fix: use O_EXCL when creating new mailboxes, and verify that
> the file hasn't changed after opening it.
>
> Btw, I have a version of mailbox.c that does V7-style
> file locking (link to foo.LOCK), so you can run the vendor's MUAs
> safely if they use that method (SunOS does).
>
>smtpserver/smtpserver.c:
> Detect and complain about SMTP commands that are
> too long to handle (>8k).
> Long arguments to SMTP HELO no longer overwrite a static buffer.
For those of you using the mea release of zmailer 2.2.1, the following
patches should fix the same bugs.
*** /tmp/T0a28784 Thu Apr 7 02:02:33 1994
--- transports/mailbox/mailbox.c Thu Apr 7 01:41:34 1994
***************
*** 448,454 ****
register char **maild;
int fdmail, uid, messagefd;
FILE *fp;
! struct stat st;
char *file, *cp, *at;
#if defined(BIFF) || defined(RBIFF)
struct biffer *nbp;
--- 448,454 ----
register char **maild;
int fdmail, uid, messagefd;
FILE *fp;
! struct stat st, s2;
char *file, *cp, *at;
#if defined(BIFF) || defined(RBIFF)
struct biffer *nbp;
***************
*** 485,499 ****
if (!setupuidgid(rp, uid, 1))
return;
file = emalloc(strlen(rp->addr->user)+1);
! strcpy(file, rp->addr->user);
! fdmail = createfile(rp, file, uid);
! setrootuid(rp);
! if (fdmail >= 0) {
! close(fdmail);
! } else {
! free(file);
! return;
}
break;
default: /* local user */
/* Zap the possible '@' for a moment -- and restore later
--- 485,500 ----
if (!setupuidgid(rp, uid, 1))
return;
file = emalloc(strlen(rp->addr->user)+1);
! (void) strcpy(file, rp->addr->user);
! if (access(file, F_OK) < 0) {
! fdmail = createfile(rp, file, uid);
! if (fdmail < 0) {
! free(file);
! return;
! }
! (void) close(fdmail);
}
+ setrootuid(rp);
break;
default: /* local user */
/* Zap the possible '@' for a moment -- and restore later
***************
*** 588,593 ****
--- 589,612 ----
DIAGNOSTIC(rp, rp->status, fmtbuf, file);
return;
}
+ /*
+ * The mbox may have been removed and symlinked
+ * after the exstat() above, but before the open(),
+ * so verify that we have the same inode.
+ */
+ if (fstat(fdmail, &s2) < 0) {
+ DIAGNOSTIC(rp, EX_TEMPFAIL,
+ "can't fstat mailbox \"%s\"", file);
+ close(fdmail);
+ return;
+ }
+ if (st.st_ino != s2.st_ino || st.st_dev != s2.st_dev ||
+ s2.st_nlink != 1) {
+ DIAGNOSTIC(rp, EX_TEMPFAIL,
+ "lost race for mailbox \"%s\"", file);
+ close(fdmail);
+ return;
+ }
if ((st.st_mode & S_IFMT) != S_IFREG)
/* don't lock non-files */;
else
***************
*** 1002,1008 ****
struct stat st;
char *cp, msg[BUFSIZ];
! if ((fd = open(file, O_RDWR|O_CREAT, MAILMODE)) < 0) {
saverrno = errno;
if ((cp = strrchr(file, '/')) != NULL) {
*cp = '\0';
--- 1021,1027 ----
struct stat st;
char *cp, msg[BUFSIZ];
! if ((fd = open(file, O_RDWR|O_CREAT|O_EXCL, MAILMODE)) < 0) {
saverrno = errno;
if ((cp = strrchr(file, '/')) != NULL) {
*cp = '\0';
***************
*** 1020,1026 ****
}
*cp = '/';
}
! if ((fd = open(file, O_RDWR|O_CREAT, MAILMODE)) < 0) {
setrootuid(rp);
saverrno = errno;
} else {
--- 1039,1045 ----
}
*cp = '/';
}
! if ((fd = open(file, O_RDWR|O_CREAT|O_EXCL, MAILMODE)) < 0) {
setrootuid(rp);
saverrno = errno;
} else {
*** /tmp/T0a28787 Thu Apr 7 02:03:06 1994
--- smtpserver/smtpserver.c Thu Apr 7 01:46:43 1994
***************
*** 152,158 ****
char *progname, *cmdline, *eocmdline, *logfile;
char *postoffice = NULL;
char *routerprog = NULL;
- char helobuf[MAXHOSTNAMELEN+1];
char myhostname[MAXHOSTNAMELEN+1];
char rhostname[MAXHOSTNAMELEN+1];
char ihostaddr[3*4+1*3+2+1 /* == 18 for '[255.255.255.255]' */ +10/*slack*/];
--- 152,157 ----
***************
*** 568,573 ****
--- 567,573 ----
char buf[8192]; /* XX: limits size of SMTP commands...
On the other hand, limit is asked
to be only 1000 chars, not 8k.. */
+ char helobuf[sizeof buf/sizeof(char)];
int VerboseCommand = 0;
/* opening the logfile should be done before we reset the uid */
***************
*** 630,636 ****
while (fgets(buf, sizeof buf, stdin)) {
if (verbose && !daemon)
fprintf(stdout,"%s",buf); /* XX: trace.. */
! report("%s", buf);
for (cp = buf + strlen(buf) - 1;
cp > buf && isascii(*cp) && isspace(*cp); --cp)
continue;
--- 630,640 ----
while (fgets(buf, sizeof buf, stdin)) {
if (verbose && !daemon)
fprintf(stdout,"%s",buf); /* XX: trace.. */
! if (strchr(buf, '\n') == NULL) {
! type(500, "Line too long");
! continue;
! }
! report("%.100s", buf);
for (cp = buf + strlen(buf) - 1;
cp > buf && isascii(*cp) && isspace(*cp); --cp)
continue;