Subversion Repositories wimsdev

Rev

Rev 10 | Rev 7076 | 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.         /* remove a tree */
  82. int remove_tree(char *dirname)
  83. {
  84.     DIR *sdir;
  85.     struct dirent *f;
  86.     struct stat dst;
  87.  
  88.     sdir=opendir(dirname);
  89.     if(sdir==NULL) {   /* Cannot open session directory. */
  90.         return -1;
  91.     }
  92.     while((f=readdir(sdir))!=NULL) {
  93.         char fname[255];
  94.         if(strcmp(".",f->d_name)==0 || strcmp("..",f->d_name)==0) continue;
  95.         snprintf(fname,sizeof(fname),"%s/%s",dirname,f->d_name);
  96.         if(lstat(fname,&dst)) continue;
  97.         if(S_ISDIR(dst.st_mode)) remove_tree(fname);
  98.         else {
  99.             if(remove(fname)<0)
  100.               fprintf(stderr,"ch..root: unable to remove %s. %s\n",fname,strerror(errno));
  101.         }
  102.     }
  103.     closedir(sdir);
  104.     if(rmdir(dirname)<0) {      /* Cannot remove directory. */
  105.         return -1;
  106.     }
  107.     return 0;
  108. }
  109.  
  110. void cleantmp(void)
  111. {
  112.     DIR *sdir_base;
  113.     struct dirent *ses;
  114.     struct stat dst;
  115.    
  116.     if(chdir("../chroot/tmp/sessions")<0) return;
  117.     sdir_base=opendir(".");
  118.     if(sdir_base==NULL) return;
  119.     while((ses=readdir(sdir_base))!=NULL) {
  120.         if(ses->d_name[0]=='.') continue;
  121.         if(lstat(ses->d_name,&dst)) continue;
  122.         if(!S_ISDIR(dst.st_mode)) continue;
  123.         if(dst.st_mtime <= now) {
  124.             if(dst.st_mtime>=now-CLEAN_DELAY) continue;
  125.             if(dst.st_mtime>=now-CLEAN_DELAY2 && (dst.st_mode&S_IRWXO)==0) continue;
  126.         }
  127.         remove_tree(ses->d_name);
  128.     }
  129. }
  130.  
  131. void cleaning(void)
  132. {
  133.     DIR *sdir_base;
  134.     struct dirent *ses;
  135.     struct stat dst;
  136.     struct utimbuf ub;
  137.     char dbuf[256];
  138.  
  139.     if(stat(timestamp,&dst)==0 && dst.st_mtime==now) return;
  140.     ub.actime=ub.modtime=now; utime(timestamp,&ub);
  141.     sdir_base=opendir("/proc");
  142.     if(sdir_base==NULL) goto tmpdir;
  143.     while((ses=readdir(sdir_base))!=NULL) {
  144.         if(ses->d_name[0]<'0' || ses->d_name[9]>'9') continue;
  145.         snprintf(dbuf,sizeof(dbuf),"/proc/%s",ses->d_name);
  146.         if(lstat(dbuf,&dst)) continue;
  147.         if(!S_ISDIR(dst.st_mode)) continue;
  148.         if(dst.st_uid<UID_MIN || dst.st_uid>UID_MIN+UID_MASK) continue;
  149.         if(((dst.st_gid-UID_MIN-now)&TIME_MASK)<=CPU_MAX) continue;
  150.         kill(atoi(ses->d_name),SIGKILL);
  151.     }
  152.     closedir(sdir_base);
  153.     tmpdir: return;
  154. }
  155.  
  156. int test_must(void)
  157. {
  158.     char *pc;
  159.     if(must) return 1;
  160.     pc=getenv("chroot"); if(pc && strcmp(pc,"must")==0) return 1;
  161.     else return 0;
  162. }
  163.  
  164. int main(int argc,char *argv[])
  165. {
  166.     char *args[1024];
  167.     char parm[MAX_PARMLEN];
  168.     char tmpbuf[256];
  169.     int i,k,uid,t;
  170.     struct stat st;
  171.     struct rlimit lim;
  172.     char *p, *pp;
  173.    
  174.     if(argc<2) return 0;
  175.     now=time(NULL);
  176.     uid=geteuid();
  177.     t=stat("../chroot/tmp/sessions/.chroot",&st);
  178.     if(uid!=0 || t!=0) {
  179.         if(test_must()) goto abandon;
  180.         args[0]="bin/wrap..exec"; k=1;
  181.     }
  182.     else {
  183.         k=0;
  184.         p=getenv("REMOTE_ADDR"); if(p && *p) {
  185.             pp=strrchr(p,'.'); if(pp) execuid=(atoi(++pp)&UID_MASK)+UID_MIN;
  186.         }
  187.         getrlimit(RLIMIT_CPU,&lim);
  188.         i=lim.rlim_max; if(i<0) i=0; if(i>=CPU_MAX) i=CPU_MAX-1;
  189.         execgid=((i+now+1)&TIME_MASK)+UID_MIN;
  190.         cleaning();
  191.     }
  192.     if(argc>1 && strcmp(argv[1],"cleantmpdir")==0) {
  193.         if(uid!=0) fprintf(stderr,"ch..root cleantmpdir: uid not changed.\n");
  194.         else cleantmp();
  195.         return 0;
  196.     }
  197.     if(argc>3 && argv[1][0]=='&') {
  198.         if(k) goto abandon;
  199.         if(strcmp(argv[2],"sh")==0) {
  200.             lim.rlim_cur=lim.rlim_max=MAX_OUTLEN;
  201.             setrlimit(RLIMIT_FSIZE,&lim);
  202.             args[0]=name_sh; args[1]=opt_sh;
  203.             snprintf(parm,sizeof(parm),"%s\n%s\n",pre_sh,argv[3]);
  204.             args[2]=parm; args[3]=NULL; must=1;
  205.             goto cont;
  206.         }
  207.         if(strcmp(argv[2],"perl")==0) {
  208.             lim.rlim_cur=lim.rlim_max=MAX_OUTLEN;
  209.             setrlimit(RLIMIT_FSIZE,&lim);
  210.             args[0]=name_perl; args[1]=opt_perl;
  211.             snprintf(parm,sizeof(parm),"%s\n%s\n",pre_perl,argv[3]);
  212.             args[2]=parm; args[3]=NULL; must=1;
  213.             goto cont;
  214.         }
  215.         goto abandon;
  216.     }
  217.     for(i=0;i<1000 && i<argc; i++) args[i+k]=argv[i+1];
  218.     args[i]=NULL;
  219.     cont:
  220.     if(uid!=0) {
  221.         if(test_must()) goto abandon;
  222.         goto ex2;
  223.     }
  224.     if(t!=0) {
  225.         stat("bin",&st); execuid=execgid=st.st_uid;
  226.         if(test_must()) goto abandon;
  227.         goto ex;
  228.     }
  229.     if(chroot("../chroot")==0) {
  230.         (void)chdir("/tmp");
  231.         lim.rlim_cur=lim.rlim_max=PROC_QUOTA;
  232.         setrlimit(RLIMIT_NPROC,&lim);
  233.         setenv("PATH",chroot_path,1);
  234.         p=getenv("w_wims_session"); if(p && *p) {
  235.             snprintf(tmpbuf,sizeof(tmpbuf),"/tmp/sessions/%s",p);
  236.             p=strchr(tmpbuf,'_'); if(p) *p=0;
  237.             setenv("TMPDIR",tmpbuf,1);
  238.             setenv("tmp_dir",tmpbuf,1);
  239.             p=getenv("w_wims_priv_chroot");
  240.             if(p && strstr(p,"tmpdir")!=NULL)
  241.               (void)chdir(tmpbuf);
  242.         }
  243.     }
  244.     else if(test_must()) goto abandon;
  245.     ex:
  246.     if(setregid(execgid,execgid)<0) goto abandon;
  247.     if(setreuid(execuid,execuid)<0) goto abandon;
  248.     ex2:
  249.     for(i=0;i<env_rm_cnt;i++) unsetenv(env_rm[i]);
  250.     if(strchr(args[0],'/')) execv(args[0],args); else execvp(args[0],args);
  251.     abandon: return 127;
  252. }
  253.  
  254.