Subversion Repositories wimsdev

Rev

Rev 11539 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. /*    Copyright (C) 1998-2003 XIAO, Gang of Universite de Nice - Sophia Antipolis
  2.  *
  3.  *  This program is free software; you can redistribute it and/or modify
  4.  *  it under the terms of the GNU General Public License as published by
  5.  *  the Free Software Foundation; either version 2 of the License, or
  6.  *  (at your option) any later version.
  7.  *
  8.  *  This program is distributed in the hope that it will be useful,
  9.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.  *  GNU General Public License for more details.
  12.  *
  13.  *  You should have received a copy of the GNU General Public License
  14.  *  along with this program; if not, write to the Free Software
  15.  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16.  */
  17.  
  18. /* Change root and exec */
  19.  
  20. #define PROC_QUOTA 15
  21. #define UID_MIN 10000
  22. #define UID_MASK 127
  23. #define CPU_MAX 4096
  24. #define TIME_MASK 16383
  25. #define CLEAN_DELAY 100
  26. #define CLEAN_DELAY2 500000
  27. #define MAX_PARMLEN 16384
  28. #define MAX_OUTLEN  65536
  29. #define chroot_tmp "../chroot/tmp/sessions"
  30. #define chroot_path "/bin:/usr/bin:/usr/local/bin"
  31. #define timestamp "../tmp/log/chroot.stamp"
  32.  
  33. #include <stdio.h>
  34. #include <stdlib.h>
  35. #include <errno.h>
  36. #include <fcntl.h>
  37. #include <unistd.h>
  38. #include <dirent.h>
  39. #include <string.h>
  40. #include <time.h>
  41. #include <signal.h>
  42. #include <utime.h>
  43. #include <sys/time.h>
  44. #include <sys/stat.h>
  45. #include <sys/types.h>
  46. #include <sys/resource.h>
  47.  
  48. int execuid=15999;
  49. int execgid=15999;
  50. int must=0;
  51. time_t now;
  52.  
  53. char *env_rm[]={
  54.   "s2_dir", "w_wims_home", "session_base_dir", "trusted_module",
  55.     "session_dir", "wims_server_base", "w_httpd_PWD",
  56.     "w_wims_sesdir", "HTTP_CONNECTION",
  57.     "w_gnuplot_format", "w_insplot_font", "w_ins_anim_limit",
  58.     "w_ins_density", "w_ins_format",
  59.     "texgif_fontdir", "texgif_texheader",
  60.     "w_wims_tmp_debug", "w_insmath_logic", "w_insmath_rawmath",
  61.     "SERVER_ADMIN", "SERVER_ADDR", "SERVER_NAME"
  62. };
  63.  
  64. #define env_rm_cnt (sizeof(env_rm)/sizeof(env_rm[0]))
  65.  
  66. char name_sh[32]="/bin/ash.static";
  67. char opt_sh[32]="-c";
  68. char *pre_sh="\
  69. cd $TMPDIR || exit\n\
  70. echo >/dev/null || exit\n\
  71. cd / 2>/dev/null && exit\n\
  72. ";
  73.  
  74. char *name_perl="/usr/bin/perl";
  75. char *opt_perl="-e";
  76. char *pre_perl="\
  77. chdir($ENV{TMPDIR}) || exit;\n\
  78. chdir(\"/\") && exit;\n\
  79. ";
  80.  
  81.  
  82. /* Remove a tree */
  83. int remove_tree(char *dirname)
  84. {
  85.   DIR *sdir;
  86.   struct dirent *f;
  87.   struct stat dst;
  88.  
  89.   sdir=opendir(dirname);
  90.   if(sdir==NULL) {   /* Cannot open session directory. */
  91.      return -1;
  92.   }
  93.   while((f=readdir(sdir))!=NULL) {
  94.     char fname[255];
  95.     if(strcmp(".",f->d_name)==0 || strcmp("..",f->d_name)==0) continue;
  96.     snprintf(fname,sizeof(fname),"%s/%s",dirname,f->d_name);
  97.     if(lstat(fname,&dst)) continue;
  98.     if(S_ISDIR(dst.st_mode)) remove_tree(fname);
  99.     else {
  100.       if(remove(fname)<0)
  101.         fprintf(stderr,"ch..root: unable to remove %s. %s\n",fname,strerror(errno));
  102.     }
  103.   }
  104.   closedir(sdir);
  105.   if(rmdir(dirname)<0) {  /* Cannot remove directory. */
  106.      return -1;
  107.   }
  108.   return 0;
  109. }
  110.  
  111. /* Clean TMP */
  112. void cleantmp(void)
  113. {
  114.   DIR *sdir_base;
  115.   struct dirent *ses;
  116.   struct stat dst;
  117.  
  118.   if(chdir("../chroot/tmp/sessions")<0) return;
  119.   sdir_base=opendir(".");
  120.   if(sdir_base==NULL) return;
  121.   while((ses=readdir(sdir_base))!=NULL) {
  122.     if(ses->d_name[0]=='.') continue;
  123.     if(lstat(ses->d_name,&dst)) continue;
  124.     if(!S_ISDIR(dst.st_mode)) continue;
  125.     if(dst.st_mtime <= now) {
  126.         if(dst.st_mtime>=now-CLEAN_DELAY) continue;
  127.         if(dst.st_mtime>=now-CLEAN_DELAY2 && (dst.st_mode&S_IRWXO)==0) continue;
  128.     }
  129.     remove_tree(ses->d_name);
  130.   }
  131. }
  132.  
  133. /* Cleaning */
  134. void cleaning(void)
  135. {
  136.   DIR *sdir_base;
  137.   struct dirent *ses;
  138.   struct stat dst;
  139.   struct utimbuf ub;
  140.   char dbuf[256];
  141.  
  142.   if(stat(timestamp,&dst)==0 && dst.st_mtime==now) return;
  143.   ub.actime=ub.modtime=now; utime(timestamp,&ub);
  144.   sdir_base=opendir("/proc");
  145.   if(sdir_base==NULL) goto tmpdir;
  146.   while((ses=readdir(sdir_base))!=NULL) {
  147.     if(ses->d_name[0]<'0' || ses->d_name[9]>'9') continue;
  148.     snprintf(dbuf,sizeof(dbuf),"/proc/%s",ses->d_name);
  149.     if(lstat(dbuf,&dst)) continue;
  150.     if(!S_ISDIR(dst.st_mode)) continue;
  151.     if(dst.st_uid<UID_MIN || dst.st_uid>UID_MIN+UID_MASK) continue;
  152.     if(((dst.st_gid-UID_MIN-now)&TIME_MASK)<=CPU_MAX) continue;
  153.     kill(atoi(ses->d_name),SIGKILL);
  154.   }
  155.   closedir(sdir_base);
  156.   tmpdir: return;
  157. }
  158.  
  159. /* Test Must */
  160. int test_must(void)
  161. {
  162.   char *pc;
  163.   if(must) return 1;
  164.   pc=getenv("chroot"); if(pc && strcmp(pc,"must")==0) return 1;
  165.   else return 0;
  166. }
  167.  
  168. /* MAIN */
  169. int main(int argc,char *argv[])
  170. {
  171.   char *args[1024];
  172.   char parm[MAX_PARMLEN];
  173.   char tmpbuf[256];
  174.   int i,k,uid,t;
  175.   struct stat st;
  176.   struct rlimit lim;
  177.   char *p, *pp;
  178.  
  179.   if(argc<2) return 0;
  180.   now=time(NULL);
  181.   uid=geteuid();
  182.   t=stat("../chroot/tmp/sessions/.chroot",&st);
  183.   if(uid!=0 || t!=0) {
  184.     if(test_must()) goto abandon;
  185.     args[0]="bin/wrap..exec"; k=1;
  186.   }
  187.   else {
  188.     k=0;
  189.     p=getenv("REMOTE_ADDR");
  190.     if(p && *p) {
  191.       pp=strrchr(p,'.'); if(pp) execuid=(atoi(++pp)&UID_MASK)+UID_MIN;
  192.     }
  193.     getrlimit(RLIMIT_CPU,&lim);
  194.     i=lim.rlim_max; if(i<0) i=0; if(i>=CPU_MAX) i=CPU_MAX-1;
  195.     execgid=((i+now+1)&TIME_MASK)+UID_MIN;
  196.     cleaning();
  197.   }
  198.   if(argc>1 && strcmp(argv[1],"cleantmpdir")==0) {
  199.     if(uid!=0) fprintf(stderr,"ch..root cleantmpdir: uid not changed.\n");
  200.     else cleantmp();
  201.     return 0;
  202.   }
  203.   if(argc>3 && argv[1][0]=='&') {
  204.     if(k) goto abandon;
  205.     if(strcmp(argv[2],"sh")==0) {
  206.       lim.rlim_cur=lim.rlim_max=MAX_OUTLEN;
  207.       setrlimit(RLIMIT_FSIZE,&lim);
  208.       args[0]=name_sh; args[1]=opt_sh;
  209.       snprintf(parm,sizeof(parm),"%s\n%s\n",pre_sh,argv[3]);
  210.       args[2]=parm; args[3]=NULL; must=1;
  211.       goto cont;
  212.     }
  213.     if(strcmp(argv[2],"perl")==0) {
  214.       lim.rlim_cur=lim.rlim_max=MAX_OUTLEN;
  215.       setrlimit(RLIMIT_FSIZE,&lim);
  216.       args[0]=name_perl; args[1]=opt_perl;
  217.       snprintf(parm,sizeof(parm),"%s\n%s\n",pre_perl,argv[3]);
  218.       args[2]=parm; args[3]=NULL; must=1;
  219.       goto cont;
  220.     }
  221.     goto abandon;
  222.   }
  223.   for(i=0;i<1000 && i<argc; i++) args[i+k]=argv[i+1];
  224.   args[i]=NULL;
  225.   cont:
  226.   if(uid!=0) {
  227.     if(test_must()) goto abandon;
  228.     goto ex2;
  229.   }
  230.   if(t!=0) {
  231.     stat("bin",&st); execuid=execgid=st.st_uid;
  232.     if(test_must()) goto abandon;
  233.     goto ex;
  234.   }
  235.   if(chroot("../chroot")==0) {
  236.     (void)chdir("/tmp");
  237.     lim.rlim_cur=lim.rlim_max=PROC_QUOTA;
  238.     setrlimit(RLIMIT_NPROC,&lim);
  239.     setenv("PATH",chroot_path,1);
  240.     p=getenv("w_wims_session");
  241.     if(p && *p) {
  242.       snprintf(tmpbuf,sizeof(tmpbuf),"/tmp/sessions/%s",p);
  243.       p=strchr(tmpbuf,'_'); if(p) *p=0;
  244.       setenv("TMPDIR",tmpbuf,1);
  245.       setenv("tmp_dir",tmpbuf,1);
  246.       p=getenv("w_wims_priv_chroot");
  247.       if(p && strstr(p,"tmpdir")!=NULL)
  248.         (void)chdir(tmpbuf);
  249.     }
  250.   }
  251.   else if(test_must()) goto abandon;
  252.   ex:
  253.   if(setregid(execgid,execgid)<0) goto abandon;
  254.   if(setreuid(execuid,execuid)<0) goto abandon;
  255.   ex2:
  256.   for(i=0;i<env_rm_cnt;i++) unsetenv(env_rm[i]);
  257.   if(strchr(args[0],'/')) execv(args[0],args); else execvp(args[0],args);
  258.   abandon: return 127;
  259. }
  260.