Browse code

clamdscan: support multiple arguments on command line

git-svn: trunk@627

Tomasz Kojm authored on 2004/06/23 01:50:58
Showing 4 changed files
... ...
@@ -1,3 +1,8 @@
1
+Tue Jun 22 18:47:32 CEST 2004 (tk)
2
+----------------------------------
3
+  * clamdscan: support multiple arguments on command line (requested by
4
+	       Dan Egli <dan*eglifamily.dnsalias.net>); major cleanup
5
+
1 6
 Tue Jun 22 11:58:06 BST 2004 (njh/trog)
2 7
 ---------------------------------------
3 8
   * libclamav/str.c:	Rewrote cli_chomp() as discussed in the clamav-devel
... ...
@@ -26,6 +26,7 @@
26 26
 #include <unistd.h>
27 27
 #include <sys/time.h>
28 28
 #include <time.h>
29
+#include <signal.h>
29 30
 
30 31
 #include "options.h"
31 32
 #include "others.h"
... ...
@@ -36,12 +37,11 @@
36 36
 
37 37
 void help(void);
38 38
 
39
-struct s_info claminfo;
40 39
 short printinfected = 0;
41 40
 
42 41
 void clamscan(struct optstruct *opt)
43 42
 {
44
-	int ds, dms, ret;
43
+	int ds, dms, ret, infected;
45 44
 	struct timeval t1, t2;
46 45
 	struct timezone tz;
47 46
 	time_t starttime;
... ...
@@ -89,10 +89,9 @@ void clamscan(struct optstruct *opt)
89 89
     /* ctime() does \n, but I need it once more */
90 90
     logg("Scan started: %s\n", ctime(&starttime));
91 91
 
92
-    memset(&claminfo, 0, sizeof(struct s_info));
93
-
94 92
     gettimeofday(&t1, &tz);
95
-    ret = client(opt);
93
+
94
+    ret = client(opt, &infected);
96 95
 
97 96
 /* Implement STATUS in clamd */
98 97
     if(!optl(opt, "disable-summary")) {
... ...
@@ -103,8 +102,8 @@ void clamscan(struct optstruct *opt)
103 103
 	dms += (dms < 0) ? (1000000):(0);
104 104
 	mprintf("\n----------- SCAN SUMMARY -----------\n");
105 105
 	    logg("\n-- summary --\n");
106
-	mprintf("Infected files: %d\n", claminfo.ifiles);
107
-	    logg("Infected files: %d\n", claminfo.ifiles);
106
+	mprintf("Infected files: %d\n", infected);
107
+	    logg("Infected files: %d\n", infected);
108 108
 	mprintf("Time: %d.%3.3d sec (%d m %d s)\n", ds, dms/1000, ds/60, ds%60);
109 109
 	    logg("Time: %d.%3.3d sec (%d m %d s)\n", ds, dms/1000, ds/60, ds%60);
110 110
     }
... ...
@@ -38,6 +38,7 @@
38 38
 #include "cfgparser.h"
39 39
 #include "memory.h"
40 40
 #include "output.h"
41
+#include "str.h"
41 42
 
42 43
 #ifdef PF_INET
43 44
 # define SOCKET_INET	PF_INET
... ...
@@ -45,36 +46,171 @@
45 45
 # define SOCKET_INET	AF_INET
46 46
 #endif
47 47
 
48
-int client(const struct optstruct *opt)
48
+
49
+int dsfile(int sockd, const char *filename)
50
+{
51
+	int infected = 0, waserror = 0;
52
+	char buff[4096], *scancmd;
53
+	FILE *fd;
54
+
55
+
56
+    scancmd = mcalloc(strlen(filename) + 20, sizeof(char));
57
+    sprintf(scancmd, "CONTSCAN %s", filename);
58
+
59
+    if(write(sockd, scancmd, strlen(scancmd)) <= 0) {
60
+	mprintf("@Can't write to the socket.\n");
61
+	free(scancmd);
62
+	return -1;
63
+    }
64
+
65
+    free(scancmd);
66
+
67
+    if((fd = fdopen(dup(sockd), "r")) == NULL) {
68
+	mprintf("@Can't open descriptor for reading.\n");
69
+	return -1;
70
+    }
71
+
72
+    while(fgets(buff, sizeof(buff), fd)) {
73
+	if(strstr(buff, "FOUND\n")) {
74
+	    infected++;
75
+	    logg("%s", buff);
76
+	    mprintf("%s", buff);
77
+	}
78
+	if (strstr(buff, "ERROR\n")) {
79
+	    logg("%s", buff);
80
+	    mprintf("%s", buff);
81
+	    waserror = 1;
82
+	}
83
+    }
84
+
85
+    fclose(fd);
86
+
87
+    if(!infected)
88
+	mprintf("%s: OK\n", filename);
89
+
90
+    return infected ? infected : (waserror ? -1 : 0);
91
+}
92
+
93
+int dsstream(int sockd)
94
+{
95
+	int wsockd, loopw = 60, bread, port, infected = 0;
96
+	struct sockaddr_in server;
97
+	char buff[4096], *pt;
98
+
99
+    if(write(sockd, "STREAM", 6) <= 0) {
100
+	mprintf("@Can't write to the socket.\n");
101
+	return 2;
102
+    }
103
+
104
+    memset(buff, 0, sizeof(buff));
105
+    while(loopw) {
106
+	read(sockd, buff, sizeof(buff));
107
+	if((pt = strstr(buff, "PORT"))) {
108
+	    pt += 5;
109
+	    sscanf(pt, "%d", &port);
110
+	    break;
111
+	}
112
+	loopw--;
113
+    }
114
+
115
+    if(!loopw) {
116
+	mprintf("@Daemon not ready for stream scanning.\n");
117
+	return -1;
118
+    }
119
+
120
+    /* connect to clamd */
121
+
122
+    if((wsockd = socket(SOCKET_INET, SOCK_STREAM, 0)) < 0) {
123
+	perror("socket()");
124
+	mprintf("@Can't create the socket.\n");
125
+	return -1;
126
+    }
127
+
128
+    server.sin_family = AF_INET;
129
+    server.sin_port = htons(port);
130
+
131
+    if(connect(wsockd, (struct sockaddr *) &server, sizeof(struct sockaddr_in)) < 0) {
132
+	close(wsockd);
133
+	perror("connect()");
134
+	mprintf("@Can't connect to clamd [port: %d].\n", port);
135
+	return -1;
136
+    }
137
+
138
+    while((bread = read(0, buff, sizeof(buff))) > 0) {
139
+	if(write(wsockd, buff, bread) <= 0) {
140
+	    mprintf("@Can't write to the socket.\n");
141
+	    close(wsockd);
142
+	    return -1;
143
+	}
144
+    }
145
+    close(wsockd);
146
+
147
+    memset(buff, 0, sizeof(buff));
148
+    while((bread = read(sockd, buff, sizeof(buff))) > 0) {
149
+	mprintf("%s", buff);
150
+	if(strstr(buff, "FOUND\n")) {
151
+	    infected++;
152
+	    logg("%s", buff);
153
+	}
154
+	if(strstr(buff, "ERROR\n")) {
155
+	    logg("%s", buff);
156
+	    return -1;
157
+	}
158
+	memset(buff, 0, sizeof(buff));
159
+    }
160
+
161
+    return infected;
162
+}
163
+
164
+char *abpath(const char *filename)
165
+{
166
+	struct stat foo;
167
+	char *fullpath, cwd[200];
168
+
169
+    if(stat(filename, &foo) == -1) {
170
+	mprintf("@Can't access file %s\n", filename);
171
+	perror(filename);
172
+	return NULL;
173
+    } else {
174
+	fullpath = mcalloc(200 + strlen(filename) + 10, sizeof(char));
175
+#ifdef C_CYGWIN
176
+	sprintf(fullpath, "%s", filename);
177
+#else
178
+	if(!getcwd(cwd, 200)) {
179
+	    mprintf("@Can't get absolute pathname of current working directory.\n");
180
+	    return NULL;
181
+	}
182
+	sprintf(fullpath, "%s/%s", cwd, filename);
183
+#endif
184
+    }
185
+
186
+    return fullpath;
187
+}
188
+
189
+int dconnect(const struct optstruct *opt)
49 190
 {
50
-	char buff[4096], cwd[200], *file, *scancmd, *pt;
51 191
 	struct sockaddr_un server;
52
-        struct sockaddr_in server2;
192
+	struct sockaddr_in server2;
53 193
 	struct hostent *he;
54 194
 	struct cfgstruct *copt, *cpt;
55
-	int sockd, wsockd, loopw = 60, bread, port;
56 195
 	const char *clamav_conf = getargl(opt, "config-file");
57
-	FILE *fd;
196
+	int sockd;
197
+
58 198
 
59 199
     if(!clamav_conf)
60 200
 	clamav_conf = DEFAULT_CFG;
61 201
 
62 202
     if((copt = parsecfg(clamav_conf, 1)) == NULL) {
63 203
 	mprintf("@Can't parse the configuration file.\n");
64
-	return 2;
204
+	return -1;
65 205
     }
66 206
 
67
-    /* Set default address to connect to; needed for scanning a stream and no TCP address specified */
207
+    /* Set default address to connect to */
68 208
     server2.sin_addr.s_addr = inet_addr("127.0.0.1");    
69
-    if(cfgopt(copt, "ScannerDaemonOutputFormat")) {
70
-	mprintf("clamdscan won't work with the ScannerDaemonOutputFormat option\n");
71
-	mprintf("enabled. Please disable it in %s\n", clamav_conf);
72
-	return 2;
73
-    }
74 209
 
75 210
     if(cfgopt(copt, "TCPSocket") && cfgopt(copt, "LocalSocket")) {
76 211
 	mprintf("@Clamd is not configured properly.\n");
77
-	return 2;
212
+	return -1;
78 213
     } else if((cpt = cfgopt(copt, "LocalSocket"))) {
79 214
 
80 215
 	server.sun_family = AF_UNIX;
... ...
@@ -83,14 +219,14 @@ int client(const struct optstruct *opt)
83 83
 	if((sockd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
84 84
 	    perror("socket()");
85 85
 	    mprintf("@Can't create the socket.\n");
86
-	    return 2;
86
+	    return -1;
87 87
 	}
88 88
 
89 89
 	if(connect(sockd, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) {
90 90
 	    close(sockd);
91 91
 	    perror("connect()");
92 92
 	    mprintf("@Can't connect to clamd.\n");
93
-	    return 2;
93
+	    return -1;
94 94
 	}
95 95
 
96 96
     } else if((cpt = cfgopt(copt, "TCPSocket"))) {
... ...
@@ -98,7 +234,7 @@ int client(const struct optstruct *opt)
98 98
 	if((sockd = socket(SOCKET_INET, SOCK_STREAM, 0)) < 0) {
99 99
 	    perror("socket()");
100 100
 	    mprintf("@Can't create the socket.\n");
101
-	    return 2;
101
+	    return -1;
102 102
 	}
103 103
 
104 104
 	server2.sin_family = AF_INET;
... ...
@@ -109,153 +245,109 @@ int client(const struct optstruct *opt)
109 109
 		close(sockd);
110 110
 		perror("gethostbyname()");
111 111
 		mprintf("@Can't lookup clamd hostname.\n");
112
-		return 2;
112
+		return -1;
113 113
 	    }
114 114
 	    server2.sin_addr = *(struct in_addr *) he->h_addr_list[0];
115
-
116 115
 	}
117 116
 
118 117
 	if(connect(sockd, (struct sockaddr *) &server2, sizeof(struct sockaddr_in)) < 0) {
119 118
 	    close(sockd);
120 119
 	    perror("connect()");
121 120
 	    mprintf("@Can't connect to clamd.\n");
122
-	    return 2;
121
+	    return -1;
123 122
 	}
124 123
 
125 124
     } else {
126 125
 	mprintf("@Clamd is not configured properly.\n");
127
-	return 2;
126
+	return -1;
128 127
     }
129 128
 
129
+    return sockd;
130
+}
130 131
 
131
-    if(opt->filename == NULL || strlen(opt->filename) == 0) {
132
-	/* we need the full path to the file */
133
-	if(!getcwd(cwd, 200)) {
134
-	    mprintf("@Can't get the absolute pathname of the current working directory.\n");
135
-	    return 2;
136
-	}
137
-	file = (char *) strdup(cwd);
138
-
139
-    } else if(!strcmp(opt->filename, "-")) { /* scan data from stdin */
140
-	if(write(sockd, "STREAM", 6) <= 0) {
141
-	    mprintf("@Can't write to the socket.\n");
142
-	    close(sockd);
143
-	    return 2;
144
-	}
132
+int client(const struct optstruct *opt, int *infected)
133
+{
134
+	char cwd[200], *fullpath;
135
+	int sockd, ret, errors = 0;
136
+	struct stat sb;
145 137
 
146
-	memset(buff, 0, sizeof(buff));
147
-	while(loopw) {
148
-	    read(sockd, buff, sizeof(buff));
149
-	    if((pt = strstr(buff, "PORT"))) {
150
-		pt += 5;
151
-		sscanf(pt, "%d", &port);
152
-		break;
153
-	    }
154
-	    loopw--;
155
-	}
156 138
 
157
-	if(!loopw) {
158
-	    mprintf("@Daemon not ready for stream scanning.\n");
159
-	    return 2;
160
-	}
139
+    *infected = 0;
161 140
 
162
-	/* connect to clamd */
141
+    /* parse argument list */
163 142
 
164
-	if((wsockd = socket(SOCKET_INET, SOCK_STREAM, 0)) < 0) {
165
-	    perror("socket()");
166
-	    mprintf("@Can't create the socket.\n");
143
+    if(opt->filename == NULL || strlen(opt->filename) == 0) {
144
+	/* scan current directory */
145
+	if(!getcwd(cwd, 200)) {
146
+	    mprintf("@Can't get absolute pathname of current working directory.\n");
167 147
 	    return 2;
168 148
 	}
169 149
 
170
-	server2.sin_family = AF_INET;
171
-	server2.sin_port = htons(port);
172
-
173
-	if(connect(wsockd, (struct sockaddr *) &server2, sizeof(struct sockaddr_in)) < 0) {
174
-	    close(wsockd);
175
-	    perror("connect()");
176
-	    mprintf("@Can't connect to clamd [port: %d].\n", port);
150
+	if((sockd = dconnect(opt)) < 0)
177 151
 	    return 2;
178
-	}
179 152
 
180
-	while((bread = read(0, buff, sizeof(buff))) > 0) {
181
-	    if(write(wsockd, buff, bread) <= 0) {
182
-		mprintf("@Can't write to the socket.\n");
183
-		close(wsockd);
184
-		return 2;
185
-	    }
186
-	}
187
-	close(wsockd);
188
-
189
-
190
-	memset(buff, 0, sizeof(buff)); /* FIXME: ugly, but needed for mprintf */
191
-	while((bread = read(sockd, buff, sizeof(buff))) > 0) {
192
-	    mprintf("%s", buff);
193
-	    if(strstr(buff, "FOUND\n")) {
194
-		claminfo.ifiles++;
195
-		logg("%s", buff);
196
-	    }
197
-	    if (strstr(buff, "ERROR\n")) {
198
-		claminfo.errors++;
199
-		logg("%s", buff);
200
-	    }
201
-	    memset(buff, 0, sizeof(buff));
202
-	}
203
-
204
-	return claminfo.ifiles ? 1 : (claminfo.errors ? 2 : 0);
153
+	if((ret = dsfile(sockd, cwd)) >= 0)
154
+	    *infected += ret;
155
+	else
156
+	    errors++;
205 157
 
206
-    } else if(opt->filename[0] == '/') {
207
-	file = (char *) strdup(opt->filename);
208
-    } else {
209
-	    struct stat foo;
158
+	close(sockd);
210 159
 
211
-	if(stat(opt->filename, &foo) == -1) {
212
-	    mprintf("@Can't access file %s\n", opt->filename);
213
-	    perror(opt->filename);
160
+    } else if(!strcmp(opt->filename, "-")) { /* scan data from stdin */
161
+	if((sockd = dconnect(opt)) < 0)
214 162
 	    return 2;
215
-	} else {
216
-	    file = mcalloc(200 + strlen(opt->filename) + 10, sizeof(char));
217
-#ifdef C_CYGWIN
218
-	    sprintf(file, "%s", opt->filename);
219
-#else
220
-	    /* we need the full path to the file */
221
-	    if(!getcwd(cwd, 200)) {
222
-		mprintf("@Can't get the absolute pathname of the current working directory.\n");
223
-		return 2;
224
-	    }
225
-	    sprintf(file, "%s/%s", cwd, opt->filename);
226
-#endif
227
-	}
228
-    }
229 163
 
164
+	if((ret = dsstream(sockd)) >= 0)
165
+	    *infected += ret;
166
+	else
167
+	    errors++;
230 168
 
231
-    scancmd = mcalloc(strlen(file) + 20, sizeof(char));
232
-    sprintf(scancmd, "CONTSCAN %s", file);
233
-    free(file);
234
-
235
-    if(write(sockd, scancmd, strlen(scancmd)) <= 0) {
236
-	mprintf("@Can't write to the socket.\n");
237 169
 	close(sockd);
238
-	return 2;
239
-    }
240 170
 
241
-    if((fd = fdopen(sockd, "r")) == NULL) {
242
-	mprintf("@Can't open descriptor %d to read.\n", sockd);
243
-	return 2;
244
-    }
171
+    } else {
172
+	int x;
173
+	char *thefilename;
174
+	for (x = 0; (thefilename = cli_strtok(opt->filename, x, "\t")) != NULL; x++) {
175
+	    fullpath = thefilename;
176
+
177
+	    if(stat(fullpath, &sb) == -1) {
178
+		mprintf("@Can't access file %s\n", fullpath);
179
+		perror(fullpath);
180
+		errors++;
181
+	    } else {
182
+		if(fullpath[0] != '/') {
183
+		    fullpath = abpath(thefilename);
184
+		    free(thefilename);
185
+
186
+		    if(!fullpath) {
187
+			mprintf("@Can't determine absolute path.\n");
188
+			return 2;
189
+		    }
190
+		}
191
+
192
+		switch(sb.st_mode & S_IFMT) {
193
+		    case S_IFREG:
194
+		    case S_IFDIR:
195
+			if((sockd = dconnect(opt)) < 0)
196
+			    return 2;
197
+
198
+			if((ret = dsfile(sockd, fullpath)) >= 0)
199
+			    *infected += ret;
200
+			else
201
+			    errors++;
202
+
203
+			close(sockd);
204
+			break;
205
+
206
+		    default:
207
+			mprintf("@Not supported file type (%s)\n", fullpath);
208
+			errors++;
209
+		}
210
+	    }
245 211
 
246
-    while(fgets(buff, sizeof(buff), fd)) {
247
-	if(strstr(buff, "FOUND\n")) {
248
-	    claminfo.ifiles++;
249
-	    logg("%s", buff);
212
+	    free(fullpath);
250 213
 	}
251
-	if (strstr(buff, "ERROR\n")) {
252
-	    claminfo.errors++;
253
-	    logg("%s", buff);
254
-	}
255
-	mprintf("%s", buff);
256 214
     }
257 215
 
258
-    fclose(fd);
259
-
260
-    return claminfo.ifiles ? 1 : (claminfo.errors ? 2 : 0);
216
+    return *infected ? 1 : (errors ? 2 : 0);
261 217
 }
... ...
@@ -21,6 +21,6 @@
21 21
 
22 22
 #include "options.h"
23 23
 
24
-int client(const struct optstruct *opt);
24
+int client(const struct optstruct *opt, int *infected);
25 25
 
26 26
 #endif