Browse code

code cleanup

git-svn: trunk@2655

Tomasz Kojm authored on 2007/01/31 06:11:32
Showing 12 changed files
... ...
@@ -1,3 +1,7 @@
1
+Tue Jan 30 22:08:22 CET 2007 (tk)
2
+---------------------------------
3
+  * clamscan: code cleanup
4
+
1 5
 Tue Jan 30 20:24:34 CET 2007 (tk)
2 6
 ---------------------------------
3 7
   * libclamav/dconf.c: enable sue, mew, upack and nspack (with agreement from
... ...
@@ -36,12 +36,11 @@ clamscan_SOURCES = \
36 36
     clamscan_opt.h \
37 37
     others.c \
38 38
     others.h \
39
-    shared.h \
39
+    global.h \
40 40
     manager.c \
41 41
     manager.h \
42 42
     treewalk.c \
43
-    treewalk.h \
44
-    defaults.h
43
+    treewalk.h
45 44
 
46 45
 DEFS = @DEFS@ -DCL_NOTHREADS
47 46
 LIBS = $(top_builddir)/libclamav/libclamav.la @ADDITIONAL_LIBS@
... ...
@@ -234,12 +234,11 @@ clamscan_SOURCES = \
234 234
     clamscan_opt.h \
235 235
     others.c \
236 236
     others.h \
237
-    shared.h \
237
+    global.h \
238 238
     manager.c \
239 239
     manager.h \
240 240
     treewalk.c \
241
-    treewalk.h \
242
-    defaults.h
241
+    treewalk.h
243 242
 
244 243
 INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/shared -I$(top_srcdir)/libclamav
245 244
 all: all-am
... ...
@@ -27,25 +27,23 @@
27 27
 #include <unistd.h>
28 28
 #include <sys/time.h>
29 29
 #include <time.h>
30
+#ifdef C_LINUX
31
+#include <sys/resource.h>
32
+#endif
30 33
 
31 34
 #include "clamscan_opt.h"
32 35
 #include "others.h"
33
-#include "shared.h"
36
+#include "global.h"
34 37
 #include "manager.h"
35
-#include "defaults.h"
36 38
 #include "treewalk.h"
37
-#include "misc.h"
38
-
39
-#include "output.h"
40
-#include "options.h"
41 39
 
42
-#ifdef C_LINUX
43
-#include <sys/resource.h>
44
-#endif
40
+#include "shared/misc.h"
41
+#include "shared/output.h"
42
+#include "shared/options.h"
45 43
 
46 44
 void help(void);
47 45
 
48
-struct s_info claminfo;
46
+struct s_info info;
49 47
 short recursion = 0, printinfected = 0, bell = 0;
50 48
 
51 49
 int main(int argc, char **argv)
... ...
@@ -180,7 +178,7 @@ int main(int argc, char **argv)
180 180
 	}
181 181
     }
182 182
 
183
-    memset(&claminfo, 0, sizeof(struct s_info));
183
+    memset(&info, 0, sizeof(struct s_info));
184 184
 
185 185
     gettimeofday(&t1, &tz);
186 186
     ret = scanmanager(opt);
... ...
@@ -192,23 +190,23 @@ int main(int argc, char **argv)
192 192
 	ds -= (dms < 0) ? (1):(0);
193 193
 	dms += (dms < 0) ? (1000000):(0);
194 194
 	logg("\n----------- SCAN SUMMARY -----------\n");
195
-	logg("Known viruses: %d\n", claminfo.signs);
195
+	logg("Known viruses: %u\n", info.sigs);
196 196
 	if(opt_check(opt, "ncore"))
197 197
 	    logg("Engine version: %s [ncore]\n", cl_retver());
198 198
 	else
199 199
 	    logg("Engine version: %s\n", cl_retver());
200
-	logg("Scanned directories: %d\n", claminfo.dirs);
201
-	logg("Scanned files: %d\n", claminfo.files);
202
-	logg("Infected files: %d\n", claminfo.ifiles);
203
-	if(claminfo.notremoved) {
204
-	    logg("Not removed: %d\n", claminfo.notremoved);
200
+	logg("Scanned directories: %u\n", info.dirs);
201
+	logg("Scanned files: %u\n", info.files);
202
+	logg("Infected files: %u\n", info.ifiles);
203
+	if(info.notremoved) {
204
+	    logg("Not removed: %u\n", info.notremoved);
205 205
 	}
206
-	if(claminfo.notmoved) {
207
-	    logg("Not %s: %d\n", opt_check(opt, "copy") ? "moved" : "copied", claminfo.notmoved);
206
+	if(info.notmoved) {
207
+	    logg("Not %s: %u\n", opt_check(opt, "copy") ? "moved" : "copied", info.notmoved);
208 208
 	}
209
-	mb = claminfo.blocks * (CL_COUNT_PRECISION / 1024) / 1024.0;
209
+	mb = info.blocks * (CL_COUNT_PRECISION / 1024) / 1024.0;
210 210
 	logg("Data scanned: %2.2lf MB\n", mb);
211
-	logg("Time: %d.%3.3d sec (%d m %d s)\n", ds, dms/1000, ds/60, ds%60);
211
+	logg("Time: %u.%3.3u sec (%u m %u s)\n", ds, dms/1000, ds/60, ds%60);
212 212
     }
213 213
 
214 214
     opt_free(opt);
215 215
deleted file mode 100644
... ...
@@ -1,32 +0,0 @@
1
-/*
2
- *  Copyright (C) 2002 Tomasz Kojm <tkojm@clamav.net>
3
- *
4
- *  This program is free software; you can redistribute it and/or modify
5
- *  it under the terms of the GNU General Public License as published by
6
- *  the Free Software Foundation; either version 2 of the License, or
7
- *  (at your option) any later version.
8
- *
9
- *  This program is distributed in the hope that it will be useful,
10
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
- *  GNU General Public License for more details.
13
- *
14
- *  You should have received a copy of the GNU General Public License
15
- *  along with this program; if not, write to the Free Software
16
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17
- *  MA 02110-1301, USA.
18
- */
19
-
20
-#ifdef CLAMAVUSER
21
-#define UNPUSER CLAMAVUSER
22
-#else
23
-#define UNPUSER "clamav"
24
-#endif
25
-
26
-#ifdef CLAMAVGROUP
27
-#define UNPGROUP CLAMAVGROUP
28
-#else
29
-#define UNPGROUP "clamav"
30
-#endif
31
-
32
-#define MAXFILENAME 1024
33 1
new file mode 100644
... ...
@@ -0,0 +1,36 @@
0
+/*
1
+ *  Copyright (C) 2002 - 2004 Tomasz Kojm <tkojm@clamav.net>
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., 51 Franklin Street, Fifth Floor, Boston,
16
+ *  MA 02110-1301, USA.
17
+ */
18
+
19
+#ifndef __GLOBAL_H
20
+#define __GLOBAL_H
21
+
22
+struct s_info {
23
+    unsigned int sigs;		/* number of signatures */
24
+    unsigned int dirs;		/* number of scanned directories */
25
+    unsigned int files;		/* number of scanned files */
26
+    unsigned int ifiles;	/* number of infected files */
27
+    unsigned int notremoved;	/* number of not removed files (if --remove) */
28
+    unsigned int notmoved;	/* number of not moved files (if --move) */
29
+    unsigned long int blocks;	/* number of read 16kb blocks */
30
+};
31
+
32
+extern struct s_info info;
33
+extern short recursion, printinfected, bell;
34
+
35
+#endif
... ...
@@ -1,5 +1,5 @@
1 1
 /*
2
- *  Copyright (C) 2002 - 2006 Tomasz Kojm <tkojm@clamav.net>
2
+ *  Copyright (C) 2002 - 2007 Tomasz Kojm <tkojm@clamav.net>
3 3
  *
4 4
  *  This program is free software; you can redistribute it and/or modify
5 5
  *  it under the terms of the GNU General Public License as published by
... ...
@@ -16,7 +16,6 @@
16 16
  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 17
  *  MA 02110-1301, USA.
18 18
  *
19
- *  Sat May 18 15:23:21 CEST 2002: included cpu autodetection from Magnus Ekdahl
20 19
  *  Wed Mar  5 03:45:31 CET 2003: included --move code from Damien Curtain
21 20
  */
22 21
 
... ...
@@ -37,34 +36,96 @@
37 37
 #include <unistd.h>
38 38
 #include <sys/types.h>
39 39
 #include <signal.h>
40
-#include "clamav.h"
41 40
 #include <errno.h>
42 41
 
43
-#include "defaults.h"
44
-#include "others.h"
45
-#include "options.h"
46 42
 #include "manager.h"
43
+#include "others.h"
47 44
 #include "treewalk.h"
48
-#include "shared.h"
49
-#include "str.h"
50
-#include "memory.h"
51
-#include "output.h"
52
-#include "misc.h"
53
-#include "../libclamav/others.h"
54
-#include "../libclamav/matcher-ac.h"
45
+#include "global.h"
46
+
47
+#include "shared/options.h"
48
+#include "shared/memory.h"
49
+#include "shared/output.h"
50
+#include "shared/misc.h"
51
+
52
+#include "libclamav/clamav.h"
53
+#include "libclamav/others.h"
54
+#include "libclamav/matcher-ac.h"
55
+#include "libclamav/str.h"
55 56
 
56 57
 #ifdef C_LINUX
57 58
 dev_t procdev;
58 59
 #endif
59 60
 
61
+static int scandirs(const char *dirname, struct cl_engine *engine, const struct passwd *user, const struct optstruct *opt, const struct cl_limits *limits, int options)
62
+{
63
+    return treewalk(dirname, engine, user, opt, limits, options, 1);
64
+}
65
+
66
+static int scanstdin(const struct cl_engine *engine, const struct cl_limits *limits, int options)
67
+{
68
+	int ret;
69
+	const char *virname, *tmpdir;
70
+	char *file, buff[FILEBUFF];
71
+	FILE *fs;
72
+
73
+
74
+    /* check write access */
75
+    tmpdir = getenv("TMPDIR");
76
+
77
+    if(tmpdir == NULL)
78
+#ifdef P_tmpdir
79
+	tmpdir = P_tmpdir;
80
+#else
81
+	tmpdir = "/tmp";
82
+#endif
83
+
84
+    if(checkaccess(tmpdir, CLAMAVUSER, W_OK) != 1) {
85
+	logg("!Can't write to temporary directory\n");
86
+	return 64;
87
+    }
88
+
89
+    file = cli_gentemp(tmpdir);
90
+
91
+    if(!(fs = fopen(file, "wb"))) {
92
+	logg("!Can't open %s for writing\n", file);
93
+	return 63;
94
+    }
95
+
96
+    while((ret = fread(buff, 1, FILEBUFF, stdin)))
97
+	fwrite(buff, 1, ret, fs);
98
+
99
+    fclose(fs);
100
+
101
+    logg("*Checking %s\n", file);
102
+    info.files++;
103
+
104
+    if((ret = cl_scanfile(file, &virname, &info.blocks, engine, limits, options)) == CL_VIRUS) {
105
+	logg("stdin: %s FOUND\n", virname);
106
+	info.ifiles++;
107
+
108
+	if(bell)
109
+	    fprintf(stderr, "\007");
110
+
111
+    } else if(ret == CL_CLEAN) {
112
+	if(!printinfected)
113
+	    mprintf("stdin: OK\n");
114
+    } else
115
+	if(!printinfected)
116
+	    logg("stdin: %s\n", cl_strerror(ret));
117
+
118
+    unlink(file);
119
+    free(file);
120
+    return ret;
121
+}
60 122
 
61 123
 int scanmanager(const struct optstruct *opt)
62 124
 {
63 125
 	mode_t fmode;
64
-	int ret = 0, compression = 0, fmodeint, options = 0, i, x;
65
-	unsigned int dboptions = 0;
66
-	struct cl_node *trie = NULL;
67
-	struct cl_limits *limits = NULL;
126
+	int ret = 0, compression = 0, fmodeint, i, x;
127
+	unsigned int options = 0, dboptions = 0;
128
+	struct cl_engine *engine = NULL;
129
+	struct cl_limits limits;
68 130
 	struct passwd *user = NULL;
69 131
 	struct stat sb;
70 132
 	char *fullpath = NULL, cwd[1024];
... ...
@@ -73,8 +134,8 @@ int scanmanager(const struct optstruct *opt)
73 73
 /* njh@bandsman.co.uk: BeOS */
74 74
 #if !defined(C_CYGWIN) && !defined(C_OS2) && !defined(C_BEOS)
75 75
     if(!geteuid()) {
76
-	if((user = getpwnam(UNPUSER)) == NULL) {
77
-	    logg("!Can't get information about user "UNPUSER"\n");
76
+	if((user = getpwnam(CLAMAVUSER)) == NULL) {
77
+	    logg("!Can't get information about user "CLAMAVUSER"\n");
78 78
 	    exit(60); /* this is critical problem, so we just exit here */
79 79
 	}
80 80
     }
... ...
@@ -115,7 +176,7 @@ int scanmanager(const struct optstruct *opt)
115 115
     }
116 116
 
117 117
     if(opt_check(opt, "database")) {
118
-	if((ret = cl_load(opt_arg(opt, "database"), &trie, &claminfo.signs, dboptions))) {
118
+	if((ret = cl_load(opt_arg(opt, "database"), &engine, &info.sigs, dboptions))) {
119 119
 	    logg("!%s\n", cl_strerror(ret));
120 120
 	    return 50;
121 121
 	}
... ...
@@ -123,7 +184,7 @@ int scanmanager(const struct optstruct *opt)
123 123
     } else {
124 124
 	    char *dbdir = freshdbdir();
125 125
 
126
-	if((ret = cl_load(dbdir, &trie, &claminfo.signs, dboptions))) {
126
+	if((ret = cl_load(dbdir, &engine, &info.sigs, dboptions))) {
127 127
 	    logg("!%s\n", cl_strerror(ret));
128 128
 	    free(dbdir);
129 129
 	    return 50;
... ...
@@ -131,19 +192,18 @@ int scanmanager(const struct optstruct *opt)
131 131
 	free(dbdir);
132 132
     }
133 133
 
134
-    if(!trie) {
134
+    if(!engine) {
135 135
 	logg("!Can't initialize the virus database\n");
136 136
 	return 50;
137 137
     }
138 138
 
139
-    if((ret = cl_build(trie)) != 0) {
139
+    if((ret = cl_build(engine)) != 0) {
140 140
 	logg("!Database initialization error: %s\n", cl_strerror(ret));;
141 141
 	return 50;
142 142
     }
143 143
 
144
-    /* set (default) limits */
145
-
146
-    limits = (struct cl_limits *) calloc(1, sizeof(struct cl_limits));
144
+    /* set limits */
145
+    memset(&limits, 0, sizeof(struct cl_limits));
147 146
 
148 147
     if(opt_check(opt, "max-space")) {
149 148
 	char *cpy, *ptr;
... ...
@@ -151,32 +211,32 @@ int scanmanager(const struct optstruct *opt)
151 151
 	if(tolower(ptr[strlen(ptr) - 1]) == 'm') {
152 152
 	    cpy = mcalloc(strlen(ptr), sizeof(char));
153 153
 	    strncpy(cpy, ptr, strlen(ptr) - 1);
154
-	    limits->maxfilesize = atoi(cpy) * 1024 * 1024;
154
+	    limits.maxfilesize = atoi(cpy) * 1024 * 1024;
155 155
 	    free(cpy);
156 156
 	} else
157
-	    limits->maxfilesize = atoi(ptr) * 1024;
157
+	    limits.maxfilesize = atoi(ptr) * 1024;
158 158
     } else
159
-	limits->maxfilesize = 10485760;
159
+	limits.maxfilesize = 10485760;
160 160
 
161 161
     if(opt_check(opt, "max-files"))
162
-	limits->maxfiles = atoi(opt_arg(opt, "max-files"));
162
+	limits.maxfiles = atoi(opt_arg(opt, "max-files"));
163 163
     else
164
-        limits->maxfiles = 500;
164
+        limits.maxfiles = 500;
165 165
 
166 166
     if(opt_check(opt, "max-recursion"))
167
-        limits->maxreclevel = atoi(opt_arg(opt, "max-recursion"));
167
+        limits.maxreclevel = atoi(opt_arg(opt, "max-recursion"));
168 168
     else
169
-        limits->maxreclevel = 8;
169
+        limits.maxreclevel = 8;
170 170
 
171 171
     if(opt_check(opt, "max-mail-recursion"))
172
-        limits->maxmailrec = atoi(opt_arg(opt, "max-mail-recursion"));
172
+        limits.maxmailrec = atoi(opt_arg(opt, "max-mail-recursion"));
173 173
     else
174
-        limits->maxmailrec = 64;
174
+        limits.maxmailrec = 64;
175 175
 
176 176
     if(opt_check(opt, "max-ratio"))
177
-        limits->maxratio = atoi(opt_arg(opt, "max-ratio"));
177
+        limits.maxratio = atoi(opt_arg(opt, "max-ratio"));
178 178
     else
179
-        limits->maxratio = 250;
179
+        limits.maxratio = 250;
180 180
 
181 181
     /* set options */
182 182
 
... ...
@@ -220,11 +280,7 @@ int scanmanager(const struct optstruct *opt)
220 220
 	options |= CL_SCAN_MAIL;
221 221
 
222 222
 	if(opt_check(opt, "mail-follow-urls"))
223
-#ifdef WITH_CURL
224 223
 	    options |= CL_SCAN_MAILURL;
225
-#else
226
-	    logg("^Support for URLs downloading with libcurl not compiled in\n");
227
-#endif
228 224
     }
229 225
 
230 226
     if(opt_check(opt, "no-algorithmic"))
... ...
@@ -246,10 +302,10 @@ int scanmanager(const struct optstruct *opt)
246 246
 	    logg("!Can't get absolute pathname of current working directory\n");
247 247
 	    ret = 57;
248 248
 	} else
249
-	    ret = scandirs(cwd, trie, user, opt, limits, options);
249
+	    ret = scandirs(cwd, engine, user, opt, &limits, options);
250 250
 
251 251
     } else if(!strcmp(opt->filename, "-")) { /* read data from stdin */
252
-	ret = checkstdin(trie, limits, options);
252
+	ret = scanstdin(engine, &limits, options);
253 253
 
254 254
     } else {
255 255
 	char *thefilename;
... ...
@@ -273,7 +329,6 @@ int scanmanager(const struct optstruct *opt)
273 273
 		    /* we need to complete the path */
274 274
 		    if(!getcwd(cwd, sizeof(cwd))) {
275 275
 			logg("!Can't get absolute pathname of current working directory\n");
276
-			free(limits);
277 276
 			return 57;
278 277
 		    } else {
279 278
 			fullpath = mcalloc(512, sizeof(char));
... ...
@@ -289,11 +344,11 @@ int scanmanager(const struct optstruct *opt)
289 289
 
290 290
 		switch(fmode & S_IFMT) {
291 291
 		    case S_IFREG:
292
-			ret = scanfile(fullpath, trie, user, opt, limits, options);
292
+			ret = scanfile(fullpath, engine, user, opt, &limits, options);
293 293
 			break;
294 294
 
295 295
 		    case S_IFDIR:
296
-			ret = scandirs(fullpath, trie, user, opt, limits, options);
296
+			ret = scandirs(fullpath, engine, user, opt, &limits, options);
297 297
 			break;
298 298
 
299 299
 		    default:
... ...
@@ -310,13 +365,11 @@ int scanmanager(const struct optstruct *opt)
310 310
 	}
311 311
     }
312 312
 
313
-    /* free the trie */
314
-    cl_free(trie);
315
-
316
-    free(limits);
313
+    /* free the engine */
314
+    cl_free(engine);
317 315
 
318 316
     /* overwrite return code */
319
-    if(claminfo.ifiles)
317
+    if(info.ifiles)
320 318
 	ret = 1;
321 319
     else if(ret < 50) /* hopefully no error detected */ 
322 320
 	ret = 0; /* just make sure it's 0 */
... ...
@@ -324,158 +377,258 @@ int scanmanager(const struct optstruct *opt)
324 324
     return ret;
325 325
 }
326 326
 
327
-int scanfile(const char *filename, struct cl_node *root, const struct passwd *user, const struct optstruct *opt, const struct cl_limits *limits, int options)
327
+/*
328
+ * -1 -> can't fork
329
+ * -2 -> can't execute
330
+ * -3 -> external signal
331
+ * 0 -> OK
332
+ */
333
+static int clamav_unpack(const char *prog, char **args, const char *tmpdir, const struct passwd *user, const struct optstruct *opt)
328 334
 {
329
-	int ret, included, printclean = 1;
330
-	const struct optnode *optnode;
331
-	char *argument;
332
-#ifdef C_LINUX
333
-	struct stat sb;
335
+	pid_t pid;
336
+	int status, wret, fdevnull;
337
+	unsigned int maxfiles, maxspace;
338
+	struct s_du n;
334 339
 
335
-    /* argh, don't scan /proc files */
336
-    if(procdev)
337
-	if(stat(filename, &sb) != -1)
338
-	    if(sb.st_dev == procdev) {
339
-		if(!printinfected)
340
-		    logg("%s: Excluded (/proc)\n", filename);
341
-		return 0;
340
+
341
+    if(opt_check(opt, "max-files"))
342
+	maxfiles = atoi(opt_arg(opt, "max-files"));
343
+    else
344
+	maxfiles = 0;
345
+
346
+    if(opt_check(opt, "max-space")) {
347
+	    char *cpy, *ptr;
348
+	ptr = opt_arg(opt, "max-space");
349
+	if(tolower(ptr[strlen(ptr) - 1]) == 'm') { /* megabytes */
350
+	    cpy = mcalloc(strlen(ptr), sizeof(char));
351
+	    strncpy(cpy, ptr, strlen(ptr) - 1);
352
+	    maxspace = atoi(cpy) * 1024;
353
+	    free(cpy);
354
+	} else /* default - kilobytes */
355
+	    maxspace = atoi(ptr);
356
+    } else
357
+	maxspace = 0;
358
+
359
+
360
+    switch(pid = fork()) {
361
+	case -1:
362
+	    return -1;
363
+	case 0:
364
+#ifndef C_CYGWIN
365
+	    if(!geteuid() && user) {
366
+
367
+#ifdef HAVE_SETGROUPS
368
+		if(setgroups(1, &user->pw_gid)) {
369
+		    fprintf(stderr, "ERROR: setgroups() failed\n");
370
+		    exit(1);
371
+		}
372
+#endif
373
+
374
+		if(setgid(user->pw_gid)) {
375
+		    fprintf(stderr, "ERROR: setgid(%d) failed\n", (int) user->pw_gid);
376
+		    exit(1);
377
+		}
378
+
379
+		if(setuid(user->pw_uid)) {
380
+		    fprintf(stderr, "ERROR: setuid(%d) failed\n", (int) user->pw_uid);
381
+		    exit(1);
382
+		}
342 383
 	    }
343
-#endif    
384
+#endif
385
+	    chdir(tmpdir);
344 386
 
345
-    if(opt_check(opt, "exclude")) {
346
-	argument = opt_firstarg(opt, "exclude", &optnode);
347
-	while(argument) {
348
-	    if(match_regex(filename, argument) == 1) {
349
-		if(!printinfected)
350
-		    logg("%s: Excluded\n", filename);
351
-		return 0;
387
+	    if(printinfected) {
388
+  	        fdevnull = open("/dev/null", O_WRONLY);
389
+		if(fdevnull == -1) {
390
+		    logg("Non fatal error: cannot open /dev/null. Continuing with full output\n");
391
+		    printinfected = 0;
392
+		} else {
393
+		    dup2(fdevnull,1);
394
+		    dup2(fdevnull,2);
395
+		}
352 396
 	    }
353
-	    argument = opt_nextarg(&optnode, "exclude");
354
-	}
397
+
398
+	    if(strchr(prog, '/')) /* we have full path */
399
+		execv(prog, args);
400
+	    else
401
+		execvp(prog, args);
402
+	    perror("execv(p)");
403
+	    abort();
404
+	    break;
405
+	default:
406
+
407
+	    if(maxfiles || maxspace) {
408
+		while(!(wret = waitpid(pid, &status, WNOHANG))) {
409
+		    memset(&n, 0, sizeof(struct s_du));
410
+
411
+		    if(!du(tmpdir, &n))
412
+			if((maxfiles && n.files > maxfiles) || (maxspace && n.space > maxspace)) {
413
+			    logg("*n.files: %d, n.space: %d\n", n.files, n.space);
414
+			    kill(pid, 9); /* stop it immediately */
415
+			}
416
+		}
417
+	    } else
418
+		waitpid(pid, &status, 0);
419
+
420
+
421
+	    if(WIFSIGNALED(status)) {
422
+		switch(WTERMSIG(status)) {
423
+
424
+		    case 9:
425
+			logg("\nUnpacker process %d stopped due to exceeded limits\n", pid);
426
+			return 0;
427
+		    case 6: /* abort */
428
+			logg("^Can't run %s\n", prog);
429
+			return -2;
430
+		    default:
431
+			logg("^\nUnpacker stopped with external signal %d\n", WTERMSIG(status));
432
+			return -3;
433
+		}
434
+	    } else if(WIFEXITED(status))
435
+		return 0;
355 436
     }
356 437
 
357
-   if(opt_check(opt, "include")) {
358
-	included = 0;
359
-	argument = opt_firstarg(opt, "include", &optnode);
360
-	while(argument && !included) {
361
-	    if(match_regex(filename, argument) == 1) {
362
-		included = 1;
363
-		break;
364
-	    }
365
-	    argument = opt_nextarg(&optnode, "include");
366
-	}
438
+    return 0;
439
+}
367 440
 
368
-	if(!included) {
369
-	    if(!printinfected)
370
-		logg("%s: Excluded\n", filename);
371
-	    return 0;
372
-	}
441
+static void move_infected(const char *filename, const struct optstruct *opt)
442
+{
443
+	char *movedir, *movefilename, *tmp, numext[4 + 1];
444
+	struct stat fstat, mfstat;
445
+	int n, len, movefilename_size;
446
+	int moveflag = opt_check(opt, "move");
447
+	struct utimbuf ubuf;
448
+
449
+
450
+    if((moveflag && !(movedir = opt_arg(opt, "move"))) ||
451
+	(!moveflag && !(movedir = opt_arg(opt, "copy")))) {
452
+        /* Should never reach here */
453
+        logg("!opt_arg() returned NULL\n", filename);
454
+        info.notmoved++;
455
+        return;
373 456
     }
374 457
 
375
-    if(fileinfo(filename, 1) == 0) {
376
-	if(!printinfected)
377
-	    logg("%s: Empty file\n", filename);
378
-	return 0;
458
+    if(access(movedir, W_OK|X_OK) == -1) {
459
+	logg("!Can't %s file '%s': cannot write to '%s': %s\n", (moveflag) ? "move" : "copy", filename, movedir, strerror(errno));
460
+        info.notmoved++;
461
+        return;
379 462
     }
380 463
 
381
-    if(geteuid())
382
-	if(checkaccess(filename, NULL, R_OK) != 1) {
383
-	    if(!printinfected)
384
-		logg("%s: Access denied\n", filename);
385
-	    return 0;
386
-	}
464
+    if(!(tmp = strrchr(filename, '/')))
465
+	tmp = (char *) filename;
387 466
 
388
-    claminfo.files++;
467
+    movefilename_size = sizeof(char) * (strlen(movedir) + strlen(tmp) + sizeof(numext) + 2);
389 468
 
390
-    /* 
391
-     * check the extension  - this is a special case, normally we don't need to
392
-     * do this (libclamav detects archive by its magic string), but here we
393
-     * want to know the exit code from internal unpacker and try to use
394
-     * external (if provided) when internal cannot extract data.
395
-     */
469
+    if(!(movefilename = mmalloc(movefilename_size))) {
470
+        logg("!mmalloc() failed\n");
471
+	exit(71);
472
+    }
396 473
 
397
-    if((cli_strbcasestr(filename, ".zip") || cli_strbcasestr(filename, ".rar")) && (options & CL_SCAN_ARCHIVE)) {
398
-	/* try to use internal archivers */
399
-	if((ret = checkfile(filename, root, limits, options, 1)) == CL_VIRUS) {
400
-	    if(opt_check(opt, "remove")) {
401
-		if(unlink(filename)) {
402
-		    logg("^%s: Can't remove\n", filename);
403
-		    claminfo.notremoved++;
404
-		} else {
405
-		    logg("%s: Removed\n", filename);
406
-		}
407
-	    } else if (opt_check(opt, "move") || opt_check(opt, "copy"))
408
-		move_infected(filename, opt);
474
+    if(!(cli_strrcpy(movefilename, movedir))) {
475
+        logg("!cli_strrcpy() returned NULL\n");
476
+        info.notmoved++;
477
+        free(movefilename);
478
+        return;
479
+    }
409 480
 
410
-	    return 1;
481
+    strcat(movefilename, "/");
411 482
 
412
-	} else if(ret == CL_CLEAN) {
413
-	    return 0;
414
-	} else if(ret == 54) {
415
-	    return ret;
416
-	}
483
+    if(!(strcat(movefilename, tmp))) {
484
+        logg("!strcat() returned NULL\n");
485
+        info.notmoved++;
486
+        free(movefilename);
487
+        return;
488
+    }
417 489
 
418
-	/* in other case try to continue with external archivers */
419
-	options &= ~CL_SCAN_ARCHIVE; /* and disable decompression for the checkfile() below */
420
-	printclean = 0;
490
+    stat(filename, &fstat);
491
+
492
+    if(!stat(movefilename, &mfstat)) {
493
+        if(fstat.st_ino == mfstat.st_ino) { /* It's the same file*/
494
+            logg("File excluded '%s'\n", filename);
495
+            info.notmoved++;
496
+            free(movefilename);
497
+            return;
498
+        } else {
499
+            /* file exists - try to append an ordinal number to the
500
+	     * quranatined file in an attempt not to overwrite existing
501
+	     * files in quarantine  
502
+	     */
503
+            len = strlen(movefilename);
504
+            n = 0;        		        		
505
+            do {
506
+                /* reset the movefilename to it's initial value by
507
+		 * truncating to the original filename length
508
+		 */
509
+                movefilename[len] = 0;
510
+                /* append .XXX */
511
+                sprintf(numext, ".%03d", n++);
512
+                strcat(movefilename, numext);            	
513
+            } while(!stat(movefilename, &mfstat) && (n < 1000));
514
+       }
421 515
     }
422 516
 
423
-    if((cli_strbcasestr(filename, ".zip") && opt_check(opt, "unzip"))
424
-    || (cli_strbcasestr(filename, ".rar") && opt_check(opt, "unrar"))
425
-    || (cli_strbcasestr(filename, ".arj") && opt_check(opt, "arj"))
426
-    || (cli_strbcasestr(filename, ".zoo") && opt_check(opt, "unzoo"))
427
-    || (cli_strbcasestr(filename, ".jar") && opt_check(opt, "jar"))
428
-    || (cli_strbcasestr(filename, ".lzh") && opt_check(opt, "lha"))
429
-    || (cli_strbcasestr(filename, ".tar") && opt_check(opt, "tar"))
430
-    || (cli_strbcasestr(filename, ".deb") && opt_check(opt, "deb"))
431
-    || ((cli_strbcasestr(filename, ".tar.gz") || cli_strbcasestr(filename, ".tgz")) 
432
-	 && (opt_check(opt, "tgz") || opt_check(opt, "deb"))) ) {
517
+    if(!moveflag || rename(filename, movefilename) == -1) {
518
+	if(filecopy(filename, movefilename) == -1) {
519
+	    logg("!Can't %s '%s' to '%s': %s\n", (moveflag) ? "move" : "copy", filename, movefilename, strerror(errno));
520
+	    info.notmoved++;
521
+	    free(movefilename);
522
+	    return;
523
+	}
433 524
 
434
-	/* check permissions */
435
-	switch(checkaccess(filename, UNPUSER, R_OK)) {
436
-	    case -1:
437
-		logg("^Can't get information about user "UNPUSER"\n");
438
-		exit(60); /* this is a critical problem so we just exit here */
439
-	    case -2:
440
-		logg("^Can't fork\n");
441
-		exit(61);
442
-	    case 0: /* read access denied */
443
-		if(geteuid()) {
444
-		    if(!printinfected)
445
-			logg("^%s: Access denied to archive\n", filename);
446
-		} else {
525
+	chmod(movefilename, fstat.st_mode);
526
+#ifndef C_OS2
527
+	chown(movefilename, fstat.st_uid, fstat.st_gid);
528
+#endif
447 529
 
448
-		    if(limits && limits->maxfilesize)
449
-			if(fileinfo(filename, 1) / 1024 > limits->maxfilesize) {
450
-			    if(!printinfected)
451
-				logg("^%s: Archive too big\n", filename);
452
-			    return 0;
453
-			}
530
+	ubuf.actime = fstat.st_atime;
531
+	ubuf.modtime = fstat.st_mtime;
532
+	utime(movefilename, &ubuf);
454 533
 
455
-		    return(scandenied(filename, root, user, opt, limits, options));
456
-		}
457
-		return 0;
458
-	    case 1:
459
-		return(scancompressed(filename, root, user, opt, limits, options));
534
+	if(moveflag && unlink(filename)) {
535
+	    logg("!Can't unlink '%s': %s\n", filename, strerror(errno));
536
+	    info.notremoved++;            
537
+	    free(movefilename);
538
+	    return;
460 539
 	}
461 540
     }
462 541
 
463
-    if((ret = checkfile(filename, root, limits, options, printclean)) == CL_VIRUS) {
464
-	if(opt_check(opt, "remove")) {
465
-	    if(unlink(filename)) {
466
-		logg("^%s: Can't remove\n", filename);
467
-		claminfo.notremoved++;
468
-	    } else {
469
-		logg("%s: Removed\n", filename);
470
-	    }
471
-	} else if (opt_check(opt, "move") || opt_check(opt, "copy"))
472
-            move_infected(filename, opt);
542
+    logg("%s: %s to '%s'\n", filename, (moveflag) ? "moved" : "copied", movefilename);
543
+
544
+    free(movefilename);
545
+}
546
+
547
+static int checkfile(const char *filename, const struct cl_engine *engine, const struct cl_limits *limits, int options, short printclean)
548
+{
549
+	int fd, ret;
550
+	const char *virname;
551
+
552
+
553
+    logg("*Scanning %s\n", filename);
554
+
555
+    if((fd = open(filename, O_RDONLY)) == -1) {
556
+	logg("^Can't open file %s\n", filename);
557
+	return 54;
473 558
     }
559
+
560
+    if((ret = cl_scandesc(fd, &virname, &info.blocks, engine, limits, options)) == CL_VIRUS) {
561
+	logg("%s: %s FOUND\n", filename, virname);
562
+	info.ifiles++;
563
+
564
+	if(bell)
565
+	    fprintf(stderr, "\007");
566
+
567
+    } else if(ret == CL_CLEAN) {
568
+	if(!printinfected && printclean)
569
+	    mprintf("%s: OK\n", filename);
570
+    } else
571
+	if(!printinfected)
572
+	    logg("%s: %s\n", filename, cl_strerror(ret));
573
+
574
+    close(fd);
474 575
     return ret;
475 576
 }
476 577
 
477
-/* it has guaranteed read access to the archive */
478
-int scancompressed(const char *filename, struct cl_node *root, const struct passwd *user, const struct optstruct *opt, const struct cl_limits *limits, int options)
578
+static int scancompressed(const char *filename, struct cl_engine *engine, const struct passwd *user, const struct optstruct *opt, const struct cl_limits *limits, int options)
479 579
 {
480 580
 	int ret = 0;
481 581
 	char *tmpdir, *gendir, *userprg;
... ...
@@ -500,7 +653,7 @@ int scancompressed(const char *filename, struct cl_node *root, const struct pass
500 500
 	tmpdir = "/tmp";
501 501
 #endif
502 502
 
503
-    if(checkaccess(tmpdir, UNPUSER, W_OK) != 1) {
503
+    if(checkaccess(tmpdir, CLAMAVUSER, W_OK) != 1) {
504 504
 	logg("!Can't write to the temporary directory\n");
505 505
 	exit(64);
506 506
     }
... ...
@@ -603,7 +756,7 @@ int scancompressed(const char *filename, struct cl_node *root, const struct pass
603 603
 	    short oldrec = recursion;
604 604
 
605 605
 	recursion = 1;
606
-	ret = treewalk(gendir, root, user, opt, limits, options, 1);
606
+	ret = treewalk(gendir, engine, user, opt, limits, options, 1);
607 607
 	recursion = oldrec;
608 608
     }
609 609
 
... ...
@@ -623,11 +776,11 @@ int scancompressed(const char *filename, struct cl_node *root, const struct pass
623 623
 	    /* This is no longer a critical error (since 0.24). We scan
624 624
 	     * raw archive.
625 625
 	     */
626
-	    if((ret = checkfile(filename, root, limits, 0, 0)) == CL_VIRUS) {
626
+	    if((ret = checkfile(filename, engine, limits, 0, 0)) == CL_VIRUS) {
627 627
 		if(opt_check(opt, "remove")) {
628 628
 		    if(unlink(filename)) {
629 629
 			logg("^%s: Can't remove\n", filename);
630
-			claminfo.notremoved++;
630
+			info.notremoved++;
631 631
 		    } else {
632 632
 			logg("%s: Removed\n", filename);
633 633
 		    }
... ...
@@ -640,11 +793,11 @@ int scancompressed(const char *filename, struct cl_node *root, const struct pass
640 640
 	case 0:
641 641
 	    /* no viruses found in archive, we scan just in case a raw file
642 642
 	     */
643
-	    if((ret = checkfile(filename, root, limits, 0, 1)) == CL_VIRUS) {
643
+	    if((ret = checkfile(filename, engine, limits, 0, 1)) == CL_VIRUS) {
644 644
 		if(opt_check(opt, "remove")) {
645 645
 		    if(unlink(filename)) {
646 646
 			logg("^%s: Can't remove\n", filename);
647
-			claminfo.notremoved++;
647
+			info.notremoved++;
648 648
 		    } else {
649 649
 			logg("%s: Removed\n", filename);
650 650
 		    }
... ...
@@ -661,7 +814,7 @@ int scancompressed(const char *filename, struct cl_node *root, const struct pass
661 661
 	    if(opt_check(opt, "remove")) {
662 662
 		if(unlink(filename)) {
663 663
 		    logg("^%s: Can't remove\n", filename);
664
-		    claminfo.notremoved++;
664
+		    info.notremoved++;
665 665
 		} else {
666 666
 		    logg("%s: Removed\n", filename);
667 667
 		}
... ...
@@ -675,7 +828,7 @@ int scancompressed(const char *filename, struct cl_node *root, const struct pass
675 675
     }
676 676
 }
677 677
 
678
-int scandenied(const char *filename, struct cl_node *root, const struct passwd *user, const struct optstruct *opt, const struct cl_limits *limits, int options)
678
+static int scandenied(const char *filename, struct cl_engine *engine, const struct passwd *user, const struct optstruct *opt, const struct cl_limits *limits, int options)
679 679
 {
680 680
 	char *tmpdir, *gendir, *tmpfile, *pt;
681 681
 	struct stat statbuf;
... ...
@@ -699,7 +852,7 @@ int scandenied(const char *filename, struct cl_node *root, const struct passwd *
699 699
 #endif
700 700
 
701 701
 
702
-    if(checkaccess(tmpdir, UNPUSER, W_OK) != 1) {
702
+    if(checkaccess(tmpdir, CLAMAVUSER, W_OK) != 1) {
703 703
 	logg("!Can't write to the temporary directory %s\n", tmpdir);
704 704
 	exit(64);
705 705
     }
... ...
@@ -735,13 +888,13 @@ int scandenied(const char *filename, struct cl_node *root, const struct passwd *
735 735
     }
736 736
 #endif
737 737
 
738
-    if((ret = treewalk(gendir, root, user, opt, limits, options, 1)) == 1) {
738
+    if((ret = treewalk(gendir, engine, user, opt, limits, options, 1)) == 1) {
739 739
 	logg("(Real infected archive: %s)\n", filename);
740 740
 
741 741
 	if(opt_check(opt, "remove")) {
742 742
 	    if(unlink(filename)) {
743 743
 		logg("^%s: Can't remove\n", filename);
744
-		claminfo.notremoved++;
744
+		info.notremoved++;
745 745
 	    } else {
746 746
 	        logg("%s: Removed\n", filename);
747 747
 	    }
... ...
@@ -758,315 +911,152 @@ int scandenied(const char *filename, struct cl_node *root, const struct passwd *
758 758
     return ret;
759 759
 }
760 760
 
761
-int scandirs(const char *dirname, struct cl_node *root, const struct passwd *user, const struct optstruct *opt, const struct cl_limits *limits, int options)
762
-{
763
-	return treewalk(dirname, root, user, opt, limits, options, 1);
764
-}
765
-
766
-int checkfile(const char *filename, const struct cl_node *root, const struct cl_limits *limits, int options, short printclean)
761
+int scanfile(const char *filename, struct cl_engine *engine, const struct passwd *user, const struct optstruct *opt, const struct cl_limits *limits, unsigned int options)
767 762
 {
768
-	int fd, ret;
769
-	const char *virname;
770
-
771
-
772
-    logg("*Scanning %s\n", filename);
773
-
774
-    if((fd = open(filename, O_RDONLY)) == -1) {
775
-	logg("^Can't open file %s\n", filename);
776
-	return 54;
777
-    }
778
-
779
-    if((ret = cl_scandesc(fd, &virname, &claminfo.blocks, root, limits, options)) == CL_VIRUS) {
780
-	logg("%s: %s FOUND\n", filename, virname);
781
-	claminfo.ifiles++;
782
-
783
-	if(bell)
784
-	    fprintf(stderr, "\007");
785
-
786
-    } else if(ret == CL_CLEAN) {
787
-	if(!printinfected && printclean)
788
-	    mprintf("%s: OK\n", filename);
789
-    } else
790
-	if(!printinfected)
791
-	    logg("%s: %s\n", filename, cl_strerror(ret));
792
-
793
-    close(fd);
794
-    return ret;
795
-}
796
-
797
-int checkstdin(const struct cl_node *root, const struct cl_limits *limits, int options)
798
-{
799
-	int ret;
800
-	const char *virname, *tmpdir;
801
-	char *file, buff[FILEBUFF];
802
-	FILE *fs;
803
-
804
-
805
-    /* check write access */
806
-    tmpdir = getenv("TMPDIR");
763
+	int ret, included, printclean = 1;
764
+	const struct optnode *optnode;
765
+	char *argument;
766
+#ifdef C_LINUX
767
+	struct stat sb;
807 768
 
808
-    if(tmpdir == NULL)
809
-#ifdef P_tmpdir
810
-	tmpdir = P_tmpdir;
811
-#else
812
-	tmpdir = "/tmp";
813
-#endif
769
+    /* argh, don't scan /proc files */
770
+    if(procdev)
771
+	if(stat(filename, &sb) != -1)
772
+	    if(sb.st_dev == procdev) {
773
+		if(!printinfected)
774
+		    logg("%s: Excluded (/proc)\n", filename);
775
+		return 0;
776
+	    }
777
+#endif    
814 778
 
815
-    if(checkaccess(tmpdir, UNPUSER, W_OK) != 1) {
816
-	logg("!Can't write to temporary directory\n");
817
-	return 64;
779
+    if(opt_check(opt, "exclude")) {
780
+	argument = opt_firstarg(opt, "exclude", &optnode);
781
+	while(argument) {
782
+	    if(match_regex(filename, argument) == 1) {
783
+		if(!printinfected)
784
+		    logg("%s: Excluded\n", filename);
785
+		return 0;
786
+	    }
787
+	    argument = opt_nextarg(&optnode, "exclude");
788
+	}
818 789
     }
819 790
 
820
-    file = cli_gentemp(tmpdir);
791
+   if(opt_check(opt, "include")) {
792
+	included = 0;
793
+	argument = opt_firstarg(opt, "include", &optnode);
794
+	while(argument && !included) {
795
+	    if(match_regex(filename, argument) == 1) {
796
+		included = 1;
797
+		break;
798
+	    }
799
+	    argument = opt_nextarg(&optnode, "include");
800
+	}
821 801
 
822
-    if(!(fs = fopen(file, "wb"))) {
823
-	logg("!Can't open %s for writing\n", file);
824
-	return 63;
802
+	if(!included) {
803
+	    if(!printinfected)
804
+		logg("%s: Excluded\n", filename);
805
+	    return 0;
806
+	}
825 807
     }
826 808
 
827
-    while((ret = fread(buff, 1, FILEBUFF, stdin)))
828
-	fwrite(buff, 1, ret, fs);
829
-
830
-    fclose(fs);
831
-
832
-    logg("*Checking %s\n", file);
833
-    claminfo.files++;
834
-
835
-    if((ret = cl_scanfile(file, &virname, &claminfo.blocks, root, limits, options)) == CL_VIRUS) {
836
-	logg("stdin: %s FOUND\n", virname);
837
-	claminfo.ifiles++;
838
-
839
-	if(bell)
840
-	    fprintf(stderr, "\007");
841
-
842
-    } else if(ret == CL_CLEAN) {
843
-	if(!printinfected)
844
-	    mprintf("stdin: OK\n");
845
-    } else
809
+    if(fileinfo(filename, 1) == 0) {
846 810
 	if(!printinfected)
847
-	    logg("stdin: %s\n", cl_strerror(ret));
848
-
849
-    unlink(file);
850
-    free(file);
851
-    return ret;
852
-}
853
-
854
-/*
855
- * -1 -> can't fork
856
- * -2 -> can't execute
857
- * -3 -> external signal
858
- * 0 -> OK
859
- */
860
-
861
-int clamav_unpack(const char *prog, char **args, const char *tmpdir, const struct passwd *user, const struct optstruct *opt)
862
-{
863
-	pid_t pid;
864
-	int status, wret, maxfiles, maxspace, fdevnull;
865
-	struct s_du n;
866
-
867
-
868
-    if(opt_check(opt, "max-files"))
869
-	maxfiles = atoi(opt_arg(opt, "max-files"));
870
-    else
871
-	maxfiles = 0;
811
+	    logg("%s: Empty file\n", filename);
812
+	return 0;
813
+    }
872 814
 
873
-    if(opt_check(opt, "max-space")) {
874
-	    char *cpy, *ptr;
875
-	ptr = opt_arg(opt, "max-space");
876
-	if(tolower(ptr[strlen(ptr) - 1]) == 'm') { /* megabytes */
877
-	    cpy = mcalloc(strlen(ptr), sizeof(char));
878
-	    strncpy(cpy, ptr, strlen(ptr) - 1);
879
-	    maxspace = atoi(cpy) * 1024;
880
-	    free(cpy);
881
-	} else /* default - kilobytes */
882
-	    maxspace = atoi(ptr);
883
-    } else
884
-	maxspace = 0;
815
+    if(geteuid())
816
+	if(checkaccess(filename, NULL, R_OK) != 1) {
817
+	    if(!printinfected)
818
+		logg("%s: Access denied\n", filename);
819
+	    return 0;
820
+	}
885 821
 
822
+    info.files++;
886 823
 
887
-    switch(pid = fork()) {
888
-	case -1:
889
-	    return -1;
890
-	case 0:
891
-#ifndef C_CYGWIN
892
-	    if(!geteuid() && user) {
824
+    /* 
825
+     * check the extension  - this is a special case, normally we don't need to
826
+     * do this (libclamav detects archive by its magic string), but here we
827
+     * want to know the exit code from internal unpacker and try to use
828
+     * external (if provided) when internal cannot extract data.
829
+     */
893 830
 
894
-#ifdef HAVE_SETGROUPS
895
-		if(setgroups(1, &user->pw_gid)) {
896
-		    fprintf(stderr, "ERROR: setgroups() failed\n");
897
-		    exit(1);
831
+    if((cli_strbcasestr(filename, ".zip") || cli_strbcasestr(filename, ".rar")) && (options & CL_SCAN_ARCHIVE)) {
832
+	/* try to use internal archivers */
833
+	if((ret = checkfile(filename, engine, limits, options, 1)) == CL_VIRUS) {
834
+	    if(opt_check(opt, "remove")) {
835
+		if(unlink(filename)) {
836
+		    logg("^%s: Can't remove\n", filename);
837
+		    info.notremoved++;
838
+		} else {
839
+		    logg("%s: Removed\n", filename);
898 840
 		}
899
-#endif
841
+	    } else if (opt_check(opt, "move") || opt_check(opt, "copy"))
842
+		move_infected(filename, opt);
900 843
 
901
-		if(setgid(user->pw_gid)) {
902
-		    fprintf(stderr, "ERROR: setgid(%d) failed\n", (int) user->pw_gid);
903
-		    exit(1);
904
-		}
844
+	    return 1;
905 845
 
906
-		if(setuid(user->pw_uid)) {
907
-		    fprintf(stderr, "ERROR: setuid(%d) failed\n", (int) user->pw_uid);
908
-		    exit(1);
909
-		}
910
-	    }
911
-#endif
912
-	    chdir(tmpdir);
846
+	} else if(ret == CL_CLEAN) {
847
+	    return 0;
848
+	} else if(ret == 54) {
849
+	    return ret;
850
+	}
913 851
 
914
-	    if(printinfected) {
915
-  	        fdevnull = open("/dev/null", O_WRONLY);
916
-		if(fdevnull == -1) {
917
-		    logg("Non fatal error: cannot open /dev/null. Continuing with full output\n");
918
-		    printinfected = 0;
919
-		} else {
920
-		    dup2(fdevnull,1);
921
-		    dup2(fdevnull,2);
922
-		}
923
-	    }
852
+	/* in other case try to continue with external archivers */
853
+	options &= ~CL_SCAN_ARCHIVE; /* and disable decompression for the checkfile() below */
854
+	printclean = 0;
855
+    }
924 856
 
925
-	    if(strchr(prog, '/')) /* we have full path */
926
-		execv(prog, args);
927
-	    else
928
-		execvp(prog, args);
929
-	    perror("execv(p)");
930
-	    abort();
931
-	    break;
932
-	default:
857
+    if((cli_strbcasestr(filename, ".zip") && opt_check(opt, "unzip"))
858
+    || (cli_strbcasestr(filename, ".rar") && opt_check(opt, "unrar"))
859
+    || (cli_strbcasestr(filename, ".arj") && opt_check(opt, "arj"))
860
+    || (cli_strbcasestr(filename, ".zoo") && opt_check(opt, "unzoo"))
861
+    || (cli_strbcasestr(filename, ".jar") && opt_check(opt, "jar"))
862
+    || (cli_strbcasestr(filename, ".lzh") && opt_check(opt, "lha"))
863
+    || (cli_strbcasestr(filename, ".tar") && opt_check(opt, "tar"))
864
+    || (cli_strbcasestr(filename, ".deb") && opt_check(opt, "deb"))
865
+    || ((cli_strbcasestr(filename, ".tar.gz") || cli_strbcasestr(filename, ".tgz")) 
866
+	 && (opt_check(opt, "tgz") || opt_check(opt, "deb"))) ) {
933 867
 
934
-	    if(maxfiles || maxspace) {
935
-		while(!(wret = waitpid(pid, &status, WNOHANG))) {
936
-		    memset(&n, 0, sizeof(struct s_du));
868
+	/* check permissions */
869
+	switch(checkaccess(filename, CLAMAVUSER, R_OK)) {
870
+	    case -1:
871
+		logg("^Can't get information about user "CLAMAVUSER"\n");
872
+		exit(60); /* this is a critical problem so we just exit here */
873
+	    case -2:
874
+		logg("^Can't fork\n");
875
+		exit(61);
876
+	    case 0: /* read access denied */
877
+		if(geteuid()) {
878
+		    if(!printinfected)
879
+			logg("^%s: Access denied to archive\n", filename);
880
+		} else {
937 881
 
938
-		    if(!du(tmpdir, &n))
939
-			if((maxfiles && n.files > maxfiles) || (maxspace && n.space > maxspace)) {
940
-			    logg("*n.files: %d, n.space: %d\n", n.files, n.space);
941
-			    kill(pid, 9); /* stop it immediately */
882
+		    if(limits && limits->maxfilesize)
883
+			if((unsigned int) fileinfo(filename, 1) / 1024 > limits->maxfilesize) {
884
+			    if(!printinfected)
885
+				logg("^%s: Archive too big\n", filename);
886
+			    return 0;
942 887
 			}
943
-		}
944
-	    } else
945
-		waitpid(pid, &status, 0);
946 888
 
947
-
948
-	    if(WIFSIGNALED(status)) {
949
-		switch(WTERMSIG(status)) {
950
-
951
-		    case 9:
952
-			logg("\nUnpacker process %d stopped due to exceeded limits\n", pid);
953
-			return 0;
954
-		    case 6: /* abort */
955
-			logg("^Can't run %s\n", prog);
956
-			return -2;
957
-		    default:
958
-			logg("^\nUnpacker stopped with external signal %d\n", WTERMSIG(status));
959
-			return -3;
889
+		    return(scandenied(filename, engine, user, opt, limits, options));
960 890
 		}
961
-	    } else if(WIFEXITED(status))
962 891
 		return 0;
963
-    }
964
-
965
-    return 0;
966
-}
967
-
968
-void move_infected(const char *filename, const struct optstruct *opt)
969
-{
970
-	char *movedir, *movefilename, *tmp, numext[4 + 1];
971
-	struct stat fstat, mfstat;
972
-	int n, len, movefilename_size;
973
-	int moveflag = opt_check(opt, "move");
974
-	struct utimbuf ubuf;
975
-
976
-
977
-    if((moveflag && !(movedir = opt_arg(opt, "move"))) ||
978
-	(!moveflag && !(movedir = opt_arg(opt, "copy")))) {
979
-        /* Should never reach here */
980
-        logg("!opt_arg() returned NULL\n", filename);
981
-        claminfo.notmoved++;
982
-        return;
983
-    }
984
-
985
-    if(access(movedir, W_OK|X_OK) == -1) {
986
-	logg("!Can't %s file '%s': cannot write to '%s': %s\n", (moveflag) ? "move" : "copy", filename, movedir, strerror(errno));
987
-        claminfo.notmoved++;
988
-        return;
989
-    }
990
-
991
-    if(!(tmp = strrchr(filename, '/')))
992
-	tmp = (char *) filename;
993
-
994
-    movefilename_size = sizeof(char) * (strlen(movedir) + strlen(tmp) + sizeof(numext) + 2);
995
-
996
-    if(!(movefilename = mmalloc(movefilename_size))) {
997
-        logg("!mmalloc() failed\n");
998
-	exit(71);
999
-    }
1000
-
1001
-    if(!(cli_strrcpy(movefilename, movedir))) {
1002
-        logg("!cli_strrcpy() returned NULL\n");
1003
-        claminfo.notmoved++;
1004
-        free(movefilename);
1005
-        return;
1006
-    }
1007
-
1008
-    strcat(movefilename, "/");
1009
-
1010
-    if(!(strcat(movefilename, tmp))) {
1011
-        logg("!strcat() returned NULL\n");
1012
-        claminfo.notmoved++;
1013
-        free(movefilename);
1014
-        return;
1015
-    }
1016
-
1017
-    stat(filename, &fstat);
1018
-
1019
-    if(!stat(movefilename, &mfstat)) {
1020
-        if(fstat.st_ino == mfstat.st_ino) { /* It's the same file*/
1021
-            logg("File excluded '%s'\n", filename);
1022
-            claminfo.notmoved++;
1023
-            free(movefilename);
1024
-            return;
1025
-        } else {
1026
-            /* file exists - try to append an ordinal number to the
1027
-	     * quranatined file in an attempt not to overwrite existing
1028
-	     * files in quarantine  
1029
-	     */
1030
-            len = strlen(movefilename);
1031
-            n = 0;        		        		
1032
-            do {
1033
-                /* reset the movefilename to it's initial value by
1034
-		 * truncating to the original filename length
1035
-		 */
1036
-                movefilename[len] = 0;
1037
-                /* append .XXX */
1038
-                sprintf(numext, ".%03d", n++);
1039
-                strcat(movefilename, numext);            	
1040
-            } while(!stat(movefilename, &mfstat) && (n < 1000));
1041
-       }
1042
-    }
1043
-
1044
-    if(!moveflag || rename(filename, movefilename) == -1) {
1045
-	if(filecopy(filename, movefilename) == -1) {
1046
-	    logg("!Can't %s '%s' to '%s': %s\n", (moveflag) ? "move" : "copy", filename, movefilename, strerror(errno));
1047
-	    claminfo.notmoved++;
1048
-	    free(movefilename);
1049
-	    return;
1050
-	}
1051
-
1052
-	chmod(movefilename, fstat.st_mode);
1053
-#ifndef C_OS2
1054
-	chown(movefilename, fstat.st_uid, fstat.st_gid);
1055
-#endif
1056
-
1057
-	ubuf.actime = fstat.st_atime;
1058
-	ubuf.modtime = fstat.st_mtime;
1059
-	utime(movefilename, &ubuf);
1060
-
1061
-	if(moveflag && unlink(filename)) {
1062
-	    logg("!Can't unlink '%s': %s\n", filename, strerror(errno));
1063
-	    claminfo.notremoved++;            
1064
-	    free(movefilename);
1065
-	    return;
892
+	    case 1:
893
+		return(scancompressed(filename, engine, user, opt, limits, options));
1066 894
 	}
1067 895
     }
1068 896
 
1069
-    logg("%s: %s to '%s'\n", filename, (moveflag) ? "moved" : "copied", movefilename);
1070
-
1071
-    free(movefilename);
897
+    if((ret = checkfile(filename, engine, limits, options, printclean)) == CL_VIRUS) {
898
+	if(opt_check(opt, "remove")) {
899
+	    if(unlink(filename)) {
900
+		logg("^%s: Can't remove\n", filename);
901
+		info.notremoved++;
902
+	    } else {
903
+		logg("%s: Removed\n", filename);
904
+	    }
905
+	} else if (opt_check(opt, "move") || opt_check(opt, "copy"))
906
+            move_infected(filename, opt);
907
+    }
908
+    return ret;
1072 909
 }
... ...
@@ -20,26 +20,13 @@
20 20
 #ifndef __MANAGER_H
21 21
 #define __MANAGER_H
22 22
 
23
-#include "libclamav/clamav.h"
24 23
 #include <pwd.h>
25
-#include "options.h"
26
-
27
-int scanmanager(const struct optstruct *opt);
28
-
29
-int scanfile(const char *filename, struct cl_node *root, const struct passwd *user, const struct optstruct *opt, const struct cl_limits *limits, int options);
30
-
31
-int scancompressed(const char *filename, struct cl_node *root, const struct passwd *user, const struct optstruct *opt, const struct cl_limits *limits, int options);
32 24
 
33
-int scandenied(const char *filename, struct cl_node *root, const struct passwd *user, const struct optstruct *opt, const struct cl_limits *limits, int options);
34
-
35
-int scandirs(const char *dirname, struct cl_node *root, const struct passwd *user, const struct optstruct *opt, const struct cl_limits *limits, int options);
36
-
37
-int checkfile(const char *filename, const struct cl_node *root, const struct cl_limits *limits, int options, short printclean);
38
-
39
-int checkstdin(const struct cl_node *root, const struct cl_limits *limits, int options);
25
+#include "libclamav/clamav.h"
26
+#include "shared/options.h"
40 27
 
41
-int clamav_unpack(const char *prog, char **args, const char *tmpdir, const struct passwd *user, const struct optstruct *opt);
28
+int scanmanager(const struct optstruct *opt);
42 29
 
43
-void move_infected(const char *filename, const struct optstruct *opt);
30
+int scanfile(const char *filename, struct cl_engine *engine, const struct passwd *user, const struct optstruct *opt, const struct cl_limits *limits, unsigned int options);
44 31
 
45 32
 #endif
... ...
@@ -16,9 +16,6 @@
16 16
  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 17
  *  MA 02110-1301, USA.
18 18
  *
19
- *  Sat May 18 15:20:26 CEST 2002: included detectCpu() from Magnus Ekdahl
20
- *  Sat Jun 29 12:19:26 CEST 2002: fixed non386 detectCpu (Magnus Ekdahl)
21
- *
22 19
  */
23 20
 
24 21
 #if HAVE_CONFIG_H
... ...
@@ -45,7 +42,7 @@
45 45
 #include <regex.h>
46 46
 #endif
47 47
 
48
-#include "output.h"
48
+#include "shared/output.h"
49 49
 #include "others.h"
50 50
 
51 51
 int fileinfo(const char *filename, short i)
52 52
deleted file mode 100644
... ...
@@ -1,37 +0,0 @@
1
-/*
2
- *  Copyright (C) 2002 - 2004 Tomasz Kojm <tkojm@clamav.net>
3
- *
4
- *  This program is free software; you can redistribute it and/or modify
5
- *  it under the terms of the GNU General Public License as published by
6
- *  the Free Software Foundation; either version 2 of the License, or
7
- *  (at your option) any later version.
8
- *
9
- *  This program is distributed in the hope that it will be useful,
10
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
- *  GNU General Public License for more details.
13
- *
14
- *  You should have received a copy of the GNU General Public License
15
- *  along with this program; if not, write to the Free Software
16
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17
- *  MA 02110-1301, USA.
18
- */
19
-
20
-#ifndef __SHARED_H
21
-#define __SHARED_H
22
-
23
-struct s_info {
24
-    int signs; /* number of signatures loaded */
25
-    int dirs; /* number of scanned directories */
26
-    int files; /* number of scanned files */
27
-    int ifiles; /* number of infected files */
28
-    int notremoved; /* number of not removed files (if --remove) */
29
-    int notmoved; /* number of not moved files (if --move) */
30
-    int errors; /*  ... of errors */
31
-    long int blocks; /* number of read 16kb blocks */
32
-};
33
-
34
-extern struct s_info claminfo;
35
-extern short recursion, printinfected, bell;
36
-
37
-#endif
... ...
@@ -32,17 +32,19 @@
32 32
 #include <dirent.h>
33 33
 #include <errno.h>
34 34
 
35
-#include "shared.h"
35
+#include "global.h"
36 36
 #include "manager.h"
37 37
 #include "others.h"
38
-#include "options.h"
39 38
 #include "treewalk.h"
40
-#include "defaults.h"
41
-#include "memory.h"
42
-#include "output.h"
43
-#include "misc.h"
44 39
 
45
-int treewalk(const char *dirname, struct cl_node *root, const struct passwd *user, const struct optstruct *opt, const struct cl_limits *limits, int options, unsigned int depth)
40
+#include "shared/options.h"
41
+#include "shared/memory.h"
42
+#include "shared/output.h"
43
+#include "shared/misc.h"
44
+
45
+#include "libclamav/clamav.h"
46
+
47
+int treewalk(const char *dirname, struct cl_engine *engine, const struct passwd *user, const struct optstruct *opt, const struct cl_limits *limits, unsigned int options, unsigned int depth)
46 48
 {
47 49
 	DIR *dd;
48 50
 	struct dirent *dent;
... ...
@@ -92,7 +94,7 @@ int treewalk(const char *dirname, struct cl_node *root, const struct passwd *use
92 92
     if(depth > maxdepth)
93 93
 	return 0;
94 94
 
95
-    claminfo.dirs++;
95
+    info.dirs++;
96 96
     depth++;
97 97
 
98 98
     if((dd = opendir(dirname)) != NULL) {
... ...
@@ -109,11 +111,11 @@ int treewalk(const char *dirname, struct cl_node *root, const struct passwd *use
109 109
 		    /* stat the file */
110 110
 		    if(lstat(fname, &statbuf) != -1) {
111 111
 			if(S_ISDIR(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode) && recursion) {
112
-			    if(treewalk(fname, root, user, opt, limits, options, depth) == 1)
112
+			    if(treewalk(fname, engine, user, opt, limits, options, depth) == 1)
113 113
 				scanret++;
114 114
 			} else {
115 115
 			    if(S_ISREG(statbuf.st_mode))
116
-				scanret += scanfile(fname, root, user, opt, limits, options);
116
+				scanret += scanfile(fname, engine, user, opt, limits, options);
117 117
 			}
118 118
 		    }
119 119
 		    free(fname);
... ...
@@ -151,7 +153,7 @@ int clamav_rmdirs(const char *dir)
151 151
 	case 0:
152 152
 #ifndef C_CYGWIN
153 153
 	    if(!geteuid()) { 
154
-		if((user = getpwnam(UNPUSER)) == NULL)
154
+		if((user = getpwnam(CLAMAVUSER)) == NULL)
155 155
 		    return -3;
156 156
 
157 157
 #ifdef HAVE_SETGROUPS
... ...
@@ -182,7 +184,6 @@ int clamav_rmdirs(const char *dir)
182 182
 	    else
183 183
 		return -2;
184 184
     }
185
-
186 185
 }
187 186
 
188 187
 int fixperms(const char *dirname)
... ...
@@ -22,15 +22,14 @@
22 22
 
23 23
 #include <pwd.h>
24 24
 #include "libclamav/clamav.h"
25
-
26
-#include "options.h"
25
+#include "shared/options.h"
27 26
 
28 27
 struct s_du {
29
-    int files;
30
-    long int space; /* in kilobytes */
28
+    unsigned int files;
29
+    unsigned long int space; /* in kilobytes */
31 30
 };
32 31
 
33
-int treewalk(const char *dirname, struct cl_node *root, const struct passwd *user, const struct optstruct *opt, const struct cl_limits *limits, int options, unsigned int depth);
32
+int treewalk(const char *dirname, struct cl_engine *engine, const struct passwd *user, const struct optstruct *opt, const struct cl_limits *limits, unsigned int options, unsigned int depth);
34 33
 
35 34
 int clamav_rmdirs(const char *dir);
36 35
 int fixperms(const char *dirname);