Browse code

clamonacc - add curl support

Mickey Sola authored on 2019/04/26 05:11:39
Showing 17 changed files
... ...
@@ -36,14 +36,14 @@ clamonacc_SOURCES = \
36 36
     $(top_srcdir)/shared/getopt.h \
37 37
     $(top_srcdir)/shared/actions.c \
38 38
     $(top_srcdir)/shared/actions.h \
39
-    $(top_srcdir)/shared/clamdcom.c \
40
-    $(top_srcdir)/shared/clamdcom.h \
41 39
     $(top_srcdir)/shared/priv-fts.h \
42 40
     clamonacc.c \
43 41
     ./client/onaccess_client.c \
44 42
     ./client/onaccess_client.h \
45 43
     ./client/onaccess_proto.c \
46 44
     ./client/onaccess_proto.h \
45
+    ./client/onaccess_com.c \
46
+    ./client/onaccess_com.h \
47 47
     ./inotif/onaccess_ddd.c \
48 48
     ./inotif/onaccess_ddd.h \
49 49
     ./fanotif/onaccess_fan.c \
... ...
@@ -64,8 +64,8 @@ AM_CFLAGS=@WERR_CFLAGS@
64 64
 endif
65 65
 
66 66
 DEFS = @DEFS@ -DCL_NOLIBCLAMAV
67
-LIBS = $(top_builddir)/libclamav/libclamav_internal_utils.la  @CLAMONACC_LIBS@ @THREAD_LIBS@
68
-AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/clamd -I$(top_srcdir)/shared -I$(top_srcdir)/libclamav @SSL_CPPFLAGS@ @CLAMONACC_CPPFLAGS@ @JSON_CPPFLAGS@ @PCRE_CPPFLAGS@
67
+LIBS = $(top_builddir)/libclamav/libclamav_internal_utils.la @CURL_LDFLAGS@ @CURL_LIBS@ @CLAMONACC_LIBS@ @THREAD_LIBS@
68
+AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/clamd -I$(top_srcdir)/shared -I$(top_srcdir)/libclamav @CURL_CPPFLAGS@ @SSL_CPPFLAGS@ @CLAMONACC_CPPFLAGS@ @JSON_CPPFLAGS@ @PCRE_CPPFLAGS@
69 69
 
70 70
 AM_INSTALLCHECK_STD_OPTIONS_EXEMPT=clamonacc$(EXEEXT)
71 71
 CLEANFILES=*.gcda *.gcno
... ...
@@ -159,11 +159,12 @@ struct onas_context *onas_init_context(void) {
159 159
 
160 160
 cl_error_t onas_check_client_connection(struct onas_context **ctx) {
161 161
 
162
+	cl_error_t err = CL_SUCCESS;
162 163
 	errno = 0;
163 164
 
164 165
 	/* 0 local, non-zero remote, errno set on error */
165
-	(*ctx)->isremote = onas_check_remote(ctx);
166
-	if (errno == 0) {
166
+	(*ctx)->isremote = onas_check_remote(ctx, &err);
167
+	if (errno == 0 && CL_SUCCESS == err ) {
167 168
 		logg("*Clamonacc: ");
168 169
 		(*ctx)->isremote ? logg("*daemon is remote\n") : logg("*daemon is local\n");
169 170
 	}
... ...
@@ -225,6 +226,9 @@ void* onas_context_cleanup(struct onas_context *ctx) {
225 225
 	close(ctx->fan_fd);
226 226
 	optfree((struct optstruct *) ctx->opts);
227 227
 	optfree((struct optstruct *) ctx->clamdopts);
228
+        if (ctx->portstr) {
229
+            free(ctx->portstr);
230
+        }
228 231
 	ctx->opts = NULL;
229 232
 	ctx->clamdopts = NULL;
230 233
 	free(ctx);
... ...
@@ -24,6 +24,16 @@
24 24
 
25 25
 #include "libclamav/clamav.h"
26 26
 
27
+#ifndef HAVE_ATTRIB_PACKED
28
+#define __attribute__(x)
29
+#endif
30
+#ifdef HAVE_PRAGMA_PACK
31
+#pragma pack(1)
32
+#endif
33
+#ifdef HAVE_PRAGMA_PACK_HPPA
34
+#pragma pack 1
35
+#endif
36
+
27 37
 struct onas_context {
28 38
 	const struct optstruct *opts;
29 39
 	const struct optstruct *clamdopts;
... ...
@@ -45,8 +55,16 @@ struct onas_context {
45 45
         int scantype;
46 46
         int isremote;
47 47
         int session;
48
-};
49 48
 
49
+        char *portstr;
50
+} __attribute__((packed));
51
+
52
+#ifdef HAVE_PRAGMA_PACK
53
+#pragma pack()
54
+#endif
55
+#ifdef HAVE_PRAGMA_PACK_HPPA
56
+#pragma pack
57
+#endif
50 58
 
51 59
 struct onas_context* onas_init_context(void);
52 60
 void* onas_cleanup(struct onas_context *ctx);
... ...
@@ -25,6 +25,7 @@
25 25
 
26 26
 #include <stdio.h>
27 27
 #include <stdlib.h>
28
+#include <curl/curl.h>
28 29
 #ifdef	HAVE_UNISTD_H
29 30
 #include <unistd.h>
30 31
 #endif
... ...
@@ -56,11 +57,12 @@
56 56
 #include "shared/output.h"
57 57
 #include "shared/misc.h"
58 58
 #include "shared/actions.h"
59
-#include "shared/clamdcom.h"
60 59
 
61 60
 #include "libclamav/str.h"
62 61
 #include "libclamav/others.h"
63 62
 
63
+
64
+#include "onaccess_com.h"
64 65
 #include "onaccess_client.h"
65 66
 #include "onaccess_proto.h"
66 67
 
... ...
@@ -80,97 +82,124 @@ static void print_server_version(struct onas_context **ctx)
80 80
 
81 81
 /* Inits the communication layer
82 82
  * Returns 0 if clamd is local, non zero if clamd is remote */
83
-int onas_check_remote(struct onas_context  **ctx) {
84
-    int s, ret;
85
-    const struct optstruct *opt;
86
-    char *ipaddr = NULL;
87
-    char port[10];
88
-    struct addrinfo hints, *info, *p;
89
-    int res;
83
+int onas_check_remote(struct onas_context  **ctx, cl_error_t *err) {
84
+	int s, ret;
85
+	const struct optstruct *opt;
86
+	CURL *curl;
87
+	CURLcode curlcode;
88
+	char *ipaddr = NULL;
89
+	char port[10];
90
+	struct addrinfo hints, *info, *p;
91
+	int res;
92
+
93
+	*err = CL_SUCCESS;
90 94
 
91 95
 #ifndef _WIN32
92
-    if((opt = optget((*ctx)->clamdopts, "LocalSocket"))->enabled) {
93
-        memset((void *)&nixsock, 0, sizeof(nixsock));
94
-        nixsock.sun_family = AF_UNIX;
95
-        strncpy(nixsock.sun_path, opt->strarg, sizeof(nixsock.sun_path));
96
-        nixsock.sun_path[sizeof(nixsock.sun_path)-1]='\0';
97
-        return 0;
98
-    }
96
+	if((opt = optget((*ctx)->clamdopts, "LocalSocket"))->enabled) {
97
+		return 0;
98
+	}
99 99
 #endif
100
-    if(!(opt = optget((*ctx)->clamdopts, "TCPSocket"))->enabled)
101
-        return 0;
100
+	if(!(opt = optget((*ctx)->clamdopts, "TCPSocket"))->enabled) {
101
+		return 0;
102
+	}
102 103
 
103
-    snprintf(port, sizeof(port), "%lld", optget((*ctx)->clamdopts, "TCPSocket")->numarg);
104
+	snprintf(port, sizeof(port), "%lld", optget((*ctx)->clamdopts, "TCPSocket")->numarg);
104 105
 
105
-    opt = optget((*ctx)->clamdopts, "TCPAddr");
106
-    while (opt) {
106
+	if ((*ctx)->portstr) {
107
+		free((*ctx)->portstr);
108
+	}
107 109
 
108
-        if (opt->strarg)
109
-            ipaddr = (!strcmp(opt->strarg, "any") ? NULL : opt->strarg);
110
+	(*ctx)->portstr = cli_strdup(port);
111
+	if ( NULL == (*ctx)->portstr ) {
112
+		*err = CL_EARG;
113
+		return 0;
114
+	}
110 115
 
111
-        memset(&hints, 0x00, sizeof(struct addrinfo));
112
-        hints.ai_family = AF_UNSPEC;
113
-        hints.ai_socktype = SOCK_STREAM;
114
-        hints.ai_flags = AI_PASSIVE;
116
+	opt = optget((*ctx)->clamdopts, "TCPAddr");
117
+	while (opt) {
118
+
119
+		if (opt->strarg) {
120
+			ipaddr = (!strcmp(opt->strarg, "any") ? NULL : opt->strarg);
121
+		}
122
+
123
+		if (NULL == ipaddr) {
124
+			logg("!ClamClient: Clamonacc does not support binding to INADDR_ANY, \
125
+					please specify an address with TCPAddr in your clamd.conf config file\n");
126
+			*err = CL_EARG;
127
+			return 1;
128
+		}
129
+
130
+		curlcode = onas_curl_init(&curl, ipaddr, port);
131
+		if (CURLE_OK != curlcode) {
132
+			logg("!ClamClient: could not init curl, %s\n", curl_easy_strerror(curlcode));
133
+			*err = CL_EARG;
134
+			return 1;
135
+		}
136
+
137
+		curlcode = curl_easy_perform(curl);
138
+		if (CURLE_OK != curlcode) {
139
+			logg("!ClamClient: could not connect to remote clam daemon, %s\n", curl_easy_strerror(curlcode));
140
+			*err = CL_EARG;
141
+			return 1;
142
+		}
143
+
144
+		curl_easy_cleanup(curl);
145
+
146
+		opt = opt->nextarg;
147
+	}
115 148
 
116
-        if ((res = getaddrinfo(ipaddr, port, &hints, &info))) {
117
-            logg("!Can't lookup clamd hostname: %s\n", gai_strerror(res));
118
-            opt = opt->nextarg;
119
-            continue;
120
-        }
149
+	if (*err == CL_SUCCESS) {
150
+		return 1;
151
+	} else {
152
+		return 0;
153
+	}
154
+}
121 155
 
122
-        for (p = info; p != NULL; p = p->ai_next) {
123
-            if((s = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0) {
124
-                logg("isremote: socket() returning: %s.\n", strerror(errno));
125
-                continue;
126
-            }
127
-
128
-            switch (p->ai_family) {
129
-            case AF_INET:
130
-                ((struct sockaddr_in *)(p->ai_addr))->sin_port = htons(INADDR_ANY);
131
-                break;
132
-            case AF_INET6:
133
-                ((struct sockaddr_in6 *)(p->ai_addr))->sin6_port = htons(INADDR_ANY);
134
-                break;
135
-            default:
136
-                break;
137
-            }
138
-
139
-            ret = bind(s, p->ai_addr, p->ai_addrlen);
140
-            if (ret) {
141
-                if (errno == EADDRINUSE) {
142
-                    /*
143
-                     * If we can't bind, then either we're attempting to listen on an IP that isn't
144
-                     * ours or that clamd is already listening on.
145
-                     */
146
-                    closesocket(s);
147
-                    freeaddrinfo(info);
148
-                    return 0;
149
-                }
150
-
151
-                closesocket(s);
152
-                freeaddrinfo(info);
153
-                return 1;
154
-            }
155
-
156
-            closesocket(s);
156
+CURLcode onas_curl_init(CURL **curl, char *ipaddr, char *port) {
157
+
158
+	CURLcode curlcode = CURLE_OK;
159
+
160
+	if (!curl || !(*curl) || !ipaddr || !port) {
161
+		logg("!ClamClient: invalid (NULL) args passed to onas_curl_init\n");
162
+		return CURLE_FAILED_INIT;
163
+	}
164
+
165
+	*curl = curl_easy_init();
166
+
167
+	curlcode = curl_easy_setopt(*curl, CURLOPT_PORT, port);
168
+        if (CURLE_OK != curlcode) {
169
+		logg("!ClamClient: could not setup curl with tcp port, %s\n", curl_easy_strerror(curlcode));
170
+		curl_easy_cleanup(*curl);
171
+		return curlcode;
157 172
         }
158 173
 
159
-        freeaddrinfo(info);
174
+	curlcode = curl_easy_setopt(*curl, CURLOPT_URL, ipaddr);
175
+        if (CURLE_OK != curlcode) {
176
+		logg("!ClamClient: could not setup curl with tcp address, %s\n", curl_easy_strerror(curlcode));
177
+		curl_easy_cleanup(*curl);
178
+		return curlcode;
179
+        }
160 180
 
161
-        opt = opt->nextarg;
162
-    }
181
+	/* we implement our own transfer protocol via send and recv, so we only need to connect */
182
+	curlcode = curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1L);
183
+	if (CURLE_OK != curlcode) {
184
+		logg("!ClamClient: could not setup curl to connect only, %s\n", curl_easy_strerror(curlcode));
185
+		curl_easy_cleanup(*curl);
186
+		return curlcode;
187
+	}
163 188
 
164
-    return 0;
189
+	return curlcode;
165 190
 }
166 191
 
167 192
 cl_error_t onas_setup_client (struct onas_context **ctx) {
168 193
 
169 194
     const struct optstruct *opts;
170 195
     const struct optstruct *opt;
171
-    errno = 0;
196
+    cl_error_t err;
172 197
     int remote;
173 198
 
199
+    errno = 0;
200
+
174 201
     opts = (*ctx)->opts;
175 202
 
176 203
     if(optget(opts, "verbose")->enabled) {
... ...
@@ -200,16 +229,20 @@ cl_error_t onas_setup_client (struct onas_context **ctx) {
200 200
 	    logg("!ClamClient: problem with internal logger\n");
201 201
             return CL_EARG;
202 202
 	}
203
-    } else
203
+    } else {
204 204
 	logg_file = NULL;
205
+    }
205 206
 
206 207
     if(actsetup(opts)) {
207 208
 	return CL_EARG;
208 209
     }
209 210
 
210
-    if (onas_check_remote(ctx)) {
211
-        (*ctx)->isremote = 1;
212
-    } else if (errno == EADDRINUSE) {
211
+    if (curl_global_init(CURL_GLOBAL_NOTHING)) {
212
+        return CL_EARG;
213
+    }
214
+
215
+    (*ctx)->isremote = onas_check_remote(ctx, &err);
216
+    if (err) {
213 217
         return CL_EARG;
214 218
     }
215 219
 
... ...
@@ -275,21 +308,51 @@ static char *onas_make_absolute(const char *basepath) {
275 275
 int onas_get_clamd_version(struct onas_context **ctx)
276 276
 {
277 277
     char *buff;
278
+    CURL *curl;
279
+    CURLcode curlcode;
280
+    cl_error_t err = CL_SUCCESS;
281
+    int b_remote;
278 282
     int len, sockd;
279 283
     struct RCVLN rcv;
280 284
 
281
-    onas_check_remote(ctx);
282
-    if((sockd = onas_dconnect(ctx)) < 0) {
283
-        return 2;
285
+    b_remote = onas_check_remote(ctx, &err);
286
+    if (CL_SUCCESS != err) {
287
+	    logg("!ClamClient: could not check to see if daemon was remote\n");
288
+	    return 2;
289
+    }
290
+
291
+    if (!b_remote) {
292
+	curl = curl_easy_init();
293
+        curlcode = curl_easy_setopt(curl, CURLOPT_UNIX_SOCKET_PATH, optget((*ctx)->clamdopts, "LocalSocket")->strarg);
294
+	if (CURLE_OK != curlcode) {
295
+		logg("!ClamClient: could not setup curl with local unix socket, %s\n", curl_easy_strerror(curlcode));
296
+		curl_easy_cleanup(curl);
297
+		return 2;
298
+	}
299
+    } else {
300
+	curlcode = onas_curl_init(&curl, optget((*ctx)->clamdopts, "TCPAddr")->strarg, (*ctx)->portstr);
301
+	if (CURLE_OK != curlcode) {
302
+		logg("!ClamClient: could not setup curl with tcp address and port, %s\n", curl_easy_strerror(curlcode));
303
+		/* curl cleanup done in ons_curl_init on error */
304
+		return 2;
305
+	}
284 306
     }
285
-    recvlninit(&rcv, sockd);
286 307
 
287
-    if(sendln(sockd, "zVERSION", 9)) {
288
-        closesocket(sockd);
308
+    onas_recvlninit(&rcv, curl);
309
+
310
+    curlcode = curl_easy_perform(curl);
311
+    if (CURLE_OK != curlcode) {
312
+	    logg("!ClamClient: could not connect to clam daemon, %s\n", curl_easy_strerror(curlcode));
313
+	    return 2;
314
+    }
315
+
316
+
317
+    if(onas_sendln(curl, "zVERSION", 9)) {
318
+        curl_easy_close(curl);
289 319
         return 2;
290 320
     }
291 321
 
292
-    while((len = recvln(&rcv, &buff, NULL))) {
322
+    while((len = onas_recvln(&rcv, &buff, NULL))) {
293 323
         if(len == -1) {
294 324
             logg("*ClamClient: clamd did not respond with version information\n");
295 325
             break;
... ...
@@ -297,12 +360,14 @@ int onas_get_clamd_version(struct onas_context **ctx)
297 297
         printf("%s\n", buff);
298 298
     }
299 299
 
300
-    closesocket(sockd);
300
+    curl_easy_close(curl);
301 301
     return 0;
302 302
 }
303 303
 
304 304
 int onas_client_scan(struct onas_context **ctx, const char *fname, STATBUF sb, int *infected, int *err, cl_error_t *ret_code)
305 305
 {
306
+	CURL *curl = NULL;
307
+	CURLcode curlcode = CURLE_OK;
306 308
 	int scantype, errors = 0;
307 309
 	int sockd, ret;
308 310
 
... ...
@@ -314,19 +379,32 @@ int onas_client_scan(struct onas_context **ctx, const char *fname, STATBUF sb, i
314 314
 		scantype = (*ctx)->scantype;
315 315
         }
316 316
 
317
+	curlcode = onas_curl_init(&curl, optget((*ctx)->clamdopts, "TCPAddr")->strarg, (*ctx)->portstr);
318
+	if (CURLE_OK != curlcode) {
319
+		logg("!ClamClient: could not setup curl with tcp address and port, %s\n", curl_easy_strerror(curlcode));
320
+		/* curl cleanup done in ons_curl_init on error */
321
+		return 2;
322
+	}
323
+
317 324
 	/* logg here is noisy even for debug, enable only for dev work if something has gone very wrong. */
318 325
         //logg("*ClamClient: connecting to daemon ...\n");
319
-	if((sockd = onas_dconnect(ctx)) >= 0 && (ret = onas_dsresult(ctx, sockd, scantype, fname, &ret, err, ret_code)) >= 0) {
326
+	curlcode = curl_easy_perform(curl);
327
+	if (CURLE_OK != curlcode) {
328
+		logg("!ClamClient: could not establish connection, %s\n", curl_easy_strerror(curlcode));
329
+		return 2;
330
+	}
331
+
332
+
333
+	if((ret = onas_dsresult(ctx, curl, scantype, fname, &ret, err, ret_code)) >= 0) {
320 334
 		*infected = ret;
321 335
 	} else {
322 336
 		logg("*ClamClient: connection could not be established ... return code %d\n", *ret_code);
323 337
 		errors = 1;
324 338
 	}
325
-	if(sockd >= 0) {
326
-		/* logg here is noisy even for debug, enable only for dev work if something has gone very wrong. */
327
-		//logg("*ClamClient: done, closing connection ...\n");
328
-		closesocket(sockd);
329
-	}
339
+	/* logg here is noisy even for debug, enable only for dev work if something has gone very wrong. */
340
+	//logg("*ClamClient: done, closing connection ...\n");
330 341
 
342
+	curl_easy_cleanup(curl);
331 343
 	return *infected ? 1 : (errors ? 2 : 0);
332 344
 }
345
+
... ...
@@ -22,6 +22,8 @@
22 22
 #ifndef __ONAS_CLIENT_H
23 23
 #define __ONAS_CLIENT_H
24 24
 
25
+#include <curl/curl.h>
26
+
25 27
 #include "shared/optparser.h"
26 28
 #include "../clamonacc.h"
27 29
 
... ...
@@ -36,8 +38,9 @@ enum {
36 36
 
37 37
 
38 38
 int onas_client_scan(struct onas_context **ctx, const char *fname, STATBUF sb, int *infected, int *err, cl_error_t *ret_code);
39
+CURLcode onas_curl_init(CURL **curl, char *ipaddr, char *port);
39 40
 int onas_get_clamd_version(struct onas_context **ctx);
40 41
 cl_error_t onas_setup_client(struct onas_context **ctx);
41
-int onas_check_remote(struct onas_context  **ctx);
42
+int onas_check_remote(struct onas_context  **ctx, cl_error_t *err);
42 43
 
43 44
 #endif
44 45
new file mode 100644
... ...
@@ -0,0 +1,156 @@
0
+/*
1
+ *  Copyright (C) 2015 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
2
+ *  Copyright (C) 2009-2010 Sourcefire, Inc.
3
+ *
4
+ *  Author: aCaB
5
+ *
6
+ *  This program is free software; you can redistribute it and/or modify
7
+ *  it under the terms of the GNU General Public License version 2 as
8
+ *  published by the Free Software Foundation.
9
+ *
10
+ *  This program is distributed in the hope that it will be useful,
11
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
+ *  GNU General Public License for more details.
14
+ *
15
+ *  You should have received a copy of the GNU General Public License
16
+ *  along with this program; if not, write to the Free Software
17
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18
+ *  MA 02110-1301, USA.
19
+ */
20
+
21
+#if HAVE_CONFIG_H
22
+#include "clamav-config.h"
23
+#endif
24
+
25
+#include <stdio.h>
26
+#include <string.h>
27
+#include <sys/types.h>
28
+#include <sys/stat.h>
29
+#include <curl/curl.h>
30
+#if HAVE_UNISTD_H
31
+#include <unistd.h>
32
+#endif
33
+#include <fcntl.h>
34
+#include <errno.h>
35
+
36
+#if !defined(_WIN32)
37
+#include <sys/socket.h>
38
+#endif
39
+
40
+#include "shared/output.h"
41
+
42
+#include "onaccess_com.h"
43
+
44
+/* Sends bytes over a socket
45
+ * Returns 0 on success */
46
+int onas_sendln(CURL *curl, const char *line, unsigned int len) {
47
+	unsigned int sent = 0;
48
+	CURLcode curlcode;
49
+
50
+	while(len) {
51
+
52
+		curlcode = curl_easy_send(curl, line, len, &sent);
53
+		if(sent <= 0) {
54
+			if(sent && errno == EINTR) {
55
+				continue;
56
+			} else {
57
+				logg("!Can't send to clamd: %s\n", strerror(errno));
58
+			}
59
+
60
+			return 1;
61
+		}
62
+
63
+		line += sent;
64
+		len -= sent;
65
+	}
66
+
67
+	return 0;
68
+}
69
+
70
+/* Inits a RECVLN struct before it can be used in recvln() - see below */
71
+void onas_recvlninit(struct RCVLN *s, CURL *curl) {
72
+	rcv_data->curl = curl;
73
+	rcv_data->curl_code = CURLE_OK;
74
+	rcv_data->lnstart = rcv_data->curr = rcv_data->buf;
75
+	rcv_data->bytes_recvd = 0;
76
+}
77
+
78
+/* Receives a full (terminated with \0) line from a socket
79
+ * Sets ret_bol to the begin of the received line, and optionally
80
+ * ret_eol to the end of line.
81
+ * Should be called repeatedly until all input is consumed
82
+ * Returns:
83
+ * - the length of the line (a positive number) on success
84
+ * - 0 if the connection is closed
85
+ * - -1 on error
86
+ */
87
+int onas_recvln(struct RCVLN *rcv_data, char **ret_bol, char **ret_eol) {
88
+	char *eol;
89
+	int ret = 0;
90
+
91
+	while(1) {
92
+		if (!rcv_data->bytes_recvd) {
93
+			rcv_data->curl_code = easy_curl_recv(rcv_data->curl, rcv_data->curr,
94
+					sizeof(rcv_data->buf) - (rcv_data->curr - rcv_data->buf), &(rcv_data->bytes_recvd));
95
+
96
+			if (rcv_data->bytes_recvd<=0) {
97
+				if (rcv_data->bytes_recvd && errno == EINTR) {
98
+					rcv_data->bytes_recvd = 0;
99
+					continue;
100
+				}
101
+
102
+				if (rcv_data->bytes_recvd || rcv_data->curr!=rcv_data->buf) {
103
+					*rcv_data->curr = '\0';
104
+
105
+					if (strcmp(rcv_data->buf, "UNKNOWN COMMAND\n")) {
106
+						logg("!Communication error\n");
107
+					} else {
108
+						logg("!Command rejected by clamd (wrong clamd version?)\n");
109
+					}
110
+
111
+					return -1;
112
+				}
113
+
114
+				return 0;
115
+			}
116
+		}
117
+
118
+		if ((eol = memchr(rcv_data->curr, 0, rcv_data->bytes_recvd))) {
119
+			eol++;
120
+			rcv_data->bytes_recvd -= eol - rcv_data->curr;
121
+
122
+			*ret_bol = rcv_data->lnstart;
123
+			if (ret_eol) {
124
+				*ret_eol = eol;
125
+			}
126
+
127
+			ret = eol - rcv_data->lnstart;
128
+			if (rcv_data->bytes_recvd) {
129
+				rcv_data->lnstart = rcv_data->curr = eol;
130
+			} else {
131
+				rcv_data->lnstart = rcv_data->curr = rcv_data->buf;
132
+			}
133
+
134
+			return ret;
135
+		}
136
+
137
+		rcv_data->bytes_recvd += rcv_data->curr - rcv_data->lnstart;
138
+
139
+		if (!eol && rcv_data->bytes_recvd==sizeof(rcv_data->buf)) {
140
+			logg("!Overlong reply from clamd\n");
141
+			return -1;
142
+		}
143
+
144
+		if (!eol) {
145
+			if(rcv_data->buf != rcv_data->lnstart) { /* old memmove sux */
146
+				memmove(rcv_data->buf, rcv_data->lnstart, rcv_data->bytes_recvd);
147
+				rcv_data->lnstart = rcv_data->buf;
148
+			}
149
+
150
+			rcv_data->curr = &rcv_data->lnstart[rcv_data->bytes_recvd];
151
+			rcv_data->bytes_recvd = 0;
152
+		}
153
+	}
154
+}
155
+
0 156
new file mode 100644
... ...
@@ -0,0 +1,48 @@
0
+/*
1
+ *  Copyright (C) 2015 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
2
+ *  Copyright (C) 2009-2010 Sourcefire, Inc.
3
+ *
4
+ *  Author: aCaB
5
+ *
6
+ *  This program is free software; you can redistribute it and/or modify
7
+ *  it under the terms of the GNU General Public License version 2 as
8
+ *  published by the Free Software Foundation.
9
+ *
10
+ *  This program is distributed in the hope that it will be useful,
11
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
+ *  GNU General Public License for more details.
14
+ *
15
+ *  You should have received a copy of the GNU General Public License
16
+ *  along with this program; if not, write to the Free Software
17
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18
+ *  MA 02110-1301, USA.
19
+ */
20
+
21
+#ifndef ONAS_COM_H
22
+#define ONAS_COM_H
23
+
24
+#if HAVE_CONFIG_H
25
+#include "clamav-config.h"
26
+#endif
27
+
28
+#if HAVE_SYS_PARAM_H
29
+#include <sys/param.h>
30
+#endif
31
+
32
+#include "shared/misc.h"
33
+
34
+struct RCVLN {
35
+    char buf[PATH_MAX+1024]; /* FIXME must match that in clamd - bb1349 */
36
+    CURL *curl;
37
+    CURLcode curlcode;
38
+    int retlen;
39
+    char *curr;
40
+    char *lnstart;
41
+};
42
+
43
+int onas_sendln(CURL *curl, const char *line, unsigned int len);
44
+void onas_recvlninit(struct RCVLN *s, CURL *curl);
45
+int onas_recvln(struct RCVLN *rcv_data, char **ret_bol, char **ret_eol);
46
+
47
+#endif
... ...
@@ -32,6 +32,7 @@
32 32
 /* must be first because it may define _XOPEN_SOURCE */
33 33
 #include "shared/fdpassing.h"
34 34
 #include <stdio.h>
35
+#include <curl/curl.h>
35 36
 #ifdef HAVE_UNISTD_H
36 37
 #include <unistd.h>
37 38
 #endif
... ...
@@ -57,8 +58,8 @@
57 57
 #include "shared/actions.h"
58 58
 #include "shared/output.h"
59 59
 #include "shared/misc.h"
60
-#include "shared/clamdcom.h"
61 60
 
61
+#include "onaccess_com.h"
62 62
 #include "onaccess_proto.h"
63 63
 #include "onaccess_client.h"
64 64
 
... ...
@@ -72,7 +73,7 @@ static const char *scancmd[] = { "CONTSCAN", "MULTISCAN", "INSTREAM", "FILDES",
72 72
 
73 73
 /* Connects to clamd
74 74
  * Returns a FD or -1 on error */
75
-int onas_dconnect(struct onas_context **ctx) {
75
+/*int onas_dconnect(struct onas_context **ctx) {
76 76
 	int sockd, res;
77 77
 	const struct optstruct *opt;
78 78
 	struct addrinfo hints, *info, *p;
... ...
@@ -134,11 +135,11 @@ int onas_dconnect(struct onas_context **ctx) {
134 134
 	}
135 135
 
136 136
 	return -1;
137
-}
137
+}*/
138 138
 
139 139
 /* Issues an INSTREAM command to clamd and streams the given file
140 140
  * Returns >0 on success, 0 soft fail, -1 hard fail */
141
-static int onas_send_stream(struct onas_context **ctx, int sockd, const char *filename) {
141
+static int onas_send_stream(struct onas_context **ctx, CURL *curl, const char *filename) {
142 142
 	uint32_t buf[BUFSIZ/sizeof(uint32_t)];
143 143
 	int fd, len;
144 144
 	unsigned long int todo = (*ctx)->maxstream;
... ...
@@ -150,7 +151,7 @@ static int onas_send_stream(struct onas_context **ctx, int sockd, const char *fi
150 150
 		}
151 151
 	} else fd = 0;
152 152
 
153
-	if(sendln(sockd, "zINSTREAM", 10)) {
153
+	if(onas_sendln(curl, "zINSTREAM", 10)) {
154 154
 		close(fd);
155 155
 		return -1;
156 156
 	}
... ...
@@ -158,7 +159,7 @@ static int onas_send_stream(struct onas_context **ctx, int sockd, const char *fi
158 158
 	while((len = read(fd, &buf[1], sizeof(buf) - sizeof(uint32_t))) > 0) {
159 159
 		if((unsigned int)len > todo) len = todo;
160 160
 		buf[0] = htonl(len);
161
-		if(sendln(sockd, (const char *)buf, len+sizeof(uint32_t))) {
161
+		if (onas_sendln(curl, (const char *)buf, len+sizeof(uint32_t))) {
162 162
 			close(fd);
163 163
 			return -1;
164 164
 		}
... ...
@@ -174,14 +175,15 @@ static int onas_send_stream(struct onas_context **ctx, int sockd, const char *fi
174 174
 		return 0;
175 175
 	}
176 176
 	*buf=0;
177
-	sendln(sockd, (const char *)buf, 4);
177
+	onas_sendln(curl, (const char *)buf, 4);
178 178
 	return 1;
179 179
 }
180 180
 
181 181
 #ifdef HAVE_FD_PASSING
182 182
 /* Issues a FILDES command and pass a FD to clamd
183 183
  * Returns >0 on success, 0 soft fail, -1 hard fail */
184
-static int onas_send_fdpass(int sockd, const char *filename) {
184
+static int onas_send_fdpass(CURL *curl, const char *filename) {
185
+	CURLcode result;
185 186
 	struct iovec iov[1];
186 187
 	struct msghdr msg;
187 188
 	struct cmsghdr *cmsg;
... ...
@@ -195,7 +197,8 @@ static int onas_send_fdpass(int sockd, const char *filename) {
195 195
 			return 0;
196 196
 		}
197 197
 	} else fd = 0;
198
-	if(sendln(sockd, "zFILDES", 8)) {
198
+	if(result = onas_sendln(curl, "zFILDES", 8)) {
199
+		logg("*ClamProto: error sending w/ curl, %s\n", curl_easy_strerror(result));
199 200
 		close(fd);
200 201
 		return -1;
201 202
 	}
... ...
@@ -212,7 +215,7 @@ static int onas_send_fdpass(int sockd, const char *filename) {
212 212
 	cmsg->cmsg_level = SOL_SOCKET;
213 213
 	cmsg->cmsg_type = SCM_RIGHTS;
214 214
 	*(int *)CMSG_DATA(cmsg) = fd;
215
-	if(sendmsg(sockd, &msg, 0) == -1) {
215
+	if(onas_sendln(curl, &msg, 0) == -1) {
216 216
 		logg("!FD send failed: %s\n", strerror(errno));
217 217
 		close(fd);
218 218
 		return -1;
... ...
@@ -244,7 +247,7 @@ static int chkpath(struct onas_context **ctx, const char *path)
244 244
  * This is used only in non IDSESSION mode
245 245
  * Returns the number of infected files or -1 on error
246 246
  * NOTE: filename may be NULL for STREAM scantype. */
247
-int onas_dsresult(struct onas_context **ctx, int sockd, int scantype, const char *filename, int *printok, int *errors, cl_error_t *ret_code) {
247
+int onas_dsresult(struct onas_context **ctx, CURL *curl, int scantype, const char *filename, int *printok, int *errors, cl_error_t *ret_code) {
248 248
 	int infected = 0, len = 0, beenthere = 0;
249 249
 	char *bol, *eol;
250 250
 	struct RCVLN rcv;
... ...
@@ -252,7 +255,8 @@ int onas_dsresult(struct onas_context **ctx, int sockd, int scantype, const char
252 252
 
253 253
 	if(filename && chkpath(ctx, filename))
254 254
 		return 0;
255
-	recvlninit(&rcv, sockd);
255
+
256
+	onas_recvlninit(&rcv, curl);
256 257
 
257 258
 	if (ret_code) {
258 259
 		*ret_code = CL_SUCCESS;
... ...
@@ -278,7 +282,7 @@ int onas_dsresult(struct onas_context **ctx, int sockd, int scantype, const char
278 278
 				return -1;
279 279
 			}
280 280
 			sprintf(bol, "z%s %s", scancmd[scantype], filename);
281
-			if(sendln(sockd, bol, len)) {
281
+			if(onas_sendln(curl, bol, len)) {
282 282
 				if (ret_code) {
283 283
 					*ret_code = CL_EWRITE;
284 284
 				}
... ...
@@ -290,12 +294,12 @@ int onas_dsresult(struct onas_context **ctx, int sockd, int scantype, const char
290 290
 
291 291
 		case STREAM:
292 292
 			/* NULL filename safe in send_stream() */
293
-			len = onas_send_stream(ctx, sockd, filename);
293
+			len = onas_send_stream(ctx, curl, filename);
294 294
 			break;
295 295
 #ifdef HAVE_FD_PASSING
296 296
 		case FILDES:
297 297
 			/* NULL filename safe in send_fdpass() */
298
-			len = onas_send_fdpass(sockd, filename);
298
+			len = onas_send_fdpass(curl, filename);
299 299
 			break;
300 300
 #endif
301 301
 	}
... ...
@@ -307,7 +311,7 @@ int onas_dsresult(struct onas_context **ctx, int sockd, int scantype, const char
307 307
 		return len;
308 308
 	}
309 309
 
310
-	while((len = recvln(&rcv, &bol, &eol))) {
310
+	while((len = onas_recvln(&rcv, &bol, &eol))) {
311 311
 		if(len == -1) {
312 312
 			if (ret_code) {
313 313
 				*ret_code = CL_EREAD;
... ...
@@ -21,9 +21,12 @@
21 21
 
22 22
 #ifndef ONAS_PROTO_H
23 23
 #define ONAS_PROTO_H
24
+
25
+#include <curl/curl.h>
26
+
24 27
 #include "shared/misc.h"
25 28
 #include "../clamonacc.h"
26 29
 
27
-int onas_dconnect(struct onas_context **ctx) ;
28
-int onas_dsresult(struct onas_context **ctx, int sockd, int scantype, const char *filename, int *printok, int *errors, cl_error_t *ret_code);
30
+/*int onas_dconnect(struct onas_context **ctx);*/
31
+int onas_dsresult(struct onas_context **ctx, CURL *curl, int scantype, const char *filename, int *printok, int *errors, cl_error_t *ret_code);
29 32
 #endif
... ...
@@ -70,10 +70,10 @@ extern pthread_t ddd_pid;
70 70
 	logg("ClamFanotif: stopped\n");
71 71
 }*/
72 72
 
73
-static int onas_fan_scanfile(const char *fname, struct fanotify_event_metadata *fmd, STATBUF sb, int scan, struct onas_context **ctx)
73
+/* TODO: rework this to feed multithreading consumer queue
74
+ * static int onas_fan_scanfile(const char *fname, struct fanotify_event_metadata *fmd, STATBUF sb, int scan, struct onas_context **ctx)
74 75
 {
75 76
     struct fanotify_response res;
76
-    const char *virname = NULL;
77 77
         int infected = 0;
78 78
         int err = 0;
79 79
     int ret             = 0;
... ...
@@ -102,7 +102,7 @@ static int onas_fan_scanfile(const char *fname, struct fanotify_event_metadata *
102 102
     }
103 103
 
104 104
     return ret;
105
-}
105
+}*/
106 106
 
107 107
 cl_error_t onas_setup_fanotif(struct onas_context **ctx) {
108 108
 
... ...
@@ -255,11 +255,12 @@ int onas_fan_eloop(struct onas_context **ctx) {
255 255
                 }
256 256
             }
257 257
 
258
+                                /* TODO: rework to feed consumer queue
258 259
 				if (onas_fan_scanfile(fname, fmd, sb, scan, ctx) == -1) {
259 260
                 close(fmd->fd);
260 261
 					logg("!ClamFanotif: error when stating and/or scanning??\n");
261 262
 						return 2;
262
-            }
263
+				}*/
263 264
 
264 265
             if (close(fmd->fd) == -1) {
265 266
 					printf("!ClamFanotif: internal error (close(%d) failed)\n", fmd->fd);
... ...
@@ -69,7 +69,7 @@ static void onas_ddd_handle_in_moved_to(struct onas_context *ctx, const char *pa
69 69
 static void onas_ddd_handle_in_create(struct onas_context *ctx, const char *path, const char *child_path, const struct inotify_event *event, int wd, uint64_t in_mask);
70 70
 static void onas_ddd_handle_in_moved_from(struct onas_context *ctx, const char *path, const char *child_path, const struct inotify_event *event, int wd);
71 71
 static void onas_ddd_handle_in_delete(struct onas_context *ctx, const char *path, const char *child_path, const struct inotify_event *event, int wd);
72
-static void onas_ddd_handle_extra_scanning(struct onas_context *ctx, const char *pathname, int extra_options);
72
+/*static void onas_ddd_handle_extra_scanning(struct onas_context *ctx, const char *pathname, int extra_options);*/
73 73
 
74 74
 static void onas_ddd_exit(int sig);
75 75
 
... ...
@@ -684,8 +684,8 @@ static void onas_ddd_handle_in_moved_to(struct onas_context *ctx,
684 684
     return;
685 685
 }
686 686
 
687
-
688
-static void onas_ddd_handle_extra_scanning(struct onas_context *ctx, const char *pathname, int extra_options) {
687
+/* TODO: rework this to use consumer queue when making multithreading changes */
688
+/*static void onas_ddd_handle_extra_scanning(struct onas_context *ctx, const char *pathname, int extra_options) {
689 689
 
690 690
     int thread_started             = 1;
691 691
     struct scth_thrarg *scth_tharg = NULL;
... ...
@@ -694,10 +694,10 @@ static void onas_ddd_handle_extra_scanning(struct onas_context *ctx, const char
694 694
 
695 695
     do {
696 696
         if (pthread_attr_init(&scth_attr)) break;
697
-        pthread_attr_setdetachstate(&scth_attr, PTHREAD_CREATE_JOINABLE);
697
+		pthread_attr_setdetachstate(&scth_attr, PTHREAD_CREATE_JOINABLE);*/
698 698
 
699 699
         /* Allocate memory for arguments. Thread is responsible for freeing it. */
700
-        if (!(scth_tharg = (struct scth_thrarg *)calloc(sizeof(struct scth_thrarg), 1))) break;
700
+		/* (!(scth_tharg = (struct scth_thrarg *) calloc(sizeof(struct scth_thrarg), 1))) break;
701 701
         if (!(scth_tharg->options = (struct cl_scan_options *)calloc(sizeof(struct cl_scan_options), 1))) break;
702 702
 
703 703
 
... ...
@@ -708,9 +708,9 @@ static void onas_ddd_handle_extra_scanning(struct onas_context *ctx, const char
708 708
         thread_started = pthread_create(&scth_pid, &scth_attr, onas_scan_th, scth_tharg);
709 709
     } while (0);
710 710
 
711
-    if (0 != thread_started) {
711
+	if (0 != thread_started) {*/
712 712
         /* Failed to create thread. Free anything we may have allocated. */
713
-		logg("!ClamInotif: Unable to kick off extra scanning.\n");
713
+		/*logg("!ClamInotif: Unable to kick off extra scanning.\n");
714 714
         if (NULL != scth_tharg) {
715 715
             if (NULL != scth_tharg->pathname) {
716 716
                 free(scth_tharg->pathname);
... ...
@@ -726,7 +726,7 @@ static void onas_ddd_handle_extra_scanning(struct onas_context *ctx, const char
726 726
     }
727 727
 
728 728
     return;
729
-}
729
+}*/
730 730
 
731 731
 static void onas_ddd_exit(int sig) {
732 732
 	logg("*ClamInotif: onas_ddd_exit(), signal %d\n", sig);
... ...
@@ -47,8 +47,6 @@
47 47
 #include "../clamonacc.h"
48 48
 #include "../client/onaccess_client.h"
49 49
 
50
-static pthread_mutex_t onas_scan_lock = PTHREAD_MUTEX_INITIALIZER;
51
-
52 50
 int onas_fan_checkowner(int pid, const struct optstruct *opts)
53 51
 {
54 52
     char path[32];
... ...
@@ -99,7 +97,9 @@ int onas_fan_checkowner(int pid, const struct optstruct *opts)
99 99
 /**
100 100
  * Thread-safe scan wrapper to ensure there's no processs contention over use of the socket.
101 101
  */
102
-int onas_scan(struct onas_context **ctx, const char *fname, STATBUF sb, int *infected, int *err, cl_error_t *ret_code)
102
+
103
+/* TODO: remove this
104
+ * int onas_scan(struct onas_context **ctx, const char *fname, STATBUF sb, int *infected, int *err, cl_error_t *ret_code)
103 105
 {
104 106
     int ret = 0;
105 107
     int i = 0;
... ...
@@ -113,7 +113,6 @@ int onas_scan(struct onas_context **ctx, const char *fname, STATBUF sb, int *inf
113 113
 
114 114
                 logg("*ClamMisc: internal issue (daemon could not access directory/file %s)\n", fname);
115 115
                 break;
116
-                /* TODO: handle other errors */
117 116
             case CL_EPARSE:
118 117
             case CL_EREAD:
119 118
             case CL_EWRITE:
... ...
@@ -135,12 +134,13 @@ int onas_scan(struct onas_context **ctx, const char *fname, STATBUF sb, int *inf
135 135
 	    }
136 136
     }
137 137
     return ret;
138
-}
138
+}*/
139 139
 
140 140
 /**
141 141
  * Thread-safe scan wrapper to ensure there's no processs contention over use of the socket.
142 142
  */
143
-int onas_scan_safe(struct onas_context **ctx, const char *fname, STATBUF sb, int *infected, int *err, cl_error_t *ret_code)
143
+/* TODO: remove this
144
+ * int onas_scan_safe(struct onas_context **ctx, const char *fname, STATBUF sb, int *infected, int *err, cl_error_t *ret_code)
144 145
 {
145 146
     int ret = 0;
146 147
 
... ...
@@ -151,7 +151,7 @@ int onas_scan_safe(struct onas_context **ctx, const char *fname, STATBUF sb, int
151 151
     pthread_mutex_unlock(&onas_scan_lock);
152 152
 
153 153
     return ret;
154
-    }
154
+}*/
155 155
 
156 156
 char **onas_get_opt_list(const char *fname, int *num_entries, cl_error_t *err)
157 157
 {
... ...
@@ -32,8 +32,8 @@ typedef enum {
32 32
 } cli_check_t;
33 33
 
34 34
 int onas_fan_checkowner(int pid, const struct optstruct *opts);
35
-int onas_scan(struct onas_context **ctx, const char *fname, STATBUF sb, int *infected, int *err, cl_error_t *ret_code);
36
-int onas_scan_safe(struct onas_context **ctx, const char *fname, STATBUF sb, int *infected, int *err, cl_error_t *ret_code);
35
+//int onas_scan(struct onas_context **ctx, const char *fname, STATBUF sb, int *infected, int *err, cl_error_t *ret_code);
36
+//int onas_scan_safe(struct onas_context **ctx, const char *fname, STATBUF sb, int *infected, int *err, cl_error_t *ret_code);
37 37
 char **onas_get_opt_list(const char *fname, int *num_entries, cl_error_t *err);
38 38
 void free_opt_list(char** opt_list, int entries);
39 39
 
... ...
@@ -30,6 +30,7 @@
30 30
 #include <fcntl.h>
31 31
 #include <signal.h>
32 32
 #include <pthread.h>
33
+#include <sys/fanotify.h>
33 34
 
34 35
 #include "shared/optparser.h"
35 36
 #include "shared/output.h"
... ...
@@ -37,14 +38,19 @@
37 37
 #include "libclamav/others.h"
38 38
 #include "../misc/priv_fts.h"
39 39
 #include "../misc/onaccess_others.h"
40
+#include "../client/onaccess_client.h"
40 41
 #include "onaccess_scth.h"
41 42
 //#include "onaccess_others.h"
42 43
 
43 44
 #include "libclamav/clamav.h"
44 45
 
45
-static int onas_scth_scanfile(const char *fname, int fd, int extinfo, struct scth_thrarg *tharg);
46
-static int onas_scth_handle_dir(const char *pathname, struct scth_thrarg *tharg);
47
-static int onas_scth_handle_file(const char *pathname, struct scth_thrarg *tharg);
46
+static pthread_mutex_t onas_scan_lock = PTHREAD_MUTEX_INITIALIZER;
47
+
48
+static int onas_scan(struct onas_context **ctx, const char *fname, STATBUF sb, int *infected, int *err, cl_error_t *ret_code);
49
+static int onas_scan_safe(struct onas_context **ctx, const char *fname, STATBUF sb, int *infected, int *err, cl_error_t *ret_code);
50
+static int onas_scth_scanfile(struct onas_context **ctx, const char *fname, STATBUF sb, struct onas_scan_event *event_data, int *infected, int *err, cl_error_t *ret_code);
51
+static int onas_scth_handle_dir(struct onas_context **ctx, const char *pathname, struct onas_scan_event *event_data);
52
+static int onas_scth_handle_file(struct onas_context **ctx, const char *pathname, struct onas_scan_event *event_data);
48 53
 
49 54
 static void onas_scth_exit(int sig);
50 55
 
... ...
@@ -55,67 +61,168 @@ static void onas_scth_exit(int sig)
55 55
     pthread_exit(NULL);
56 56
 }
57 57
 
58
-static int onas_scth_scanfile(const char *fname, int fd, int extinfo, struct scth_thrarg *tharg)
58
+/**
59
+ * Scan wrapper, used by both inotify and fanotify threads. Owned by scanthread to force multithreaded client archtiecture
60
+ * which better avoids kernel level deadlocks from fanotify blocking/prevention
61
+ */
62
+static int onas_scan(struct onas_context **ctx, const char *fname, STATBUF sb, int *infected, int *err, cl_error_t *ret_code)
59 63
 {
60 64
     int ret             = 0;
61
-    const char *virname = NULL;
65
+    int i = 0;
66
+
67
+    ret = onas_scan_safe(ctx, fname, sb, infected, err, ret_code);
68
+
69
+    if (*err) {
70
+        switch (*ret_code) {
71
+            case CL_EACCES:
72
+            case CL_ESTAT:
73
+
74
+                logg("*ClamMisc: internal issue (daemon could not access directory/file %s)\n", fname);
75
+                break;
76
+                /* TODO: handle other errors */
77
+            case CL_EPARSE:
78
+            case CL_EREAD:
79
+            case CL_EWRITE:
80
+            case CL_EMEM:
81
+            case CL_ENULLARG:
82
+            default:
83
+                logg("~ClamMisc: internal issue (client failed to scan)\n");
84
+        }
85
+	    if ((*ctx)->retry_on_error) {
86
+		    logg("*ClamMisc: reattempting scan ... \n");
87
+		    while (err) {
88
+			    ret = onas_scan_safe(ctx, fname, sb, infected, err, ret_code);
89
+
90
+			    i++;
91
+			    if (*err && i == (*ctx)->retry_attempts) {
92
+				    *err = 0;
93
+			    }
94
+		    }
95
+	    }
96
+    }
62 97
 
63
-    //return onas_scan(fname, fd, &virname, tharg->engine, tharg->options, extinfo);
64 98
     return ret;
65 99
 }
66 100
 
67
-static int onas_scth_handle_dir(const char *pathname, struct scth_thrarg *tharg)
101
+/**
102
+ * Thread-safe scan wrapper to ensure there's no processs contention over use of the socket.
103
+ */
104
+static int onas_scan_safe(struct onas_context **ctx, const char *fname, STATBUF sb, int *infected, int *err, cl_error_t *ret_code)
68 105
 {
106
+	int ret = 0;
107
+
108
+	pthread_mutex_lock(&onas_scan_lock);
109
+
110
+	ret = onas_client_scan(ctx, fname, sb, infected, err, ret_code);
111
+
112
+	pthread_mutex_unlock(&onas_scan_lock);
113
+
114
+	return ret;
115
+}
116
+
117
+static int onas_scth_scanfile(struct onas_context **ctx, const char *fname, STATBUF sb, struct onas_scan_event *event_data, int *infected, int *err, cl_error_t *ret_code)
118
+{
119
+	struct fanotify_response res;
120
+	int ret = 0;
121
+	int i = 0;
122
+
123
+	if (event_data->b_fanotify) {
124
+		res.fd = event_data->fmd->fd;
125
+		res.response = FAN_ALLOW;
126
+	}
127
+
128
+	if (event_data->b_scan) {
129
+		ret = onas_scan(ctx, fname, sb, infected, err, ret_code);
130
+
131
+		if (err && ret_code != CL_SUCCESS) {
132
+			logg("*Clamonacc: scan failed with error code %d\n", *ret_code);
133
+		}
134
+
135
+
136
+		if (event_data->b_fanotify) {
137
+			if ((err && ret_code && (*ctx)->deny_on_error) || infected) {
138
+				res.response = FAN_DENY;
139
+			}
140
+		}
141
+	}
142
+
143
+
144
+	if (event_data->b_fanotify) {
145
+		if(event_data->fmd->mask & FAN_ALL_PERM_EVENTS) {
146
+			ret = write((*ctx)->fan_fd, &res, sizeof(res));
147
+			if(ret == -1)
148
+				logg("!Clamonacc: internal error (can't write to fanotify)\n");
149
+		}
150
+	}
151
+
152
+	return ret;
153
+}
154
+
155
+static int onas_scth_handle_dir(struct onas_context **ctx, const char *pathname, struct onas_scan_event *event_data) {
69 156
     FTS *ftsp = NULL;
70
-    int fd;
71
-    int ftspopts = FTS_PHYSICAL | FTS_XDEV;
72
-    int extinfo;
73
-    int ret;
157
+	int32_t ftspopts = FTS_PHYSICAL | FTS_XDEV;
158
+	int32_t infected = 0;
159
+	int32_t err = 0;
160
+        cl_error_t ret_code = CL_SUCCESS;
161
+	int32_t ret = 0;
162
+	int32_t fres = 0;
74 163
     FTSENT *curr = NULL;
75
-
76
-    extinfo = optget(tharg->opts, "ExtendedDetectionInfo")->enabled;
164
+        STATBUF sb;
77 165
 
78 166
     char *const pathargv[] = {(char *)pathname, NULL};
79 167
     if (!(ftsp = _priv_fts_open(pathargv, ftspopts, NULL))) return CL_EOPEN;
80 168
 
81 169
     while ((curr = _priv_fts_read(ftsp))) {
82 170
         if (curr->fts_info != FTS_D) {
83
-            if ((fd = safe_open(curr->fts_path, O_RDONLY | O_BINARY)) == -1)
84
-                return CL_EOPEN;
85 171
 
86
-            if (onas_scth_scanfile(curr->fts_path, fd, extinfo, tharg) == CL_VIRUS)
87
-                ;
88
-            ret = CL_VIRUS;
172
+			fres = CLAMSTAT(curr->fts_path, &sb);
173
+
174
+			if ((*ctx)->sizelimit) {
175
+				if (fres != 0 || sb.st_size > (*ctx)->sizelimit)  {
176
+					//okay to skip, directory from inotify events (probably) won't block w/ protection enabled
177
+                                        //log here later
178
+					continue;
179
+				}
180
+			}
89 181
 
90
-            close(fd);
182
+                        ret = onas_scth_scanfile(ctx, curr->fts_path, sb, event_data, &infected, &err, &ret_code);
183
+                        // probs need to error check here later, or at least log
91 184
         }
92 185
     }
93 186
 
94 187
     return ret;
95 188
 }
96 189
 
97
-static int onas_scth_handle_file(const char *pathname, struct scth_thrarg *tharg)
98
-{
99
-    int fd;
100
-    int extinfo;
101
-    int ret;
190
+static int onas_scth_handle_file(struct onas_context **ctx, const char *pathname, struct onas_scan_event *event_data) {
102 191
 
103
-    if (!pathname) return CL_ENULLARG;
192
+	STATBUF sb;
193
+	int32_t infected = 0;
194
+	int32_t err = 0;
195
+	cl_error_t ret_code = CL_SUCCESS;
196
+	int fres = 0;
197
+	int ret = 0;
104 198
 
105
-    extinfo = optget(tharg->opts, "ExtendedDetectionInfo")->enabled;
199
+	if (!pathname) return CL_ENULLARG;
106 200
 
107
-    if ((fd = safe_open(pathname, O_RDONLY | O_BINARY)) == -1)
108
-        return CL_EOPEN;
109
-    ret = onas_scth_scanfile(pathname, fd, extinfo, tharg);
201
+	fres = CLAMSTAT(pathname, &sb);
202
+	if ((*ctx)->sizelimit) {
203
+		if (fres != 0 || sb.st_size > (*ctx)->sizelimit)  {
204
+			/* don't skip so we avoid lockups, but don't scan either */
205
+			event_data->b_scan = 0;
206
+		}
207
+	}
110 208
 
111
-    close(fd);
209
+	ret = onas_scth_scanfile(ctx, pathname, sb, event_data, &infected, &err, &ret_code);
210
+	// probs need to error check here later, or at least log
112 211
 
113 212
     return ret;
114 213
 }
115 214
 
116
-void *onas_scan_th(void *arg)
117
-{
215
+void *onas_scan_th(void *arg) {
216
+
118 217
     struct scth_thrarg *tharg = (struct scth_thrarg *)arg;
218
+	struct onas_scan_event *event_data = NULL;
219
+	struct onas_context **ctx = NULL;
119 220
     sigset_t sigset;
120 221
     struct sigaction act;
121 222
 
... ...
@@ -126,7 +233,7 @@ void *onas_scan_th(void *arg)
126 126
 	 * SIGFPE, SIGILL, SIGSEGV, or SIGBUS signal */
127 127
     sigdelset(&sigset, SIGFPE);
128 128
     sigdelset(&sigset, SIGILL);
129
-    sigdelset(&sigset, SIGSEGV);
129
+	//sigdelset(&sigset, SIGSEGV);
130 130
 #ifdef SIGBUS
131 131
     sigdelset(&sigset, SIGBUS);
132 132
 #endif
... ...
@@ -137,29 +244,45 @@ void *onas_scan_th(void *arg)
137 137
     sigaction(SIGUSR1, &act, NULL);
138 138
     sigaction(SIGSEGV, &act, NULL);
139 139
 
140
-    if (NULL == tharg || NULL == tharg->pathname || NULL == tharg->opts || NULL == tharg->engine) {
140
+	if (NULL == tharg || NULL == tharg->ctx || NULL == tharg->event_data || NULL == tharg->event_data->pathname || NULL == (*(tharg->ctx))->opts) {
141 141
         logg("ScanOnAccess: Invalid thread arguments for extra scanning\n");
142 142
         goto done;
143 143
     }
144 144
 
145
-    if (tharg->extra_options & ONAS_SCTH_ISDIR) {
146
-        logg("*ScanOnAccess: Performing additional scanning on directory '%s'\n", tharg->pathname);
147
-        onas_scth_handle_dir(tharg->pathname, tharg);
148
-    } else if (tharg->extra_options & ONAS_SCTH_ISFILE) {
149
-        logg("*ScanOnAccess: Performing additional scanning on file '%s'\n", tharg->pathname);
150
-        onas_scth_handle_file(tharg->pathname, tharg);
145
+        /* this event_data is ours and ours alone */
146
+	event_data = tharg->event_data;
147
+
148
+        /* we share this context globally--it's not ours to touch/edit */
149
+	ctx = tharg->ctx;
150
+
151
+        if (event_data->b_inotify) {
152
+            if (event_data->extra_options & ONAS_SCTH_ISDIR) {
153
+                logg("*ScanOnAccess: Performing additional scanning on directory '%s'\n", event_data->pathname);
154
+                onas_scth_handle_dir(ctx, event_data->pathname, event_data);
155
+            } else if (event_data->extra_options & ONAS_SCTH_ISFILE) {
156
+                logg("*ScanOnAccess: Performing additional scanning on file '%s'\n", event_data->pathname);
157
+                onas_scth_handle_file(ctx, event_data->pathname, event_data);
158
+            }
159
+        } else if (event_data->b_fanotify) {
160
+            logg("*ScanOnAccess: Performing scanning on file '%s'\n", event_data->pathname);
161
+            onas_scth_handle_file(ctx, event_data->pathname, event_data);
151 162
     }
163
+        /* TODO: else something went wrong and we should error out here */
152 164
 
153 165
 done:
154
-    if (NULL != tharg->pathname) {
155
-        free(tharg->pathname);
156
-        tharg->pathname = NULL;
166
+        /* our job to cleanup event data: worker queue just kicks us off, drops the event object
167
+         * from the queue and forgets about us. */
168
+
169
+	if (NULL != tharg) {
170
+		if (NULL != tharg->event_data) {
171
+			if (NULL != tharg->event_data->pathname) {
172
+				free(tharg->event_data->pathname);
173
+				event_data->pathname = NULL;
157 174
     }
158
-    if (NULL != tharg->options) {
159
-        free(tharg->options);
160
-        tharg->options = NULL;
175
+			free(tharg->event_data);
176
+			tharg->event_data = NULL;
161 177
     }
162
-    if (NULL != tharg) {
178
+		/* don't free context, cleanup for context is handled at the highest layer */
163 179
         free(tharg);
164 180
     }
165 181
 
... ...
@@ -21,18 +21,26 @@
21 21
 #ifndef __ONAS_SCTH_H
22 22
 #define __ONAS_SCTH_H
23 23
 
24
+
25
+#include <sys/fanotify.h>
24 26
 #include "shared/optparser.h"
25 27
 #include "libclamav/clamav.h"
26 28
 
27 29
 #define ONAS_SCTH_ISDIR 0x01
28 30
 #define ONAS_SCTH_ISFILE 0x02
29 31
 
30
-struct scth_thrarg {
31
-    uint32_t extra_options;
32
-    struct cl_scan_options *options;
33
-    const struct optstruct *opts;
34
-    const struct cl_engine *engine;
32
+struct onas_scan_event {
35 33
     char *pathname;
34
+        struct fanotify_event_metadata *fmd;
35
+	int16_t b_inotify;
36
+	int16_t b_fanotify;
37
+        int16_t b_scan;
38
+	uint32_t extra_options;
39
+};
40
+
41
+struct scth_thrarg {
42
+	struct onas_scan_event *event_data;
43
+	struct onas_context **ctx;
36 44
 };
37 45
 
38 46
 void *onas_scan_th(void *arg);
... ...
@@ -51,7 +51,7 @@
51 51
 #include "crtmgr.h"
52 52
 
53 53
 #ifdef HAVE_JSON
54
-#include "json.h"
54
+#include "json-c/json.h"
55 55
 #endif
56 56
 
57 57
 #ifdef HAVE_YARA
... ...
@@ -37,5 +37,9 @@ AC_SUBST([SSL_LDFLAGS])
37 37
 AC_SUBST([JSON_LIBS])
38 38
 AC_SUBST([JSON_LDFLAGS])
39 39
 AC_SUBST([CURL_LIBS])
40
+<<<<<<< HEAD
40 41
 AC_SUBST([CURL_LDFLAGS])
41 42
 
43
+=======
44
+AC_SUBST([CURL_LIBS])
45
+>>>>>>> clamonacc - add curl support