diff -u stunnel-3.22/client.c stunnel-3.22-sg/client.c
--- stunnel-3.22/client.c	Sun Dec 23 14:41:32 2001
+++ stunnel-3.22-sg/client.c	Wed May 29 02:51:34 2002
@@ -220,7 +220,9 @@
     else
         c->ip=0;
     /* Setup c->remote_fd, now */
-    if(options.option&OPT_REMOTE)
+    if (options.option&OPT_FDS)
+	fd=options.use_fd;
+    else if(options.option&OPT_REMOTE)
         fd=connect_remote(c);
     else /* NOT in remote mode */
         fd=connect_local(c);
@@ -845,9 +847,9 @@
 
 int fdprintf(int fd, char *format, ...) {
     va_list arglist;
-    char line[STRLEN], logline[STRLEN];
+    char line[STRLEN];
+    int len;
     char crlf[]="\r\n";
-    int len, ptr, written, towrite;
 
     va_start(arglist, format);
 #ifdef HAVE_VSNPRINTF
@@ -858,58 +860,87 @@
     va_end(arglist);
     safeconcat(line, crlf);
     len+=2;
-    for(ptr=0, towrite=len; towrite>0; ptr+=written, towrite-=written) {
-        switch(waitforsocket(fd, 1 /* write */)) {
-        case -1: /* Error */
-            sockerror("select");
-            return -1;
-        case 0: /* Timeout */
-            log(LOG_ERR, "Select timeout (fdprintf)");
-            return -1;
-        }
-        written=writesocket(fd, line+ptr, towrite);
-        if(written<0) {
-            sockerror("writesocket (fdprintf)");
-            return -1;
-        }
-    }
-    safecopy(logline, line);
-    safestring(logline);
-    log(LOG_DEBUG, " -> %s", logline);
-    return len;
+    if (fdwrite(fd,line,len) < 0)
+      return -1;
+    else
+      return len;
 }
 
-int fdscanf(int fd, char *format, char *buffer) {
-    char line[STRLEN], logline[STRLEN];
+int fdputs(int fd, char *line) {
+  char crlf[]="\r\n";
+  
+  if (fdwrite(fd, line, strlen(line)) < 0)
+    return -1;
+  return fdwrite(fd,crlf,strlen(crlf));
+}
+
+int fdwrite(int fd, char *buffer, int len) {
+  char logline[STRLEN];
+  int ptr, written, towrite;
+
+  for(ptr=0, towrite=len; towrite>0; ptr+=written, towrite-=written) {
+    switch(waitforsocket(fd, 1 /* write */)) {
+    case -1: /* Error */
+      sockerror("select");
+      return -1;
+    case 0: /* Timeout */
+      log(LOG_ERR, "Select timeout (fdwrite)");
+      return -1;
+    }
+    
+    written=writesocket(fd, buffer+ptr, towrite);
+    if(written<0) {
+      sockerror("writesocket (fdwrite)");
+      return -1;
+    }
+  }
+  safecopy(logline, buffer);
+  safestring(logline);
+  log(LOG_DEBUG, " -> %s", logline);
+  return 0;
+}  
+
+int fdgets(int fd, char *buffer) {
+    char logline[STRLEN];
     int ptr;
 
-    for(ptr=0; ptr<STRLEN-1; ptr++) {
+    for(ptr=0; ptr<STRLEN-1;) {
         switch(waitforsocket(fd, 0 /* read */)) {
         case -1: /* Error */
             sockerror("select");
             return -1;
         case 0: /* Timeout */
-            log(LOG_ERR, "Select timeout (fdscanf)");
+            log(LOG_ERR, "Select timeout (fdgets)");
             return -1;
         }
-        switch(readsocket(fd, line+ptr, 1)) {
+        switch(readsocket(fd, buffer+ptr, 1)) {
         case -1: /* error */
-            sockerror("readsocket (fdscanf)");
+            sockerror("readsocket (fdgets)");
             return -1;
         case 0: /* EOF */
-            log(LOG_ERR, "Unexpected socket close (fdscanf)");
+            log(LOG_ERR, "Unexpected socket close (fdgets)");
             return -1;
         }
-        if(line[ptr]=='\r')
+        if(buffer[ptr]=='\r')
             continue;
-        if(line[ptr]=='\n')
+        if(buffer[ptr]=='\n')
             break;
+	ptr++;
     }
-    line[ptr]='\0';
-    safecopy(logline, line);
+    buffer[ptr]='\0';
+    safecopy(logline, buffer);
     safestring(logline);
     log(LOG_DEBUG, " <- %s", logline);
-    return sscanf(line, format, buffer);
+    return 0;
+}
+
+int fdscanf(int fd, char *format, char *buffer) {
+  char line[STRLEN];
+  
+  if (fdgets(fd, line) < 0)
+    return -1;
+
+  return sscanf(line, format, buffer);
 }
 
 static int waitforsocket(int fd, int dir) {
diff -u stunnel-3.22/options.c stunnel-3.22-sg/options.c
--- stunnel-3.22/options.c	Sun Dec 23 15:08:51 2001
+++ stunnel-3.22-sg/options.c	Wed May 15 03:55:41 2002
@@ -69,7 +69,7 @@
     options.verify_use_only_my=0;
     options.debug_level=5;
 #ifndef USE_WIN32
-    options.facility=LOG_DAEMON;
+   options.facility=LOG_DAEMON;
 #endif
     options.session_timeout=300;
     options.cipher_list=NULL;
@@ -84,8 +84,13 @@
     options.random_bytes=RANDOM_BYTES;
     options.output_file=NULL;
     options.local_ip=NULL;
+    options.chroot_dir=NULL;
     opterr=0;
-    while ((c = getopt(argc, argv, "A:a:cp:v:d:fTl:L:r:s:g:t:u:n:N:hC:D:O:E:R:WB:VP:S:o:I:")) != EOF)
+    while ((c = getopt(argc, argv, "A:a:cp:v:d:fTl:L:r:s:g:t:u:n:N:hC:D:O:E:R:WB:VP:S:o:I:"
+	               "F:"
+                       "/:"
+                       "i"
+          )) != EOF)
         switch (c) {
             case 'A':
                     safecopy(options.cert_file,optarg);
@@ -140,6 +145,16 @@
             case 'f':
                 options.option|=OPT_FOREGROUND;
                 break;
+            case 'F':
+ 	        options.option|=OPT_FDS;
+		options.use_fd=atoi(optarg);
+	        break;
+  	    case 'i':
+	        options.option|=OPT_SUID_FIRST; 
+                break;
+            case '/':
+	        options.chroot_dir=optarg;
+		break;
             case 'T':
                 options.option|=OPT_TRANSPARENT;
                 break;
@@ -257,8 +272,8 @@
         print_info();
     }
 #endif
-    if(!(options.option&(OPT_REMOTE|OPT_PROGRAM))) {
-        log(LOG_ERR, "Either -r, -l (or -L) option must be used");
+    if(!(options.option&(OPT_REMOTE|OPT_PROGRAM|OPT_FDS))) {
+        log(LOG_ERR, "Either -r, -l (or -L), or -F option must be used");
         print_info();
     }
     if((options.option&OPT_REMOTE) && (options.option&OPT_PROGRAM)
@@ -331,9 +346,12 @@
         "[-S sources] "
         "[-t timeout] "
         "\n\t"
-        "[-u ident_username] "
         "[-s setuid_user] "
         "[-g setgid_group] "
+	"[-i] "
+        "[-/ chroot-dir] "
+        "\n\t"
+        "[-u ident_username] "
         "[-n protocol]"
         "\n\t"
         "[-R randfile] "
@@ -345,7 +363,7 @@
 #ifndef USE_WIN32
         "[-P { dir/ | filename | none } ] "
         "\n\t[-d [host:]port [-f] ] "
-        "\n\t[-r [host:]port | { -l | -L }  program [-- args] ] "
+        "\n\t[-r [host:]port | { -l | -L }  program [-- args] | -F fd-num ] "
 #else
         "\n\t-d [host:]port -r [host:]port"
 #endif
@@ -360,6 +378,7 @@
 #ifndef USE_WIN32
         "\n  -l program\texecute local inetd-type program"
         "\n  -L program\topen local pty and execute program"
+        "\n  -F fd-num\tuse the already-open socket on file descriptor fd-num"
 #endif
         "\n"
         "\n  -c\t\tclient mode (remote service uses SSL)"
@@ -388,6 +407,8 @@
 #ifndef USE_WIN32
         "\n  -s username\tsetuid() to username in daemon mode"
         "\n  -g groupname\tsetgid() to groupname in daemon mode"
+        "\n  -i\t\tsetuid() and/or setgid() immediately"
+	"\n  -/ chroot-dir\tchroot() to chroot-dir immediately after starting"
         "\n  -P arg\tspecify pid file { dir/ | filename | none }"
 #endif
         "\n  -C list\tset permitted SSL ciphers"
diff -u stunnel-3.22/protocol.c stunnel-3.22-sg/protocol.c
--- stunnel-3.22/protocol.c	Thu Dec 20 02:52:37 2001
+++ stunnel-3.22-sg/protocol.c	Wed May 29 03:33:35 2002
@@ -36,9 +36,11 @@
 static int smb_client(CLI *);
 static int smb_server(CLI *);
 static int smtp_client(CLI *);
-static int smtp_server(CLI *);
+static int smtp_server(CLI *, int allow_downgrade);
 static int pop3_client(CLI *);
-static int pop3_server(CLI *);
+static int pop3_server(CLI *, int allow_downgrade);
+static int imap_client(CLI *);
+static int imap_server(CLI *, int allow_downgrade);
 static int nntp_client(CLI *);
 static int nntp_server(CLI *);
 static int telnet_client(CLI *);
@@ -58,17 +60,35 @@
         else
             return smb_server(c);
     }
-    if(!strcmp(protocol, "smtp")) {
+    if(!strncmp(protocol, "smtp",4)) {
         if(client)
             return smtp_client(c);
-        else
-            return smtp_server(c);
+        else {
+	  if (protocol[4] == '-')
+            return smtp_server(c,1);
+	  else if (protocol[4] == '\0')
+	    return smtp_server(c,0);
+	}
     }
-    if(!strcmp(protocol, "pop3")) {
+    if(!strncmp(protocol, "pop3",4)) {
         if(client)
             return pop3_client(c);
-        else
-            return pop3_server(c);
+        else {
+	  if (protocol[4] == '-')
+            return pop3_server(c,1);
+	  else if (protocol[4] == '\0')
+	    return pop3_server(c,0);
+	}
+    }
+    if(!strncmp(protocol, "imap",4)) {
+        if(client)
+	  return imap_client(c);
+        else {
+	  if (protocol[4] == '-')
+            return imap_server(c,1);
+	  else if (protocol[4] == '\0')
+	    return imap_server(c,0);
+	}
     }
     if(!strcmp(protocol, "nntp")) {
         if(client)
@@ -131,33 +151,181 @@
     return 0;
 }
 
-static int smtp_server(CLI *c) {
+#define PP_BUFSIZE 8192
+static int plaintext_proxy(CLI *c)
+{
+  fd_set rd_set, wr_set;
+  char rbuf[PP_BUFSIZE];
+  int rbufend,rdone;
+  char lbuf[PP_BUFSIZE];
+  int lbufend,ldone;
+  struct timeval tv;
+  int ready;
+  int fdmax;
+  int howmuch, sofar;
+
+  fdmax = c->remote_fd;
+  if (c->local_wfd > fdmax)
+    fdmax = c->local_wfd;
+  if (c->local_rfd > fdmax)
+    fdmax = c->local_rfd;
+  fdmax++;
+  
+  lbufend = rbufend = 0;
+  rdone = ldone = 0;
+
+  tv.tv_sec = 86400;
+  tv.tv_usec = 0;
+  while( !( (rdone || ldone) && (!rbufend && !lbufend) ) ) {
+    log(LOG_DEBUG,"rdone=%d, ldone=%d, rbufend=%d, lbufend=%d",rdone,ldone,rbufend,lbufend);
+    FD_ZERO(&rd_set);
+    FD_ZERO(&wr_set);
+    if (rbufend)
+      FD_SET((c->local_wfd),&wr_set);
+    else if (!rdone)
+      FD_SET(c->remote_fd,&rd_set);
+    
+    if (lbufend)
+      FD_SET(c->remote_fd,&wr_set);
+    else if (!ldone)
+      FD_SET(c->local_rfd,&rd_set);
+    
+    do { /* Skip "Interrupted system call" errors */
+      ready=select(fdmax, &rd_set, &wr_set, NULL, &tv);
+    } while(ready<0 && get_last_socket_error()==EINTR);
+    
+    if(ready<0) { /* Break the connection for others */
+      sockerror("select");
+      c->error=1;
+      return 1;
+    }
+    if(!ready) { /* Timeout */
+      log(LOG_DEBUG, "select timeout - connection reset");
+      c->error=1;
+      return 1;
+    }
+    
+    if (lbufend > 0) {
+      if (FD_ISSET(c->remote_fd,&wr_set))
+	{
+	  sofar = 0;
+	  while (sofar < lbufend) {
+	    if ((howmuch=write(c->remote_fd,lbuf+sofar,lbufend-sofar)) < 0) {
+	      sockerror("write");
+	      c->error=1;
+	      return 1;
+	    }
+	    sofar += howmuch;
+	  }
+	  lbufend = 0;
+	}
+    } else {
+      if (FD_ISSET(c->local_rfd,&rd_set)) {
+	if ( (lbufend = read(c->local_rfd,lbuf,PP_BUFSIZE)) < 0) {
+	  sockerror("read");
+	  c->error = 1;
+	  return 1;
+	}
+	if (lbufend == 0) /* EOF */
+        {
+	  log(LOG_DEBUG,"EOF reading from local");
+	  ldone=1;
+	}
+      }
+    }
+
+    if (rbufend > 0) {
+      if (FD_ISSET(c->local_wfd, &wr_set)) {
+	sofar = 0;
+	while (sofar < rbufend) {
+	  if ( (howmuch = write(c->local_wfd, rbuf + sofar, rbufend - sofar)) < 0) {
+	    sockerror("write");
+	    c->error=1;
+	    return 1;
+	  }
+	  sofar += howmuch;
+	}
+	rbufend = 0;
+      }
+    } else {
+      if (FD_ISSET(c->remote_fd,&rd_set)) {
+	if ( (rbufend = read(c->remote_fd,rbuf,PP_BUFSIZE)) < 0) {
+	  sockerror("read");
+	  c->error = 1;
+	  return 1;
+	}
+	if (rbufend == 0) /* EOF */ {
+	  log(LOG_DEBUG,"EOF reading from remote");
+	  rdone=1;
+	}
+      }
+    }
+  }
+
+  log(LOG_DEBUG, "plaintext_proxy finished normally.");
+  return 0;
+}
+
+static int smtp_server(CLI *c, int allow_downgrade) {
     char line[STRLEN];
+    int read_ret;
 
     if(RFC2487(c->local_rfd)==0)
         return 0; /* Return if RFC 2487 is not used */
 
-    if(fdscanf(c->remote_fd, "220%[^\n]", line)!=1) {
+    if(fdscanf(c->remote_fd, "220%[^\r\n]", line)!=1) {
         log(LOG_ERR, "Unknown server welcome");
         return -1;
     }
     if(fdprintf(c->local_wfd, "220%s + stunnel", line)<0)
         return -1;
-    if(fdscanf(c->local_rfd, "EHLO %[^\n]", line)!=1) {
-        log(LOG_ERR, "Unknown client EHLO");
-        return -1;
-    }
-    if(fdprintf(c->local_wfd, "250-%s Welcome", line)<0)
-        return -1;
-    if(fdprintf(c->local_wfd, "250 STARTTLS")<0)
-        return -1;
-    if(fdscanf(c->local_rfd, "STARTTLS", line)<0) {
-        log(LOG_ERR, "STARTTLS expected");
-        return -1;
+    
+    /* See if we get an EHLO command */
+    if (((read_ret=fdgets(c->local_rfd, line)) >= 0) &&
+	(strlen(line) >= 4) &&
+	(!line[4] || isspace(line[4])) &&
+	 (strncasecmp(line,"ehlo",4) == 0) ) {
+      if (fdputs(c->remote_fd,line) < 0)
+	return -1;
+      while ( (fdgets(c->remote_fd, line) >= 0) 
+	      && (line[3] == '-') ) {
+	if (fdputs(c->local_wfd,line) < 0)
+	  return -1;
+      }
+      line[3] = '-';
+      if (fdputs(c->local_wfd,line) < 0)
+	return -1;
+      if (fdputs(c->local_wfd,"250 STARTTLS") < 0)
+	return -1;
+      
+      /* See if we get a STARTTLS command */
+      if (((read_ret=fdgets(c->local_rfd, line)) >= 0) &&
+	  (strlen(line) >= 8) &&
+	  (!line[8] || isspace(line[8])) &&
+	  (strncasecmp(line,"starttls",8) == 0) ) {
+	if (!line[8]) {
+	  /* Technically, we should shut down the SMTP connection and get
+	   * a new one, but screw it for now. */
+	  if(fdputs(c->local_wfd, "220 Go ahead") >= 0)
+	    return 0;
+	} else {
+	  fdputs(c->local_wfd,"501 Syntax error (no parameters allowed; STARTTLS disabled) (#5.5.4)");
+	  return -1;
+	} 
+	
+      }
+    }
+    if (read_ret < 0)
+      return -1;
+    if (allow_downgrade) {
+      if (fdputs(c->remote_fd,line) < 0)
+	return -1;
+      exit(plaintext_proxy(c));
+    }
+    else {
+      fdputs(c->local_wfd,"421 Encryption required; must use STARTTLS");
+      return -1;
     }
-    if(fdprintf(c->local_wfd, "220 Go ahead", line)<0)
-        return -1;
-    return 0;
 }
 
 static int pop3_client(CLI *c) {
@@ -182,31 +350,157 @@
     return 0;
 }
 
-static int pop3_server(CLI *c) {
+static int pop3_server(CLI *c, int allow_downgrade) {
     char line[STRLEN];
 
-    if(fdscanf(c->remote_fd, "%[^\n]", line)<0)
-        return -1;
+    if(fdscanf(c->remote_fd, "%[^\r\n]", line)<0)
+      return -1;
+
     if(fdprintf(c->local_wfd, "%s + stunnel", line)<0)
         return -1;
-    if(fdscanf(c->local_rfd, "%[^\n]", line)<0)
+
+    while(1) {
+      if(fdgets(c->local_rfd, line)<0)
         return -1;
-    if(!strncmp(line, "CAPA", 4)) { /* Client wants RFC 2449 extensions */
-        if(fdprintf(c->local_wfd, "-ERR Stunnel does not support capabilities")<0)
-            return -1;
-        if(fdscanf(c->local_rfd, "%[^\n]", line)<0)
-            return -1;
+      if(strncasecmp(line, "CAPA", 4) == 0) { /* Client wants RFC 2449 extensions */
+	fdputs(c->remote_fd,line);
+	if (fdgets(c->remote_fd,line) < 0)
+	  return -1;
+	if (line[0] == '+') {
+	  if (fdputs(c->local_wfd,line) < 0)
+	    return -1;
+	  while ( (fdgets(c->remote_fd,line) >= 0)
+		  && ( (strlen(line) > 1) || (line[0] != '.') ) ) {
+	    if (fdputs(c->local_wfd,line) < 0)
+	      return -1;
+	  }
+	} else {
+	  if (fdputs(c->local_wfd,"+OK Stunnel capability list follows") < 0)
+	    return -1;
+	}
+	  if (fdputs(c->local_wfd,"STLS") < 0)
+	    return -1;
+	  if (fdputs(c->local_wfd,".") < 0)
+	    return -1;
+      } else if (strncasecmp(line, "STLS", 4) == 0) {
+	if(fdputs(c->local_wfd, "+OK stunnel starting TLS negotiation")<0)
+	  return -1;
+	return 0;
+      }
+      else {
+	if (fdputs(c->remote_fd,line) < 0)
+	  return -1;
+	if (allow_downgrade)
+	  exit(plaintext_proxy(c));
+	else {
+	  fdputs(c->local_wfd,"-Encryption required; must use STLS");
+	  return -1;
+	}
+      }
     }
-    if(strncmp(line, "STLS", 4)) {
-        log(LOG_ERR, "Client does not want TLS");
+}
+
+static int imap_client(CLI *c) {
+    char line[STRLEN];
+
+    if(fdgets(c->remote_fd, line)<0)
+        return -1;
+    if(strncasecmp(line,"* OK ",4)) {
+        log(LOG_ERR, "Unknown server welcome");
         return -1;
     }
-    if(fdprintf(c->local_wfd, "+OK Stunnel starts TLS negotiation")<0)
+    if(fdputs(c->local_wfd, line)<0)
         return -1;
-
+    if(fdprintf(c->remote_fd, "a STARTTLS")<0)
+        return -1;
+    if(fdgets(c->remote_fd, line)<0)
+        return -1;
+    if(strncasecmp(line,"a OK ",5)) {
+        log(LOG_ERR, "Server does not support TLS");
+        return -1;
+    }
     return 0;
 }
 
+static int imap_server(CLI *c, int allow_downgrade) {
+    char line[STRLEN];
+    char procline[STRLEN];
+    char *tag, *cmd;
+    int do_if_fail = 0;
+
+    if (fdgets(c->remote_fd,line) < 0)
+      return -1;
+
+    if(fdprintf(c->local_wfd, "%s + stunnel", line)<0)
+        return -1;
+
+    while(1) {
+      if(fdgets(c->local_rfd, line)<0)
+        return -1;
+      safecopy(procline, line);
+      tag = procline;
+      if (!(cmd=strchr(procline,' '))) {
+	do_if_fail = 1;
+	break;
+      }
+      *cmd='\0';
+      cmd++;
+      if(strncasecmp(cmd, "CAPABILITY", 11) == 0) {
+	fdputs(c->remote_fd,line);
+	if (fdgets(c->remote_fd,line) < 0)
+	  return -1;
+	if (strncasecmp(line,"* CAPABILITY",12) == 0) {
+	  safeconcat(line," STARTTLS");
+	  fdputs(c->local_wfd,line);
+	} else {
+	  do_if_fail = 2;
+	  break;
+	}
+	if (fdgets(c->remote_fd,line) < 0)
+	  return -1;
+	if ( (strncasecmp(line,tag,strlen(tag)) != 0) ||
+	     (line[strlen(tag)] != ' ') ||
+	     (strncasecmp(line+strlen(tag)+1,"OK",2) != 0) )
+	  {
+	    do_if_fail = 2;
+	    break;
+	  }
+	if (fdputs(c->local_wfd,line) < 0)
+	  return -1;
+      }
+      else if (strncasecmp(cmd, "STARTTLS", 8) == 0) {
+	if (fdwrite(c->local_wfd,tag,strlen(tag)) < 0)
+	  return -1;
+	if (fdwrite(c->local_wfd," ",1) < 0)
+	  return -1;
+	if (fdputs(c->local_wfd,"OK Begin TLS negotiation now") < 0)
+	  return -1;
+
+	return 0;
+      } else {
+	do_if_fail = 1;
+	break;
+      }
+    }
+    
+    if (allow_downgrade) {
+      if (do_if_fail == 1) {
+	if (fdputs(c->remote_fd,line) < 0)
+	  return -1;
+      } else if (do_if_fail == 2) {
+	if (fdputs(c->local_wfd,line) < 0)
+	  return -1;
+      }
+      exit(plaintext_proxy(c));
+    }
+    else {
+      fdputs(c->local_wfd,"-Encryption required; must use STLS");
+      return -1;
+    }
+
+}
+
+
 static int nntp_client(CLI *c) {
     char line[STRLEN];
 
diff -u stunnel-3.22/prototypes.h stunnel-3.22-sg/prototypes.h
--- stunnel-3.22/prototypes.h	Sun Nov 11 14:16:01 2001
+++ stunnel-3.22-sg/prototypes.h	Wed May 29 02:15:43 2002
@@ -41,7 +41,10 @@
 /* Prototypes for client.c */
 void *client(void *);
 /* descriptor versions of fprintf/fscanf */
+int fdwrite(int fd, char *buffer, int len);
+int fdputs(int fd, char *line);
 int fdprintf(int, char *, ...);
+int fdgets(int fd, char *buffer);
 int fdscanf(int, char *, char *);
 
 /* Prototypes for log.c */
@@ -79,6 +82,8 @@
 #define OPT_REMOTE      0x20
 #define OPT_TRANSPARENT 0x40
 #define OPT_PTY         0x80
+#define OPT_FDS         0x100
+#define OPT_SUID_FIRST  0x200
 
 typedef struct {
     char pem[STRLEN];                        /* pem (priv key/cert) filename */
@@ -111,6 +116,8 @@
     int cert_defaults;
     char *output_file;
     u32 *local_ip;
+    int use_fd;
+    char *chroot_dir;
 } server_options;
 
 typedef enum {
Only in stunnel-3.22-sg: prototypes.h~
Only in stunnel-3.22-sg: pty.o
diff -u stunnel-3.22/ssl.c stunnel-3.22-sg/ssl.c
--- stunnel-3.22/ssl.c	Sun Dec 23 14:46:03 2001
+++ stunnel-3.22-sg/ssl.c	Wed May 15 03:54:39 2002
@@ -46,6 +46,7 @@
 #include <openssl/ssl.h>
 #include <openssl/err.h>
 #include <openssl/rand.h>
+#include <openssl/conf.h>
 #else
 #include <lhash.h>
 #include <ssl.h>
@@ -71,7 +72,6 @@
 SSL_CTX *ctx; /* global SSL context */
 
 void context_init() { /* init SSL */
-
     if(!init_prng())
         log(LOG_INFO, "PRNG seeded successfully");
     SSLeay_add_ssl_algorithms();
Only in stunnel-3.22-sg: ssl.c~
Only in stunnel-3.22-sg: ssl.o
Only in stunnel-3.22-sg: sthreads.o
Only in stunnel-3.22-sg: stunnel
diff -u stunnel-3.22/stunnel.c stunnel-3.22-sg/stunnel.c
--- stunnel-3.22/stunnel.c	Thu Dec 20 02:53:54 2001
+++ stunnel-3.22-sg/stunnel.c	Tue May 28 04:03:39 2002
@@ -54,6 +54,8 @@
 static void create_pid();
 static void delete_pid();
 #endif
+void do_setugid(char *user, char *group);
+int is_alldigits(char *s);
 
     /* Socket functions */
 static int listen_local();
@@ -119,6 +121,24 @@
     if(!(options.option&OPT_FOREGROUND))
         options.foreground=0;
     log_open();
+    if (options.chroot_dir)
+      {
+	log(LOG_DEBUG,"chroot(%s)",options.chroot_dir);
+	if (chroot(options.chroot_dir) < 0)
+	  {
+	    ioerror("chroot");
+	    exit(1);
+	  }
+
+	if (chdir("/") < 0)
+	  {
+	    ioerror("chdir");
+	    exit(1);
+	  }
+      }
+    if ( options.option&OPT_SUID_FIRST && 
+	 (options.setuid_user || options.setgid_group))
+      do_setugid(options.setuid_user,options.setgid_group);
     log(LOG_NOTICE, "Using '%s' as tcpwrapper service name", options.servname);
 
     /* check if certificate exists */
@@ -371,49 +391,9 @@
         exit(1);
     }
 
-#ifndef USE_WIN32
-    if(options.setgid_group) {
-        struct group *gr;
-        gid_t gr_list[1];
-
-        gr=getgrnam(options.setgid_group);
-        if(!gr) {
-            log(LOG_ERR, "Failed to get GID for group %s",
-                options.setgid_group);
-            exit(1);
-        }
-        if(setgid(gr->gr_gid)) {
-            sockerror("setgid");
-            exit(1);
-        }
-        gr_list[0]=gr->gr_gid;
-        if(setgroups(1, gr_list)) {
-            sockerror("setgroups");
-            exit(1);
-        }
-    }
-
-    if(options.setuid_user) {
-        struct passwd *pw;
-
-        pw=getpwnam(options.setuid_user);
-        if(!pw) {
-            log(LOG_ERR, "Failed to get UID for user %s",
-                options.setuid_user);
-            exit(1);
-        }
-#ifndef USE_WIN32
-        /* gotta chown that pid file, or we can't remove it. */
-        if ( options.pidfile[0] && chown( options.pidfile, pw->pw_uid, -1) ) {
-            log(LOG_ERR, "Failed to chown pidfile %s", options.pidfile);
-        }
-#endif
-        if(setuid(pw->pw_uid)) {
-            sockerror("setuid");
-            exit(1);
-        }
-    }
-#endif /* USE_WIN32 */
+    if (!(options.option&OPT_SUID_FIRST) &&
+        (options.setuid_user || options.setgid_group))
+      do_setugid(options.setuid_user,options.setgid_group);
 
     return ls;
 }
@@ -682,4 +662,79 @@
     return retval;
 }
 
+void do_setugid(char *user, char *group)
+  {
+    uid_t uid;
+    gid_t gid;
+
+#ifndef USE_WIN32
+    if(group) {
+      struct group *gr;
+      gid_t gr_list[1];
+      
+      if (is_alldigits(group))
+	{
+	  gid=atoi(group);
+	}
+      else
+	{
+	  gr=getgrnam(group);
+	  if(!gr) {
+	    log(LOG_ERR, "Failed to get GID for group %s",
+		group);
+	    exit(1);
+	  }
+	  gid = gr->gr_gid;
+	}
+
+      if(setgid(gid)) {
+	sockerror("setgid");
+	exit(1);
+      }
+      gr_list[0]=gid;
+      if(setgroups(1, gr_list)) {
+	sockerror("setgroups");
+	exit(1);
+      }
+    }
+#endif
+    
+    if(user) {
+      struct passwd *pw;
+      
+      if (is_alldigits(user))
+	{
+	  uid = atoi(user);
+	}
+      else
+	{
+	  pw=getpwnam(user);
+	  if(!pw) {
+            log(LOG_ERR, "Failed to get UID for user %s",
+                user);
+            exit(1);
+	  }
+	  uid=pw->pw_uid;
+	}
+      
+#ifndef USE_WIN32
+	  /* gotta chown that pid file, or we can't remove it. */
+	  if ( options.pidfile[0] && chown( options.pidfile, uid, -1) ) {
+            log(LOG_ERR, "Failed to chown pidfile %s", options.pidfile);
+	  }
+#endif
+	  if(setuid(uid)) {
+            sockerror("setuid");
+            exit(1);
+	  }
+    }
+  }
+
+int is_alldigits(char *s) {
+  while (*s)
+    if (!isdigit(*s++))
+      return 0;
+  return 1;
+}
+      
 /* End of stunnel.c */
