[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;