~ubuntu-branches/ubuntu/saucy/clamav/saucy-backports

« back to all changes in this revision

Viewing changes to libclamav/www.c

  • Committer: Package Import Robot
  • Author(s): Scott Kitterman
  • Date: 2014-07-15 01:08:10 UTC
  • mfrom: (0.35.47 sid)
  • Revision ID: package-import@ubuntu.com-20140715010810-ru66ek4fun2iseba
Tags: 0.98.4+dfsg-2~ubuntu13.10.1
No-change backport to saucy (LP: #1341962)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved.
 
3
 *
 
4
 *  Author: Shawn Webb
 
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 <stdlib.h>
 
27
#include <string.h>
 
28
 
 
29
#if HAVE_UNISTD_H
 
30
#include <unistd.h>
 
31
#endif
 
32
 
 
33
#include <ctype.h>
 
34
 
 
35
#include <sys/types.h>
 
36
#include <fcntl.h>
 
37
 
 
38
#include <errno.h>
 
39
 
 
40
#if !defined(_WIN32)
 
41
#include <sys/socket.h>
 
42
#include <sys/select.h>
 
43
#include <netinet/in.h>
 
44
#include <netdb.h>
 
45
#endif
 
46
 
 
47
#include "platform.h"
 
48
 
 
49
#include <openssl/ssl.h>
 
50
#include <openssl/err.h>
 
51
#include "libclamav/crypto.h"
 
52
 
 
53
#include "libclamav/others.h"
 
54
#include "libclamav/clamav.h"
 
55
#include "libclamav/www.h"
 
56
 
 
57
int connect_host(const char *host, const char *port, uint32_t timeout, int useAsync)
 
58
{
 
59
    int sockfd;
 
60
    struct addrinfo hints, *servinfo, *p;
 
61
    int flags, error;
 
62
    socklen_t len;
 
63
    fd_set read_fds, write_fds;
 
64
    struct timeval tv;
 
65
#ifdef _WIN32
 
66
        int iResult;
 
67
        WSADATA wsaData;
 
68
 
 
69
        /* Force initialization of Windows sockets, even if it already happened elsewhere */
 
70
        iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
 
71
        if (iResult != 0)
 
72
                return -1;
 
73
#endif
 
74
 
 
75
    memset(&hints, 0x00, sizeof(struct addrinfo));
 
76
    hints.ai_family = AF_UNSPEC;
 
77
    hints.ai_socktype = SOCK_STREAM;
 
78
 
 
79
    if (getaddrinfo(host, port, &hints, &servinfo))
 
80
        return -1;
 
81
 
 
82
    for (p = servinfo; p != NULL; p = p->ai_next) {
 
83
        sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
 
84
        if (sockfd < 0)
 
85
            continue;
 
86
 
 
87
        if (useAsync) {
 
88
            flags = fcntl(sockfd, F_GETFL, 0);
 
89
            if (fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) < 0) {
 
90
                closesocket(sockfd);
 
91
                continue;
 
92
            }
 
93
        }
 
94
 
 
95
        if ((error = connect(sockfd, p->ai_addr, p->ai_addrlen))) {
 
96
            if (useAsync) {
 
97
                if (errno != EINPROGRESS) {
 
98
                    closesocket(sockfd);
 
99
                    continue;
 
100
                }
 
101
                errno = 0;
 
102
 
 
103
                FD_ZERO(&write_fds);
 
104
                FD_ZERO(&read_fds);
 
105
                FD_SET(sockfd, &read_fds);
 
106
                FD_SET(sockfd, &write_fds);
 
107
 
 
108
                /* TODO: Make this timeout configurable */
 
109
                tv.tv_sec = timeout;
 
110
                tv.tv_usec = 0;
 
111
                if (select(sockfd + 1, &read_fds, &write_fds, NULL, &tv) <= 0) {
 
112
                    closesocket(sockfd);
 
113
                    continue;
 
114
                }
 
115
 
 
116
                if (FD_ISSET(sockfd, &read_fds) || FD_ISSET(sockfd, &write_fds)) {
 
117
                    len = sizeof(error);
 
118
                    if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
 
119
                        closesocket(sockfd);
 
120
                        continue;
 
121
                    }
 
122
                } else {
 
123
                    closesocket(sockfd);
 
124
                    continue;
 
125
                }
 
126
            } else {
 
127
                closesocket(sockfd);
 
128
                continue;
 
129
            }
 
130
        }
 
131
 
 
132
 
 
133
        /* Connected to host */
 
134
        break;
 
135
    }
 
136
 
 
137
    if (!(p)) {
 
138
        freeaddrinfo(servinfo);
 
139
        if (sockfd >= 0)
 
140
            closesocket(sockfd);
 
141
        return -1;
 
142
    }
 
143
 
 
144
    freeaddrinfo(servinfo);
 
145
 
 
146
    /* Return to using a synchronous socket to make Linux happy */
 
147
    if (useAsync) {
 
148
        if (fcntl(sockfd, F_SETFL, flags) < 0) {
 
149
            closesocket(sockfd);
 
150
            return -1;
 
151
        }
 
152
    }
 
153
 
 
154
    return sockfd;
 
155
}
 
156
 
 
157
size_t encoded_size(const char *postdata)
 
158
{
 
159
    const char *p;
 
160
    size_t len=0;
 
161
 
 
162
    for (p = postdata; *p != '\0'; p++)
 
163
        len += isalnum(*p) ? 1 : 3;
 
164
 
 
165
    return len;
 
166
}
 
167
 
 
168
char *encode_data(const char *postdata)
 
169
{
 
170
    char *buf;
 
171
    size_t bufsz, i, j;
 
172
 
 
173
    bufsz = encoded_size(postdata);
 
174
    if (bufsz == 0)
 
175
        return NULL;
 
176
 
 
177
    buf = cli_calloc(1, bufsz+1);
 
178
    if (!(buf))
 
179
        return NULL;
 
180
 
 
181
    for (i=0, j=0; postdata[i] != '\0'; i++) {
 
182
        if (isalnum(postdata[i])) {
 
183
            buf[j++] = postdata[i];
 
184
        } else {
 
185
            sprintf(buf+j, "%%%02x", postdata[i]);
 
186
            j += 3;
 
187
        }
 
188
    }
 
189
 
 
190
    return buf;
 
191
}
 
192
 
 
193
void submit_post(const char *host, const char *port, const char *method, const char *url, const char *postdata, uint32_t timeout)
 
194
{
 
195
    int sockfd, n;
 
196
    unsigned int i;
 
197
    char *buf, *encoded=NULL;
 
198
    size_t bufsz;
 
199
    ssize_t recvsz;
 
200
    char chunkedlen[21];
 
201
    fd_set readfds;
 
202
    struct timeval tv;
 
203
    char *acceptable_methods[] = {
 
204
        "GET",
 
205
        "PUT",
 
206
        "POST",
 
207
        NULL
 
208
    };
 
209
 
 
210
    for (i=0; acceptable_methods[i] != NULL; i++)
 
211
        if (!strcmp(method, acceptable_methods[i]))
 
212
            break;
 
213
 
 
214
    if (acceptable_methods[i] == NULL)
 
215
        return;
 
216
 
 
217
    bufsz = strlen(method);
 
218
    bufsz += sizeof("   HTTP/1.1") + 2; /* Yes. Three blank spaces. +1 for the \n */
 
219
    bufsz += strlen(url);
 
220
    bufsz += sizeof("Host: \r\n");
 
221
    bufsz += strlen(host);
 
222
    bufsz += sizeof("Connection: Close\r\n");
 
223
    bufsz += 4; /* +4 for \r\n\r\n */
 
224
 
 
225
    if (!strcmp(method, "POST") || !strcmp(method, "PUT")) {
 
226
        encoded = encode_data(postdata);
 
227
        if (!(encoded))
 
228
            return;
 
229
#if defined(_WIN32)
 
230
                snprintf(chunkedlen, sizeof(chunkedlen), "%u", strlen(encoded));
 
231
#else
 
232
        snprintf(chunkedlen, sizeof(chunkedlen), "%zu", strlen(encoded));
 
233
#endif
 
234
        bufsz += sizeof("Content-Type: application/x-www-form-urlencoded\r\n");
 
235
        bufsz += sizeof("Content-Length: \r\n");
 
236
        bufsz += strlen(chunkedlen);
 
237
        bufsz += strlen(encoded);
 
238
    }
 
239
 
 
240
    buf = cli_calloc(1, bufsz);
 
241
    if (!(buf)) {
 
242
        if ((encoded))
 
243
            free(encoded);
 
244
 
 
245
        return;
 
246
    }
 
247
 
 
248
    snprintf(buf, bufsz, "%s %s HTTP/1.1\r\n", method, url);
 
249
    snprintf(buf+strlen(buf), bufsz-strlen(buf), "Host: %s\r\n", host);
 
250
    snprintf(buf+strlen(buf), bufsz-strlen(buf), "Connection: Close\r\n");
 
251
 
 
252
    if (!strcmp(method, "POST") || !strcmp(method, "PUT")) {
 
253
        snprintf(buf+strlen(buf), bufsz-strlen(buf), "Content-Type: application/x-www-form-urlencoded\r\n");
 
254
        snprintf(buf+strlen(buf), bufsz-strlen(buf), "Content-Length: %s\r\n", chunkedlen);
 
255
        snprintf(buf+strlen(buf), bufsz-strlen(buf), "\r\n");
 
256
        snprintf(buf+strlen(buf), bufsz-strlen(buf), "%s", encoded);
 
257
        free(encoded);
 
258
    }
 
259
#if defined(_WIN32)
 
260
        sockfd = connect_host(host, port, timeout, 0);
 
261
#else
 
262
    sockfd = connect_host(host, port, timeout, 1);
 
263
#endif
 
264
    if (sockfd < 0) {
 
265
        free(buf);
 
266
        return;
 
267
    }
 
268
 
 
269
    cli_dbgmsg("stats - Connected to %s:%s\n", host, port);
 
270
 
 
271
    if (send(sockfd, buf, strlen(buf), 0) != strlen(buf)) {
 
272
        closesocket(sockfd);
 
273
        free(buf);
 
274
        return;
 
275
    }
 
276
 
 
277
    cli_dbgmsg("stats - Sending %s\n", buf);
 
278
 
 
279
    while (1) {
 
280
        FD_ZERO(&readfds);
 
281
        FD_SET(sockfd, &readfds);
 
282
 
 
283
        /*
 
284
         * Check to make sure the stats submitted okay (so that we don't kill the HTTP request
 
285
         * while it's being processed). Give a ten-second timeout so we don't have a major
 
286
         * impact on scanning.
 
287
         */
 
288
        tv.tv_sec = timeout;
 
289
        tv.tv_usec = 0;
 
290
        if ((n = select(sockfd+1, &readfds, NULL, NULL, &tv)) <= 0)
 
291
            break;
 
292
 
 
293
        if (FD_ISSET(sockfd, &readfds)) {
 
294
            memset(buf, 0x00, bufsz);
 
295
            if ((recvsz = recv(sockfd, buf, bufsz-1, 0) <= 0))
 
296
                break;
 
297
 
 
298
            buf[bufsz-1] = '\0';
 
299
 
 
300
            cli_dbgmsg("stats - received: %s\n", buf);
 
301
 
 
302
            if (strstr(buf, "STATOK")) {
 
303
                cli_dbgmsg("stats - Data received okay\n");
 
304
                break;
 
305
            }
 
306
        }
 
307
    }
 
308
 
 
309
    closesocket(sockfd);
 
310
    free(buf);
 
311
}