Browse code

added support for file descriptor passing

git-svn-id: file:///var/lib/svn/clamav-devel/trunk/clamav-devel@1163 77e5149b-7576-45b1-b177-96237e5ba77b

Tomasz Kojm authored on 2004/12/07 10:53:16
Showing 12 changed files
... ...
@@ -118,6 +118,7 @@ Thomas Lamy <Thomas.Lamy*in-online.net>
118 118
 Marty Lee <marty*maui.co.uk>
119 119
 Peter N Lewis <peter*stairways.com.au>
120 120
 Roger Lucas <roger*planbit.co.uk>
121
+Richard Lyons <frob-clamav*webcentral.com.au>
121 122
 David S. Madole <david*madole.net>
122 123
 Joe Maimon <jmaimon*ttec.com>
123 124
 Andrey V. Malyshev <amal*krasn.ru>
... ...
@@ -1,3 +1,8 @@
1
+Tue Dec  7 02:48:08 CET 2004 (tk)
2
+---------------------------------
3
+  * clamd: added support for file descriptor passing (patch by Richard Lyons
4
+	   <frob-clamav*webcentral.com.au>)
5
+
1 6
 Mon Dec  6 22:33:26 GMT 2004 (njh)
2 7
 ----------------------------------
3 8
   * clamav-milter:	Ensure the date is kept in the quarantine path
... ...
@@ -75,12 +75,18 @@
75 75
 /* file i/o buffer size */
76 76
 #undef FILEBUFF
77 77
 
78
+/* access rights in msghdr */
79
+#undef HAVE_ACCRIGHTS_IN_MSGHDR
80
+
78 81
 /* "attrib packed" */
79 82
 #undef HAVE_ATTRIB_PACKED
80 83
 
81 84
 /* have bzip2 */
82 85
 #undef HAVE_BZLIB_H
83 86
 
87
+/* ancillary data style fd pass */
88
+#undef HAVE_CONTROL_IN_MSGHDR
89
+
84 90
 /* Define to 1 if you have the <dlfcn.h> header file. */
85 91
 #undef HAVE_DLFCN_H
86 92
 
... ...
@@ -153,12 +159,18 @@
153 153
 /* readdir_r takes 3 arguments */
154 154
 #undef HAVE_READDIR_R_3
155 155
 
156
+/* Define to 1 if you have the `recvmsg' function. */
157
+#undef HAVE_RECVMSG
158
+
156 159
 /* Define to 1 if you have the <regex.h> header file. */
157 160
 #undef HAVE_REGEX_H
158 161
 
159 162
 /* have resolv.h */
160 163
 #undef HAVE_RESOLV_H
161 164
 
165
+/* Define to 1 if you have the `sendmsg' function. */
166
+#undef HAVE_SENDMSG
167
+
162 168
 /* Define to 1 if you have the `setgroups' function. */
163 169
 #undef HAVE_SETGROUPS
164 170
 
... ...
@@ -216,6 +228,9 @@
216 216
 /* Define to 1 if you have the <tcpd.h> header file. */
217 217
 #undef HAVE_TCPD_H
218 218
 
219
+/* Define to 1 if you have the <uio.h> header file. */
220
+#undef HAVE_UIO_H
221
+
219 222
 /* Define to 1 if you have the <unistd.h> header file. */
220 223
 #undef HAVE_UNISTD_H
221 224
 
... ...
@@ -225,6 +240,9 @@
225 225
 /* zlib installed */
226 226
 #undef HAVE_ZLIB_H
227 227
 
228
+/* Early Linux doesn't set cmsg fields */
229
+#undef INCOMPLETE_CMSG
230
+
228 231
 /* bzip funtions do not have bz2 prefix */
229 232
 #undef NOBZ2PREFIX
230 233
 
... ...
@@ -32,12 +32,16 @@
32 32
 #include <sys/time.h>
33 33
 #include <sys/socket.h>
34 34
 #include <sys/ioctl.h>
35
+
35 36
 #if HAVE_SYS_TYPES_H
36 37
 #include <sys/types.h>
37 38
 #endif
38 39
 #if HAVE_SYS_FILIO_H
39 40
 #include <sys/filio.h>
40 41
 #endif
42
+#ifdef HAVE_SYS_UIO_H
43
+#include <sys/uio.h>
44
+#endif
41 45
 
42 46
 /* submitted by breiter@wolfereiter.com: do not use poll(2) on Interix */
43 47
 #ifdef C_INTERIX
... ...
@@ -58,6 +62,7 @@
58 58
 
59 59
 #include "memory.h"
60 60
 #include "cfgparser.h"
61
+#include "session.h"
61 62
 
62 63
 void virusaction(const char *virname, const struct cfgstruct *copt)
63 64
 {
... ...
@@ -220,3 +225,65 @@ int writen(int fd, void *buff, unsigned int count)
220 220
  
221 221
     return count;
222 222
 }
223
+
224
+/* Submitted by Richard Lyons <frob-clamav*webcentral.com.au> */
225
+
226
+#if defined(HAVE_RECVMSG) && (defined(HAVE_ACCRIGHTS_IN_MSGHDR) || defined(HAVE_CONTROL_IN_MSGHDR)) && !defined(C_CYGWIN)
227
+
228
+int readsock(int sockfd, char *buf, size_t size)
229
+{
230
+	int fd;
231
+	ssize_t n;
232
+	struct msghdr msg;
233
+	struct iovec iov[1];
234
+#ifdef HAVE_CONTROL_IN_MSGHDR
235
+	struct cmsghdr *cmsg;
236
+	char tmp[CMSG_SPACE(sizeof(fd))];
237
+#endif
238
+
239
+    iov[0].iov_base = buf;
240
+    iov[0].iov_len = size;
241
+    memset(&msg, 0, sizeof(msg));
242
+    msg.msg_iov = iov;
243
+    msg.msg_iovlen = 1;
244
+#ifdef HAVE_ACCRIGHTS_IN_MSGHDR
245
+    msg.msg_accrights = (caddr_t)&fd;
246
+    msg.msg_accrightslen = sizeof(fd);
247
+#endif
248
+#ifdef HAVE_CONTROL_IN_MSGHDR
249
+    msg.msg_control = tmp;
250
+    msg.msg_controllen = sizeof(tmp);
251
+#endif
252
+    fd = -1;
253
+    if ((n = recvmsg(sockfd, &msg, 0)) <= 0)
254
+	return n;
255
+    errno = EBADF;
256
+    if (n != 1 || buf[0] != 0)
257
+	return !strncmp(buf, CMD12, strlen(CMD12)) ? -1 : n;
258
+#ifdef HAVE_ACCRIGHTS_IN_MSGHDR
259
+    if (msg.msg_accrightslen != sizeof(fd))
260
+	return -1;
261
+#endif
262
+#ifdef HAVE_CONTROL_IN_MSGHDR
263
+    cmsg = CMSG_FIRSTHDR(&msg);
264
+    if (cmsg == NULL)
265
+	return -1;
266
+#ifndef INCOMPLETE_CMSG
267
+    if (cmsg->cmsg_type != SCM_RIGHTS)
268
+	return -1;
269
+    if (cmsg->cmsg_len != CMSG_LEN(sizeof(fd)))
270
+	return -1;
271
+#endif
272
+    fd = *(int *)CMSG_DATA(cmsg);
273
+#endif
274
+    if (fd < 0)
275
+	return -1;
276
+    n = snprintf(buf, size, "FD %d", fd);
277
+    if (n >= size)
278
+	return -1;
279
+    return n;
280
+}
281
+
282
+#else
283
+#define	readsock	read
284
+#endif
... ...
@@ -31,5 +31,6 @@ int poll_fd(int fd, int timeout_sec);
31 31
 int is_fd_connected(int fd);
32 32
 void virusaction(const char *virname, const struct cfgstruct *copt);
33 33
 int writen(int fd, void *buff, unsigned int count);
34
+int readsock(int sockfd, char *buf, size_t size);
34 35
 
35 36
 #endif
... ...
@@ -261,6 +261,37 @@ int scan(const char *filename, unsigned long int *scanned, const struct cl_node
261 261
     return ret;
262 262
 }
263 263
 
264
+int scanfd(const int fd, unsigned long int *scanned, const struct cl_node *root, const struct cl_limits *limits, int options, const struct cfgstruct *copt, int odesc, short contscan)
265
+{
266
+	int ret;
267
+	const char *virname;
268
+	struct stat statbuf;
269
+
270
+
271
+    if(fstat(fd, &statbuf) == -1)
272
+	return -1;
273
+
274
+    if(!S_ISREG(statbuf.st_mode))
275
+	return -1;
276
+
277
+    ret = cl_scandesc(fd, &virname, scanned, root, limits, options);
278
+
279
+    if(ret == CL_VIRUS) {
280
+	mdprintf(odesc, "fd[%d]: %s FOUND\n", fd, virname);
281
+	logg("fd[%d]: %s FOUND\n", fd, virname);
282
+	virusaction(virname, copt);
283
+    } else if(ret != CL_CLEAN) {
284
+	mdprintf(odesc, "fd[%d]: %s ERROR\n", fd, cl_strerror(ret));
285
+	logg("fd[%d]: %s ERROR\n", fd, cl_strerror(ret));
286
+    } else {
287
+	mdprintf(odesc, "fd[%d]: OK\n", fd);
288
+        if(logok)
289
+	    logg("fd[%d]: OK\n", fd); 
290
+    }
291
+
292
+    return ret;
293
+}
294
+
264 295
 int scanstream(int odesc, unsigned long int *scanned, const struct cl_node *root, const struct cl_limits *limits, int options, const struct cfgstruct *copt)
265 296
 {
266 297
 	int ret, portscan = CL_DEFAULT_MAXPORTSCAN, sockfd, port, acceptd;
... ...
@@ -442,7 +473,7 @@ int scanstream(int odesc, unsigned long int *scanned, const struct cl_node *root
442 442
 	logg("stream: %s ERROR\n", cl_strerror(ret));
443 443
     } else {
444 444
 	mdprintf(odesc, "stream: OK\n");
445
-        if (logok)
445
+        if(logok)
446 446
 	    logg("stream: OK\n"); 
447 447
     }
448 448
 
... ...
@@ -27,6 +27,8 @@ int dirscan(const char *dirname, const char **virname, unsigned long int *scanne
27 27
 
28 28
 int scan(const char *filename, unsigned long int *scanned, const struct cl_node *root, const struct cl_limits *limits, int options, const struct cfgstruct *copt, int odesc, short contscan);
29 29
 
30
+int scanfd(const int fd, unsigned long int *scanned, const struct cl_node *root, const struct cl_limits *limits, int options, const struct cfgstruct *copt, int odesc, short contscan);
31
+
30 32
 int scanstream(int odesc, unsigned long int *scanned, const struct cl_node *root, const struct cl_limits *limits, int options, const struct cfgstruct *copt);
31 33
 
32 34
 #endif
... ...
@@ -44,18 +44,6 @@
44 44
 #include "output.h"
45 45
 #include "memory.h"
46 46
 
47
-#define CMD1 "SCAN"
48
-#define CMD2 "RAWSCAN"
49
-#define CMD3 "QUIT" /* deprecated */
50
-#define CMD4 "RELOAD"
51
-#define CMD5 "PING"
52
-#define CMD6 "CONTSCAN"
53
-#define CMD7 "VERSION"
54
-#define CMD8 "STREAM"
55
-#define CMD9 "SESSION"
56
-#define CMD10 "END"
57
-#define CMD11 "SHUTDOWN"
58
-
59 47
 pthread_mutex_t ctime_mutex = PTHREAD_MUTEX_INITIALIZER;
60 48
 
61 49
 int command(int desc, const struct cl_node *root, const struct cl_limits *limits, int options, const struct cfgstruct *copt, int timeout)
... ...
@@ -77,7 +65,7 @@ int command(int desc, const struct cl_node *root, const struct cl_limits *limits
77 77
 	return -1;
78 78
     }
79 79
 
80
-    while((bread = read(desc, buff, 1024)) == -1 && errno == EINTR);
80
+    while((bread = readsock(desc, buff, 1024)) == -1 && errno == EINTR);
81 81
 
82 82
     if(!bread)
83 83
 	return 0;
... ...
@@ -188,6 +176,12 @@ int command(int desc, const struct cl_node *root, const struct cl_limits *limits
188 188
     } else if(!strncmp(buff, CMD11, strlen(CMD11))) { /* SHUTDOWN */
189 189
 	return COMMAND_SHUTDOWN;
190 190
 
191
+    } else if(!strncmp(buff, CMD12, strlen(CMD12))) { /* FD */
192
+	    int fd = atoi(buff + strlen(CMD12) + 1);
193
+
194
+	scanfd(fd, NULL, root, limits, options, copt, desc, 0);
195
+	close(fd); /* FIXME: should we close it here? */
196
+
191 197
     } else {
192 198
 	mdprintf(desc, "UNKNOWN COMMAND\n");
193 199
     }
... ...
@@ -23,6 +23,19 @@
23 23
 #define COMMAND_RELOAD 2
24 24
 #define COMMAND_END 3
25 25
 
26
+#define CMD1 "SCAN"
27
+#define CMD2 "RAWSCAN"
28
+#define CMD3 "QUIT" /* deprecated */
29
+#define CMD4 "RELOAD"
30
+#define CMD5 "PING"
31
+#define CMD6 "CONTSCAN"
32
+#define CMD7 "VERSION"
33
+#define CMD8 "STREAM"
34
+#define CMD9 "SESSION"
35
+#define CMD10 "END"
36
+#define CMD11 "SHUTDOWN"
37
+#define CMD12 "FD"
38
+
26 39
 #include <clamav.h>
27 40
 #include "cfgparser.h"
28 41
 
... ...
@@ -33,6 +33,10 @@
33 33
 #include <utime.h>
34 34
 #include <errno.h>
35 35
 
36
+#ifdef HAVE_SYS_UIO_H
37
+#include <sys/uio.h>
38
+#endif
39
+
36 40
 #include "others.h"
37 41
 #include "defaults.h"
38 42
 #include "shared.h"
... ...
@@ -50,27 +54,18 @@
50 50
 # define SOCKET_INET	AF_INET
51 51
 #endif
52 52
 
53
+/* #define ENABLE_FD_PASSING	    FIXME: Doesn't work yet */
54
+
53 55
 void move_infected(const char *filename, const struct optstruct *opt);
54 56
 int notremoved = 0, notmoved = 0;
55 57
 
56
-int dsfile(int sockd, const char *filename, const struct optstruct *opt)
58
+int dsresult(int sockd, const struct optstruct *opt)
57 59
 {
58 60
 	int infected = 0, waserror = 0;
59
-	char buff[4096], *scancmd, *pt;
61
+	char buff[4096], *pt;
60 62
 	FILE *fd;
61 63
 
62 64
 
63
-    scancmd = mcalloc(strlen(filename) + 20, sizeof(char));
64
-    sprintf(scancmd, "CONTSCAN %s", filename);
65
-
66
-    if(write(sockd, scancmd, strlen(scancmd)) <= 0) {
67
-	mprintf("@Can't write to the socket.\n");
68
-	free(scancmd);
69
-	return -1;
70
-    }
71
-
72
-    free(scancmd);
73
-
74 65
     if((fd = fdopen(dup(sockd), "r")) == NULL) {
75 66
 	mprintf("@Can't open descriptor for reading.\n");
76 67
 	return -1;
... ...
@@ -99,6 +94,7 @@ int dsfile(int sockd, const char *filename, const struct optstruct *opt)
99 99
 		}
100 100
 	    }
101 101
 	}
102
+
102 103
 	if(strstr(buff, "ERROR\n")) {
103 104
 	    logg("%s", buff);
104 105
 	    mprintf("%s", buff);
... ...
@@ -108,12 +104,78 @@ int dsfile(int sockd, const char *filename, const struct optstruct *opt)
108 108
 
109 109
     fclose(fd);
110 110
 
111
-    if(!infected && !waserror)
111
+    return infected ? infected : (waserror ? -1 : 0);
112
+}
113
+
114
+int dsfile(int sockd, const char *filename, const struct optstruct *opt)
115
+{
116
+	int ret;
117
+	char buff[4096], *scancmd, *pt;
118
+	FILE *fd;
119
+
120
+
121
+    scancmd = mcalloc(strlen(filename) + 20, sizeof(char));
122
+    sprintf(scancmd, "CONTSCAN %s", filename);
123
+
124
+    if(write(sockd, scancmd, strlen(scancmd)) <= 0) {
125
+	mprintf("@Can't write to the socket.\n");
126
+	free(scancmd);
127
+	return -1;
128
+    }
129
+
130
+    free(scancmd);
131
+
132
+    ret = dsresult(sockd, opt);
133
+
134
+    if(!ret)
112 135
 	mprintf("%s: OK\n", filename);
113 136
 
114
-    return infected ? infected : (waserror ? -1 : 0);
137
+    return ret;
115 138
 }
116 139
 
140
+#if defined(ENABLE_FD_PASSING) && defined(HAVE_SENDMSG) && (defined(HAVE_ACCRIGHTS_IN_MSGHDR) || defined(HAVE_CONTROL_IN_MSGHDR)) && !defined(C_CYGWIN)
141
+
142
+/* Submitted by Richard Lyons <frob-clamav*webcentral.com.au> */
143
+int dsfd(int sockfd, int fd, const struct optstruct *opt)
144
+{
145
+	struct iovec iov[1];
146
+	struct msghdr msg;
147
+#ifdef HAVE_CONTROL_IN_MSGHDR
148
+	struct cmsghdr *cmsg;
149
+	char tmp[CMSG_SPACE(sizeof(fd))];
150
+#endif
151
+
152
+    iov[0].iov_base = "";
153
+    iov[0].iov_len = 1;
154
+    memset(&msg, 0, sizeof(msg));
155
+    msg.msg_iov = iov;
156
+    msg.msg_iovlen = 1;
157
+#ifdef HAVE_CONTROL_IN_MSGHDR
158
+    msg.msg_control = tmp;
159
+    msg.msg_controllen = sizeof(tmp);
160
+    cmsg = CMSG_FIRSTHDR(&msg);
161
+    cmsg->cmsg_level = SOL_SOCKET;
162
+    cmsg->cmsg_type = SCM_RIGHTS;
163
+    cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
164
+    *(int *)CMSG_DATA(cmsg) = fd;
165
+#endif
166
+#ifdef HAVE_ACCRIGHTS_IN_MSGHDR
167
+    msg.msg_accrights = (caddr_t)&fd;
168
+    msg.msg_accrightslen = sizeof(fd);
169
+#endif
170
+    if (sendmsg(sockfd, &msg, 0) != iov[0].iov_len) {
171
+	mprintf("@Can't write to the socket.\n");
172
+	return -1;
173
+    }
174
+    return dsresult(sockfd, opt);
175
+}
176
+#else
177
+int dsfd(int sockfd, int fd, const struct optstruct *opt)
178
+{
179
+    return -1;
180
+}
181
+#endif
182
+
117 183
 int dsstream(int sockd, const struct optstruct *opt)
118 184
 {
119 185
 	int wsockd, loopw = 60, bread, port, infected = 0;
... ...
@@ -122,6 +184,7 @@ int dsstream(int sockd, const struct optstruct *opt)
122 122
 	int peer_size;
123 123
 	char buff[4096], *pt;
124 124
 
125
+
125 126
     if(write(sockd, "STREAM", 6) <= 0) {
126 127
 	mprintf("@Can't write to the socket.\n");
127 128
 	return 2;
... ...
@@ -195,25 +258,8 @@ int dsstream(int sockd, const struct optstruct *opt)
195 195
 	if(strstr(buff, "FOUND\n")) {
196 196
 	    infected++;
197 197
 	    logg("%s", buff);
198
-	    if(optl(opt, "move")) {
199
-		pt = strrchr(buff, ':');
200
-		*pt = 0;
201
-		move_infected(buff, opt);
202 198
 
203
-	    } else if(optl(opt, "remove")) {
204
-		pt = strrchr(buff, ':');
205
-		*pt = 0;
206
-		if(unlink(buff)) {
207
-		    mprintf("%s: Can't remove.\n", buff);
208
-		    logg("%s: Can't remove.\n", buff);
209
-		    notremoved++;
210
-		} else {
211
-		    mprintf("%s: Removed.\n", buff);
212
-		    logg("%s: Removed.\n", buff);
213
-		}
214
-	    }
215
-	}
216
-	if(strstr(buff, "ERROR\n")) {
199
+	} else if(strstr(buff, "ERROR\n")) {
217 200
 	    logg("%s", buff);
218 201
 	    return -1;
219 202
 	}
... ...
@@ -354,6 +400,18 @@ int client(const struct optstruct *opt, int *infected)
354 354
 
355 355
 	close(sockd);
356 356
 
357
+#if defined(ENABLE_FD_PASSING) && defined(HAVE_SENDMSG) && (defined(HAVE_ACCRIGHTS_IN_MSGHDR) || defined(HAVE_CONTROL_IN_MSGHDR)) && !defined(C_CYGWIN)
358
+    } else if(!strcmp(opt->filename, "-")) { /* scan data from stdin */
359
+	if((sockd = dconnect(opt)) < 0)
360
+	    return 2;
361
+
362
+	if((ret = dsfd(sockd, 0, opt)) >= 0)
363
+	    *infected += ret;
364
+	else
365
+	    errors++;
366
+
367
+	close(sockd);
368
+#else
357 369
     } else if(!strcmp(opt->filename, "-")) { /* scan data from stdin */
358 370
 	if((sockd = dconnect(opt)) < 0)
359 371
 	    return 2;
... ...
@@ -364,6 +422,7 @@ int client(const struct optstruct *opt, int *infected)
364 364
 	    errors++;
365 365
 
366 366
 	close(sockd);
367
+#endif
367 368
 
368 369
     } else {
369 370
 	int x;
... ...
@@ -8547,7 +8547,8 @@ fi
8547 8547
 
8548 8548
 
8549 8549
 
8550
-for ac_header in stdint.h unistd.h sys/int_types.h dlfcn.h inttypes.h sys/inttypes.h memory.h ndir.h stdlib.h strings.h string.h sys/mman.h sys/param.h sys/stat.h sys/types.h malloc.h poll.h regex.h limits.h sys/filio.h
8550
+
8551
+for ac_header in stdint.h unistd.h sys/int_types.h dlfcn.h inttypes.h sys/inttypes.h memory.h ndir.h stdlib.h strings.h string.h sys/mman.h sys/param.h sys/stat.h sys/types.h malloc.h poll.h regex.h limits.h sys/filio.h uio.h
8551 8552
 do
8552 8553
 as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
8553 8554
 if eval "test \"\${$as_ac_Header+set}\" = set"; then
... ...
@@ -11537,6 +11538,15 @@ _ACEOF
11537 11537
 	fi
11538 11538
 	CLAMSCAN_LIBS="$CLAMSCAN_LIBS -lpthread"
11539 11539
     fi
11540
+    case `uname -r` in
11541
+    1.*|2.0.*)
11542
+
11543
+cat >>confdefs.h <<\_ACEOF
11544
+#define INCOMPLETE_CMSG 1
11545
+_ACEOF
11546
+
11547
+       ;;
11548
+    esac
11540 11549
     ;;
11541 11550
 cygwin*)
11542 11551
 
... ...
@@ -12354,6 +12364,244 @@ fi
12354 12354
 fi
12355 12355
 
12356 12356
 
12357
+
12358
+for ac_func in recvmsg sendmsg
12359
+do
12360
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
12361
+echo "$as_me:$LINENO: checking for $ac_func" >&5
12362
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
12363
+if eval "test \"\${$as_ac_var+set}\" = set"; then
12364
+  echo $ECHO_N "(cached) $ECHO_C" >&6
12365
+else
12366
+  cat >conftest.$ac_ext <<_ACEOF
12367
+/* confdefs.h.  */
12368
+_ACEOF
12369
+cat confdefs.h >>conftest.$ac_ext
12370
+cat >>conftest.$ac_ext <<_ACEOF
12371
+/* end confdefs.h.  */
12372
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
12373
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
12374
+#define $ac_func innocuous_$ac_func
12375
+
12376
+/* System header to define __stub macros and hopefully few prototypes,
12377
+    which can conflict with char $ac_func (); below.
12378
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
12379
+    <limits.h> exists even on freestanding compilers.  */
12380
+
12381
+#ifdef __STDC__
12382
+# include <limits.h>
12383
+#else
12384
+# include <assert.h>
12385
+#endif
12386
+
12387
+#undef $ac_func
12388
+
12389
+/* Override any gcc2 internal prototype to avoid an error.  */
12390
+#ifdef __cplusplus
12391
+extern "C"
12392
+{
12393
+#endif
12394
+/* We use char because int might match the return type of a gcc2
12395
+   builtin and then its argument prototype would still apply.  */
12396
+char $ac_func ();
12397
+/* The GNU C library defines this for functions which it implements
12398
+    to always fail with ENOSYS.  Some functions are actually named
12399
+    something starting with __ and the normal name is an alias.  */
12400
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
12401
+choke me
12402
+#else
12403
+char (*f) () = $ac_func;
12404
+#endif
12405
+#ifdef __cplusplus
12406
+}
12407
+#endif
12408
+
12409
+int
12410
+main ()
12411
+{
12412
+return f != $ac_func;
12413
+  ;
12414
+  return 0;
12415
+}
12416
+_ACEOF
12417
+rm -f conftest.$ac_objext conftest$ac_exeext
12418
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
12419
+  (eval $ac_link) 2>conftest.er1
12420
+  ac_status=$?
12421
+  grep -v '^ *+' conftest.er1 >conftest.err
12422
+  rm -f conftest.er1
12423
+  cat conftest.err >&5
12424
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
12425
+  (exit $ac_status); } &&
12426
+	 { ac_try='test -z "$ac_c_werror_flag"			 || test ! -s conftest.err'
12427
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
12428
+  (eval $ac_try) 2>&5
12429
+  ac_status=$?
12430
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
12431
+  (exit $ac_status); }; } &&
12432
+	 { ac_try='test -s conftest$ac_exeext'
12433
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
12434
+  (eval $ac_try) 2>&5
12435
+  ac_status=$?
12436
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
12437
+  (exit $ac_status); }; }; then
12438
+  eval "$as_ac_var=yes"
12439
+else
12440
+  echo "$as_me: failed program was:" >&5
12441
+sed 's/^/| /' conftest.$ac_ext >&5
12442
+
12443
+eval "$as_ac_var=no"
12444
+fi
12445
+rm -f conftest.err conftest.$ac_objext \
12446
+      conftest$ac_exeext conftest.$ac_ext
12447
+fi
12448
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
12449
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
12450
+if test `eval echo '${'$as_ac_var'}'` = yes; then
12451
+  cat >>confdefs.h <<_ACEOF
12452
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
12453
+_ACEOF
12454
+
12455
+fi
12456
+done
12457
+
12458
+echo "$as_me:$LINENO: checking for msg_accrights field in struct msghdr" >&5
12459
+echo $ECHO_N "checking for msg_accrights field in struct msghdr... $ECHO_C" >&6
12460
+if test "${ac_cv_have_accrights_in_msghdr+set}" = set; then
12461
+  echo $ECHO_N "(cached) $ECHO_C" >&6
12462
+else
12463
+
12464
+    if test "$cross_compiling" = yes; then
12465
+  { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling
12466
+See \`config.log' for more details." >&5
12467
+echo "$as_me: error: cannot run test program while cross compiling
12468
+See \`config.log' for more details." >&2;}
12469
+   { (exit 1); exit 1; }; }
12470
+else
12471
+  cat >conftest.$ac_ext <<_ACEOF
12472
+/* confdefs.h.  */
12473
+_ACEOF
12474
+cat confdefs.h >>conftest.$ac_ext
12475
+cat >>conftest.$ac_ext <<_ACEOF
12476
+/* end confdefs.h.  */
12477
+
12478
+#include <sys/types.h>
12479
+#include <sys/socket.h>
12480
+#include <sys/uio.h>
12481
+int main() {
12482
+#ifdef msg_accrights
12483
+exit(1);
12484
+#endif
12485
+struct msghdr m;
12486
+m.msg_accrights = 0;
12487
+exit(0);
12488
+}
12489
+
12490
+_ACEOF
12491
+rm -f conftest$ac_exeext
12492
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
12493
+  (eval $ac_link) 2>&5
12494
+  ac_status=$?
12495
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
12496
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
12497
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
12498
+  (eval $ac_try) 2>&5
12499
+  ac_status=$?
12500
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
12501
+  (exit $ac_status); }; }; then
12502
+   ac_cv_have_accrights_in_msghdr="yes"
12503
+else
12504
+  echo "$as_me: program exited with status $ac_status" >&5
12505
+echo "$as_me: failed program was:" >&5
12506
+sed 's/^/| /' conftest.$ac_ext >&5
12507
+
12508
+( exit $ac_status )
12509
+ ac_cv_have_accrights_in_msghdr="no"
12510
+
12511
+fi
12512
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
12513
+fi
12514
+
12515
+fi
12516
+echo "$as_me:$LINENO: result: $ac_cv_have_accrights_in_msghdr" >&5
12517
+echo "${ECHO_T}$ac_cv_have_accrights_in_msghdr" >&6
12518
+if test "x$ac_cv_have_accrights_in_msghdr" = "xyes" ; then
12519
+
12520
+cat >>confdefs.h <<\_ACEOF
12521
+#define HAVE_ACCRIGHTS_IN_MSGHDR 1
12522
+_ACEOF
12523
+
12524
+fi
12525
+
12526
+echo "$as_me:$LINENO: checking for msg_control field in struct msghdr" >&5
12527
+echo $ECHO_N "checking for msg_control field in struct msghdr... $ECHO_C" >&6
12528
+if test "${ac_cv_have_control_in_msghdr+set}" = set; then
12529
+  echo $ECHO_N "(cached) $ECHO_C" >&6
12530
+else
12531
+
12532
+    if test "$cross_compiling" = yes; then
12533
+  { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling
12534
+See \`config.log' for more details." >&5
12535
+echo "$as_me: error: cannot run test program while cross compiling
12536
+See \`config.log' for more details." >&2;}
12537
+   { (exit 1); exit 1; }; }
12538
+else
12539
+  cat >conftest.$ac_ext <<_ACEOF
12540
+/* confdefs.h.  */
12541
+_ACEOF
12542
+cat confdefs.h >>conftest.$ac_ext
12543
+cat >>conftest.$ac_ext <<_ACEOF
12544
+/* end confdefs.h.  */
12545
+
12546
+#include <sys/types.h>
12547
+#include <sys/socket.h>
12548
+#include <sys/uio.h>
12549
+int main() {
12550
+#ifdef msg_control
12551
+exit(1);
12552
+#endif
12553
+struct msghdr m;
12554
+m.msg_control = 0;
12555
+exit(0);
12556
+}
12557
+
12558
+_ACEOF
12559
+rm -f conftest$ac_exeext
12560
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
12561
+  (eval $ac_link) 2>&5
12562
+  ac_status=$?
12563
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
12564
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
12565
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
12566
+  (eval $ac_try) 2>&5
12567
+  ac_status=$?
12568
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
12569
+  (exit $ac_status); }; }; then
12570
+   ac_cv_have_control_in_msghdr="yes"
12571
+else
12572
+  echo "$as_me: program exited with status $ac_status" >&5
12573
+echo "$as_me: failed program was:" >&5
12574
+sed 's/^/| /' conftest.$ac_ext >&5
12575
+
12576
+( exit $ac_status )
12577
+ ac_cv_have_control_in_msghdr="no"
12578
+
12579
+fi
12580
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
12581
+fi
12582
+
12583
+fi
12584
+echo "$as_me:$LINENO: result: $ac_cv_have_control_in_msghdr" >&5
12585
+echo "${ECHO_T}$ac_cv_have_control_in_msghdr" >&6
12586
+if test "x$ac_cv_have_control_in_msghdr" = "xyes" ; then
12587
+
12588
+cat >>confdefs.h <<\_ACEOF
12589
+#define HAVE_CONTROL_IN_MSGHDR 1
12590
+_ACEOF
12591
+
12592
+fi
12593
+
12594
+
12357 12595
 # Check whether --with-tcpwrappers or --without-tcpwrappers was given.
12358 12596
 if test "${with_tcpwrappers+set}" = set; then
12359 12597
   withval="$with_tcpwrappers"
... ...
@@ -38,7 +38,7 @@ AC_DEFINE(SCANBUFF, 131072, [scan buffer size])
38 38
 AC_DEFINE(FILEBUFF, 8192,   [file i/o buffer size])
39 39
 
40 40
 AC_HEADER_STDC
41
-AC_CHECK_HEADERS(stdint.h unistd.h sys/int_types.h dlfcn.h inttypes.h sys/inttypes.h memory.h ndir.h stdlib.h strings.h string.h sys/mman.h sys/param.h sys/stat.h sys/types.h malloc.h poll.h regex.h limits.h sys/filio.h)
41
+AC_CHECK_HEADERS(stdint.h unistd.h sys/int_types.h dlfcn.h inttypes.h sys/inttypes.h memory.h ndir.h stdlib.h strings.h string.h sys/mman.h sys/param.h sys/stat.h sys/types.h malloc.h poll.h regex.h limits.h sys/filio.h uio.h)
42 42
 AC_CHECK_HEADER(syslog.h,AC_DEFINE(USE_SYSLOG,1,[use syslog]),)
43 43
 
44 44
 AC_TYPE_OFF_T
... ...
@@ -314,6 +314,11 @@ linux*)
314 314
 	fi
315 315
 	CLAMSCAN_LIBS="$CLAMSCAN_LIBS -lpthread"
316 316
     fi
317
+    case `uname -r` in
318
+    1.*|2.0.*)
319
+       AC_DEFINE(INCOMPLETE_CMSG,1,[Early Linux doesn't set cmsg fields])
320
+       ;;
321
+    esac
317 322
     ;;
318 323
 cygwin*)
319 324
     AC_DEFINE(C_CYGWIN,1,[os is cygwin])
... ...
@@ -518,6 +523,57 @@ then
518 518
     AC_PATH_PROG(SENDMAIL, sendmail, /usr/lib/sendmail, $PATH:/usr/lib:/usr/sbin:/etc:/usr/local/lib:/usr/local/sbin:/usr/bin:/usr/local/bin)
519 519
 fi
520 520
 
521
+dnl Check if we can do fd passing
522
+dnl Submitted by Richard Lyons <frob-clamav@webcentral.com.au>
523
+AC_CHECK_FUNCS(recvmsg sendmsg)
524
+AC_CACHE_CHECK([for msg_accrights field in struct msghdr],
525
+	ac_cv_have_accrights_in_msghdr, [
526
+    AC_TRY_RUN(
527
+	[
528
+#include <sys/types.h>
529
+#include <sys/socket.h>
530
+#include <sys/uio.h>
531
+int main() {
532
+#ifdef msg_accrights
533
+exit(1);
534
+#endif
535
+struct msghdr m;
536
+m.msg_accrights = 0;
537
+exit(0);
538
+}
539
+	],
540
+	[ ac_cv_have_accrights_in_msghdr="yes" ],
541
+	[ ac_cv_have_accrights_in_msghdr="no" ]
542
+    )
543
+])
544
+if test "x$ac_cv_have_accrights_in_msghdr" = "xyes" ; then
545
+    AC_DEFINE(HAVE_ACCRIGHTS_IN_MSGHDR,1,[access rights in msghdr])
546
+fi
547
+
548
+AC_CACHE_CHECK([for msg_control field in struct msghdr],
549
+	ac_cv_have_control_in_msghdr, [
550
+    AC_TRY_RUN(
551
+	[
552
+#include <sys/types.h>
553
+#include <sys/socket.h>
554
+#include <sys/uio.h>
555
+int main() {
556
+#ifdef msg_control
557
+exit(1);
558
+#endif
559
+struct msghdr m;
560
+m.msg_control = 0;
561
+exit(0);
562
+}
563
+	],
564
+	[ ac_cv_have_control_in_msghdr="yes" ],
565
+	[ ac_cv_have_control_in_msghdr="no" ]
566
+    )
567
+])
568
+if test "x$ac_cv_have_control_in_msghdr" = "xyes" ; then
569
+    AC_DEFINE(HAVE_CONTROL_IN_MSGHDR,1,[ancillary data style fd pass])
570
+fi
571
+
521 572
 dnl tcpwrappers support
522 573
 dnl rules from http://ma.ph-freiburg.de/tng/tng-technical/2002-01/msg00094.html
523 574
 AC_ARG_WITH(tcpwrappers,