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