Rev 11133 | 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 | |
11529 | georgesk | 48 | void inline IGNORE() {} /* Ignore GCC Unused Result */ |
49 | void IGNORE(); /* see http://stackoverflow.com/a/16245669/490291 */ |
||
50 | |||
10 | reyssat | 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 | |||
7076 | obado | 67 | #define env_rm_cnt (sizeof(env_rm)/sizeof(env_rm[0])) |
10 | reyssat | 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 | |||
7076 | obado | 84 | |
85 | /* Remove a tree */ |
||
10 | reyssat | 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. */ |
||
7076 | obado | 94 | return -1; |
10 | reyssat | 95 | } |
96 | while((f=readdir(sdir))!=NULL) { |
||
7076 | obado | 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 | } |
||
10 | reyssat | 106 | } |
107 | closedir(sdir); |
||
7076 | obado | 108 | if(rmdir(dirname)<0) { /* Cannot remove directory. */ |
109 | return -1; |
||
10 | reyssat | 110 | } |
111 | return 0; |
||
112 | } |
||
113 | |||
7076 | obado | 114 | /* Clean TMP */ |
10 | reyssat | 115 | void cleantmp(void) |
116 | { |
||
117 | DIR *sdir_base; |
||
118 | struct dirent *ses; |
||
119 | struct stat dst; |
||
11133 | bpr | 120 | |
10 | reyssat | 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) { |
||
7076 | obado | 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); |
||
10 | reyssat | 133 | } |
134 | } |
||
135 | |||
7076 | obado | 136 | /* Cleaning */ |
10 | reyssat | 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) { |
||
7076 | obado | 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); |
||
10 | reyssat | 157 | } |
158 | closedir(sdir_base); |
||
159 | tmpdir: return; |
||
160 | } |
||
161 | |||
7076 | obado | 162 | /* Test Must */ |
10 | reyssat | 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 | |||
7076 | obado | 171 | /* MAIN */ |
10 | reyssat | 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; |
||
11133 | bpr | 181 | |
10 | reyssat | 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) { |
||
7076 | obado | 187 | if(test_must()) goto abandon; |
188 | args[0]="bin/wrap..exec"; k=1; |
||
10 | reyssat | 189 | } |
190 | else { |
||
7076 | obado | 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(); |
||
10 | reyssat | 200 | } |
201 | if(argc>1 && strcmp(argv[1],"cleantmpdir")==0) { |
||
7076 | obado | 202 | if(uid!=0) fprintf(stderr,"ch..root cleantmpdir: uid not changed.\n"); |
203 | else cleantmp(); |
||
204 | return 0; |
||
10 | reyssat | 205 | } |
206 | if(argc>3 && argv[1][0]=='&') { |
||
7076 | obado | 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; |
||
10 | reyssat | 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) { |
||
7076 | obado | 230 | if(test_must()) goto abandon; |
231 | goto ex2; |
||
10 | reyssat | 232 | } |
233 | if(t!=0) { |
||
7076 | obado | 234 | stat("bin",&st); execuid=execgid=st.st_uid; |
235 | if(test_must()) goto abandon; |
||
236 | goto ex; |
||
10 | reyssat | 237 | } |
238 | if(chroot("../chroot")==0) { |
||
11529 | georgesk | 239 | IGNORE(chdir("/tmp")); |
7076 | obado | 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) |
||
11529 | georgesk | 251 | IGNORE(chdir(tmpbuf)); |
7076 | obado | 252 | } |
10 | reyssat | 253 | } |
254 | else if(test_must()) goto abandon; |
||
255 | ex: |
||
256 | if(setregid(execgid,execgid)<0) goto abandon; |
||
11133 | bpr | 257 | if(setreuid(execuid,execuid)<0) goto abandon; |
10 | reyssat | 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 |