~ubuntu-branches/ubuntu/wily/clamav/wily-proposed

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
AC_DEFUN([CONFTEST_FDPASS],[[
AC_LANG_SOURCE([[
$1 
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#ifdef HAVE_SYS_UIO_H
#include <sys/uio.h>
#endif
#include <signal.h>
#include <sys/socket.h>

#if !defined CMSG_SPACE || !defined CMSG_LEN
#ifndef ALIGN
#define ALIGN(len) len
#endif

#ifndef CMSG_SPACE
#define CMSG_SPACE(len) (ALIGN(sizeof(struct cmsghdr)) + ALIGN(len))
#endif

#ifndef CMSG_LEN
#define CMSG_LEN(len) (ALIGN(sizeof(struct cmsghdr)) + len)
#endif
#endif

#define TEST "test"

static int send_fd(int s, int fd)
{
    struct msghdr msg;
    struct cmsghdr *cmsg;
    unsigned char fdbuf[CMSG_SPACE(sizeof(int))];
    struct iovec iov[1];
    char dummy[] = "";

    iov[0].iov_base = dummy;
    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;
}

static 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));
}

static 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;
        }
        if(write(pip[1], TEST, sizeof(TEST)) != sizeof(TEST)) {
		close(pip[1]);
		return -1;
	}
        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
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include <sys/socket.h>
#ifdef HAVE_SYS_UIO_H
#include <sys/uio.h>
#endif
],
[
#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
    dnl Check whether FD passing works <edwin@clamav.net>
    AC_MSG_CHECKING([BSD 4.4 / RFC2292 style fd passing])
    AC_ARG_ENABLE([fdpassing],[AS_HELP_STRING([--disable-fdpassing], [do not 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
])