Rev 11539 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
10 | reyssat | 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 | |||
7076 | obado | 18 | /* Change root and exec */ |
10 | reyssat | 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> |
||
11133 | bpr | 47 | |
10 | reyssat | 48 | int execuid=15999; |
49 | int execgid=15999; |
||
50 | int must=0; |
||
51 | time_t now; |
||
52 | |||
53 | char *env_rm[]={ |
||
12248 | bpr | 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" |
||
10 | reyssat | 62 | }; |
63 | |||
7076 | obado | 64 | #define env_rm_cnt (sizeof(env_rm)/sizeof(env_rm[0])) |
10 | reyssat | 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 | |||
7076 | obado | 81 | |
82 | /* Remove a tree */ |
||
10 | reyssat | 83 | int remove_tree(char *dirname) |
84 | { |
||
12248 | bpr | 85 | DIR *sdir; |
86 | struct dirent *f; |
||
87 | struct stat dst; |
||
10 | reyssat | 88 | |
12248 | bpr | 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)); |
||
10 | reyssat | 102 | } |
12248 | bpr | 103 | } |
104 | closedir(sdir); |
||
105 | if(rmdir(dirname)<0) { /* Cannot remove directory. */ |
||
106 | return -1; |
||
107 | } |
||
108 | return 0; |
||
10 | reyssat | 109 | } |
110 | |||
7076 | obado | 111 | /* Clean TMP */ |
10 | reyssat | 112 | void cleantmp(void) |
113 | { |
||
12248 | bpr | 114 | DIR *sdir_base; |
115 | struct dirent *ses; |
||
116 | struct stat dst; |
||
11133 | bpr | 117 | |
12248 | bpr | 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; |
||
10 | reyssat | 128 | } |
12248 | bpr | 129 | remove_tree(ses->d_name); |
130 | } |
||
10 | reyssat | 131 | } |
132 | |||
7076 | obado | 133 | /* Cleaning */ |
10 | reyssat | 134 | void cleaning(void) |
135 | { |
||
12248 | bpr | 136 | DIR *sdir_base; |
137 | struct dirent *ses; |
||
138 | struct stat dst; |
||
139 | struct utimbuf ub; |
||
140 | char dbuf[256]; |
||
10 | reyssat | 141 | |
12248 | bpr | 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; |
||
10 | reyssat | 157 | } |
158 | |||
7076 | obado | 159 | /* Test Must */ |
10 | reyssat | 160 | int test_must(void) |
161 | { |
||
12248 | bpr | 162 | char *pc; |
163 | if(must) return 1; |
||
164 | pc=getenv("chroot"); if(pc && strcmp(pc,"must")==0) return 1; |
||
165 | else return 0; |
||
10 | reyssat | 166 | } |
167 | |||
7076 | obado | 168 | /* MAIN */ |
10 | reyssat | 169 | int main(int argc,char *argv[]) |
170 | { |
||
12248 | bpr | 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; |
||
11133 | bpr | 178 | |
12248 | bpr | 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; |
||
10 | reyssat | 192 | } |
12248 | bpr | 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; |
||
10 | reyssat | 212 | } |
12248 | bpr | 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; |
||
10 | reyssat | 220 | } |
12248 | bpr | 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); |
||
10 | reyssat | 249 | } |
12248 | bpr | 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; |
||
10 | reyssat | 259 | } |