"Fossies" - the Fresh Open Source Software Archive 
Member "tlswrap-1.04/parse.c" (25 Nov 2006, 13325 Bytes) of package /linux/privat/old/tlswrap-1.04.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "parse.c" see the
Fossies "Dox" file reference documentation.
1 /*
2 * Copyright (c) 2002-2006 Tomas Svensson <ts@codepix.com>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
17 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
18 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
19 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include <stdio.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #ifdef WIN32
32 #define WIN32_LEAN_AND_MEAN /* Exclude rarely-used stuff from Windows headers */
33 #include <Winsock2.h>
34 #define snprintf _snprintf
35 #define strcasecmp _stricmp
36 #define strncasecmp _strnicmp
37 typedef __int32 ssize_t;
38 int write(SOCKET s, void *buf, int len);
39 int read(SOCKET s, void *buf, int len);
40 #else
41 #include <unistd.h>
42 #endif
43
44 #include "parse.h"
45 #include "misc.h"
46 #include "network.h"
47 #include "tls.h"
48
49 extern int debug;
50
51 struct ftp_cmd {
52 char *cmd;
53 int dir;
54 };
55
56 void intercept_user_buf(struct user_data *ud, char *buf, ssize_t *len)
57 {
58 int i;
59
60 struct ftp_cmd cmd[] = {
61 { "LIST", DATA_DOWN },
62 { "RETR", DATA_DOWN },
63 { "NLST", DATA_DOWN },
64 { "STOR", DATA_UP },
65 { "APPE", DATA_UP },
66 { "PORT", DATA_PORT },
67 { "EPRT", DATA_PORT },
68 { (char*)NULL, 0 }
69 };
70
71 if (debug)
72 printf("intercept_user_buf\n");
73
74 if (*len < 4)
75 return;
76
77 for (i = 0; cmd[i].cmd; i++)
78 if (memcmp(buf, cmd[i].cmd, 4) == 0) {
79 if (cmd[i].dir != DATA_PORT) {
80 ud->data_direction = cmd[i].dir;
81 if (debug)
82 printf("set direction for %s\n", cmd[i].cmd);
83 } else if (!ud->active) {
84 unsigned int port;
85 char ip[17], *ptr;
86 int r;
87 struct dns_msg dns;
88
89 if (debug)
90 printf("data port\n");
91 if ((r = port_to_ipport(buf, ip, sizeof(ip), &port))
92 == 0) {
93 ud->active = 1;
94 if (debug)
95 printf("PORT - ip: %s port: %u\n",ip, port);
96 strlcpy(ud->serv_data_host, ip,
97 sizeof(ud->serv_data_host));
98 snprintf(ud->serv_data_port, sizeof(ud->serv_data_port),
99 "%u", port);
100 strlcpy(dns.hostname, ip, sizeof(dns.hostname));
101 strlcpy(dns.port, ud->serv_data_port, sizeof(dns.port));
102 ptr = (char*)memchr(buf, '\n', *len);
103
104 if (ptr != NULL)
105 *len = 0;
106 setup_connect_2(ud, &dns, 1);
107 if (ud->data_connected == CONN_YES)
108 open_local_dataport(ud);
109 } else if (r == -1) { // unsupported EPRT network number
110 *len = 0;
111 print_to_ud(ud,"522 Network protocol not supported, use (1)\r\n");
112 }
113 }
114 }
115 }
116
117 int change_serv_buf(struct user_data *ud, char *buf)
118 {
119 unsigned int port;
120 char ip[17];
121 int r;
122 struct dns_msg dns;
123 char *ptr, *ptr2;
124
125 if (ud->prot == 'C')
126 return 0;
127
128 if (memcmp(buf,"227 ",4) == 0) { /* PASV reply detected */
129 ud->epsv = 0;
130 if ((r = pasv_to_ipport(buf, ip, sizeof(ip), &port))
131 == 0) {
132 if (debug)
133 printf("ip: %s port: %u\n",ip, port);
134 strlcpy(ud->serv_data_host, ip,
135 sizeof(ud->serv_data_host));
136 snprintf(ud->serv_data_port, sizeof(ud->serv_data_port),
137 "%u", port);
138 strlcpy(dns.hostname, ip, sizeof(dns.hostname));
139 strlcpy(dns.port, ud->serv_data_port, sizeof(dns.port));
140 setup_connect_2(ud, &dns, 1);
141 if (ud->data_connected == CONN_YES) {
142 open_local_dataport(ud);
143 }
144 return 1;
145 }
146 else printf("change_serv_buf failed %d (%s)\n", r, buf);
147 } else if (memcmp(buf,"229 ",4) == 0) { /* EPSV reply detected */
148 if (debug)
149 printf("EPSV (%s)\n", buf);
150 ud->epsv = 1;
151 ptr = strstr(buf, "(|||");
152 if (ptr == NULL)
153 return 0;
154 ptr += 4;
155 if (strlen(ptr) < 3) return 0;
156 ptr2 = strstr(ptr, "|)");
157 if (ptr == NULL)
158 return 0;
159 *ptr2 = '\0';
160 strlcpy(ud->serv_data_port, ptr, sizeof(ud->serv_data_port));
161 strlcpy(ud->serv_data_host, ud->serv_host,
162 sizeof(ud->serv_data_host));
163 /*
164 strlcpy(dns.hostname, ud->serv_host, sizeof(dns.hostname));
165 */
166 dns = ud->serv_dns;
167 strlcpy(dns.port, ud->serv_data_port, sizeof(dns.port));
168 setup_connect_2(ud, &dns, 1);
169 if (ud->data_connected == CONN_YES)
170 open_local_dataport(ud);
171 return 1;
172
173 }
174 return 0;
175 }
176
177 void open_local_dataport(struct user_data *ud)
178 {
179 char port[6];
180 char pasv[25];
181 char tmp[80], *ep;
182 char myip[NI_MAXHOST];
183
184 port[0] = '\0';
185 if (ud->active)
186 get_local_ip(ud->serv_fd, myip, sizeof(myip));
187 else
188 get_local_ip(ud->user_fd, myip, sizeof(myip));
189 if (debug)
190 printf("my local ip is %s\n", myip);
191 ud->user_data_fd = setup_listen(5, myip, port, sizeof(port));
192 if (debug)
193 printf("open_local_dataport: fd = %d, port = %s\n",ud->user_data_fd, port);
194 ipport_to_pasv(pasv, sizeof(pasv), myip, strtol(port, &ep, 10));
195 if (ud->active) {
196 snprintf(tmp, sizeof(tmp), "PORT %s\r\n", pasv);
197 print_to_serv(ud, tmp);
198 } else {
199 if (ud->epsv)
200 snprintf(tmp, sizeof(tmp), "229 Entering Extended Passive Mode (|||%u|)\r\n",(unsigned int)strtol(port, &ep, 10));
201 else
202 snprintf(tmp, sizeof(tmp), "227 Entering Passive Mode (%s)\r\n",pasv);
203 write(ud->user_fd, tmp, strlen(tmp));
204 }
205 if (debug)
206 printf("sent %s",tmp);
207 ud->data_connected = CONN_DATA_LISTEN;
208 }
209
210 int pasv_to_ipport(char *buf, char *ip, int iplen, unsigned int *port)
211 {
212 char *ep, *ptr, *ptr2;
213 int i;
214 int num;
215
216 if ( (ptr = strchr(buf, '(')) == NULL)
217 return 1;
218
219 ptr2 = ++ptr;
220 for (i = 0; i<4; i++) {
221 if ((ptr = strchr(++ptr, ',') ) == NULL)
222 return 2;
223 *ptr = '.';
224 }
225 *ptr++ = '\0';
226 strlcpy(ip, ptr2, iplen);
227 ptr2 = ptr;
228 if ((ptr = strchr(ptr, ',')) == NULL)
229 return 3;
230 *ptr++ = '\0';
231 num = strtol(ptr2, &ep, 10);
232 if (num < 0 || *ep != '\0')
233 return 4;
234 *port = num * 256;
235 ptr2 = ptr;
236 if ((ptr = strchr(ptr, ')')) == NULL)
237 return 5;
238 *ptr = '\0';
239 num = strtol(ptr2, &ep, 10);
240 if (num < 0 || *ep != '\0') {
241 printf("pasv_to_ipport FAILED with %s that got changed into %d (at %s)\n", ptr2, num, ep);
242 return 6;
243 }
244 *port += num;
245
246 return 0;
247 }
248
249 void
250 ipport_to_pasv(char *buf, int len, const char *ip, unsigned int port)
251 {
252 char *ptr;
253 char tmp[16];
254
255 strlcpy(tmp, ip, sizeof(tmp));
256 while ( (ptr = strchr(tmp, '.')) )
257 *ptr = ',';
258 snprintf(buf, len, "%s,%d,%d", tmp, port / 256, port % 256);
259 }
260
261 int port_to_ipport(char *buf, char *ip, int iplen, unsigned int *port)
262 {
263 char *ep, *ptr, *ptr2, sep;
264 int i;
265 int num;
266
267 if (memcmp(buf, "PORT", 4) == 0) {
268
269 if ( (ptr = strchr(buf, ' ')) == NULL)
270 return 1;
271
272 ptr2 = ++ptr;
273 for (i = 0; i<4; i++) {
274 if ((ptr = strchr(++ptr, ',') ) == NULL)
275 return 2;
276 *ptr = '.';
277 }
278 *ptr++ = '\0';
279 strlcpy(ip, ptr2, iplen);
280 ptr2 = ptr;
281 if ((ptr = strchr(ptr, ',')) == NULL)
282 return 3;
283 *ptr++ = '\0';
284 num = strtol(ptr2, &ep, 10);
285 if (num < 0 || *ep != '\0')
286 return 4;
287 *port = num * 256;
288 ptr2 = ptr;
289 if ((ptr = strchr(ptr, '\r')) == NULL)
290 return 5;
291 *ptr = '\0';
292 num = strtol(ptr2, &ep, 10);
293 if (num < 0 || *ep != '\0') {
294 printf("port_to_ipport FAILED with %s that got changed into %d (at %s)\n", ptr2, num, ep);
295 return 6;
296 }
297 *port += num;
298 } else { // EPRT
299 if ((ptr = strchr(buf, ' ')) == NULL)
300 return 1;
301 sep = *(++ptr);
302 if ((ptr2 = strchr(++ptr, sep)) == NULL)
303 return 1;
304 *ptr2 = '\0';
305 num = strtol(ptr, &ep, 10);
306 if (num != 1)
307 return -1; // unsupported network
308 ptr2++; // ptr2 now points to beginning of the ip address
309 if ((ptr = strchr(ptr2, sep)) == NULL)
310 return 1;
311 *ptr = '\0';
312 strlcpy(ip, ptr2, iplen);
313 ptr++; // ptr now points to beginning of the port number
314 if ((ptr2 = strchr(ptr, sep)) == NULL)
315 return 1;
316 *ptr2 = '\0';
317 num = strtol(ptr, &ep, 10);
318 if (num < 0 || *ep != '\0') {
319 printf("port_to_ipport FAILED with %s that got changed into %d (at %s)\n", ptr2, num, ep);
320 return 6;
321 }
322 *port = num;
323
324 }
325 return 0;
326 }
327
328 int
329 parse_serv_buf(struct user_data *ud, int index, char *ucertspath, char *cafile)
330 {
331 int size;
332 char dst[BUF_SIZE], s[100];
333
334 if ( (size = extr_str(ud->serv_input, BUF_SIZE, dst, sizeof(dst))) == 0)
335 return 1; /* Nothing could be extracted */
336
337
338 if ((ud->serv_status == SERV_CONN) && (strncasecmp(dst,"220 ",4) == 0) ) {
339 print_to_serv(ud, "AUTH TLS\r\n");
340 ud->serv_status = SERV_AUTH;
341 } else if ((ud->serv_status == SERV_AUTH) && (strncasecmp(dst,"234 ",4) == 0) ) {
342 ud->serv_status = SERV_TLS;
343 tls_auth(ud, 0, ucertspath, cafile);
344 } else if ((ud->serv_status == SERV_TLS_OK) && (strncasecmp(dst,"200 ",4) == 0) ) {
345 ud->serv_status = SERV_PBSZ;
346 snprintf(s, sizeof(s), "PROT %c\r\n", ud->prot);
347 if (debug)
348 printf(s);
349 print_to_serv(ud,s);
350 } else if ((ud->serv_status == SERV_PBSZ) && (strncasecmp(dst,"200 ",4) == 0) ) {
351 ud->serv_status = SERV_PROT;
352 snprintf(s, sizeof(s), "USER %s\r\n",ud->user);
353 print_to_serv(ud, s);
354 ud->delay_prot = 0;
355 } else if ((ud->serv_status == SERV_PBSZ) && (strncasecmp(dst,"530 ",4) == 0) ) {
356 ud->serv_status = SERV_PROT;
357 snprintf(s, sizeof(s), "USER %s\r\n",ud->user);
358 print_to_serv(ud, s);
359 ud->delay_prot = 1;
360 } else if ((ud->serv_status == SERV_PROT) && (strncasecmp(dst,"331 ",4) == 0) ) {
361 snprintf(s, sizeof(s), "PASS %s\r\n",ud->pass);
362 print_to_serv(ud, s);
363 if (!ud->delay_prot)
364 ud->serv_status = SERV_FLOW;
365 } else if (ud->delay_prot && (ud->serv_status == SERV_PROT) && (strncasecmp(dst,"230 ",4) == 0) ) {
366 snprintf(s, sizeof(s), "PROT %c\r\n", ud->prot);
367 if (debug)
368 printf(s);
369 print_to_serv(ud,s);
370 } else if (ud->delay_prot && (ud->serv_status == SERV_PROT) && (strncasecmp(dst,"200 ",4) == 0) ) {
371 write(ud->user_fd, "230 Bypassed login text because the ftpd can't handle PROT before USER.\r\n", 73);
372 ud->serv_status = SERV_FLOW;
373 }
374 memmove(ud->serv_input, &ud->serv_input[size], BUF_SIZE - size - 1);
375 ud->serv_ptr -= size;
376 return 0;
377 }
378
379
380 int
381 parse_buf(struct user_data *ud, int index, int dns_write_pipe, char *token)
382 {
383 int size, updated;
384 char dst[BUF_SIZE], *ptr, s[100], tmp[200];
385
386 if ( (size = extr_str(ud->user_input, BUF_SIZE, dst, sizeof(dst))) == 0)
387 return 1; /* Nothing could be extracted */
388
389 /* Parse starts here and is ugly */
390
391 if ((ud->connected == CONN_NO) && (strncasecmp(dst,"USER ",5) == 0)) {
392 strlcpy(tmp, dst + 5, sizeof(tmp));
393 ptr = memchr(tmp, token[1], strlen(tmp));
394 if (ptr != NULL) {
395 *ptr++ = 0;
396 if ( (strlen(tmp) > 0) && (strlen(ptr) > 0) ) {
397 updated = 0;
398 if (tmp[0] == token[0]) {
399 ud->prot = 'C'; /* Encrypt control only */
400 strlcpy(ud->user, tmp + 1, sizeof(ud->user));
401 memmove(tmp, tmp + 1, strlen(tmp));
402 updated = 1;
403 }
404 if (tmp[0] == token[3]) { // Implicit SSL crap
405 if (!updated)
406 ud->prot = 'P'; /* Encrypt everything */
407 strlcpy(ud->user, tmp + 1, sizeof(ud->user));
408 memmove(tmp, tmp + 1, strlen(tmp));
409 ud->issl = 1;
410 updated = 1;
411 }
412 if (tmp[0] == token[4]) { // + Set security level
413 if (!updated)
414 ud->prot = 'P'; /* Encrypt everything */
415 if ((tmp[1] - '0' >= 0) && (tmp[1] - '0' <= 4))
416 ud->sec_level = tmp[1] - '0';
417 strlcpy(ud->user, tmp + 2, sizeof(ud->user));
418 updated = 1;
419 }
420 if (!updated) {
421 ud->prot = 'P'; /* Encrypt everything */
422 strlcpy(ud->user, tmp, sizeof(ud->user));
423 }
424 strlcpy(ud->serv_host, ptr, sizeof(ud->serv_host));
425 ptr = memchr(ud->serv_host, token[2], strlen(ud->serv_host));
426 if (ptr != NULL) {
427 *ptr++ = 0;
428 if (strlen(ptr) > 0)
429 strlcpy(ud->serv_port, ptr, sizeof(ud->serv_port));
430 else
431 ptr = NULL;
432 }
433
434 if (ptr == NULL)
435 strlcpy(ud->serv_port, "21", sizeof(ud->serv_port));
436 ud->connected = CONN_USER;
437 if (debug)
438 printf("Username: %s, Host: %s, Port: %s\n",ud->user,
439 ud->serv_host, ud->serv_port);
440 snprintf(s, sizeof(s), "331 Password required for %s.\r\n", ud->user);
441 print_to_ud(ud, s);
442 }
443 } else {
444 if (debug)
445 printf("don't find any @\n");
446 user_close(ud);
447 }
448 } else
449
450 /* Attempt connection directly after receiving PASS */
451
452 if ((ud->connected == CONN_USER) && (strncasecmp(dst,"PASS ",5) == 0)) {
453 strlcpy(ud->pass, dst + 5, sizeof(ud->pass));
454 ud->connected = CONN_PASS;
455 setup_connect_1(ud, index, ud->serv_host, ud->serv_port, dns_write_pipe);
456 } else
457
458 /* Reject AUTH stuff */
459
460 if ((ud->connected == CONN_NO) && (strncasecmp(dst,"AUTH ",5) == 0)) {
461 snprintf(s, sizeof(s), "502 RFC 2228 authentication not implemented.\r\n");
462 print_to_ud(ud, s);
463 }
464
465 memmove(ud->user_input, &ud->user_input[size], BUF_SIZE - size - 1);
466 ud->user_ptr -= size;
467 return 0;
468 }
469