Subversion Repositories wimsdev

Rev

Rev 11133 | 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. void inline IGNORE() {}  /* Ignore GCC Unused Result */
  49. void IGNORE();  /* see http://stackoverflow.com/a/16245669/490291 */
  50.  
  51. int execuid=15999;
  52. int execgid=15999;
  53. int must=0;
  54. time_t now;
  55.  
  56. char *env_rm[]={
  57.     "s2_dir", "w_wims_home", "session_base_dir", "trusted_module",
  58.       "session_dir", "wims_server_base", "w_httpd_PWD",
  59.       "w_wims_sesdir", "HTTP_CONNECTION",
  60.       "w_gnuplot_format", "w_insplot_font", "w_ins_anim_limit",
  61.       "w_ins_density", "w_ins_format",
  62.       "texgif_fontdir", "texgif_texheader",
  63.       "w_wims_tmp_debug", "w_insmath_logic", "w_insmath_rawmath",
  64.       "SERVER_ADMIN", "SERVER_ADDR", "SERVER_NAME"
  65. };
  66.  
  67. #define env_rm_cnt (sizeof(env_rm)/sizeof(env_rm[0]))
  68.  
  69. char name_sh[32]="/bin/ash.static";
  70. char opt_sh[32]="-c";
  71. char *pre_sh="\
  72. cd $TMPDIR || exit\n\
  73. echo >/dev/null || exit\n\
  74. cd / 2>/dev/null && exit\n\
  75. ";
  76.  
  77. char *name_perl="/usr/bin/perl";
  78. char *opt_perl="-e";
  79. char *pre_perl="\
  80. chdir($ENV{TMPDIR}) || exit;\n\
  81. chdir(\"/\") && exit;\n\
  82. ";
  83.  
  84.  
  85. /* Remove a tree */
  86. int remove_tree(char *dirname)
  87. {
  88.     DIR *sdir;
  89.     struct dirent *f;
  90.     struct stat dst;
  91.  
  92.     sdir=opendir(dirname);
  93.     if(sdir==NULL) {   /* Cannot open session directory. */
  94.        return -1;
  95.     }
  96.     while((f=readdir(sdir))!=NULL) {
  97.         char fname[255];
  98.         if(strcmp(".",f->d_name)==0 || strcmp("..",f->d_name)==0) continue;
  99.         snprintf(fname,sizeof(fname),"%s/%s",dirname,f->d_name);
  100.         if(lstat(fname,&dst)) continue;
  101.         if(S_ISDIR(dst.st_mode)) remove_tree(fname);
  102.         else {
  103.             if(remove(fname)<0)
  104.               fprintf(stderr,"ch..root: unable to remove %s. %s\n",fname,strerror(errno));
  105.         }
  106.     }
  107.     closedir(sdir);
  108.     if(rmdir(dirname)<0) {  /* Cannot remove directory. */
  109.        return -1;
  110.     }
  111.     return 0;
  112. }
  113.  
  114. /* Clean TMP */
  115. void cleantmp(void)
  116. {
  117.     DIR *sdir_base;
  118.     struct dirent *ses;
  119.     struct stat dst;
  120.  
  121.     if(chdir("../chroot/tmp/sessions")<0) return;
  122.     sdir_base=opendir(".");
  123.     if(sdir_base==NULL) return;
  124.     while((ses=readdir(sdir_base))!=NULL) {
  125.         if(ses->d_name[0]=='.') continue;
  126.         if(lstat(ses->d_name,&dst)) continue;
  127.         if(!S_ISDIR(dst.st_mode)) continue;
  128.         if(dst.st_mtime <= now) {
  129.             if(dst.st_mtime>=now-CLEAN_DELAY) continue;
  130.             if(dst.st_mtime>=now-CLEAN_DELAY2 && (dst.st_mode&S_IRWXO)==0) continue;
  131.         }
  132.         remove_tree(ses->d_name);
  133.     }
  134. }
  135.  
  136. /* Cleaning */
  137. void cleaning(void)
  138. {
  139.     DIR *sdir_base;
  140.     struct dirent *ses;
  141.     struct stat dst;
  142.     struct utimbuf ub;
  143.     char dbuf[256];
  144.  
  145.     if(stat(timestamp,&dst)==0 && dst.st_mtime==now) return;
  146.     ub.actime=ub.modtime=now; utime(timestamp,&ub);
  147.     sdir_base=opendir("/proc");
  148.     if(sdir_base==NULL) goto tmpdir;
  149.     while((ses=readdir(sdir_base))!=NULL) {
  150.         if(ses->d_name[0]<'0' || ses->d_name[9]>'9') continue;
  151.         snprintf(dbuf,sizeof(dbuf),"/proc/%s",ses->d_name);
  152.         if(lstat(dbuf,&dst)) continue;
  153.         if(!S_ISDIR(dst.st_mode)) continue;
  154.         if(dst.st_uid<UID_MIN || dst.st_uid>UID_MIN+UID_MASK) continue;
  155.         if(((dst.st_gid-UID_MIN-now)&TIME_MASK)<=CPU_MAX) continue;
  156.         kill(atoi(ses->d_name),SIGKILL);
  157.     }
  158.     closedir(sdir_base);
  159.     tmpdir: return;
  160. }
  161.  
  162. /* Test Must */
  163. int test_must(void)
  164. {
  165.     char *pc;
  166.     if(must) return 1;
  167.     pc=getenv("chroot"); if(pc && strcmp(pc,"must")==0) return 1;
  168.     else return 0;
  169. }
  170.  
  171. /* MAIN */
  172. int main(int argc,char *argv[])
  173. {
  174.     char *args[1024];
  175.     char parm[MAX_PARMLEN];
  176.     char tmpbuf[256];
  177.     int i,k,uid,t;
  178.     struct stat st;
  179.     struct rlimit lim;
  180.     char *p, *pp;
  181.  
  182.     if(argc<2) return 0;
  183.     now=time(NULL);
  184.     uid=geteuid();
  185.     t=stat("../chroot/tmp/sessions/.chroot",&st);
  186.     if(uid!=0 || t!=0) {
  187.         if(test_must()) goto abandon;
  188.         args[0]="bin/wrap..exec"; k=1;
  189.     }
  190.     else {
  191.         k=0;
  192.         p=getenv("REMOTE_ADDR");
  193.         if(p && *p) {
  194.             pp=strrchr(p,'.'); if(pp) execuid=(atoi(++pp)&UID_MASK)+UID_MIN;
  195.         }
  196.         getrlimit(RLIMIT_CPU,&lim);
  197.         i=lim.rlim_max; if(i<0) i=0; if(i>=CPU_MAX) i=CPU_MAX-1;
  198.         execgid=((i+now+1)&TIME_MASK)+UID_MIN;
  199.         cleaning();
  200.     }
  201.     if(argc>1 && strcmp(argv[1],"cleantmpdir")==0) {
  202.         if(uid!=0) fprintf(stderr,"ch..root cleantmpdir: uid not changed.\n");
  203.         else cleantmp();
  204.         return 0;
  205.     }
  206.     if(argc>3 && argv[1][0]=='&') {
  207.         if(k) goto abandon;
  208.         if(strcmp(argv[2],"sh")==0) {
  209.             lim.rlim_cur=lim.rlim_max=MAX_OUTLEN;
  210.             setrlimit(RLIMIT_FSIZE,&lim);
  211.             args[0]=name_sh; args[1]=opt_sh;
  212.             snprintf(parm,sizeof(parm),"%s\n%s\n",pre_sh,argv[3]);
  213.             args[2]=parm; args[3]=NULL; must=1;
  214.             goto cont;
  215.         }
  216.         if(strcmp(argv[2],"perl")==0) {
  217.             lim.rlim_cur=lim.rlim_max=MAX_OUTLEN;
  218.             setrlimit(RLIMIT_FSIZE,&lim);
  219.             args[0]=name_perl; args[1]=opt_perl;
  220.             snprintf(parm,sizeof(parm),"%s\n%s\n",pre_perl,argv[3]);
  221.             args[2]=parm; args[3]=NULL; must=1;
  222.             goto cont;
  223.         }
  224.         goto abandon;
  225.     }
  226.     for(i=0;i<1000 && i<argc; i++) args[i+k]=argv[i+1];
  227.     args[i]=NULL;
  228.     cont:
  229.     if(uid!=0) {
  230.         if(test_must()) goto abandon;
  231.         goto ex2;
  232.     }
  233.     if(t!=0) {
  234.         stat("bin",&st); execuid=execgid=st.st_uid;
  235.         if(test_must()) goto abandon;
  236.         goto ex;
  237.     }
  238.     if(chroot("../chroot")==0) {
  239.         IGNORE(chdir("/tmp"));
  240.         lim.rlim_cur=lim.rlim_max=PROC_QUOTA;
  241.         setrlimit(RLIMIT_NPROC,&lim);
  242.         setenv("PATH",chroot_path,1);
  243.         p=getenv("w_wims_session");
  244.         if(p && *p) {
  245.             snprintf(tmpbuf,sizeof(tmpbuf),"/tmp/sessions/%s",p);
  246.             p=strchr(tmpbuf,'_'); if(p) *p=0;
  247.             setenv("TMPDIR",tmpbuf,1);
  248.             setenv("tmp_dir",tmpbuf,1);
  249.             p=getenv("w_wims_priv_chroot");
  250.             if(p && strstr(p,"tmpdir")!=NULL)
  251.               IGNORE(chdir(tmpbuf));
  252.         }
  253.     }
  254.     else if(test_must()) goto abandon;
  255.     ex:
  256.     if(setregid(execgid,execgid)<0) goto abandon;
  257.     if(setreuid(execuid,execuid)<0) goto abandon;
  258.     ex2:
  259.     for(i=0;i<env_rm_cnt;i++) unsetenv(env_rm[i]);
  260.     if(strchr(args[0],'/')) execv(args[0],args); else execvp(args[0],args);
  261.     abandon: return 127;
  262. }
  263.  
  264.