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(&fi, (ipstate_t **)&fi.fin_state, 409 ifs); 410 } 411 ip->ip_len = slen; 412 ip->ip_src = swip; 413 ip->ip_dst = swip2; 414 } else { 415 ipstate_t *is; 416 417 nat_update(&fi, nat2, nat->nat_ptr); 418 READ_ENTER(&ifs->ifs_ipf_state); 419 is = nat2->nat_state; 420 if (is != NULL) { 421 MUTEX_ENTER(&is->is_lock); 422 (void)fr_tcp_age(&is->is_sti, &fi, ifs->ifs_ips_tqtqb, 423 is->is_flags); 424 MUTEX_EXIT(&is->is_lock); 425 } 426 RWLOCK_EXIT(&ifs->ifs_ipf_state); 427 } 428 return APR_INC(inc); 429 } 430 431 432 int ippr_ftp_client(fin, ip, nat, ftp, dlen, ifsftp) 433 fr_info_t *fin; 434 nat_t *nat; 435 ftpinfo_t *ftp; 436 ip_t *ip; 437 int dlen; 438 ifs_ftppxy_t *ifsftp; 439 { 440 char *rptr, *wptr, cmd[6], c; 441 ftpside_t *f; 442 int inc, i; 443 444 inc = 0; 445 f = &ftp->ftp_side[0]; 446 rptr = f->ftps_rptr; 447 wptr = f->ftps_wptr; 448 449 for (i = 0; (i < 5) && (i < dlen); i++) { 450 c = rptr[i]; 451 if (ISALPHA(c)) { 452 cmd[i] = TOUPPER(c); 453 } else { 454 cmd[i] = c; 455 } 456 } 457 cmd[i] = '\0'; 458 459 ftp->ftp_incok = 0; 460 if (!strncmp(cmd, "USER ", 5) || !strncmp(cmd, "XAUT ", 5)) { 461 if (ftp->ftp_passok == FTPXY_ADOK_1 || 462 ftp->ftp_passok == FTPXY_AUOK_1) { 463 ftp->ftp_passok = FTPXY_USER_2; 464 ftp->ftp_incok = 1; 465 } else { 466 ftp->ftp_passok = FTPXY_USER_1; 467 ftp->ftp_incok = 1; 468 } 469 } else if (!strncmp(cmd, "AUTH ", 5)) { 470 ftp->ftp_passok = FTPXY_AUTH_1; 471 ftp->ftp_incok = 1; 472 } else if (!strncmp(cmd, "PASS ", 5)) { 473 if (ftp->ftp_passok == FTPXY_USOK_1) { 474 ftp->ftp_passok = FTPXY_PASS_1; 475 ftp->ftp_incok = 1; 476 } else if (ftp->ftp_passok == FTPXY_USOK_2) { 477 ftp->ftp_passok = FTPXY_PASS_2; 478 ftp->ftp_incok = 1; 479 } 480 } else if ((ftp->ftp_passok == FTPXY_AUOK_1) && 481 !strncmp(cmd, "ADAT ", 5)) { 482 ftp->ftp_passok = FTPXY_ADAT_1; 483 ftp->ftp_incok = 1; 484 } else if ((ftp->ftp_passok == FTPXY_PAOK_1 || 485 ftp->ftp_passok == FTPXY_PAOK_2) && 486 !strncmp(cmd, "ACCT ", 5)) { 487 ftp->ftp_passok = FTPXY_ACCT_1; 488 ftp->ftp_incok = 1; 489 } else if ((ftp->ftp_passok == FTPXY_GO) && 490 !ifsftp->ippr_ftp_pasvonly && 491 !strncmp(cmd, "PORT ", 5)) { 492 inc = ippr_ftp_port(fin, ip, nat, f, dlen, ifsftp); 493 } else if (ifsftp->ippr_ftp_insecure && !ifsftp->ippr_ftp_pasvonly && 494 !strncmp(cmd, "PORT ", 5)) { 495 inc = ippr_ftp_port(fin, ip, nat, f, dlen, ifsftp); 496 } 497 498 while ((*rptr++ != '\n') && (rptr < wptr)) 499 ; 500 f->ftps_rptr = rptr; 501 return inc; 502 } 503 504 505 int ippr_ftp_pasv(fin, ip, nat, ftp, dlen, ifsftp) 506 fr_info_t *fin; 507 ip_t *ip; 508 nat_t *nat; 509 ftpinfo_t *ftp; 510 int dlen; 511 ifs_ftppxy_t *ifsftp; 512 { 513 u_int a1, a2, a3, a4, data_ip; 514 char newbuf[IPF_FTPBUFSZ]; 515 char *s, *brackets[2]; 516 u_short a5, a6; 517 ftpside_t *f; 518 519 if (ifsftp->ippr_ftp_forcepasv != 0 && 520 ftp->ftp_side[0].ftps_cmds != FTPXY_C_PASV) { 521 if (ifsftp->ippr_ftp_debug > 0) 522 printf("ippr_ftp_pasv:ftps_cmds(%d) != FTPXY_C_PASV\n", 523 ftp->ftp_side[0].ftps_cmds); 524 return 0; 525 } 526 527 f = &ftp->ftp_side[1]; 528 529 #define PASV_REPLEN 24 530 /* 531 * Check for PASV reply message. 532 */ 533 if (dlen < IPF_MIN227LEN) { 534 if (ifsftp->ippr_ftp_debug > 1) 535 printf("ippr_ftp_pasv:dlen(%d) < IPF_MIN227LEN\n", 536 dlen); 537 return 0; 538 } else if (strncmp(f->ftps_rptr, 539 "227 Entering Passive Mod", PASV_REPLEN)) { 540 if (ifsftp->ippr_ftp_debug > 0) 541 printf("ippr_ftp_pasv:%d reply wrong\n", 227); 542 return 0; 543 } 544 545 brackets[0] = ""; 546 brackets[1] = ""; 547 /* 548 * Skip the PASV reply + space 549 */ 550 s = f->ftps_rptr + PASV_REPLEN; 551 while (*s && !ISDIGIT(*s)) { 552 if (*s == '(') { 553 brackets[0] = "("; 554 brackets[1] = ")"; 555 } 556 s++; 557 } 558 559 /* 560 * Pick out the address components, two at a time. 561 */ 562 a1 = ippr_ftp_atoi(&s); 563 if (s == NULL) { 564 if (ifsftp->ippr_ftp_debug > 1) 565 printf("ippr_ftp_pasv:ippr_ftp_atoi(%d) failed\n", 1); 566 return 0; 567 } 568 a2 = ippr_ftp_atoi(&s); 569 if (s == NULL) { 570 if (ifsftp->ippr_ftp_debug > 1) 571 printf("ippr_ftp_pasv:ippr_ftp_atoi(%d) failed\n", 2); 572 return 0; 573 } 574 575 /* 576 * check that IP address in the PASV reply is the same as the 577 * sender of the command - prevents using PASV for port scanning. 578 */ 579 a1 <<= 16; 580 a1 |= a2; 581 582 if (((nat->nat_dir == NAT_INBOUND) && 583 (a1 != ntohl(nat->nat_inip.s_addr))) || 584 ((nat->nat_dir == NAT_OUTBOUND) && 585 (a1 != ntohl(nat->nat_oip.s_addr)))) { 586 if (ifsftp->ippr_ftp_debug > 0) 587 printf("ippr_ftp_pasv:%s != nat->nat_oip\n", "a1"); 588 return 0; 589 } 590 591 a5 = ippr_ftp_atoi(&s); 592 if (s == NULL) { 593 if (ifsftp->ippr_ftp_debug > 1) 594 printf("ippr_ftp_pasv:ippr_ftp_atoi(%d) failed\n", 3); 595 return 0; 596 } 597 598 if (*s == ')') 599 s++; 600 if (*s == '.') 601 s++; 602 if (*s == '\n') 603 s--; 604 /* 605 * check for CR-LF at the end. 606 */ 607 if ((*s == '\r') && (*(s + 1) == '\n')) { 608 s += 2; 609 } else { 610 if (ifsftp->ippr_ftp_debug > 1) 611 printf("ippr_ftp_pasv:missing %s", "cr-lf\n"); 612 return 0; 613 } 614 615 a6 = a5 & 0xff; 616 a5 >>= 8; 617 /* 618 * Calculate new address parts for 227 reply 619 */ 620 if (nat->nat_dir == NAT_INBOUND) { 621 data_ip = nat->nat_outip.s_addr; 622 a1 = ntohl(data_ip); 623 } else 624 data_ip = htonl(a1); 625 626 a2 = (a1 >> 16) & 0xff; 627 a3 = (a1 >> 8) & 0xff; 628 a4 = a1 & 0xff; 629 a1 >>= 24; 630 631 #if defined(SNPRINTF) && defined(_KERNEL) 632 (void) SNPRINTF(newbuf, sizeof(newbuf), "%s %s%u,%u,%u,%u,%u,%u%s\r\n", 633 "227 Entering Passive Mode", brackets[0], a1, a2, a3, a4, 634 a5, a6, brackets[1]); 635 #else 636 (void) sprintf(newbuf, "%s %s%u,%u,%u,%u,%u,%u%s\r\n", 637 "227 Entering Passive Mode", brackets[0], a1, a2, a3, a4, 638 a5, a6, brackets[1]); 639 #endif 640 return ippr_ftp_pasvreply(fin, ip, nat, f, (a5 << 8 | a6), 641 newbuf, s, data_ip, ifsftp); 642 } 643 644 int ippr_ftp_pasvreply(fin, ip, nat, f, port, newmsg, s, data_ip, ifsftp) 645 fr_info_t *fin; 646 ip_t *ip; 647 nat_t *nat; 648 ftpside_t *f; 649 u_int port; 650 char *newmsg; 651 char *s; 652 u_int data_ip; 653 ifs_ftppxy_t *ifsftp; 654 { 655 int inc, off, nflags, sflags; 656 tcphdr_t *tcp, tcph, *tcp2; 657 struct in_addr swip, swip2; 658 struct in_addr data_addr; 659 size_t nlen, olen; 660 fr_info_t fi; 661 nat_t *nat2; 662 mb_t *m; 663 ipf_stack_t *ifs = fin->fin_ifs; 664 665 m = fin->fin_m; 666 tcp = (tcphdr_t *)fin->fin_dp; 667 off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff; 668 669 data_addr.s_addr = data_ip; 670 tcp2 = &tcph; 671 inc = 0; 672 673 674 olen = s - f->ftps_rptr; 675 nlen = strlen(newmsg); 676 inc = nlen - olen; 677 if ((inc + ip->ip_len) > 65535) { 678 if (ifsftp->ippr_ftp_debug > 0) 679 printf("ippr_ftp_pasv:inc(%d) + ip->ip_len > 65535\n", 680 inc); 681 return 0; 682 } 683 684 #if !defined(_KERNEL) 685 bcopy(newmsg, MTOD(m, char *) + off, nlen); 686 #else 687 # if defined(MENTAT) 688 if (inc < 0) 689 (void)adjmsg(m, inc); 690 # else /* defined(MENTAT) */ 691 /* 692 * m_adj takes care of pkthdr.len, if required and treats inc<0 to 693 * mean remove -len bytes from the end of the packet. 694 * The mbuf chain will be extended if necessary by m_copyback(). 695 */ 696 if (inc < 0) 697 m_adj(m, inc); 698 # endif /* defined(MENTAT) */ 699 #endif /* !defined(_KERNEL) */ 700 COPYBACK(m, off, nlen, newmsg); 701 702 if (inc != 0) { 703 ip->ip_len += inc; 704 fin->fin_dlen += inc; 705 fin->fin_plen += inc; 706 } 707 708 /* 709 * Add skeleton NAT entry for connection which will come back the 710 * other way. 711 */ 712 bcopy((char *)fin, (char *)&fi, sizeof(fi)); 713 fi.fin_state = NULL; 714 fi.fin_nat = NULL; 715 fi.fin_flx |= FI_IGNORE; 716 fi.fin_data[0] = 0; 717 fi.fin_data[1] = port; 718 nflags = IPN_TCP|SI_W_SPORT; 719 if (ifsftp->ippr_ftp_pasvrdr && f->ftps_ifp) 720 nflags |= SI_W_DPORT; 721 if (nat->nat_dir == NAT_OUTBOUND) 722 nat2 = nat_outlookup(&fi, nflags|NAT_SEARCH, 723 nat->nat_p, nat->nat_inip, nat->nat_oip); 724 else 725 nat2 = nat_inlookup(&fi, nflags|NAT_SEARCH, 726 nat->nat_p, nat->nat_inip, nat->nat_oip); 727 if (nat2 == NULL) { 728 int slen; 729 730 slen = ip->ip_len; 731 ip->ip_len = fin->fin_hlen + sizeof(*tcp2); 732 bzero((char *)tcp2, sizeof(*tcp2)); 733 tcp2->th_win = htons(8192); 734 tcp2->th_sport = 0; /* XXX - fake it for nat_new */ 735 TCP_OFF_A(tcp2, 5); 736 tcp2->th_flags = TH_SYN; 737 fi.fin_data[1] = port; 738 fi.fin_dlen = sizeof(*tcp2); 739 tcp2->th_dport = htons(port); 740 fi.fin_data[0] = 0; 741 fi.fin_dp = (char *)tcp2; 742 fi.fin_plen = fi.fin_hlen + sizeof(*tcp); 743 fi.fin_fr = &ifsftp->ftppxyfr; 744 fi.fin_out = nat->nat_dir; 745 fi.fin_flx &= FI_LOWTTL|FI_FRAG|FI_TCPUDP|FI_OPTIONS|FI_IGNORE; 746 swip = ip->ip_src; 747 swip2 = ip->ip_dst; 748 if (nat->nat_dir == NAT_OUTBOUND) { 749 fi.fin_fi.fi_daddr = data_addr.s_addr; 750 fi.fin_fi.fi_saddr = nat->nat_inip.s_addr; 751 ip->ip_dst = data_addr; 752 ip->ip_src = nat->nat_inip; 753 } else if (nat->nat_dir == NAT_INBOUND) { 754 fi.fin_fi.fi_saddr = nat->nat_oip.s_addr; 755 fi.fin_fi.fi_daddr = nat->nat_outip.s_addr; 756 ip->ip_src = nat->nat_oip; 757 ip->ip_dst = nat->nat_outip; 758 } 759 760 sflags = nflags; 761 nflags |= NAT_SLAVE; 762 if (nat->nat_dir == NAT_INBOUND) 763 nflags |= NAT_NOTRULEPORT; 764 nat2 = nat_new(&fi, nat->nat_ptr, NULL, nflags, nat->nat_dir); 765 if (nat2 != NULL) { 766 (void) nat_proto(&fi, nat2, IPN_TCP); 767 nat_update(&fi, nat2, nat->nat_ptr); 768 fi.fin_ifp = NULL; 769 if (nat->nat_dir == NAT_INBOUND) { 770 fi.fin_fi.fi_daddr = nat->nat_inip.s_addr; 771 ip->ip_dst = nat->nat_inip; 772 } 773 (void) fr_addstate(&fi, &nat2->nat_state, sflags); 774 if (fi.fin_state != NULL) 775 fr_statederef(&fi, (ipstate_t **)&fi.fin_state, 776 ifs); 777 } 778 779 ip->ip_len = slen; 780 ip->ip_src = swip; 781 ip->ip_dst = swip2; 782 } else { 783 ipstate_t *is; 784 785 nat_update(&fi, nat2, nat->nat_ptr); 786 READ_ENTER(&ifs->ifs_ipf_state); 787 is = nat2->nat_state; 788 if (is != NULL) { 789 MUTEX_ENTER(&is->is_lock); 790 (void) fr_tcp_age(&is->is_sti, &fi, ifs->ifs_ips_tqtqb, 791 is->is_flags); 792 MUTEX_EXIT(&is->is_lock); 793 } 794 RWLOCK_EXIT(&ifs->ifs_ipf_state); 795 } 796 return inc; 797 } 798 799 800 int ippr_ftp_server(fin, ip, nat, ftp, dlen, ifsftp) 801 fr_info_t *fin; 802 ip_t *ip; 803 nat_t *nat; 804 ftpinfo_t *ftp; 805 int dlen; 806 ifs_ftppxy_t *ifsftp; 807 { 808 char *rptr, *wptr; 809 ftpside_t *f; 810 int inc; 811 812 inc = 0; 813 f = &ftp->ftp_side[1]; 814 rptr = f->ftps_rptr; 815 wptr = f->ftps_wptr; 816 817 if (*rptr == ' ') 818 goto server_cmd_ok; 819 if (!ISDIGIT(*rptr) || !ISDIGIT(*(rptr + 1)) || !ISDIGIT(*(rptr + 2))) 820 return 0; 821 if (ftp->ftp_passok == FTPXY_GO) { 822 if (!strncmp(rptr, "227 ", 4)) 823 inc = ippr_ftp_pasv(fin, ip, nat, ftp, dlen, ifsftp); 824 else if (!strncmp(rptr, "229 ", 4)) 825 inc = ippr_ftp_epsv(fin, ip, nat, f, dlen, ifsftp); 826 } else if (ifsftp->ippr_ftp_insecure && !strncmp(rptr, "227 ", 4)) { 827 inc = ippr_ftp_pasv(fin, ip, nat, ftp, dlen, ifsftp); 828 } else if (ifsftp->ippr_ftp_insecure && !strncmp(rptr, "229 ", 4)) { 829 inc = ippr_ftp_epsv(fin, ip, nat, f, dlen, ifsftp); 830 } else if (*rptr == '5' || *rptr == '4') 831 ftp->ftp_passok = FTPXY_INIT; 832 else if (ftp->ftp_incok) { 833 if (*rptr == '3') { 834 if (ftp->ftp_passok == FTPXY_ACCT_1) 835 ftp->ftp_passok = FTPXY_GO; 836 else 837 ftp->ftp_passok++; 838 } else if (*rptr == '2') { 839 switch (ftp->ftp_passok) 840 { 841 case FTPXY_USER_1 : 842 case FTPXY_USER_2 : 843 case FTPXY_PASS_1 : 844 case FTPXY_PASS_2 : 845 case FTPXY_ACCT_1 : 846 ftp->ftp_passok = FTPXY_GO; 847 break; 848 default : 849 ftp->ftp_passok += 3; 850 break; 851 } 852 } 853 } 854 server_cmd_ok: 855 ftp->ftp_incok = 0; 856 857 while ((*rptr++ != '\n') && (rptr < wptr)) 858 ; 859 f->ftps_rptr = rptr; 860 return inc; 861 } 862 863 864 /* 865 * Look to see if the buffer starts with something which we recognise as 866 * being the correct syntax for the FTP protocol. 867 */ 868 int ippr_ftp_client_valid(ftps, buf, len, ifsftp) 869 ftpside_t *ftps; 870 char *buf; 871 size_t len; 872 ifs_ftppxy_t *ifsftp; 873 { 874 register char *s, c, pc; 875 register size_t i = len; 876 char cmd[5]; 877 878 s = buf; 879 880 if (ftps->ftps_junk == 1) 881 return 1; 882 883 if (i < 5) { 884 if (ifsftp->ippr_ftp_debug > 3) 885 printf("ippr_ftp_client_valid:i(%d) < 5\n", (int)i); 886 return 2; 887 } 888 889 i--; 890 c = *s++; 891 892 if (ISALPHA(c)) { 893 cmd[0] = TOUPPER(c); 894 c = *s++; 895 i--; 896 if (ISALPHA(c)) { 897 cmd[1] = TOUPPER(c); 898 c = *s++; 899 i--; 900 if (ISALPHA(c)) { 901 cmd[2] = TOUPPER(c); 902 c = *s++; 903 i--; 904 if (ISALPHA(c)) { 905 cmd[3] = TOUPPER(c); 906 c = *s++; 907 i--; 908 if ((c != ' ') && (c != '\r')) 909 goto bad_client_command; 910 } else if ((c != ' ') && (c != '\r')) 911 goto bad_client_command; 912 } else 913 goto bad_client_command; 914 } else 915 goto bad_client_command; 916 } else { 917 bad_client_command: 918 if (ifsftp->ippr_ftp_debug > 3) 919 printf("%s:bad:junk %d len %d/%d c 0x%x buf [%*s]\n", 920 "ippr_ftp_client_valid", 921 ftps->ftps_junk, (int)len, (int)i, c, 922 (int)len, buf); 923 return 1; 924 } 925 926 for (; i; i--) { 927 pc = c; 928 c = *s++; 929 if ((pc == '\r') && (c == '\n')) { 930 cmd[4] = '\0'; 931 if (!strcmp(cmd, "PASV")) 932 ftps->ftps_cmds = FTPXY_C_PASV; 933 else 934 ftps->ftps_cmds = 0; 935 return 0; 936 } 937 } 938 #if !defined(_KERNEL) 939 printf("ippr_ftp_client_valid:junk after cmd[%*.*s]\n", 940 (int)len, (int)len, buf); 941 #endif 942 return 2; 943 } 944 945 946 int ippr_ftp_server_valid(ftps, buf, len, ifsftp) 947 ftpside_t *ftps; 948 char *buf; 949 size_t len; 950 ifs_ftppxy_t *ifsftp; 951 { 952 register char *s, c, pc; 953 register size_t i = len; 954 int cmd; 955 956 s = buf; 957 cmd = 0; 958 959 if (ftps->ftps_junk == 1) 960 return 1; 961 962 if (i < 5) { 963 if (ifsftp->ippr_ftp_debug > 3) 964 printf("ippr_ftp_servert_valid:i(%d) < 5\n", (int)i); 965 return 2; 966 } 967 968 c = *s++; 969 i--; 970 if (c == ' ') 971 goto search_eol; 972 973 if (ISDIGIT(c)) { 974 cmd = (c - '0') * 100; 975 c = *s++; 976 i--; 977 if (ISDIGIT(c)) { 978 cmd += (c - '0') * 10; 979 c = *s++; 980 i--; 981 if (ISDIGIT(c)) { 982 cmd += (c - '0'); 983 c = *s++; 984 i--; 985 if ((c != '-') && (c != ' ')) 986 goto bad_server_command; 987 } else 988 goto bad_server_command; 989 } else 990 goto bad_server_command; 991 } else { 992 bad_server_command: 993 if (ifsftp->ippr_ftp_debug > 3) 994 printf("%s:bad:junk %d len %d/%d c 0x%x buf [%*s]\n", 995 "ippr_ftp_server_valid", 996 ftps->ftps_junk, (int)len, (int)i, 997 c, (int)len, buf); 998 return 1; 999 } 1000 search_eol: 1001 for (; i; i--) { 1002 pc = c; 1003 c = *s++; 1004 if ((pc == '\r') && (c == '\n')) { 1005 ftps->ftps_cmds = cmd; 1006 return 0; 1007 } 1008 } 1009 if (ifsftp->ippr_ftp_debug > 3) 1010 printf("ippr_ftp_server_valid:junk after cmd[%*s]\n", 1011 (int)len, buf); 1012 return 2; 1013 } 1014 1015 1016 int ippr_ftp_valid(ftp, side, buf, len, ifsftp) 1017 ftpinfo_t *ftp; 1018 int side; 1019 char *buf; 1020 size_t len; 1021 ifs_ftppxy_t *ifsftp; 1022 { 1023 ftpside_t *ftps; 1024 int ret; 1025 1026 ftps = &ftp->ftp_side[side]; 1027 1028 if (side == 0) 1029 ret = ippr_ftp_client_valid(ftps, buf, len, ifsftp); 1030 else 1031 ret = ippr_ftp_server_valid(ftps, buf, len, ifsftp); 1032 return ret; 1033 } 1034 1035 1036 /* 1037 * For map rules, the following applies: 1038 * rv == 0 for outbound processing, 1039 * rv == 1 for inbound processing. 1040 * For rdr rules, the following applies: 1041 * rv == 0 for inbound processing, 1042 * rv == 1 for outbound processing. 1043 */ 1044 int ippr_ftp_process(fin, nat, ftp, rv, ifsftp) 1045 fr_info_t *fin; 1046 nat_t *nat; 1047 ftpinfo_t *ftp; 1048 int rv; 1049 ifs_ftppxy_t *ifsftp; 1050 { 1051 int mlen, len, off, inc, i, sel, sel2, ok, ackoff, seqoff; 1052 char *rptr, *wptr, *s; 1053 u_32_t thseq, thack; 1054 ap_session_t *aps; 1055 ftpside_t *f, *t; 1056 tcphdr_t *tcp; 1057 ip_t *ip; 1058 mb_t *m; 1059 1060 m = fin->fin_m; 1061 ip = fin->fin_ip; 1062 tcp = (tcphdr_t *)fin->fin_dp; 1063 off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff; 1064 1065 f = &ftp->ftp_side[rv]; 1066 t = &ftp->ftp_side[1 - rv]; 1067 thseq = ntohl(tcp->th_seq); 1068 thack = ntohl(tcp->th_ack); 1069 1070 #ifdef __sgi 1071 mlen = fin->fin_plen - off; 1072 #else 1073 mlen = MSGDSIZE(m) - off; 1074 #endif 1075 if (ifsftp->ippr_ftp_debug > 4) 1076 printf("ippr_ftp_process: mlen %d\n", mlen); 1077 1078 if (mlen <= 0) { 1079 if ((tcp->th_flags & TH_OPENING) == TH_OPENING) { 1080 f->ftps_seq[0] = thseq + 1; 1081 t->ftps_seq[0] = thack; 1082 } 1083 return 0; 1084 } 1085 aps = nat->nat_aps; 1086 1087 sel = aps->aps_sel[1 - rv]; 1088 sel2 = aps->aps_sel[rv]; 1089 if (rv == 0) { 1090 seqoff = aps->aps_seqoff[sel]; 1091 if (aps->aps_seqmin[sel] > seqoff + thseq) 1092 seqoff = aps->aps_seqoff[!sel]; 1093 ackoff = aps->aps_ackoff[sel2]; 1094 if (aps->aps_ackmin[sel2] > ackoff + thack) 1095 ackoff = aps->aps_ackoff[!sel2]; 1096 } else { 1097 seqoff = aps->aps_ackoff[sel]; 1098 if (ifsftp->ippr_ftp_debug > 2) 1099 printf("seqoff %d thseq %x ackmin %x\n", seqoff, thseq, 1100 aps->aps_ackmin[sel]); 1101 if (aps->aps_ackmin[sel] > seqoff + thseq) 1102 seqoff = aps->aps_ackoff[!sel]; 1103 1104 ackoff = aps->aps_seqoff[sel2]; 1105 if (ifsftp->ippr_ftp_debug > 2) 1106 printf("ackoff %d thack %x seqmin %x\n", ackoff, thack, 1107 aps->aps_seqmin[sel2]); 1108 if (ackoff > 0) { 1109 if (aps->aps_seqmin[sel2] > ackoff + thack) 1110 ackoff = aps->aps_seqoff[!sel2]; 1111 } else { 1112 if (aps->aps_seqmin[sel2] > thack) 1113 ackoff = aps->aps_seqoff[!sel2]; 1114 } 1115 } 1116 if (ifsftp->ippr_ftp_debug > 2) { 1117 printf("%s: %x seq %x/%d ack %x/%d len %d/%d off %d\n", 1118 rv ? "IN" : "OUT", tcp->th_flags, thseq, seqoff, 1119 thack, ackoff, mlen, fin->fin_plen, off); 1120 printf("sel %d seqmin %x/%x offset %d/%d\n", sel, 1121 aps->aps_seqmin[sel], aps->aps_seqmin[sel2], 1122 aps->aps_seqoff[sel], aps->aps_seqoff[sel2]); 1123 printf("sel %d ackmin %x/%x offset %d/%d\n", sel2, 1124 aps->aps_ackmin[sel], aps->aps_ackmin[sel2], 1125 aps->aps_ackoff[sel], aps->aps_ackoff[sel2]); 1126 } 1127 1128 /* 1129 * XXX - Ideally, this packet should get dropped because we now know 1130 * that it is out of order (and there is no real danger in doing so 1131 * apart from causing packets to go through here ordered). 1132 */ 1133 if (ifsftp->ippr_ftp_debug > 2) { 1134 printf("rv %d t:seq[0] %x seq[1] %x %d/%d\n", 1135 rv, t->ftps_seq[0], t->ftps_seq[1], seqoff, ackoff); 1136 } 1137 1138 ok = 0; 1139 if (t->ftps_seq[0] == 0) { 1140 t->ftps_seq[0] = thack; 1141 ok = 1; 1142 } else { 1143 if (ackoff == 0) { 1144 if (t->ftps_seq[0] == thack) 1145 ok = 1; 1146 else if (t->ftps_seq[1] == thack) { 1147 t->ftps_seq[0] = thack; 1148 ok = 1; 1149 } 1150 } else { 1151 if (t->ftps_seq[0] + ackoff == thack) 1152 ok = 1; 1153 else if (t->ftps_seq[0] == thack + ackoff) 1154 ok = 1; 1155 else if (t->ftps_seq[1] + ackoff == thack) { 1156 t->ftps_seq[0] = thack - ackoff; 1157 ok = 1; 1158 } else if (t->ftps_seq[1] == thack + ackoff) { 1159 t->ftps_seq[0] = thack - ackoff; 1160 ok = 1; 1161 } 1162 } 1163 } 1164 1165 if (ifsftp->ippr_ftp_debug > 2) { 1166 if (!ok) 1167 printf("%s ok\n", "not"); 1168 } 1169 1170 if (!mlen) { 1171 if (t->ftps_seq[0] + ackoff != thack) { 1172 if (ifsftp->ippr_ftp_debug > 1) { 1173 printf("%s:seq[0](%x) + (%x) != (%x)\n", 1174 "ippr_ftp_process", t->ftps_seq[0], 1175 ackoff, thack); 1176 } 1177 return APR_ERR(1); 1178 } 1179 1180 if (ifsftp->ippr_ftp_debug > 2) { 1181 printf("ippr_ftp_process:f:seq[0] %x seq[1] %x\n", 1182 f->ftps_seq[0], f->ftps_seq[1]); 1183 } 1184 1185 if (tcp->th_flags & TH_FIN) { 1186 if (thseq == f->ftps_seq[1]) { 1187 f->ftps_seq[0] = f->ftps_seq[1] - seqoff; 1188 f->ftps_seq[1] = thseq + 1 - seqoff; 1189 } else { 1190 if (ifsftp->ippr_ftp_debug > 1) { 1191 printf("FIN: thseq %x seqoff %d ftps_seq %x\n", 1192 thseq, seqoff, f->ftps_seq[0]); 1193 } 1194 return APR_ERR(1); 1195 } 1196 } 1197 f->ftps_len = 0; 1198 return 0; 1199 } 1200 1201 ok = 0; 1202 if ((thseq == f->ftps_seq[0]) || (thseq == f->ftps_seq[1])) { 1203 ok = 1; 1204 /* 1205 * Retransmitted data packet. 1206 */ 1207 } else if ((thseq + mlen == f->ftps_seq[0]) || 1208 (thseq + mlen == f->ftps_seq[1])) { 1209 ok = 1; 1210 } 1211 1212 if (ok == 0) { 1213 inc = thseq - f->ftps_seq[0]; 1214 if (ifsftp->ippr_ftp_debug > 1) { 1215 printf("inc %d sel %d rv %d\n", inc, sel, rv); 1216 printf("th_seq %x ftps_seq %x/%x\n", 1217 thseq, f->ftps_seq[0], f->ftps_seq[1]); 1218 printf("ackmin %x ackoff %d\n", aps->aps_ackmin[sel], 1219 aps->aps_ackoff[sel]); 1220 printf("seqmin %x seqoff %d\n", aps->aps_seqmin[sel], 1221 aps->aps_seqoff[sel]); 1222 } 1223 1224 return APR_ERR(1); 1225 } 1226 1227 inc = 0; 1228 rptr = f->ftps_rptr; 1229 wptr = f->ftps_wptr; 1230 f->ftps_seq[0] = thseq; 1231 f->ftps_seq[1] = f->ftps_seq[0] + mlen; 1232 f->ftps_len = mlen; 1233 1234 while (mlen > 0) { 1235 len = MIN(mlen, sizeof(f->ftps_buf) - (wptr - rptr)); 1236 COPYDATA(m, off, len, wptr); 1237 mlen -= len; 1238 off += len; 1239 wptr += len; 1240 1241 if (ifsftp->ippr_ftp_debug > 3) 1242 printf("%s:len %d/%d off %d wptr %lx junk %d [%*s]\n", 1243 "ippr_ftp_process", 1244 len, mlen, off, (u_long)wptr, f->ftps_junk, 1245 len, rptr); 1246 1247 f->ftps_wptr = wptr; 1248 if (f->ftps_junk != 0) { 1249 i = f->ftps_junk; 1250 f->ftps_junk = ippr_ftp_valid(ftp, rv, rptr, 1251 wptr - rptr, ifsftp); 1252 1253 if (ifsftp->ippr_ftp_debug > 5) 1254 printf("%s:junk %d -> %d\n", 1255 "ippr_ftp_process", i, f->ftps_junk); 1256 1257 if (f->ftps_junk != 0) { 1258 if (wptr - rptr == sizeof(f->ftps_buf)) { 1259 if (ifsftp->ippr_ftp_debug > 4) 1260 printf("%s:full buffer\n", 1261 "ippr_ftp_process"); 1262 f->ftps_rptr = f->ftps_buf; 1263 f->ftps_wptr = f->ftps_buf; 1264 rptr = f->ftps_rptr; 1265 wptr = f->ftps_wptr; 1266 /* 1267 * Because we throw away data here that 1268 * we would otherwise parse, set the 1269 * junk flag to indicate just ignore 1270 * any data upto the next CRLF. 1271 */ 1272 f->ftps_junk = 1; 1273 continue; 1274 } 1275 } 1276 } 1277 1278 while ((f->ftps_junk == 0) && (wptr > rptr)) { 1279 len = wptr - rptr; 1280 f->ftps_junk = ippr_ftp_valid(ftp, rv, rptr, len, ifsftp); 1281 1282 if (ifsftp->ippr_ftp_debug > 3) { 1283 printf("%s=%d len %d rv %d ptr %lx/%lx ", 1284 "ippr_ftp_valid", 1285 f->ftps_junk, len, rv, (u_long)rptr, 1286 (u_long)wptr); 1287 printf("buf [%*s]\n", len, rptr); 1288 } 1289 1290 if (f->ftps_junk == 0) { 1291 f->ftps_rptr = rptr; 1292 if (rv) 1293 inc += ippr_ftp_server(fin, ip, nat, 1294 ftp, len, ifsftp); 1295 else 1296 inc += ippr_ftp_client(fin, ip, nat, 1297 ftp, len, ifsftp); 1298 rptr = f->ftps_rptr; 1299 wptr = f->ftps_wptr; 1300 } 1301 } 1302 1303 /* 1304 * Off to a bad start so lets just forget about using the 1305 * ftp proxy for this connection. 1306 */ 1307 if ((f->ftps_cmds == 0) && (f->ftps_junk == 1)) { 1308 /* f->ftps_seq[1] += inc; */ 1309 1310 if (ifsftp->ippr_ftp_debug > 1) 1311 printf("%s:cmds == 0 junk == 1\n", 1312 "ippr_ftp_process"); 1313 return APR_ERR(2); 1314 } 1315 1316 if ((f->ftps_junk != 0) && (rptr < wptr)) { 1317 for (s = rptr; s < wptr; s++) { 1318 if ((*s == '\r') && (s + 1 < wptr) && 1319 (*(s + 1) == '\n')) { 1320 rptr = s + 2; 1321 f->ftps_junk = 0; 1322 break; 1323 } 1324 } 1325 } 1326 1327 if (rptr == wptr) { 1328 rptr = wptr = f->ftps_buf; 1329 } else { 1330 /* 1331 * Compact the buffer back to the start. The junk 1332 * flag should already be set and because we're not 1333 * throwing away any data, it is preserved from its 1334 * current state. 1335 */ 1336 if (rptr > f->ftps_buf) { 1337 bcopy(rptr, f->ftps_buf, len); 1338 wptr -= rptr - f->ftps_buf; 1339 rptr = f->ftps_buf; 1340 } 1341 } 1342 f->ftps_rptr = rptr; 1343 f->ftps_wptr = wptr; 1344 } 1345 1346 /* f->ftps_seq[1] += inc; */ 1347 if (tcp->th_flags & TH_FIN) 1348 f->ftps_seq[1]++; 1349 if (ifsftp->ippr_ftp_debug > 3) { 1350 #ifdef __sgi 1351 mlen = fin->fin_plen; 1352 #else 1353 mlen = MSGDSIZE(m); 1354 #endif 1355 mlen -= off; 1356 printf("ftps_seq[1] = %x inc %d len %d\n", 1357 f->ftps_seq[1], inc, mlen); 1358 } 1359 1360 f->ftps_rptr = rptr; 1361 f->ftps_wptr = wptr; 1362 return APR_INC(inc); 1363 } 1364 1365 1366 int ippr_ftp_out(fin, aps, nat, private) 1367 fr_info_t *fin; 1368 ap_session_t *aps; 1369 nat_t *nat; 1370 void *private; 1371 { 1372 ftpinfo_t *ftp; 1373 int rev; 1374 1375 ftp = aps->aps_data; 1376 if (ftp == NULL) 1377 return 0; 1378 1379 rev = (nat->nat_dir == NAT_OUTBOUND) ? 0 : 1; 1380 if (ftp->ftp_side[1 - rev].ftps_ifp == NULL) 1381 ftp->ftp_side[1 - rev].ftps_ifp = fin->fin_ifp; 1382 1383 return ippr_ftp_process(fin, nat, ftp, rev, (ifs_ftppxy_t *)private); 1384 } 1385 1386 1387 int ippr_ftp_in(fin, aps, nat, private) 1388 fr_info_t *fin; 1389 ap_session_t *aps; 1390 nat_t *nat; 1391 void *private; 1392 { 1393 ftpinfo_t *ftp; 1394 int rev; 1395 1396 ftp = aps->aps_data; 1397 if (ftp == NULL) 1398 return 0; 1399 1400 rev = (nat->nat_dir == NAT_OUTBOUND) ? 0 : 1; 1401 if (ftp->ftp_side[rev].ftps_ifp == NULL) 1402 ftp->ftp_side[rev].ftps_ifp = fin->fin_ifp; 1403 1404 return ippr_ftp_process(fin, nat, ftp, 1 - rev, (ifs_ftppxy_t *)private); 1405 } 1406 1407 1408 /* 1409 * ippr_ftp_atoi - implement a version of atoi which processes numbers in 1410 * pairs separated by commas (which are expected to be in the range 0 - 255), 1411 * returning a 16 bit number combining either side of the , as the MSB and 1412 * LSB. 1413 */ 1414 u_short ippr_ftp_atoi(ptr) 1415 char **ptr; 1416 { 1417 register char *s = *ptr, c; 1418 register u_char i = 0, j = 0; 1419 1420 while (((c = *s++) != '\0') && ISDIGIT(c)) { 1421 i *= 10; 1422 i += c - '0'; 1423 } 1424 if (c != ',') { 1425 *ptr = NULL; 1426 return 0; 1427 } 1428 while (((c = *s++) != '\0') && ISDIGIT(c)) { 1429 j *= 10; 1430 j += c - '0'; 1431 } 1432 *ptr = s; 1433 i &= 0xff; 1434 j &= 0xff; 1435 return (i << 8) | j; 1436 } 1437 1438 1439 int ippr_ftp_epsv(fin, ip, nat, f, dlen, ifsftp) 1440 fr_info_t *fin; 1441 ip_t *ip; 1442 nat_t *nat; 1443 ftpside_t *f; 1444 int dlen; 1445 ifs_ftppxy_t *ifsftp; 1446 { 1447 char newbuf[IPF_FTPBUFSZ]; 1448 char *s; 1449 u_short ap = 0; 1450 1451 #define EPSV_REPLEN 33 1452 /* 1453 * Check for EPSV reply message. 1454 */ 1455 if (dlen < IPF_MIN229LEN) 1456 return (0); 1457 else if (strncmp(f->ftps_rptr, 1458 "229 Entering Extended Passive Mode", EPSV_REPLEN)) 1459 return (0); 1460 1461 /* 1462 * Skip the EPSV command + space 1463 */ 1464 s = f->ftps_rptr + 33; 1465 while (*s && !ISDIGIT(*s)) 1466 s++; 1467 1468 /* 1469 * As per RFC 2428, there are no addres components in the EPSV 1470 * response. So we'll go straight to getting the port. 1471 */ 1472 while (*s && ISDIGIT(*s)) { 1473 ap *= 10; 1474 ap += *s++ - '0'; 1475 } 1476 1477 if (!s) 1478 return 0; 1479 1480 if (*s == '|') 1481 s++; 1482 if (*s == ')') 1483 s++; 1484 if (*s == '\n') 1485 s--; 1486 /* 1487 * check for CR-LF at the end. 1488 */ 1489 if ((*s == '\r') && (*(s + 1) == '\n')) { 1490 s += 2; 1491 } else 1492 return 0; 1493 1494 #if defined(SNPRINTF) && defined(_KERNEL) 1495 (void) SNPRINTF(newbuf, sizeof(newbuf), "%s (|||%u|)\r\n", 1496 "229 Entering Extended Passive Mode", ap); 1497 #else 1498 (void) sprintf(newbuf, "%s (|||%u|)\r\n", 1499 "229 Entering Extended Passive Mode", ap); 1500 #endif 1501 1502 return ippr_ftp_pasvreply(fin, ip, nat, f, (u_int)ap, newbuf, s, 1503 ip->ip_src.s_addr, ifsftp); 1504 } 1505