Subversion Repositories wimsdev

Rev

Rev 11529 | Rev 12248 | 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.  
  261.