Subversion Repositories wimsdev

Rev

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