1 /* 2 * Copyright (C) 1997-2003 by Darren Reed 3 * 4 * See the IPFILTER.LICENCE file for details on licencing. 5 * 6 * $Id: ip_ftp_pxy.c,v 2.88.2.15 2005/03/19 19:38:10 darrenr Exp $ 7 * 8 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 9 * Use is subject to license terms. 10 * 11 * Simple FTP transparent proxy for in-kernel use. For use with the NAT 12 * code. 13 */ 14 15 #define IPF_FTP_PROXY 16 17 #define IPF_MINPORTLEN 18 18 #define IPF_MAXPORTLEN 30 19 #define IPF_MIN227LEN 39 20 #define IPF_MAX227LEN 51 21 #define IPF_MIN229LEN 47 22 #define IPF_MAX229LEN 51 23 24 #define FTPXY_GO 0 25 #define FTPXY_INIT 1 26 #define FTPXY_USER_1 2 27 #define FTPXY_USOK_1 3 28 #define FTPXY_PASS_1 4 29 #define FTPXY_PAOK_1 5 30 #define FTPXY_AUTH_1 6 31 #define FTPXY_AUOK_1 7 32 #define FTPXY_ADAT_1 8 33 #define FTPXY_ADOK_1 9 34 #define FTPXY_ACCT_1 10 35 #define FTPXY_ACOK_1 11 36 #define FTPXY_USER_2 12 37 #define FTPXY_USOK_2 13 38 #define FTPXY_PASS_2 14 39 #define FTPXY_PAOK_2 15 40 41 /* 42 * Values for FTP commands. Numerics cover 0-999 43 */ 44 #define FTPXY_C_PASV 1000 45 46 typedef struct ifs_ftppxy { 47 frentry_t ftppxyfr; 48 int ftp_proxy_init; 49 int ippr_ftp_pasvonly; 50 int ippr_ftp_insecure; 51 /* Do not require logins before transfers */ 52 int ippr_ftp_pasvrdr; 53 int ippr_ftp_forcepasv; 54 /* PASV must be last command prior to 227 */ 55 /* 56 * 1 - security 57 * 2 - errors 58 * 3 - error debugging 59 * 4 - parsing errors 60 * 5 - parsing info 61 * 6 - parsing debug 62 */ 63 int ippr_ftp_debug; 64 ipftuneable_t ftptune; 65 } ifs_ftppxy_t; 66 67 int ippr_ftp_client __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int, 68 ifs_ftppxy_t *)); 69 int ippr_ftp_complete __P((char *, size_t)); 70 int ippr_ftp_in __P((fr_info_t *, ap_session_t *, nat_t *, void *)); 71 int ippr_ftp_init __P((void **, ipf_stack_t *)); 72 void ippr_ftp_fini __P((void **, ipf_stack_t *)); 73 int ippr_ftp_new __P((fr_info_t *, ap_session_t *, nat_t *, void *)); 74 int ippr_ftp_out __P((fr_info_t *, ap_session_t *, nat_t *, void *)); 75 int ippr_ftp_pasv __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int, 76 ifs_ftppxy_t *)); 77 int ippr_ftp_epsv __P((fr_info_t *, ip_t *, nat_t *, ftpside_t *, int, 78 ifs_ftppxy_t *)); 79 int ippr_ftp_port __P((fr_info_t *, ip_t *, nat_t *, ftpside_t *, int, 80 ifs_ftppxy_t *)); 81 int ippr_ftp_process __P((fr_info_t *, nat_t *, ftpinfo_t *, int, 82 ifs_ftppxy_t *)); 83 int ippr_ftp_server __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int, 84 ifs_ftppxy_t *)); 85 int ippr_ftp_valid __P((ftpinfo_t *, int, char *, size_t, ifs_ftppxy_t *)); 86 int ippr_ftp_server_valid __P((ftpside_t *, char *, size_t, ifs_ftppxy_t *)); 87 int ippr_ftp_client_valid __P((ftpside_t *, char *, size_t, ifs_ftppxy_t *)); 88 u_short ippr_ftp_atoi __P((char **)); 89 int ippr_ftp_pasvreply __P((fr_info_t *, ip_t *, nat_t *, ftpside_t *, 90 u_int, char *, char *, u_int, ifs_ftppxy_t *)); 91 92 /* 93 * Initialize local structures. 94 */ 95 int ippr_ftp_init(private, ifs) 96 void **private; 97 ipf_stack_t *ifs; 98 { 99 ifs_ftppxy_t *ifsftp; 100 101 KMALLOC(ifsftp, ifs_ftppxy_t *); 102 if (ifsftp == NULL) 103 return -1; 104 105 bzero((char *)&ifsftp->ftppxyfr, sizeof(ifsftp->ftppxyfr)); 106 ifsftp->ftppxyfr.fr_ref = 1; 107 ifsftp->ftppxyfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; 108 MUTEX_INIT(&ifsftp->ftppxyfr.fr_lock, "FTP Proxy Mutex"); 109 ifsftp->ftp_proxy_init = 1; 110 ifsftp->ippr_ftp_pasvonly = 0; 111 ifsftp->ippr_ftp_insecure = 0; 112 ifsftp->ippr_ftp_pasvrdr = 0; 113 ifsftp->ippr_ftp_forcepasv = 0; 114 #if defined(_KERNEL) 115 ifsftp->ippr_ftp_debug = 0; 116 #else 117 ifsftp->ippr_ftp_debug = 2; 118 #endif 119 bzero((char *)&ifsftp->ftptune, sizeof(ifsftp->ftptune)); 120 ifsftp->ftptune.ipft_pint = (uint_t *)&ifsftp->ippr_ftp_debug; 121 ifsftp->ftptune.ipft_name = "ippr_ftp_debug"; 122 ifsftp->ftptune.ipft_max = 10; 123 ifsftp->ftptune.ipft_sz = sizeof(ifsftp->ippr_ftp_debug); 124 ifsftp->ftptune.ipft_next = NULL; 125 126 (void) fr_addipftune(&ifsftp->ftptune, ifs); 127 128 *private = (void *)ifsftp; 129 130 return 0; 131 } 132 133 134 void ippr_ftp_fini(private, ifs) 135 void **private; 136 ipf_stack_t *ifs; 137 { 138 ifs_ftppxy_t *ifsftp = *((ifs_ftppxy_t **)private); 139 140 (void) fr_delipftune(&ifsftp->ftptune, ifs); 141 142 if (ifsftp->ftp_proxy_init == 1) { 143 MUTEX_DESTROY(&ifsftp->ftppxyfr.fr_lock); 144 ifsftp->ftp_proxy_init = 0; 145 } 146 147 KFREE(ifsftp); 148 *private = NULL; 149 } 150 151 152 /*ARGSUSED*/ 153 int ippr_ftp_new(fin, aps, nat, private) 154 fr_info_t *fin; 155 ap_session_t *aps; 156 nat_t *nat; 157 void *private; 158 { 159 ftpinfo_t *ftp; 160 ftpside_t *f; 161 162 KMALLOC(ftp, ftpinfo_t *); 163 if (ftp == NULL) 164 return -1; 165 166 fin = fin; /* LINT */ 167 nat = nat; /* LINT */ 168 169 aps->aps_data = ftp; 170 aps->aps_psiz = sizeof(ftpinfo_t); 171 172 bzero((char *)ftp, sizeof(*ftp)); 173 f = &ftp->ftp_side[0]; 174 f->ftps_rptr = f->ftps_buf; 175 f->ftps_wptr = f->ftps_buf; 176 f = &ftp->ftp_side[1]; 177 f->ftps_rptr = f->ftps_buf; 178 f->ftps_wptr = f->ftps_buf; 179 ftp->ftp_passok = FTPXY_INIT; 180 ftp->ftp_incok = 0; 181 return 0; 182 } 183 184 185 int ippr_ftp_port(fin, ip, nat, f, dlen, ifsftp) 186 fr_info_t *fin; 187 ip_t *ip; 188 nat_t *nat; 189 ftpside_t *f; 190 int dlen; 191 ifs_ftppxy_t *ifsftp; 192 { 193 tcphdr_t *tcp, tcph, *tcp2 = &tcph; 194 char newbuf[IPF_FTPBUFSZ], *s; 195 struct in_addr swip, swip2; 196 u_int a1, a2, a3, a4; 197 int inc, off, flags; 198 u_short a5, a6, sp; 199 size_t nlen, olen; 200 fr_info_t fi; 201 nat_t *nat2; 202 mb_t *m; 203 ipf_stack_t *ifs = fin->fin_ifs; 204 205 m = fin->fin_m; 206 tcp = (tcphdr_t *)fin->fin_dp; 207 off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff; 208 209 /* 210 * Check for client sending out PORT message. 211 */ 212 if (dlen < IPF_MINPORTLEN) { 213 if (ifsftp->ippr_ftp_debug > 1) 214 printf("ippr_ftp_port:dlen(%d) < IPF_MINPORTLEN\n", 215 dlen); 216 return 0; 217 } 218 /* 219 * Skip the PORT command + space 220 */ 221 s = f->ftps_rptr + 5; 222 /* 223 * Pick out the address components, two at a time. 224 */ 225 a1 = ippr_ftp_atoi(&s); 226 if (s == NULL) { 227 if (ifsftp->ippr_ftp_debug > 1) 228 printf("ippr_ftp_port:ippr_ftp_atoi(%d) failed\n", 1); 229 return 0; 230 } 231 a2 = ippr_ftp_atoi(&s); 232 if (s == NULL) { 233 if (ifsftp->ippr_ftp_debug > 1) 234 printf("ippr_ftp_port:ippr_ftp_atoi(%d) failed\n", 2); 235 return 0; 236 } 237 238 /* 239 * Check that IP address in the PORT/PASV reply is the same as the 240 * sender of the command - prevents using PORT for port scanning. 241 */ 242 a1 <<= 16; 243 a1 |= a2; 244 if (((nat->nat_dir == NAT_OUTBOUND) && 245 (a1 != ntohl(nat->nat_inip.s_addr))) || 246 ((nat->nat_dir == NAT_INBOUND) && 247 (a1 != ntohl(nat->nat_oip.s_addr)))) { 248 if (ifsftp->ippr_ftp_debug > 0) 249 printf("ippr_ftp_port:%s != nat->nat_inip\n", "a1"); 250 return APR_ERR(1); 251 } 252 253 a5 = ippr_ftp_atoi(&s); 254 if (s == NULL) { 255 if (ifsftp->ippr_ftp_debug > 1) 256 printf("ippr_ftp_port:ippr_ftp_atoi(%d) failed\n", 3); 257 return 0; 258 } 259 if (*s == ')') 260 s++; 261 262 /* 263 * check for CR-LF at the end. 264 */ 265 if (*s == '\n') 266 s--; 267 if ((*s == '\r') && (*(s + 1) == '\n')) { 268 s += 2; 269 a6 = a5 & 0xff; 270 } else { 271 if (ifsftp->ippr_ftp_debug > 1) 272 printf("ippr_ftp_port:missing %s\n", "cr-lf"); 273 return 0; 274 } 275 276 a5 >>= 8; 277 a5 &= 0xff; 278 sp = a5 << 8 | a6; 279 /* 280 * Don't allow the PORT command to specify a port < 1024 due to 281 * security crap. 282 */ 283 if (sp < 1024) { 284 if (ifsftp->ippr_ftp_debug > 0) 285 printf("ippr_ftp_port:sp(%d) < 1024\n", sp); 286 return 0; 287 } 288 /* 289 * Calculate new address parts for PORT command 290 */ 291 if (nat->nat_dir == NAT_INBOUND) 292 a1 = ntohl(nat->nat_oip.s_addr); 293 else 294 a1 = ntohl(ip->ip_src.s_addr); 295 a2 = (a1 >> 16) & 0xff; 296 a3 = (a1 >> 8) & 0xff; 297 a4 = a1 & 0xff; 298 a1 >>= 24; 299 olen = s - f->ftps_rptr; 300 /* DO NOT change this to snprintf! */ 301 #if defined(SNPRINTF) && defined(_KERNEL) 302 (void) SNPRINTF(newbuf, sizeof(newbuf), "%s %u,%u,%u,%u,%u,%u\r\n", 303 "PORT", a1, a2, a3, a4, a5, a6); 304 #else 305 (void) sprintf(newbuf, "%s %u,%u,%u,%u,%u,%u\r\n", 306 "PORT", a1, a2, a3, a4, a5, a6); 307 #endif 308 309 nlen = strlen(newbuf); 310 inc = nlen - olen; 311 if ((inc + ip->ip_len) > 65535) { 312 if (ifsftp->ippr_ftp_debug > 0) 313 printf("ippr_ftp_port:inc(%d) + ip->ip_len > 65535\n", 314 inc); 315 return 0; 316 } 317 318 #if !defined(_KERNEL) 319 bcopy(newbuf, MTOD(m, char *) + off, nlen); 320 #else 321 # if defined(MENTAT) 322 if (inc < 0) 323 (void)adjmsg(m, inc); 324 # else /* defined(MENTAT) */ 325 /* 326 * m_adj takes care of pkthdr.len, if required and treats inc<0 to 327 * mean remove -len bytes from the end of the packet. 328 * The mbuf chain will be extended if necessary by m_copyback(). 329 */ 330 if (inc < 0) 331 m_adj(m, inc); 332 # endif /* defined(MENTAT) */ 333 #endif /* !defined(_KERNEL) */ 334 COPYBACK(m, off, nlen, newbuf); 335 336 if (inc != 0) { 337 ip->ip_len += inc; 338 fin->fin_dlen += inc; 339 fin->fin_plen += inc; 340 } 341 342 /* 343 * The server may not make the connection back from port 20, but 344 * it is the most likely so use it here to check for a conflicting 345 * mapping. 346 */ 347 bcopy((char *)fin, (char *)&fi, sizeof(fi)); 348 fi.fin_flx |= FI_IGNORE; 349 fi.fin_data[0] = sp; 350 fi.fin_data[1] = fin->fin_data[1] - 1; 351 /* 352 * Add skeleton NAT entry for connection which will come back the 353 * other way. 354 */ 355 if (nat->nat_dir == NAT_OUTBOUND) 356 nat2 = nat_outlookup(&fi, NAT_SEARCH|IPN_TCP, nat->nat_p, 357 nat->nat_inip, nat->nat_oip); 358 else 359 nat2 = nat_inlookup(&fi, NAT_SEARCH|IPN_TCP, nat->nat_p, 360 nat->nat_inip, nat->nat_oip); 361 if (nat2 == NULL) { 362 int slen; 363 364 slen = ip->ip_len; 365 ip->ip_len = fin->fin_hlen + sizeof(*tcp2); 366 bzero((char *)tcp2, sizeof(*tcp2)); 367 tcp2->th_win = htons(8192); 368 tcp2->th_sport = htons(sp); 369 TCP_OFF_A(tcp2, 5); 370 tcp2->th_flags = TH_SYN; 371 tcp2->th_dport = 0; /* XXX - don't specify remote port */ 372 fi.fin_data[1] = 0; 373 fi.fin_dlen = sizeof(*tcp2); 374 fi.fin_plen = fi.fin_hlen + sizeof(*tcp2); 375 fi.fin_dp = (char *)tcp2; 376 fi.fin_fr = &ifsftp->ftppxyfr; 377 fi.fin_out = nat->nat_dir; 378 fi.fin_flx &= FI_LOWTTL|FI_FRAG|FI_TCPUDP|FI_OPTIONS|FI_IGNORE; 379 swip = ip->ip_src; 380 swip2 = ip->ip_dst; 381 if (nat->nat_dir == NAT_OUTBOUND) { 382 fi.fin_fi.fi_saddr = nat->nat_inip.s_addr; 383 ip->ip_src = nat->nat_inip; 384 } else if (nat->nat_dir == NAT_INBOUND) { 385 fi.fin_fi.fi_saddr = nat->nat_oip.s_addr; 386 ip->ip_src = nat->nat_oip; 387 } 388 389 flags = NAT_SLAVE|IPN_TCP|SI_W_DPORT; 390 if (nat->nat_dir == NAT_INBOUND) 391 flags |= NAT_NOTRULEPORT; 392 nat2 = nat_new(&fi, nat->nat_ptr, NULL, flags, nat->nat_dir); 393 394 if (nat2 != NULL) { 395 (void) nat_proto(&fi, nat2, IPN_TCP); 396 nat_update(&fi, nat2, nat->nat_ptr); 397 fi.fin_ifp = NULL; 398 if (nat->nat_dir == NAT_INBOUND) { 399 fi.fin_fi.fi_daddr = nat->nat_inip.s_addr; 400 ip->ip_dst = nat->nat_inip; 401 } 402 (void) fr_addstate(&fi, &nat2->nat_state, SI_W_DPORT); 403 } 404 ip->ip_len = slen; 405 ip->ip_src = swip; 406 ip->ip_dst = swip2; 407 } else { 408 ipstate_t *is; 409 410 nat_update(&fi, nat2, nat->nat_ptr); 411 READ_ENTER(&ifs->ifs_ipf_state); 412 is = nat2->nat_state; 413 if (is != NULL) { 414 MUTEX_ENTER(&is->is_lock); 415 (void)fr_tcp_age(&is->is_sti, &fi, ifs->ifs_ips_tqtqb, 416 is->is_flags); 417 MUTEX_EXIT(&is->is_lock); 418 } 419 RWLOCK_EXIT(&ifs->ifs_ipf_state); 420 } 421 return APR_INC(inc); 422 } 423 424 425 int ippr_ftp_client(fin, ip, nat, ftp, dlen, ifsftp) 426 fr_info_t *fin; 427 nat_t *nat; 428 ftpinfo_t *ftp; 429 ip_t *ip; 430 int dlen; 431 ifs_ftppxy_t *ifsftp; 432 { 433 char *rptr, *wptr, cmd[6], c; 434 ftpside_t *f; 435 int inc, i; 436 437 inc = 0; 438 f = &ftp->ftp_side[0]; 439 rptr = f->ftps_rptr; 440 wptr = f->ftps_wptr; 441 442 for (i = 0; (i < 5) && (i < dlen); i++) { 443 c = rptr[i]; 444 if (ISALPHA(c)) { 445 cmd[i] = TOUPPER(c); 446 } else { 447 cmd[i] = c; 448 } 449 } 450 cmd[i] = '\0'; 451 452 ftp->ftp_incok = 0; 453 if (!strncmp(cmd, "USER ", 5) || !strncmp(cmd, "XAUT ", 5)) { 454 if (ftp->ftp_passok == FTPXY_ADOK_1 || 455 ftp->ftp_passok == FTPXY_AUOK_1) { 456 ftp->ftp_passok = FTPXY_USER_2; 457 ftp->ftp_incok = 1; 458 } else { 459 ftp->ftp_passok = FTPXY_USER_1; 460 ftp->ftp_incok = 1; 461 } 462 } else if (!strncmp(cmd, "AUTH ", 5)) { 463 ftp->ftp_passok = FTPXY_AUTH_1; 464 ftp->ftp_incok = 1; 465 } else if (!strncmp(cmd, "PASS ", 5)) { 466 if (ftp->ftp_passok == FTPXY_USOK_1) { 467 ftp->ftp_passok = FTPXY_PASS_1; 468 ftp->ftp_incok = 1; 469 } else if (ftp->ftp_passok == FTPXY_USOK_2) { 470 ftp->ftp_passok = FTPXY_PASS_2; 471 ftp->ftp_incok = 1; 472 } 473 } else if ((ftp->ftp_passok == FTPXY_AUOK_1) && 474 !strncmp(cmd, "ADAT ", 5)) { 475 ftp->ftp_passok = FTPXY_ADAT_1; 476 ftp->ftp_incok = 1; 477 } else if ((ftp->ftp_passok == FTPXY_PAOK_1 || 478 ftp->ftp_passok == FTPXY_PAOK_2) && 479 !strncmp(cmd, "ACCT ", 5)) { 480 ftp->ftp_passok = FTPXY_ACCT_1; 481 ftp->ftp_incok = 1; 482 } else if ((ftp->ftp_passok == FTPXY_GO) && 483 !ifsftp->ippr_ftp_pasvonly && 484 !strncmp(cmd, "PORT ", 5)) { 485 inc = ippr_ftp_port(fin, ip, nat, f, dlen, ifsftp); 486 } else if (ifsftp->ippr_ftp_insecure && !ifsftp->ippr_ftp_pasvonly && 487 !strncmp(cmd, "PORT ", 5)) { 488 inc = ippr_ftp_port(fin, ip, nat, f, dlen, ifsftp); 489 } 490 491 while ((*rptr++ != '\n') && (rptr < wptr)) 492 ; 493 f->ftps_rptr = rptr; 494 return inc; 495 } 496 497 498 int ippr_ftp_pasv(fin, ip, nat, ftp, dlen, ifsftp) 499 fr_info_t *fin; 500 ip_t *ip; 501 nat_t *nat; 502 ftpinfo_t *ftp; 503 int dlen; 504 ifs_ftppxy_t *ifsftp; 505 { 506 u_int a1, a2, a3, a4, data_ip; 507 char newbuf[IPF_FTPBUFSZ]; 508 char *s, *brackets[2]; 509 u_short a5, a6; 510 ftpside_t *f; 511 512 if (ifsftp->ippr_ftp_forcepasv != 0 && 513 ftp->ftp_side[0].ftps_cmds != FTPXY_C_PASV) { 514 if (ifsftp->ippr_ftp_debug > 0) 515 printf("ippr_ftp_pasv:ftps_cmds(%d) != FTPXY_C_PASV\n", 516 ftp->ftp_side[0].ftps_cmds); 517 return 0; 518 } 519 520 f = &ftp->ftp_side[1]; 521 522 #define PASV_REPLEN 24 523 /* 524 * Check for PASV reply message. 525 */ 526 if (dlen < IPF_MIN227LEN) { 527 if (ifsftp->ippr_ftp_debug > 1) 528 printf("ippr_ftp_pasv:dlen(%d) < IPF_MIN227LEN\n", 529 dlen); 530 return 0; 531 } else if (strncmp(f->ftps_rptr, 532 "227 Entering Passive Mod", PASV_REPLEN)) { 533 if (ifsftp->ippr_ftp_debug > 0) 534 printf("ippr_ftp_pasv:%d reply wrong\n", 227); 535 return 0; 536 } 537 538 brackets[0] = ""; 539 brackets[1] = ""; 540 /* 541 * Skip the PASV reply + space 542 */ 543 s = f->ftps_rptr + PASV_REPLEN; 544 while (*s && !ISDIGIT(*s)) { 545 if (*s == '(') { 546 brackets[0] = "("; 547 brackets[1] = ")"; 548 } 549 s++; 550 } 551 552 /* 553 * Pick out the address components, two at a time. 554 */ 555 a1 = ippr_ftp_atoi(&s); 556 if (s == NULL) { 557 if (ifsftp->ippr_ftp_debug > 1) 558 printf("ippr_ftp_pasv:ippr_ftp_atoi(%d) failed\n", 1); 559 return 0; 560 } 561 a2 = ippr_ftp_atoi(&s); 562 if (s == NULL) { 563 if (ifsftp->ippr_ftp_debug > 1) 564 printf("ippr_ftp_pasv:ippr_ftp_atoi(%d) failed\n", 2); 565 return 0; 566 } 567 568 /* 569 * check that IP address in the PASV reply is the same as the 570 * sender of the command - prevents using PASV for port scanning. 571 */ 572 a1 <<= 16; 573 a1 |= a2; 574 575 if (((nat->nat_dir == NAT_INBOUND) && 576 (a1 != ntohl(nat->nat_inip.s_addr))) || 577 ((nat->nat_dir == NAT_OUTBOUND) && 578 (a1 != ntohl(nat->nat_oip.s_addr)))) { 579 if (ifsftp->ippr_ftp_debug > 0) 580 printf("ippr_ftp_pasv:%s != nat->nat_oip\n", "a1"); 581 return 0; 582 } 583 584 a5 = ippr_ftp_atoi(&s); 585 if (s == NULL) { 586 if (ifsftp->ippr_ftp_debug > 1) 587 printf("ippr_ftp_pasv:ippr_ftp_atoi(%d) failed\n", 3); 588 return 0; 589 } 590 591 if (*s == ')') 592 s++; 593 if (*s == '.') 594 s++; 595 if (*s == '\n') 596 s--; 597 /* 598 * check for CR-LF at the end. 599 */ 600 if ((*s == '\r') && (*(s + 1) == '\n')) { 601 s += 2; 602 } else { 603 if (ifsftp->ippr_ftp_debug > 1) 604 printf("ippr_ftp_pasv:missing %s", "cr-lf\n"); 605 return 0; 606 } 607 608 a6 = a5 & 0xff; 609 a5 >>= 8; 610 /* 611 * Calculate new address parts for 227 reply 612 */ 613 if (nat->nat_dir == NAT_INBOUND) { 614 data_ip = nat->nat_outip.s_addr; 615 a1 = ntohl(data_ip); 616 } else 617 data_ip = htonl(a1); 618 619 a2 = (a1 >> 16) & 0xff; 620 a3 = (a1 >> 8) & 0xff; 621 a4 = a1 & 0xff; 622 a1 >>= 24; 623 624 #if defined(SNPRINTF) && defined(_KERNEL) 625 (void) SNPRINTF(newbuf, sizeof(newbuf), "%s %s%u,%u,%u,%u,%u,%u%s\r\n", 626 "227 Entering Passive Mode", brackets[0], a1, a2, a3, a4, 627 a5, a6, brackets[1]); 628 #else 629 (void) sprintf(newbuf, "%s %s%u,%u,%u,%u,%u,%u%s\r\n", 630 "227 Entering Passive Mode", brackets[0], a1, a2, a3, a4, 631 a5, a6, brackets[1]); 632 #endif 633 return ippr_ftp_pasvreply(fin, ip, nat, f, (a5 << 8 | a6), 634 newbuf, s, data_ip, ifsftp); 635 } 636 637 int ippr_ftp_pasvreply(fin, ip, nat, f, port, newmsg, s, data_ip, ifsftp) 638 fr_info_t *fin; 639 ip_t *ip; 640 nat_t *nat; 641 ftpside_t *f; 642 u_int port; 643 char *newmsg; 644 char *s; 645 u_int data_ip; 646 ifs_ftppxy_t *ifsftp; 647 { 648 int inc, off, nflags, sflags; 649 tcphdr_t *tcp, tcph, *tcp2; 650 struct in_addr swip, swip2; 651 struct in_addr data_addr; 652 size_t nlen, olen; 653 fr_info_t fi; 654 nat_t *nat2; 655 mb_t *m; 656 ipf_stack_t *ifs = fin->fin_ifs; 657 658 m = fin->fin_m; 659 tcp = (tcphdr_t *)fin->fin_dp; 660 off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff; 661 662 data_addr.s_addr = data_ip; 663 tcp2 = &tcph; 664 inc = 0; 665 666 667 olen = s - f->ftps_rptr; 668 nlen = strlen(newmsg); 669 inc = nlen - olen; 670 if ((inc + ip->ip_len) > 65535) { 671 if (ifsftp->ippr_ftp_debug > 0) 672 printf("ippr_ftp_pasv:inc(%d) + ip->ip_len > 65535\n", 673 inc); 674 return 0; 675 } 676 677 #if !defined(_KERNEL) 678 bcopy(newmsg, MTOD(m, char *) + off, nlen); 679 #else 680 # if defined(MENTAT) 681 if (inc < 0) 682 (void)adjmsg(m, inc); 683 # else /* defined(MENTAT) */ 684 /* 685 * m_adj takes care of pkthdr.len, if required and treats inc<0 to 686 * mean remove -len bytes from the end of the packet. 687 * The mbuf chain will be extended if necessary by m_copyback(). 688 */ 689 if (inc < 0) 690 m_adj(m, inc); 691 # endif /* defined(MENTAT) */ 692 #endif /* !defined(_KERNEL) */ 693 COPYBACK(m, off, nlen, newmsg); 694 695 if (inc != 0) { 696 ip->ip_len += inc; 697 fin->fin_dlen += inc; 698 fin->fin_plen += inc; 699 } 700 701 /* 702 * Add skeleton NAT entry for connection which will come back the 703 * other way. 704 */ 705 bcopy((char *)fin, (char *)&fi, sizeof(fi)); 706 fi.fin_flx |= FI_IGNORE; 707 fi.fin_data[0] = 0; 708 fi.fin_data[1] = port; 709 nflags = IPN_TCP|SI_W_SPORT; 710 if (ifsftp->ippr_ftp_pasvrdr && f->ftps_ifp) 711 nflags |= SI_W_DPORT; 712 if (nat->nat_dir == NAT_OUTBOUND) 713 nat2 = nat_outlookup(&fi, nflags|NAT_SEARCH, 714 nat->nat_p, nat->nat_inip, nat->nat_oip); 715 else 716 nat2 = nat_inlookup(&fi, nflags|NAT_SEARCH, 717 nat->nat_p, nat->nat_inip, nat->nat_oip); 718 if (nat2 == NULL) { 719 int slen; 720 721 slen = ip->ip_len; 722 ip->ip_len = fin->fin_hlen + sizeof(*tcp2); 723 bzero((char *)tcp2, sizeof(*tcp2)); 724 tcp2->th_win = htons(8192); 725 tcp2->th_sport = 0; /* XXX - fake it for nat_new */ 726 TCP_OFF_A(tcp2, 5); 727 tcp2->th_flags = TH_SYN; 728 fi.fin_data[1] = port; 729 fi.fin_dlen = sizeof(*tcp2); 730 tcp2->th_dport = htons(port); 731 fi.fin_data[0] = 0; 732 fi.fin_dp = (char *)tcp2; 733 fi.fin_plen = fi.fin_hlen + sizeof(*tcp); 734 fi.fin_fr = &ifsftp->ftppxyfr; 735 fi.fin_out = nat->nat_dir; 736 fi.fin_flx &= FI_LOWTTL|FI_FRAG|FI_TCPUDP|FI_OPTIONS|FI_IGNORE; 737 swip = ip->ip_src; 738 swip2 = ip->ip_dst; 739 if (nat->nat_dir == NAT_OUTBOUND) { 740 fi.fin_fi.fi_daddr = data_addr.s_addr; 741 fi.fin_fi.fi_saddr = nat->nat_inip.s_addr; 742 ip->ip_dst = data_addr; 743 ip->ip_src = nat->nat_inip; 744 } else if (nat->nat_dir == NAT_INBOUND) { 745 fi.fin_fi.fi_saddr = nat->nat_oip.s_addr; 746 fi.fin_fi.fi_daddr = nat->nat_outip.s_addr; 747 ip->ip_src = nat->nat_oip; 748 ip->ip_dst = nat->nat_outip; 749 } 750 751 sflags = nflags; 752 nflags |= NAT_SLAVE; 753 if (nat->nat_dir == NAT_INBOUND) 754 nflags |= NAT_NOTRULEPORT; 755 nat2 = nat_new(&fi, nat->nat_ptr, NULL, nflags, nat->nat_dir); 756 if (nat2 != NULL) { 757 (void) nat_proto(&fi, nat2, IPN_TCP); 758 nat_update(&fi, nat2, nat->nat_ptr); 759 fi.fin_ifp = NULL; 760 if (nat->nat_dir == NAT_INBOUND) { 761 fi.fin_fi.fi_daddr = nat->nat_inip.s_addr; 762 ip->ip_dst = nat->nat_inip; 763 } 764 (void) fr_addstate(&fi, &nat2->nat_state, sflags); 765 } 766 767 ip->ip_len = slen; 768 ip->ip_src = swip; 769 ip->ip_dst = swip2; 770 } else { 771 ipstate_t *is; 772 773 nat_update(&fi, nat2, nat->nat_ptr); 774 READ_ENTER(&ifs->ifs_ipf_state); 775 is = nat2->nat_state; 776 if (is != NULL) { 777 MUTEX_ENTER(&is->is_lock); 778 (void) fr_tcp_age(&is->is_sti, &fi, ifs->ifs_ips_tqtqb, 779 is->is_flags); 780 MUTEX_EXIT(&is->is_lock); 781 } 782 RWLOCK_EXIT(&ifs->ifs_ipf_state); 783 } 784 return inc; 785 } 786 787 788 int ippr_ftp_server(fin, ip, nat, ftp, dlen, ifsftp) 789 fr_info_t *fin; 790 ip_t *ip; 791 nat_t *nat; 792 ftpinfo_t *ftp; 793 int dlen; 794 ifs_ftppxy_t *ifsftp; 795 { 796 char *rptr, *wptr; 797 ftpside_t *f; 798 int inc; 799 800 inc = 0; 801 f = &ftp->ftp_side[1]; 802 rptr = f->ftps_rptr; 803 wptr = f->ftps_wptr; 804 805 if (*rptr == ' ') 806 goto server_cmd_ok; 807 if (!ISDIGIT(*rptr) || !ISDIGIT(*(rptr + 1)) || !ISDIGIT(*(rptr + 2))) 808 return 0; 809 if (ftp->ftp_passok == FTPXY_GO) { 810 if (!strncmp(rptr, "227 ", 4)) 811 inc = ippr_ftp_pasv(fin, ip, nat, ftp, dlen, ifsftp); 812 else if (!strncmp(rptr, "229 ", 4)) 813 inc = ippr_ftp_epsv(fin, ip, nat, f, dlen, ifsftp); 814 } else if (ifsftp->ippr_ftp_insecure && !strncmp(rptr, "227 ", 4)) { 815 inc = ippr_ftp_pasv(fin, ip, nat, ftp, dlen, ifsftp); 816 } else if (ifsftp->ippr_ftp_insecure && !strncmp(rptr, "229 ", 4)) { 817 inc = ippr_ftp_epsv(fin, ip, nat, f, dlen, ifsftp); 818 } else if (*rptr == '5' || *rptr == '4') 819 ftp->ftp_passok = FTPXY_INIT; 820 else if (ftp->ftp_incok) { 821 if (*rptr == '3') { 822 if (ftp->ftp_passok == FTPXY_ACCT_1) 823 ftp->ftp_passok = FTPXY_GO; 824 else 825 ftp->ftp_passok++; 826 } else if (*rptr == '2') { 827 switch (ftp->ftp_passok) 828 { 829 case FTPXY_USER_1 : 830 case FTPXY_USER_2 : 831 case FTPXY_PASS_1 : 832 case FTPXY_PASS_2 : 833 case FTPXY_ACCT_1 : 834 ftp->ftp_passok = FTPXY_GO; 835 break; 836 default : 837 ftp->ftp_passok += 3; 838 break; 839 } 840 } 841 } 842 server_cmd_ok: 843 ftp->ftp_incok = 0; 844 845 while ((*rptr++ != '\n') && (rptr < wptr)) 846 ; 847 f->ftps_rptr = rptr; 848 return inc; 849 } 850 851 852 /* 853 * Look to see if the buffer starts with something which we recognise as 854 * being the correct syntax for the FTP protocol. 855 */ 856 int ippr_ftp_client_valid(ftps, buf, len, ifsftp) 857 ftpside_t *ftps; 858 char *buf; 859 size_t len; 860 ifs_ftppxy_t *ifsftp; 861 { 862 register char *s, c, pc; 863 register size_t i = len; 864 char cmd[5]; 865 866 s = buf; 867 868 if (ftps->ftps_junk == 1) 869 return 1; 870 871 if (i < 5) { 872 if (ifsftp->ippr_ftp_debug > 3) 873 printf("ippr_ftp_client_valid:i(%d) < 5\n", (int)i); 874 return 2; 875 } 876 877 i--; 878 c = *s++; 879 880 if (ISALPHA(c)) { 881 cmd[0] = TOUPPER(c); 882 c = *s++; 883 i--; 884 if (ISALPHA(c)) { 885 cmd[1] = TOUPPER(c); 886 c = *s++; 887 i--; 888 if (ISALPHA(c)) { 889 cmd[2] = TOUPPER(c); 890 c = *s++; 891 i--; 892 if (ISALPHA(c)) { 893 cmd[3] = TOUPPER(c); 894 c = *s++; 895 i--; 896 if ((c != ' ') && (c != '\r')) 897 goto bad_client_command; 898 } else if ((c != ' ') && (c != '\r')) 899 goto bad_client_command; 900 } else 901 goto bad_client_command; 902 } else 903 goto bad_client_command; 904 } else { 905 bad_client_command: 906 if (ifsftp->ippr_ftp_debug > 3) 907 printf("%s:bad:junk %d len %d/%d c 0x%x buf [%*s]\n", 908 "ippr_ftp_client_valid", 909 ftps->ftps_junk, (int)len, (int)i, c, 910 (int)len, buf); 911 return 1; 912 } 913 914 for (; i; i--) { 915 pc = c; 916 c = *s++; 917 if ((pc == '\r') && (c == '\n')) { 918 cmd[4] = '\0'; 919 if (!strcmp(cmd, "PASV")) 920 ftps->ftps_cmds = FTPXY_C_PASV; 921 else 922 ftps->ftps_cmds = 0; 923 return 0; 924 } 925 } 926 #if !defined(_KERNEL) 927 printf("ippr_ftp_client_valid:junk after cmd[%*.*s]\n", 928 (int)len, (int)len, buf); 929 #endif 930 return 2; 931 } 932 933 934 int ippr_ftp_server_valid(ftps, buf, len, ifsftp) 935 ftpside_t *ftps; 936 char *buf; 937 size_t len; 938 ifs_ftppxy_t *ifsftp; 939 { 940 register char *s, c, pc; 941 register size_t i = len; 942 int cmd; 943 944 s = buf; 945 cmd = 0; 946 947 if (ftps->ftps_junk == 1) 948 return 1; 949 950 if (i < 5) { 951 if (ifsftp->ippr_ftp_debug > 3) 952 printf("ippr_ftp_servert_valid:i(%d) < 5\n", (int)i); 953 return 2; 954 } 955 956 c = *s++; 957 i--; 958 if (c == ' ') 959 goto search_eol; 960 961 if (ISDIGIT(c)) { 962 cmd = (c - '0') * 100; 963 c = *s++; 964 i--; 965 if (ISDIGIT(c)) { 966 cmd += (c - '0') * 10; 967 c = *s++; 968 i--; 969 if (ISDIGIT(c)) { 970 cmd += (c - '0'); 971 c = *s++; 972 i--; 973 if ((c != '-') && (c != ' ')) 974 goto bad_server_command; 975 } else 976 goto bad_server_command; 977 } else 978 goto bad_server_command; 979 } else { 980 bad_server_command: 981 if (ifsftp->ippr_ftp_debug > 3) 982 printf("%s:bad:junk %d len %d/%d c 0x%x buf [%*s]\n", 983 "ippr_ftp_server_valid", 984 ftps->ftps_junk, (int)len, (int)i, 985 c, (int)len, buf); 986 return 1; 987 } 988 search_eol: 989 for (; i; i--) { 990 pc = c; 991 c = *s++; 992 if ((pc == '\r') && (c == '\n')) { 993 ftps->ftps_cmds = cmd; 994 return 0; 995 } 996 } 997 if (ifsftp->ippr_ftp_debug > 3) 998 printf("ippr_ftp_server_valid:junk after cmd[%*s]\n", 999 (int)len, buf); 1000 return 2; 1001 } 1002 1003 1004 int ippr_ftp_valid(ftp, side, buf, len, ifsftp) 1005 ftpinfo_t *ftp; 1006 int side; 1007 char *buf; 1008 size_t len; 1009 ifs_ftppxy_t *ifsftp; 1010 { 1011 ftpside_t *ftps; 1012 int ret; 1013 1014 ftps = &ftp->ftp_side[side]; 1015 1016 if (side == 0) 1017 ret = ippr_ftp_client_valid(ftps, buf, len, ifsftp); 1018 else 1019 ret = ippr_ftp_server_valid(ftps, buf, len, ifsftp); 1020 return ret; 1021 } 1022 1023 1024 /* 1025 * For map rules, the following applies: 1026 * rv == 0 for outbound processing, 1027 * rv == 1 for inbound processing. 1028 * For rdr rules, the following applies: 1029 * rv == 0 for inbound processing, 1030 * rv == 1 for outbound processing. 1031 */ 1032 int ippr_ftp_process(fin, nat, ftp, rv, ifsftp) 1033 fr_info_t *fin; 1034 nat_t *nat; 1035 ftpinfo_t *ftp; 1036 int rv; 1037 ifs_ftppxy_t *ifsftp; 1038 { 1039 int mlen, len, off, inc, i, sel, sel2, ok, ackoff, seqoff; 1040 char *rptr, *wptr, *s; 1041 u_32_t thseq, thack; 1042 ap_session_t *aps; 1043 ftpside_t *f, *t; 1044 tcphdr_t *tcp; 1045 ip_t *ip; 1046 mb_t *m; 1047 1048 m = fin->fin_m; 1049 ip = fin->fin_ip; 1050 tcp = (tcphdr_t *)fin->fin_dp; 1051 off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff; 1052 1053 f = &ftp->ftp_side[rv]; 1054 t = &ftp->ftp_side[1 - rv]; 1055 thseq = ntohl(tcp->th_seq); 1056 thack = ntohl(tcp->th_ack); 1057 1058 #ifdef __sgi 1059 mlen = fin->fin_plen - off; 1060 #else 1061 mlen = MSGDSIZE(m) - off; 1062 #endif 1063 if (ifsftp->ippr_ftp_debug > 4) 1064 printf("ippr_ftp_process: mlen %d\n", mlen); 1065 1066 if (mlen <= 0) { 1067 if ((tcp->th_flags & TH_OPENING) == TH_OPENING) { 1068 f->ftps_seq[0] = thseq + 1; 1069 t->ftps_seq[0] = thack; 1070 } 1071 return 0; 1072 } 1073 aps = nat->nat_aps; 1074 1075 sel = aps->aps_sel[1 - rv]; 1076 sel2 = aps->aps_sel[rv]; 1077 if (rv == 0) { 1078 seqoff = aps->aps_seqoff[sel]; 1079 if (aps->aps_seqmin[sel] > seqoff + thseq) 1080 seqoff = aps->aps_seqoff[!sel]; 1081 ackoff = aps->aps_ackoff[sel2]; 1082 if (aps->aps_ackmin[sel2] > ackoff + thack) 1083 ackoff = aps->aps_ackoff[!sel2]; 1084 } else { 1085 seqoff = aps->aps_ackoff[sel]; 1086 if (ifsftp->ippr_ftp_debug > 2) 1087 printf("seqoff %d thseq %x ackmin %x\n", seqoff, thseq, 1088 aps->aps_ackmin[sel]); 1089 if (aps->aps_ackmin[sel] > seqoff + thseq) 1090 seqoff = aps->aps_ackoff[!sel]; 1091 1092 ackoff = aps->aps_seqoff[sel2]; 1093 if (ifsftp->ippr_ftp_debug > 2) 1094 printf("ackoff %d thack %x seqmin %x\n", ackoff, thack, 1095 aps->aps_seqmin[sel2]); 1096 if (ackoff > 0) { 1097 if (aps->aps_seqmin[sel2] > ackoff + thack) 1098 ackoff = aps->aps_seqoff[!sel2]; 1099 } else { 1100 if (aps->aps_seqmin[sel2] > thack) 1101 ackoff = aps->aps_seqoff[!sel2]; 1102 } 1103 } 1104 if (ifsftp->ippr_ftp_debug > 2) { 1105 printf("%s: %x seq %x/%d ack %x/%d len %d/%d off %d\n", 1106 rv ? "IN" : "OUT", tcp->th_flags, thseq, seqoff, 1107 thack, ackoff, mlen, fin->fin_plen, off); 1108 printf("sel %d seqmin %x/%x offset %d/%d\n", sel, 1109 aps->aps_seqmin[sel], aps->aps_seqmin[sel2], 1110 aps->aps_seqoff[sel], aps->aps_seqoff[sel2]); 1111 printf("sel %d ackmin %x/%x offset %d/%d\n", sel2, 1112 aps->aps_ackmin[sel], aps->aps_ackmin[sel2], 1113 aps->aps_ackoff[sel], aps->aps_ackoff[sel2]); 1114 } 1115 1116 /* 1117 * XXX - Ideally, this packet should get dropped because we now know 1118 * that it is out of order (and there is no real danger in doing so 1119 * apart from causing packets to go through here ordered). 1120 */ 1121 if (ifsftp->ippr_ftp_debug > 2) { 1122 printf("rv %d t:seq[0] %x seq[1] %x %d/%d\n", 1123 rv, t->ftps_seq[0], t->ftps_seq[1], seqoff, ackoff); 1124 } 1125 1126 ok = 0; 1127 if (t->ftps_seq[0] == 0) { 1128 t->ftps_seq[0] = thack; 1129 ok = 1; 1130 } else { 1131 if (ackoff == 0) { 1132 if (t->ftps_seq[0] == thack) 1133 ok = 1; 1134 else if (t->ftps_seq[1] == thack) { 1135 t->ftps_seq[0] = thack; 1136 ok = 1; 1137 } 1138 } else { 1139 if (t->ftps_seq[0] + ackoff == thack) 1140 ok = 1; 1141 else if (t->ftps_seq[0] == thack + ackoff) 1142 ok = 1; 1143 else if (t->ftps_seq[1] + ackoff == thack) { 1144 t->ftps_seq[0] = thack - ackoff; 1145 ok = 1; 1146 } else if (t->ftps_seq[1] == thack + ackoff) { 1147 t->ftps_seq[0] = thack - ackoff; 1148 ok = 1; 1149 } 1150 } 1151 } 1152 1153 if (ifsftp->ippr_ftp_debug > 2) { 1154 if (!ok) 1155 printf("%s ok\n", "not"); 1156 } 1157 1158 if (!mlen) { 1159 if (t->ftps_seq[0] + ackoff != thack) { 1160 if (ifsftp->ippr_ftp_debug > 1) { 1161 printf("%s:seq[0](%x) + (%x) != (%x)\n", 1162 "ippr_ftp_process", t->ftps_seq[0], 1163 ackoff, thack); 1164 } 1165 return APR_ERR(1); 1166 } 1167 1168 if (ifsftp->ippr_ftp_debug > 2) { 1169 printf("ippr_ftp_process:f:seq[0] %x seq[1] %x\n", 1170 f->ftps_seq[0], f->ftps_seq[1]); 1171 } 1172 1173 if (tcp->th_flags & TH_FIN) { 1174 if (thseq == f->ftps_seq[1]) { 1175 f->ftps_seq[0] = f->ftps_seq[1] - seqoff; 1176 f->ftps_seq[1] = thseq + 1 - seqoff; 1177 } else { 1178 if (ifsftp->ippr_ftp_debug > 1) { 1179 printf("FIN: thseq %x seqoff %d ftps_seq %x\n", 1180 thseq, seqoff, f->ftps_seq[0]); 1181 } 1182 return APR_ERR(1); 1183 } 1184 } 1185 f->ftps_len = 0; 1186 return 0; 1187 } 1188 1189 ok = 0; 1190 if ((thseq == f->ftps_seq[0]) || (thseq == f->ftps_seq[1])) { 1191 ok = 1; 1192 /* 1193 * Retransmitted data packet. 1194 */ 1195 } else if ((thseq + mlen == f->ftps_seq[0]) || 1196 (thseq + mlen == f->ftps_seq[1])) { 1197 ok = 1; 1198 } 1199 1200 if (ok == 0) { 1201 inc = thseq - f->ftps_seq[0]; 1202 if (ifsftp->ippr_ftp_debug > 1) { 1203 printf("inc %d sel %d rv %d\n", inc, sel, rv); 1204 printf("th_seq %x ftps_seq %x/%x\n", 1205 thseq, f->ftps_seq[0], f->ftps_seq[1]); 1206 printf("ackmin %x ackoff %d\n", aps->aps_ackmin[sel], 1207 aps->aps_ackoff[sel]); 1208 printf("seqmin %x seqoff %d\n", aps->aps_seqmin[sel], 1209 aps->aps_seqoff[sel]); 1210 } 1211 1212 return APR_ERR(1); 1213 } 1214 1215 inc = 0; 1216 rptr = f->ftps_rptr; 1217 wptr = f->ftps_wptr; 1218 f->ftps_seq[0] = thseq; 1219 f->ftps_seq[1] = f->ftps_seq[0] + mlen; 1220 f->ftps_len = mlen; 1221 1222 while (mlen > 0) { 1223 len = MIN(mlen, sizeof(f->ftps_buf) - (wptr - rptr)); 1224 COPYDATA(m, off, len, wptr); 1225 mlen -= len; 1226 off += len; 1227 wptr += len; 1228 1229 if (ifsftp->ippr_ftp_debug > 3) 1230 printf("%s:len %d/%d off %d wptr %lx junk %d [%*s]\n", 1231 "ippr_ftp_process", 1232 len, mlen, off, (u_long)wptr, f->ftps_junk, 1233 len, rptr); 1234 1235 f->ftps_wptr = wptr; 1236 if (f->ftps_junk != 0) { 1237 i = f->ftps_junk; 1238 f->ftps_junk = ippr_ftp_valid(ftp, rv, rptr, 1239 wptr - rptr, ifsftp); 1240 1241 if (ifsftp->ippr_ftp_debug > 5) 1242 printf("%s:junk %d -> %d\n", 1243 "ippr_ftp_process", i, f->ftps_junk); 1244 1245 if (f->ftps_junk != 0) { 1246 if (wptr - rptr == sizeof(f->ftps_buf)) { 1247 if (ifsftp->ippr_ftp_debug > 4) 1248 printf("%s:full buffer\n", 1249 "ippr_ftp_process"); 1250 f->ftps_rptr = f->ftps_buf; 1251 f->ftps_wptr = f->ftps_buf; 1252 rptr = f->ftps_rptr; 1253 wptr = f->ftps_wptr; 1254 /* 1255 * Because we throw away data here that 1256 * we would otherwise parse, set the 1257 * junk flag to indicate just ignore 1258 * any data upto the next CRLF. 1259 */ 1260 f->ftps_junk = 1; 1261 continue; 1262 } 1263 } 1264 } 1265 1266 while ((f->ftps_junk == 0) && (wptr > rptr)) { 1267 len = wptr - rptr; 1268 f->ftps_junk = ippr_ftp_valid(ftp, rv, rptr, len, ifsftp); 1269 1270 if (ifsftp->ippr_ftp_debug > 3) { 1271 printf("%s=%d len %d rv %d ptr %lx/%lx ", 1272 "ippr_ftp_valid", 1273 f->ftps_junk, len, rv, (u_long)rptr, 1274 (u_long)wptr); 1275 printf("buf [%*s]\n", len, rptr); 1276 } 1277 1278 if (f->ftps_junk == 0) { 1279 f->ftps_rptr = rptr; 1280 if (rv) 1281 inc += ippr_ftp_server(fin, ip, nat, 1282 ftp, len, ifsftp); 1283 else 1284 inc += ippr_ftp_client(fin, ip, nat, 1285 ftp, len, ifsftp); 1286 rptr = f->ftps_rptr; 1287 wptr = f->ftps_wptr; 1288 } 1289 } 1290 1291 /* 1292 * Off to a bad start so lets just forget about using the 1293 * ftp proxy for this connection. 1294 */ 1295 if ((f->ftps_cmds == 0) && (f->ftps_junk == 1)) { 1296 /* f->ftps_seq[1] += inc; */ 1297 1298 if (ifsftp->ippr_ftp_debug > 1) 1299 printf("%s:cmds == 0 junk == 1\n", 1300 "ippr_ftp_process"); 1301 return APR_ERR(2); 1302 } 1303 1304 if ((f->ftps_junk != 0) && (rptr < wptr)) { 1305 for (s = rptr; s < wptr; s++) { 1306 if ((*s == '\r') && (s + 1 < wptr) && 1307 (*(s + 1) == '\n')) { 1308 rptr = s + 2; 1309 f->ftps_junk = 0; 1310 break; 1311 } 1312 } 1313 } 1314 1315 if (rptr == wptr) { 1316 rptr = wptr = f->ftps_buf; 1317 } else { 1318 /* 1319 * Compact the buffer back to the start. The junk 1320 * flag should already be set and because we're not 1321 * throwing away any data, it is preserved from its 1322 * current state. 1323 */ 1324 if (rptr > f->ftps_buf) { 1325 bcopy(rptr, f->ftps_buf, len); 1326 wptr -= rptr - f->ftps_buf; 1327 rptr = f->ftps_buf; 1328 } 1329 } 1330 f->ftps_rptr = rptr; 1331 f->ftps_wptr = wptr; 1332 } 1333 1334 /* f->ftps_seq[1] += inc; */ 1335 if (tcp->th_flags & TH_FIN) 1336 f->ftps_seq[1]++; 1337 if (ifsftp->ippr_ftp_debug > 3) { 1338 #ifdef __sgi 1339 mlen = fin->fin_plen; 1340 #else 1341 mlen = MSGDSIZE(m); 1342 #endif 1343 mlen -= off; 1344 printf("ftps_seq[1] = %x inc %d len %d\n", 1345 f->ftps_seq[1], inc, mlen); 1346 } 1347 1348 f->ftps_rptr = rptr; 1349 f->ftps_wptr = wptr; 1350 return APR_INC(inc); 1351 } 1352 1353 1354 int ippr_ftp_out(fin, aps, nat, private) 1355 fr_info_t *fin; 1356 ap_session_t *aps; 1357 nat_t *nat; 1358 void *private; 1359 { 1360 ftpinfo_t *ftp; 1361 int rev; 1362 1363 ftp = aps->aps_data; 1364 if (ftp == NULL) 1365 return 0; 1366 1367 rev = (nat->nat_dir == NAT_OUTBOUND) ? 0 : 1; 1368 if (ftp->ftp_side[1 - rev].ftps_ifp == NULL) 1369 ftp->ftp_side[1 - rev].ftps_ifp = fin->fin_ifp; 1370 1371 return ippr_ftp_process(fin, nat, ftp, rev, (ifs_ftppxy_t *)private); 1372 } 1373 1374 1375 int ippr_ftp_in(fin, aps, nat, private) 1376 fr_info_t *fin; 1377 ap_session_t *aps; 1378 nat_t *nat; 1379 void *private; 1380 { 1381 ftpinfo_t *ftp; 1382 int rev; 1383 1384 ftp = aps->aps_data; 1385 if (ftp == NULL) 1386 return 0; 1387 1388 rev = (nat->nat_dir == NAT_OUTBOUND) ? 0 : 1; 1389 if (ftp->ftp_side[rev].ftps_ifp == NULL) 1390 ftp->ftp_side[rev].ftps_ifp = fin->fin_ifp; 1391 1392 return ippr_ftp_process(fin, nat, ftp, 1 - rev, (ifs_ftppxy_t *)private); 1393 } 1394 1395 1396 /* 1397 * ippr_ftp_atoi - implement a version of atoi which processes numbers in 1398 * pairs separated by commas (which are expected to be in the range 0 - 255), 1399 * returning a 16 bit number combining either side of the , as the MSB and 1400 * LSB. 1401 */ 1402 u_short ippr_ftp_atoi(ptr) 1403 char **ptr; 1404 { 1405 register char *s = *ptr, c; 1406 register u_char i = 0, j = 0; 1407 1408 while (((c = *s++) != '\0') && ISDIGIT(c)) { 1409 i *= 10; 1410 i += c - '0'; 1411 } 1412 if (c != ',') { 1413 *ptr = NULL; 1414 return 0; 1415 } 1416 while (((c = *s++) != '\0') && ISDIGIT(c)) { 1417 j *= 10; 1418 j += c - '0'; 1419 } 1420 *ptr = s; 1421 i &= 0xff; 1422 j &= 0xff; 1423 return (i << 8) | j; 1424 } 1425 1426 1427 int ippr_ftp_epsv(fin, ip, nat, f, dlen, ifsftp) 1428 fr_info_t *fin; 1429 ip_t *ip; 1430 nat_t *nat; 1431 ftpside_t *f; 1432 int dlen; 1433 ifs_ftppxy_t *ifsftp; 1434 { 1435 char newbuf[IPF_FTPBUFSZ]; 1436 char *s; 1437 u_short ap = 0; 1438 1439 #define EPSV_REPLEN 33 1440 /* 1441 * Check for EPSV reply message. 1442 */ 1443 if (dlen < IPF_MIN229LEN) 1444 return (0); 1445 else if (strncmp(f->ftps_rptr, 1446 "229 Entering Extended Passive Mode", EPSV_REPLEN)) 1447 return (0); 1448 1449 /* 1450 * Skip the EPSV command + space 1451 */ 1452 s = f->ftps_rptr + 33; 1453 while (*s && !ISDIGIT(*s)) 1454 s++; 1455 1456 /* 1457 * As per RFC 2428, there are no addres components in the EPSV 1458 * response. So we'll go straight to getting the port. 1459 */ 1460 while (*s && ISDIGIT(*s)) { 1461 ap *= 10; 1462 ap += *s++ - '0'; 1463 } 1464 1465 if (!s) 1466 return 0; 1467 1468 if (*s == '|') 1469 s++; 1470 if (*s == ')') 1471 s++; 1472 if (*s == '\n') 1473 s--; 1474 /* 1475 * check for CR-LF at the end. 1476 */ 1477 if ((*s == '\r') && (*(s + 1) == '\n')) { 1478 s += 2; 1479 } else 1480 return 0; 1481 1482 #if defined(SNPRINTF) && defined(_KERNEL) 1483 (void) SNPRINTF(newbuf, sizeof(newbuf), "%s (|||%u|)\r\n", 1484 "229 Entering Extended Passive Mode", ap); 1485 #else 1486 (void) sprintf(newbuf, "%s (|||%u|)\r\n", 1487 "229 Entering Extended Passive Mode", ap); 1488 #endif 1489 1490 return ippr_ftp_pasvreply(fin, ip, nat, f, (u_int)ap, newbuf, s, 1491 ip->ip_src.s_addr, ifsftp); 1492 } 1493