git-svn: trunk@627
Tomasz Kojm authored on 2004/06/23 01:50:58... | ... |
@@ -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 |
} |