Browse code

Revert "Fix crash on Windows when --enable-stats is set"

This reverts commit 0b1ad9dbcab6beba52a2ae4e677fb8f5a8ed8878.

Shawn Webb authored on 2014/05/07 03:42:48
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,288 @@
0
+/*
1
+ *  Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved.
2
+ *
3
+ *  Author: Shawn Webb
4
+ *
5
+ *  This program is free software; you can redistribute it and/or modify
6
+ *  it under the terms of the GNU General Public License version 2 as
7
+ *  published by the Free Software Foundation.
8
+ *
9
+ *  This program is distributed in the hope that it will be useful,
10
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
+ *  GNU General Public License for more details.
13
+ *
14
+ *  You should have received a copy of the GNU General Public License
15
+ *  along with this program; if not, write to the Free Software
16
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17
+ *  MA 02110-1301, USA.
18
+ */
19
+
20
+#include <stdio.h>
21
+#include <stdlib.h>
22
+#include <string.h>
23
+
24
+#if HAVE_UNISTD_H
25
+#include <unistd.h>
26
+#endif
27
+
28
+#include <ctype.h>
29
+
30
+#include <sys/types.h>
31
+#include <fcntl.h>
32
+
33
+#include <errno.h>
34
+
35
+#if !defined(_WIN32)
36
+#include <sys/socket.h>
37
+#include <sys/select.h>
38
+#include <netinet/in.h>
39
+#include <netdb.h>
40
+#endif
41
+
42
+#include <openssl/ssl.h>
43
+#include <openssl/err.h>
44
+#include "libclamav/crypto.h"
45
+
46
+#include "libclamav/others.h"
47
+#include "libclamav/clamav.h"
48
+#include "libclamav/www.h"
49
+
50
+int connect_host(const char *host, const char *port, uint32_t timeout, int useAsync)
51
+{
52
+    int sockfd;
53
+    struct addrinfo hints, *servinfo, *p;
54
+    int flags, error;
55
+    socklen_t len;
56
+    fd_set read_fds, write_fds;
57
+    struct timeval tv;
58
+
59
+    memset(&hints, 0x00, sizeof(struct addrinfo));
60
+    hints.ai_family = AF_UNSPEC;
61
+    hints.ai_socktype = SOCK_STREAM;
62
+
63
+    if (getaddrinfo(host, port, &hints, &servinfo))
64
+        return -1;
65
+
66
+    for (p = servinfo; p != NULL; p = p->ai_next) {
67
+        sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
68
+        if (sockfd < 0)
69
+            continue;
70
+
71
+        if (useAsync) {
72
+            flags = fcntl(sockfd, F_GETFL, 0);
73
+            if (fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) < 0) {
74
+                close(sockfd);
75
+                continue;
76
+            }
77
+        }
78
+
79
+        if ((error = connect(sockfd, p->ai_addr, p->ai_addrlen))) {
80
+            if (useAsync) {
81
+                if (errno != EINPROGRESS) {
82
+                    close(sockfd);
83
+                    continue;
84
+                }
85
+                errno = 0;
86
+
87
+                FD_ZERO(&write_fds);
88
+                FD_ZERO(&read_fds);
89
+                FD_SET(sockfd, &read_fds);
90
+                FD_SET(sockfd, &write_fds);
91
+
92
+                /* TODO: Make this timeout configurable */
93
+                tv.tv_sec = timeout;
94
+                tv.tv_usec = 0;
95
+                if (select(sockfd + 1, &read_fds, &write_fds, NULL, &tv) <= 0) {
96
+                    close(sockfd);
97
+                    continue;
98
+                }
99
+
100
+                if (FD_ISSET(sockfd, &read_fds) || FD_ISSET(sockfd, &write_fds)) {
101
+                    len = sizeof(error);
102
+                    if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
103
+                        close(sockfd);
104
+                        continue;
105
+                    }
106
+                } else {
107
+                    close(sockfd);
108
+                    continue;
109
+                }
110
+            } else {
111
+                close(sockfd);
112
+                continue;
113
+            }
114
+        }
115
+
116
+
117
+        /* Connected to host */
118
+        break;
119
+    }
120
+
121
+    if (!(p)) {
122
+        freeaddrinfo(servinfo);
123
+        if (sockfd >= 0)
124
+            close(sockfd);
125
+        return -1;
126
+    }
127
+
128
+    freeaddrinfo(servinfo);
129
+
130
+    /* Return to using a synchronous socket to make Linux happy */
131
+    if (useAsync) {
132
+        if (fcntl(sockfd, F_SETFL, flags) < 0) {
133
+            close(sockfd);
134
+            return -1;
135
+        }
136
+    }
137
+
138
+    return sockfd;
139
+}
140
+
141
+size_t encoded_size(const char *postdata)
142
+{
143
+    const char *p;
144
+    size_t len=0;
145
+
146
+    for (p = postdata; *p != '\0'; p++)
147
+        len += isalnum(*p) ? 1 : 3;
148
+
149
+    return len;
150
+}
151
+
152
+char *encode_data(const char *postdata)
153
+{
154
+    char *buf;
155
+    size_t bufsz, i, j;
156
+
157
+    bufsz = encoded_size(postdata);
158
+    if (bufsz == 0)
159
+        return NULL;
160
+
161
+    buf = cli_calloc(1, bufsz+1);
162
+    if (!(buf))
163
+        return NULL;
164
+
165
+    for (i=0, j=0; postdata[i] != '\0'; i++) {
166
+        if (isalnum(postdata[i])) {
167
+            buf[j++] = postdata[i];
168
+        } else {
169
+            sprintf(buf+j, "%%%02x", postdata[i]);
170
+            j += 3;
171
+        }
172
+    }
173
+
174
+    return buf;
175
+}
176
+
177
+void submit_post(const char *host, const char *port, const char *method, const char *url, const char *postdata, uint32_t timeout)
178
+{
179
+    int sockfd, n;
180
+    unsigned int i;
181
+    char *buf, *encoded=NULL;
182
+    size_t bufsz;
183
+    ssize_t recvsz;
184
+    char chunkedlen[21];
185
+    fd_set readfds;
186
+    struct timeval tv;
187
+    char *acceptable_methods[] = {
188
+        "GET",
189
+        "PUT",
190
+        "POST",
191
+        NULL
192
+    };
193
+
194
+    for (i=0; acceptable_methods[i] != NULL; i++)
195
+        if (!strcmp(method, acceptable_methods[i]))
196
+            break;
197
+
198
+    if (acceptable_methods[i] == NULL)
199
+        return;
200
+
201
+    bufsz = strlen(method);
202
+    bufsz += sizeof("   HTTP/1.1") + 2; /* Yes. Three blank spaces. +1 for the \n */
203
+    bufsz += strlen(url);
204
+    bufsz += sizeof("Host: \r\n");
205
+    bufsz += strlen(host);
206
+    bufsz += sizeof("Connection: Close\r\n");
207
+    bufsz += 4; /* +4 for \r\n\r\n */
208
+
209
+    if (!strcmp(method, "POST") || !strcmp(method, "PUT")) {
210
+        encoded = encode_data(postdata);
211
+        if (!(encoded))
212
+            return;
213
+
214
+        snprintf(chunkedlen, sizeof(chunkedlen), "%zu", strlen(encoded));
215
+        bufsz += sizeof("Content-Type: application/x-www-form-urlencoded\r\n");
216
+        bufsz += sizeof("Content-Length: \r\n");
217
+        bufsz += strlen(chunkedlen);
218
+        bufsz += strlen(encoded);
219
+    }
220
+
221
+    buf = cli_calloc(1, bufsz);
222
+    if (!(buf)) {
223
+        if ((encoded))
224
+            free(encoded);
225
+
226
+        return;
227
+    }
228
+
229
+    snprintf(buf, bufsz, "%s %s HTTP/1.1\r\n", method, url);
230
+    snprintf(buf+strlen(buf), bufsz-strlen(buf), "Host: %s\r\n", host);
231
+    snprintf(buf+strlen(buf), bufsz-strlen(buf), "Connection: Close\r\n");
232
+
233
+    if (!strcmp(method, "POST") || !strcmp(method, "PUT")) {
234
+        snprintf(buf+strlen(buf), bufsz-strlen(buf), "Content-Type: application/x-www-form-urlencoded\r\n");
235
+        snprintf(buf+strlen(buf), bufsz-strlen(buf), "Content-Length: %s\r\n", chunkedlen);
236
+        snprintf(buf+strlen(buf), bufsz-strlen(buf), "\r\n");
237
+        snprintf(buf+strlen(buf), bufsz-strlen(buf), "%s", encoded);
238
+        free(encoded);
239
+    }
240
+
241
+    sockfd = connect_host(host, port, timeout, 1);
242
+    if (sockfd < 0) {
243
+        free(buf);
244
+        return;
245
+    }
246
+
247
+    cli_dbgmsg("stats - Connected to %s:%s\n", host, port);
248
+
249
+    if (send(sockfd, buf, strlen(buf), 0) != strlen(buf)) {
250
+        close(sockfd);
251
+        free(buf);
252
+        return;
253
+    }
254
+
255
+    cli_dbgmsg("stats - Sending %s\n", buf);
256
+
257
+    while (1) {
258
+        FD_ZERO(&readfds);
259
+        FD_SET(sockfd, &readfds);
260
+
261
+        /*
262
+         * Check to make sure the stats submitted okay (so that we don't kill the HTTP request
263
+         * while it's being processed). Give a ten-second timeout so we don't have a major
264
+         * impact on scanning.
265
+         */
266
+        tv.tv_sec = timeout;
267
+        tv.tv_usec = 0;
268
+        if ((n = select(sockfd+1, &readfds, NULL, NULL, &tv)) <= 0)
269
+            break;
270
+
271
+        if (FD_ISSET(sockfd, &readfds)) {
272
+            memset(buf, 0x00, bufsz);
273
+            if ((recvsz = recv(sockfd, buf, bufsz-1, 0) <= 0))
274
+                break;
275
+
276
+            buf[bufsz-1] = '\0';
277
+
278
+            if (strstr(buf, "STATOK")) {
279
+                cli_dbgmsg("stats - Data received okay\n");
280
+                break;
281
+            }
282
+        }
283
+    }
284
+
285
+    close(sockfd);
286
+    free(buf);
287
+}