mirror of https://github.com/Cisco-Talos/clamav
m4/fdpassing.m4: move all FD passing checks here clamd/session.[ch], scanner.[ch]: contrib/clamd_fdscan: add rfc2292/bsd4.4 style file descriptor passing support this code is from Marc Balmer <marc*msys.ch>, with some portability fixes applied git-svn: trunk@3849remotes/push_mirror/metadata
parent
43edf874c8
commit
725a296922
@ -0,0 +1,18 @@ |
||||
CC=cc
|
||||
|
||||
# Solaris needs these:
|
||||
#CFLAGS=-D_XOPEN_SOURCE=500
|
||||
#LDFLAGS=-lsocket
|
||||
|
||||
CFLAGS=
|
||||
LDFLAGS=
|
||||
all: clamd_fdscan |
||||
|
||||
strlcpy.o: strlcpy.c |
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
clamd_fdscan.o: clamd_fdscan.c clamd_fdscan.h |
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
clamd_fdscan: clamd_fdscan.o strlcpy.o |
||||
$(CC) -o $@ clamd_fdscan.o strlcpy.o
|
||||
@ -0,0 +1,132 @@ |
||||
/* $Id: clamd_fdscan.c,v 1.2 2007/01/18 16:59:50 mbalmer Exp $ */ |
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Marc Balmer <mbalmer@openbsd.org> |
||||
* |
||||
* Permission to use, copy, modify, and distribute this software for any |
||||
* purpose with or without fee is hereby granted, provided that the above |
||||
* copyright notice and this permission notice appear in all copies. |
||||
* |
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
||||
*/ |
||||
|
||||
#include <sys/types.h> |
||||
#include <sys/socket.h> |
||||
#include <sys/un.h> |
||||
#include <sys/uio.h> |
||||
#include <string.h> |
||||
|
||||
#include <stdio.h> |
||||
#include <err.h> |
||||
#include <unistd.h> |
||||
|
||||
#include "clamd_fdscan.h" |
||||
|
||||
#define CLAMD_BUFSIZ 256 |
||||
|
||||
size_t strlcpy(char *dst, const char *src, size_t siz); |
||||
/*
|
||||
* clamd_fdscan lets a running clamd process scan the contents of an open |
||||
* filedescriptor by passing the filedescriptor to clamd. The parameters |
||||
* are as follows: |
||||
* fd the open filedescriptor to pass for scanning |
||||
* soname the path to the local clamd listening socket |
||||
* name virus name, if a virus is found |
||||
* len max len of the virus name |
||||
* |
||||
* The functions returns 0 if the file was scanned and contains no virus, |
||||
* -1 if an error occurs and 1 if a virus is found. |
||||
*/ |
||||
int |
||||
clamd_fdscan(int fd, char *soname, char *name, size_t len) |
||||
{ |
||||
struct sockaddr_un addr; |
||||
struct msghdr msg; |
||||
struct cmsghdr *cmsg; |
||||
unsigned char fdbuf[CMSG_SPACE(sizeof(int))]; |
||||
FILE *sp; |
||||
char buf[CLAMD_BUFSIZ], *p, *q; |
||||
off_t pos; |
||||
int s; |
||||
struct iovec iov[1]; |
||||
|
||||
iov[0].iov_base = ""; |
||||
iov[0].iov_len = 1; |
||||
|
||||
pos = lseek(fd, 0, SEEK_CUR); |
||||
s = socket(AF_UNIX, SOCK_STREAM, 0); |
||||
memset(&addr, 0, sizeof(addr)); |
||||
addr.sun_family = AF_UNIX; |
||||
strlcpy(addr.sun_path, soname, sizeof(addr.sun_path)); |
||||
if (connect(s, (struct sockaddr *)&addr, sizeof(addr))) { |
||||
perror("connect"); |
||||
return -1; |
||||
} |
||||
|
||||
memset(&msg, 0, sizeof(msg)); |
||||
msg.msg_control = fdbuf; |
||||
/* must send/receive at least one byte */ |
||||
msg.msg_iov = iov; |
||||
msg.msg_iovlen = 1; |
||||
msg.msg_controllen = CMSG_LEN(sizeof(int)); |
||||
|
||||
cmsg = CMSG_FIRSTHDR(&msg); |
||||
cmsg->cmsg_len = CMSG_LEN(sizeof(int)); |
||||
cmsg->cmsg_level = SOL_SOCKET; |
||||
cmsg->cmsg_type = SCM_RIGHTS; |
||||
*(int *)CMSG_DATA(cmsg) = fd; |
||||
|
||||
write(s, "FILDES\n", sizeof("FILDES\n")-1); |
||||
if (sendmsg(s, &msg, 0) == -1) { |
||||
perror("sendmsg"); |
||||
close(s); |
||||
return -1; |
||||
} |
||||
|
||||
sp = fdopen(s,"r"); |
||||
fgets(buf, sizeof(buf), sp); |
||||
fclose(sp); |
||||
close(s); |
||||
|
||||
if (pos != -1) |
||||
lseek(fd, pos, SEEK_SET); |
||||
if ((p = strrchr(buf, ' ')) != NULL) { |
||||
++p; |
||||
if (!strncmp(p, "OK", 2)) |
||||
return 0; |
||||
else if (!strncmp(p, "FOUND", 5)) { |
||||
if (name != NULL) { |
||||
*--p = '\0'; |
||||
q = strrchr(buf, ' ') + 1; |
||||
strlcpy(name, q, len); |
||||
} |
||||
return 1; |
||||
} else { |
||||
puts(buf); |
||||
} |
||||
} |
||||
return -1; |
||||
} |
||||
|
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
char virusname[CLAMD_BUFSIZ]; |
||||
if(argc != 2) { |
||||
fprintf(stderr,"Usage: %s <clamd_socket>\n", argv[0]); |
||||
return 1; |
||||
} |
||||
virusname[0]=0; |
||||
if(clamd_fdscan(0, argv[1],virusname, sizeof(virusname)) == -1) { |
||||
perror("Error sending fd!"); |
||||
return 2; |
||||
} else { |
||||
printf("FOUND: %s\n", virusname); |
||||
} |
||||
return 0; |
||||
} |
||||
@ -0,0 +1,19 @@ |
||||
/* $Id: clamd_fdscan.h,v 1.1.1.1 2007/01/18 14:01:24 mbalmer Exp $ */ |
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Marc Balmer <mbalmer@openbsd.org> |
||||
* |
||||
* Permission to use, copy, modify, and distribute this software for any |
||||
* purpose with or without fee is hereby granted, provided that the above |
||||
* copyright notice and this permission notice appear in all copies. |
||||
* |
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
||||
*/ |
||||
|
||||
extern int clamd_fdscan(int fd, char *soname, char *name, size_t len); |
||||
@ -0,0 +1,52 @@ |
||||
/*
|
||||
* This code is derived from OpenBSD's libc, original license follows: |
||||
* |
||||
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> |
||||
* |
||||
* Permission to use, copy, modify, and distribute this software for any |
||||
* purpose with or without fee is hereby granted, provided that the above |
||||
* copyright notice and this permission notice appear in all copies. |
||||
* |
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
||||
*/ |
||||
|
||||
#include <sys/types.h> |
||||
#include <string.h> |
||||
|
||||
/*
|
||||
* Copy src to string dst of size siz. At most siz-1 characters |
||||
* will be copied. Always NUL terminates (unless siz == 0). |
||||
* Returns strlen(src); if retval >= siz, truncation occurred. |
||||
*/ |
||||
size_t |
||||
strlcpy(char *dst, const char *src, size_t siz) |
||||
{ |
||||
char *d = dst; |
||||
const char *s = src; |
||||
size_t n = siz; |
||||
|
||||
/* Copy as many bytes as will fit */ |
||||
if (n != 0) { |
||||
while (--n != 0) { |
||||
if ((*d++ = *s++) == '\0') |
||||
break; |
||||
} |
||||
} |
||||
|
||||
/* Not enough room in dst, add NUL and traverse rest of src */ |
||||
if (n == 0) { |
||||
if (siz != 0) |
||||
*d = '\0'; /* NUL-terminate dst */ |
||||
while (*s++) |
||||
; |
||||
} |
||||
|
||||
return(s - src - 1); /* count does not include NUL */ |
||||
} |
||||
|
||||
@ -0,0 +1,188 @@ |
||||
|
||||
AC_DEFUN([CONFTEST_FDPASS],[[ |
||||
AC_LANG_SOURCE([[ |
||||
$1 |
||||
#include <sys/types.h> |
||||
#include <sys/wait.h> |
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <unistd.h> |
||||
#include <string.h> |
||||
#include <sys/uio.h> |
||||
#include <signal.h> |
||||
#include <sys/socket.h> |
||||
|
||||
|
||||
#define TEST "test" |
||||
|
||||
int send_fd(int s, int fd) |
||||
{ |
||||
struct msghdr msg; |
||||
struct cmsghdr *cmsg; |
||||
unsigned char fdbuf[CMSG_SPACE(sizeof(int))]; |
||||
struct iovec iov[1]; |
||||
|
||||
iov[0].iov_base = ""; |
||||
iov[0].iov_len = 1; |
||||
|
||||
memset(&msg, 0, sizeof(msg)); |
||||
msg.msg_control = fdbuf; |
||||
/* must send/receive at least one byte */ |
||||
msg.msg_iov = iov; |
||||
msg.msg_iovlen = 1; |
||||
msg.msg_controllen = CMSG_LEN(sizeof(int)); |
||||
|
||||
cmsg = CMSG_FIRSTHDR(&msg); |
||||
cmsg->cmsg_len = CMSG_LEN(sizeof(int)); |
||||
cmsg->cmsg_level = SOL_SOCKET; |
||||
cmsg->cmsg_type = SCM_RIGHTS; |
||||
*(int *)CMSG_DATA(cmsg) = fd; |
||||
|
||||
if (sendmsg(s, &msg, 0) == -1) { |
||||
perror("sendmsg"); |
||||
close(s); |
||||
return -1; |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
int testfd(int desc) |
||||
{ |
||||
char buf[256]; |
||||
if(read(desc, buf, sizeof(buf)) != sizeof(TEST)) { |
||||
fprintf(stderr, "test data not received correctly!"); |
||||
return 1; |
||||
} |
||||
return memcmp(buf, TEST, sizeof(TEST)); |
||||
} |
||||
|
||||
int recv_fd(int desc) |
||||
{ |
||||
unsigned char buf[CMSG_SPACE(sizeof(int))]; |
||||
struct msghdr msg; |
||||
struct cmsghdr *cmsg; |
||||
struct iovec iov[1]; |
||||
char dummy; |
||||
int ret=2; |
||||
|
||||
memset(&msg, 0, sizeof(msg)); |
||||
iov[0].iov_base = &dummy; |
||||
iov[0].iov_len = 1; |
||||
msg.msg_iov = iov; |
||||
msg.msg_iovlen = 1; |
||||
msg.msg_control = buf; |
||||
msg.msg_controllen = sizeof(buf); |
||||
|
||||
if (recvmsg(desc, &msg, 0) == -1) { |
||||
perror("recvmsg failed!"); |
||||
return -1; |
||||
} |
||||
if ((msg.msg_flags & MSG_TRUNC) || (msg.msg_flags & MSG_CTRUNC)) { |
||||
fprintf(stderr, "control message truncated"); |
||||
return -1; |
||||
} |
||||
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; |
||||
cmsg = CMSG_NXTHDR(&msg, cmsg)) { |
||||
if (cmsg->cmsg_len == CMSG_LEN(sizeof(int)) && |
||||
cmsg->cmsg_level == SOL_SOCKET && |
||||
cmsg->cmsg_type == SCM_RIGHTS) { |
||||
int fd = *(int *)CMSG_DATA(cmsg); |
||||
ret = testfd(fd); |
||||
close(fd); |
||||
} |
||||
} |
||||
return ret; |
||||
} |
||||
|
||||
int main(void) |
||||
{ |
||||
int fd[2]; |
||||
int pip[2]; |
||||
pid_t pid; |
||||
int status; |
||||
|
||||
if(pipe(pip)) { |
||||
perror("pipe"); |
||||
return 1; |
||||
} |
||||
|
||||
if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd)) { |
||||
perror("socketpair"); |
||||
return 1; |
||||
} |
||||
|
||||
if((pid=fork()) < 0) { |
||||
perror("fork"); |
||||
} else if (!pid) { |
||||
exit( recv_fd(fd[1]) ); |
||||
} else { |
||||
/* parent */ |
||||
if(send_fd(fd[0], pip[0]) == -1) { |
||||
kill(pid, 9); |
||||
waitpid(pid, NULL, 0); |
||||
return 2; |
||||
} |
||||
write(pip[1], TEST, sizeof(TEST)); |
||||
close(pip[1]); |
||||
waitpid(pid, &status, 0); |
||||
} |
||||
return status; |
||||
} |
||||
]]) |
||||
]]) |
||||
|
||||
AC_DEFUN([AC_C_FDPASSING],[ |
||||
dnl Check if we can do fd passing |
||||
dnl Submitted by Richard Lyons <frob-clamav@webcentral.com.au> |
||||
AC_CHECK_FUNCS([recvmsg sendmsg]) |
||||
AC_CACHE_CHECK([for msg_control field in struct msghdr], |
||||
[ac_cv_have_control_in_msghdr], [ |
||||
AC_TRY_COMPILE( |
||||
[ |
||||
#define _XOPEN_SOURCE 500 |
||||
#include <sys/types.h> |
||||
#include <sys/socket.h> |
||||
#include <sys/uio.h> |
||||
], |
||||
[ |
||||
#ifdef msg_control |
||||
#error msg_control defined |
||||
#endif |
||||
struct msghdr m; |
||||
m.msg_control = 0; |
||||
return 0; |
||||
], [ ac_cv_have_control_in_msghdr="yes" ], [ ac_cv_have_control_in_msghdr="no" ]) |
||||
]) |
||||
if test "x$ac_cv_have_control_in_msghdr" = "xyes" ; then |
||||
AC_DEFINE([HAVE_CONTROL_IN_MSGHDR],1,[ancillary data style fd pass]) |
||||
|
||||
dnl Check whether FD passing works <edwin@clamav.net> |
||||
AC_MSG_CHECKING([BSD 4.4 / RFC2292 style fd passing]) |
||||
AC_ARG_ENABLE([fdpassing],[ --disable-fdpassing don't build file descriptor passing support], |
||||
want_fdpassing=$enableval, want_fdpassing="yes") |
||||
|
||||
if test "x$want_fdpassing" = "xyes"; then |
||||
dnl Try without _XOPEN_SOURCE first |
||||
AC_RUN_IFELSE(CONFTEST_FDPASS([]), [have_fdpass=1; fdpass_need_xopen=0], [have_fdpass=0],[have_fdpass=0]) |
||||
|
||||
if test $have_fdpass = 0; then |
||||
AC_RUN_IFELSE(CONFTEST_FDPASS([#define _XOPEN_SOURCE 500]), [have_fdpass=1; fdpass_need_xopen=1],[have_fdpass=0],[have_fdpass=0]) |
||||
fi |
||||
|
||||
if test $have_fdpass = 1; then |
||||
AC_DEFINE([HAVE_FD_PASSING],1,[have working file descriptor passing support]) |
||||
if test $fdpass_need_xopen = 1; then |
||||
AC_DEFINE([FDPASS_NEED_XOPEN],1,[whether _XOPEN_SOURCE needs to be defined for fd passing to work]) |
||||
AC_MSG_RESULT([yes, by defining _XOPEN_SOURCE]) |
||||
else |
||||
AC_MSG_RESULT([yes]) |
||||
fi |
||||
else |
||||
AC_MSG_RESULT([no]) |
||||
fi |
||||
|
||||
else |
||||
AC_MSG_RESULT([disabled]) |
||||
fi |
||||
fi |
||||
]) |
||||
Loading…
Reference in new issue