--- suexec_org.c	Thu Jan 17 19:19:13 2002
+++ suexec.c	Thu Jan 17 19:39:16 2002
@@ -93,6 +93,9 @@
 
 #include "suexec.h"
 
+#define _SUEXEC_CHROOT
+#define _SUEXEC_CHROOT_DIRECTORY "/home"
+
 /*
  ***********************************************************************
  * There is no initgroups() in QNX, so I believe this is safe :-)
@@ -168,6 +171,21 @@
     NULL
 };
 
+#ifdef _SUEXEC_CHROOT
+#include <unistd.h>
+static int chroot_check_string_first(const char* first,const char* target)
+{
+  int i=0;
+  if(first == 0 || target == 0) return -1;
+  if(first[0] == '\0' || target[i] == '\0') return -1;
+  for(i=0;i<AP_MAXPATH && first[i] != '\0' && target[i] != '\0';i++){
+    if(first[i] != target[i]) return -1;
+  }
+  if(i < 1) return -1;
+  if(first[i] == '\0') return i;
+  return -1;
+}
+#endif
 
 static void err_output(const char *fmt, va_list ap)
 {
@@ -179,6 +197,9 @@
 	if ((log = fopen(LOG_EXEC, "a")) == NULL) {
 	    fprintf(stderr, "failed to open log file\n");
 	    perror("fopen");
+#ifdef _SUEXEC_CHROOT
+	    vfprintf(stderr, fmt, ap);
+#endif
 	    exit(1);
 	}
     }
@@ -267,6 +288,10 @@
     struct group *gr;		/* group entry holder        */
     struct stat dir_info;	/* directory info holder     */
     struct stat prg_info;	/* program info holder       */
+#ifdef _SUEXEC_CHROOT
+    char* chroot_dir = 0; /* chroot directory */
+    int chroot_dir_pathlen = 0; /* chroot directory path len */
+#endif
 
     prog = argv[0];
     /*
@@ -470,6 +495,56 @@
 	exit(109);
     }
 
+#ifdef _SUEXEC_CHROOT
+#ifdef _SUEXEC_CHROOT_DIRECTORY
+    chroot_dir = _SUEXEC_CHROOT_DIRECTORY;
+#else
+    chroot_dir = target_homedir;
+#endif
+    if (getcwd(cwd, AP_MAXPATH) == NULL) {
+      log_err("emerg: cannot get current working directory\n");
+      exit(111);
+    }
+    chroot_dir_pathlen = chroot_check_string_first(chroot_dir,target_homedir);
+    if(chroot_dir_pathlen < 1 || chroot_dir_pathlen >= AP_MAXPATH){
+      log_err("crit:chroot dir(%s) is not equal target_homedir(%s)\n",chroot_dir,target_homedir);
+      exit(110);
+    }
+    if(chroot_check_string_first(chroot_dir,cwd) != chroot_dir_pathlen){
+      log_err("crit:chroot dir(%s) is not equal current(%s)\n",chroot_dir,cwd);
+      exit(110);
+    }
+    if(!userdir){
+      if(chroot_check_string_first(chroot_dir,DOC_ROOT) != chroot_dir_pathlen){
+        log_err("crit:chroot dir(%s) is not equal DOC_ROOT(%s)\n",chroot_dir,DOC_ROOT);
+        exit(110);
+      }
+    }
+    if(chroot_check_string_first(chroot_dir,LOG_EXEC) != chroot_dir_pathlen){
+      log_err("info: log closed(%s)\n",LOG_EXEC);
+      if (log != NULL) {
+        fclose(log);
+        log = NULL;
+      }
+    }
+    /* chroot */
+    if(chroot_dir == 0 || chroot_dir[0] == '\0'){
+      log_err("crit:chroot dir is fail\n");
+      exit(110);
+    }
+    if((chroot(chroot_dir)) != 0){
+      log_err("crit: cannot chroot (%s)\n",chroot_dir);
+      exit(110);
+    }
+    log_err("info: chroot to: %s\n",chroot_dir);
+    if(target_homedir[chroot_dir_pathlen] == '\0'){
+      target_homedir[0] = '/';
+      target_homedir[1] = '\0';
+    }else{
+      target_homedir += chroot_dir_pathlen;
+    }
+#endif
+
     /*
      * setuid() to the target user.  Error out on fail.
      */
@@ -502,12 +577,30 @@
 	}
     }
     else {
+#ifdef _SUEXEC_CHROOT
+    {
+    char* docroot = strdup(DOC_ROOT);
+    if(docroot[chroot_dir_pathlen] == '\0'){
+      docroot[0] = '/';
+      docroot[1] = '\0';
+    }else{
+      docroot += chroot_dir_pathlen;
+    }
+	if (((chdir(docroot)) != 0) ||
+	    ((getcwd(dwd, AP_MAXPATH)) == NULL) ||
+	    ((chdir(cwd)) != 0)) {
+	    log_err("emerg: cannot get docroot information (%s)\n", docroot);
+	    exit(113);
+	}
+    }
+#else
 	if (((chdir(DOC_ROOT)) != 0) ||
 	    ((getcwd(dwd, AP_MAXPATH)) == NULL) ||
 	    ((chdir(cwd)) != 0)) {
 	    log_err("emerg: cannot get docroot information (%s)\n", DOC_ROOT);
 	    exit(113);
 	}
+#endif
     }
 
     if ((strncmp(cwd, dwd, strlen(dwd))) != 0) {
