1 1.96 jkoshy /* $NetBSD: ftpcmd.y,v 1.96 2024/02/16 19:32:38 jkoshy Exp $ */ 2 1.41 lukem 3 1.41 lukem /*- 4 1.89 lukem * Copyright (c) 1997-2009 The NetBSD Foundation, Inc. 5 1.41 lukem * All rights reserved. 6 1.41 lukem * 7 1.41 lukem * This code is derived from software contributed to The NetBSD Foundation 8 1.41 lukem * by Luke Mewburn. 9 1.41 lukem * 10 1.41 lukem * Redistribution and use in source and binary forms, with or without 11 1.41 lukem * modification, are permitted provided that the following conditions 12 1.41 lukem * are met: 13 1.41 lukem * 1. Redistributions of source code must retain the above copyright 14 1.41 lukem * notice, this list of conditions and the following disclaimer. 15 1.41 lukem * 2. Redistributions in binary form must reproduce the above copyright 16 1.41 lukem * notice, this list of conditions and the following disclaimer in the 17 1.41 lukem * documentation and/or other materials provided with the distribution. 18 1.41 lukem * 19 1.41 lukem * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.41 lukem * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.41 lukem * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.41 lukem * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.41 lukem * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.41 lukem * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.41 lukem * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.41 lukem * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.41 lukem * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.41 lukem * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.41 lukem * POSSIBILITY OF SUCH DAMAGE. 30 1.41 lukem */ 31 1.5 cgd 32 1.1 cgd /* 33 1.4 deraadt * Copyright (c) 1985, 1988, 1993, 1994 34 1.4 deraadt * The Regents of the University of California. All rights reserved. 35 1.1 cgd * 36 1.1 cgd * Redistribution and use in source and binary forms, with or without 37 1.1 cgd * modification, are permitted provided that the following conditions 38 1.1 cgd * are met: 39 1.1 cgd * 1. Redistributions of source code must retain the above copyright 40 1.1 cgd * notice, this list of conditions and the following disclaimer. 41 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 42 1.1 cgd * notice, this list of conditions and the following disclaimer in the 43 1.1 cgd * documentation and/or other materials provided with the distribution. 44 1.77 agc * 3. Neither the name of the University nor the names of its contributors 45 1.1 cgd * may be used to endorse or promote products derived from this software 46 1.1 cgd * without specific prior written permission. 47 1.1 cgd * 48 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 49 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 50 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 51 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 52 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 53 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 54 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 55 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 56 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 57 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 58 1.1 cgd * SUCH DAMAGE. 59 1.1 cgd * 60 1.4 deraadt * @(#)ftpcmd.y 8.3 (Berkeley) 4/6/94 61 1.1 cgd */ 62 1.1 cgd 63 1.1 cgd /* 64 1.1 cgd * Grammar for FTP commands. 65 1.1 cgd * See RFC 959. 66 1.1 cgd */ 67 1.1 cgd 68 1.1 cgd %{ 69 1.13 christos #include <sys/cdefs.h> 70 1.1 cgd 71 1.1 cgd #ifndef lint 72 1.5 cgd #if 0 73 1.4 deraadt static char sccsid[] = "@(#)ftpcmd.y 8.3 (Berkeley) 4/6/94"; 74 1.5 cgd #else 75 1.96 jkoshy __RCSID("$NetBSD: ftpcmd.y,v 1.96 2024/02/16 19:32:38 jkoshy Exp $"); 76 1.5 cgd #endif 77 1.1 cgd #endif /* not lint */ 78 1.1 cgd 79 1.1 cgd #include <sys/param.h> 80 1.1 cgd #include <sys/socket.h> 81 1.1 cgd #include <sys/stat.h> 82 1.4 deraadt 83 1.1 cgd #include <netinet/in.h> 84 1.1 cgd #include <arpa/ftp.h> 85 1.15 mrg #include <arpa/inet.h> 86 1.4 deraadt 87 1.4 deraadt #include <ctype.h> 88 1.4 deraadt #include <errno.h> 89 1.4 deraadt #include <pwd.h> 90 1.4 deraadt #include <stdio.h> 91 1.4 deraadt #include <stdlib.h> 92 1.4 deraadt #include <string.h> 93 1.1 cgd #include <syslog.h> 94 1.1 cgd #include <time.h> 95 1.18 lukem #include <tzfile.h> 96 1.1 cgd #include <unistd.h> 97 1.32 itojun #include <netdb.h> 98 1.26 explorer 99 1.26 explorer #ifdef KERBEROS5 100 1.36 christos #include <krb5/krb5.h> 101 1.26 explorer #endif 102 1.4 deraadt 103 1.4 deraadt #include "extern.h" 104 1.45 lukem #include "version.h" 105 1.1 cgd 106 1.1 cgd static int cmd_type; 107 1.1 cgd static int cmd_form; 108 1.1 cgd static int cmd_bytesz; 109 1.44 lukem 110 1.60 aidan char cbuf[FTP_BUFLEN]; 111 1.60 aidan char *cmdp; 112 1.1 cgd char *fromname; 113 1.24 lukem 114 1.82 lukem extern int epsvall; 115 1.82 lukem struct tab sitetab[]; 116 1.82 lukem 117 1.82 lukem static int check_write(const char *, int); 118 1.82 lukem static void help(struct tab *, const char *); 119 1.82 lukem static void port_check(const char *, int); 120 1.82 lukem int yylex(void); 121 1.82 lukem 122 1.1 cgd %} 123 1.1 cgd 124 1.4 deraadt %union { 125 1.70 lukem struct { 126 1.74 lukem LLT ll; 127 1.70 lukem int i; 128 1.70 lukem } u; 129 1.89 lukem char *s; 130 1.89 lukem const char *cs; 131 1.4 deraadt } 132 1.4 deraadt 133 1.1 cgd %token 134 1.1 cgd A B C E F I 135 1.1 cgd L N P R S T 136 1.1 cgd 137 1.80 lukem SP CRLF COMMA ALL 138 1.1 cgd 139 1.23 lukem USER PASS ACCT CWD CDUP SMNT 140 1.23 lukem QUIT REIN PORT PASV TYPE STRU 141 1.23 lukem MODE RETR STOR STOU APPE ALLO 142 1.23 lukem REST RNFR RNTO ABOR DELE RMD 143 1.23 lukem MKD PWD LIST NLST SITE SYST 144 1.23 lukem STAT HELP NOOP 145 1.23 lukem 146 1.25 lukem AUTH ADAT PROT PBSZ CCC MIC 147 1.25 lukem CONF ENC 148 1.25 lukem 149 1.23 lukem FEAT OPTS 150 1.21 lukem 151 1.47 lukem SIZE MDTM MLST MLSD 152 1.1 cgd 153 1.32 itojun LPRT LPSV EPRT EPSV 154 1.32 itojun 155 1.23 lukem MAIL MLFL MRCP MRSQ MSAM MSND 156 1.23 lukem MSOM 157 1.23 lukem 158 1.41 lukem CHMOD IDLE RATEGET RATEPUT UMASK 159 1.1 cgd 160 1.1 cgd LEXERR 161 1.1 cgd 162 1.4 deraadt %token <s> STRING 163 1.70 lukem %token <u> NUMBER 164 1.4 deraadt 165 1.70 lukem %type <u.i> check_login octal_number byte_size 166 1.70 lukem %type <u.i> struct_code mode_code type_code form_code decimal_integer 167 1.4 deraadt %type <s> pathstring pathname password username 168 1.25 lukem %type <s> mechanism_name base64data prot_code 169 1.4 deraadt 170 1.60 aidan %start cmd_sel 171 1.1 cgd 172 1.1 cgd %% 173 1.1 cgd 174 1.60 aidan cmd_sel 175 1.60 aidan : cmd 176 1.4 deraadt { 177 1.78 lukem REASSIGN(fromname, NULL); 178 1.1 cgd restart_point = (off_t) 0; 179 1.1 cgd } 180 1.23 lukem 181 1.60 aidan | rcmd 182 1.23 lukem 183 1.1 cgd ; 184 1.1 cgd 185 1.4 deraadt cmd 186 1.23 lukem /* RFC 959 */ 187 1.4 deraadt : USER SP username CRLF 188 1.4 deraadt { 189 1.4 deraadt user($3); 190 1.4 deraadt free($3); 191 1.4 deraadt } 192 1.23 lukem 193 1.4 deraadt | PASS SP password CRLF 194 1.4 deraadt { 195 1.4 deraadt pass($3); 196 1.94 shm explicit_memset($3, 0, strlen($3)); 197 1.4 deraadt free($3); 198 1.1 cgd } 199 1.23 lukem 200 1.23 lukem | CWD check_login CRLF 201 1.23 lukem { 202 1.23 lukem if ($2) 203 1.51 lukem cwd(homedir); 204 1.23 lukem } 205 1.23 lukem 206 1.23 lukem | CWD check_login SP pathname CRLF 207 1.23 lukem { 208 1.23 lukem if ($2 && $4 != NULL) 209 1.23 lukem cwd($4); 210 1.23 lukem if ($4 != NULL) 211 1.23 lukem free($4); 212 1.23 lukem } 213 1.23 lukem 214 1.23 lukem | CDUP check_login CRLF 215 1.23 lukem { 216 1.23 lukem if ($2) 217 1.23 lukem cwd(".."); 218 1.23 lukem } 219 1.23 lukem 220 1.23 lukem | QUIT CRLF 221 1.23 lukem { 222 1.27 lukem if (logged_in) { 223 1.49 sommerfe reply(-221, "%s", ""); 224 1.48 lukem reply(0, 225 1.55 lukem "Data traffic for this session was " LLF " byte%s in " LLF " file%s.", 226 1.55 lukem (LLT)total_data, PLURAL(total_data), 227 1.55 lukem (LLT)total_files, PLURAL(total_files)); 228 1.48 lukem reply(0, 229 1.55 lukem "Total traffic for this session was " LLF " byte%s in " LLF " transfer%s.", 230 1.55 lukem (LLT)total_bytes, PLURAL(total_bytes), 231 1.55 lukem (LLT)total_xfers, PLURAL(total_xfers)); 232 1.31 lukem } 233 1.31 lukem reply(221, 234 1.31 lukem "Thank you for using the FTP service on %s.", 235 1.31 lukem hostname); 236 1.59 lukem if (logged_in && logging) { 237 1.27 lukem syslog(LOG_INFO, 238 1.55 lukem "Data traffic: " LLF " byte%s in " LLF " file%s", 239 1.55 lukem (LLT)total_data, PLURAL(total_data), 240 1.55 lukem (LLT)total_files, PLURAL(total_files)); 241 1.27 lukem syslog(LOG_INFO, 242 1.55 lukem "Total traffic: " LLF " byte%s in " LLF " transfer%s", 243 1.55 lukem (LLT)total_bytes, PLURAL(total_bytes), 244 1.55 lukem (LLT)total_xfers, PLURAL(total_xfers)); 245 1.27 lukem } 246 1.31 lukem 247 1.23 lukem dologout(0); 248 1.23 lukem } 249 1.23 lukem 250 1.15 mrg | PORT check_login SP host_port CRLF 251 1.4 deraadt { 252 1.52 lukem if ($2) 253 1.52 lukem port_check("PORT", AF_INET); 254 1.32 itojun } 255 1.32 itojun 256 1.34 itojun | LPRT check_login SP host_long_port4 CRLF 257 1.32 itojun { 258 1.52 lukem if ($2) 259 1.52 lukem port_check("LPRT", AF_INET); 260 1.34 itojun } 261 1.34 itojun 262 1.34 itojun | LPRT check_login SP host_long_port6 CRLF 263 1.34 itojun { 264 1.57 lukem #ifdef INET6 265 1.52 lukem if ($2) 266 1.52 lukem port_check("LPRT", AF_INET6); 267 1.57 lukem #else 268 1.57 lukem reply(500, "IPv6 support not available."); 269 1.57 lukem #endif 270 1.1 cgd } 271 1.23 lukem 272 1.32 itojun | EPRT check_login SP STRING CRLF 273 1.32 itojun { 274 1.42 lukem if ($2) { 275 1.54 itojun if (extended_port($4) == 0) 276 1.54 itojun port_check("EPRT", -1); 277 1.42 lukem } 278 1.42 lukem free($4); 279 1.32 itojun } 280 1.32 itojun 281 1.20 tv | PASV check_login CRLF 282 1.4 deraadt { 283 1.42 lukem if ($2) { 284 1.56 lukem if (CURCLASS_FLAGS_ISSET(passive)) 285 1.42 lukem passive(); 286 1.42 lukem else 287 1.42 lukem reply(500, "PASV mode not available."); 288 1.20 tv } 289 1.1 cgd } 290 1.23 lukem 291 1.42 lukem | LPSV check_login CRLF 292 1.32 itojun { 293 1.42 lukem if ($2) { 294 1.69 tv if (CURCLASS_FLAGS_ISSET(passive)) { 295 1.69 tv if (epsvall) 296 1.69 tv reply(501, 297 1.69 tv "LPSV disallowed after EPSV ALL"); 298 1.69 tv else 299 1.69 tv long_passive("LPSV", PF_UNSPEC); 300 1.69 tv } else 301 1.69 tv reply(500, "LPSV mode not available."); 302 1.42 lukem } 303 1.32 itojun } 304 1.32 itojun 305 1.42 lukem | EPSV check_login SP NUMBER CRLF 306 1.32 itojun { 307 1.69 tv if ($2) { 308 1.69 tv if (CURCLASS_FLAGS_ISSET(passive)) 309 1.70 lukem long_passive("EPSV", 310 1.70 lukem epsvproto2af($4.i)); 311 1.69 tv else 312 1.69 tv reply(500, "EPSV mode not available."); 313 1.69 tv } 314 1.32 itojun } 315 1.32 itojun 316 1.42 lukem | EPSV check_login SP ALL CRLF 317 1.32 itojun { 318 1.42 lukem if ($2) { 319 1.69 tv if (CURCLASS_FLAGS_ISSET(passive)) { 320 1.70 lukem reply(200, 321 1.70 lukem "EPSV ALL command successful."); 322 1.69 tv epsvall++; 323 1.69 tv } else 324 1.69 tv reply(500, "EPSV mode not available."); 325 1.32 itojun } 326 1.32 itojun } 327 1.32 itojun 328 1.42 lukem | EPSV check_login CRLF 329 1.32 itojun { 330 1.69 tv if ($2) { 331 1.69 tv if (CURCLASS_FLAGS_ISSET(passive)) 332 1.69 tv long_passive("EPSV", PF_UNSPEC); 333 1.69 tv else 334 1.69 tv reply(500, "EPSV mode not available."); 335 1.69 tv } 336 1.32 itojun } 337 1.32 itojun 338 1.42 lukem | TYPE check_login SP type_code CRLF 339 1.4 deraadt { 340 1.42 lukem if ($2) { 341 1.42 lukem 342 1.1 cgd switch (cmd_type) { 343 1.1 cgd 344 1.1 cgd case TYPE_A: 345 1.1 cgd if (cmd_form == FORM_N) { 346 1.1 cgd reply(200, "Type set to A."); 347 1.1 cgd type = cmd_type; 348 1.1 cgd form = cmd_form; 349 1.1 cgd } else 350 1.1 cgd reply(504, "Form must be N."); 351 1.1 cgd break; 352 1.1 cgd 353 1.1 cgd case TYPE_E: 354 1.1 cgd reply(504, "Type E not implemented."); 355 1.1 cgd break; 356 1.1 cgd 357 1.1 cgd case TYPE_I: 358 1.1 cgd reply(200, "Type set to I."); 359 1.1 cgd type = cmd_type; 360 1.1 cgd break; 361 1.1 cgd 362 1.1 cgd case TYPE_L: 363 1.1 cgd #if NBBY == 8 364 1.1 cgd if (cmd_bytesz == 8) { 365 1.1 cgd reply(200, 366 1.1 cgd "Type set to L (byte size 8)."); 367 1.1 cgd type = cmd_type; 368 1.1 cgd } else 369 1.1 cgd reply(504, "Byte size must be 8."); 370 1.1 cgd #else /* NBBY == 8 */ 371 1.1 cgd UNIMPLEMENTED for NBBY != 8 372 1.1 cgd #endif /* NBBY == 8 */ 373 1.1 cgd } 374 1.42 lukem 375 1.42 lukem } 376 1.1 cgd } 377 1.23 lukem 378 1.42 lukem | STRU check_login SP struct_code CRLF 379 1.4 deraadt { 380 1.42 lukem if ($2) { 381 1.42 lukem switch ($4) { 382 1.1 cgd 383 1.42 lukem case STRU_F: 384 1.42 lukem reply(200, "STRU F ok."); 385 1.42 lukem break; 386 1.1 cgd 387 1.42 lukem default: 388 1.42 lukem reply(504, "Unimplemented STRU type."); 389 1.42 lukem } 390 1.1 cgd } 391 1.1 cgd } 392 1.23 lukem 393 1.42 lukem | MODE check_login SP mode_code CRLF 394 1.4 deraadt { 395 1.42 lukem if ($2) { 396 1.42 lukem switch ($4) { 397 1.1 cgd 398 1.42 lukem case MODE_S: 399 1.42 lukem reply(200, "MODE S ok."); 400 1.42 lukem break; 401 1.1 cgd 402 1.42 lukem default: 403 1.42 lukem reply(502, "Unimplemented MODE type."); 404 1.42 lukem } 405 1.1 cgd } 406 1.1 cgd } 407 1.23 lukem 408 1.4 deraadt | RETR check_login SP pathname CRLF 409 1.4 deraadt { 410 1.1 cgd if ($2 && $4 != NULL) 411 1.22 lukem retrieve(NULL, $4); 412 1.1 cgd if ($4 != NULL) 413 1.4 deraadt free($4); 414 1.1 cgd } 415 1.23 lukem 416 1.56 lukem | STOR SP pathname CRLF 417 1.4 deraadt { 418 1.56 lukem if (check_write($3, 1)) 419 1.56 lukem store($3, "w", 0); 420 1.56 lukem if ($3 != NULL) 421 1.56 lukem free($3); 422 1.1 cgd } 423 1.23 lukem 424 1.56 lukem | STOU SP pathname CRLF 425 1.4 deraadt { 426 1.56 lukem if (check_write($3, 1)) 427 1.56 lukem store($3, "w", 1); 428 1.56 lukem if ($3 != NULL) 429 1.56 lukem free($3); 430 1.1 cgd } 431 1.23 lukem 432 1.56 lukem | APPE SP pathname CRLF 433 1.4 deraadt { 434 1.56 lukem if (check_write($3, 1)) 435 1.56 lukem store($3, "a", 0); 436 1.56 lukem if ($3 != NULL) 437 1.56 lukem free($3); 438 1.1 cgd } 439 1.23 lukem 440 1.42 lukem | ALLO check_login SP NUMBER CRLF 441 1.4 deraadt { 442 1.42 lukem if ($2) 443 1.42 lukem reply(202, "ALLO command ignored."); 444 1.1 cgd } 445 1.23 lukem 446 1.42 lukem | ALLO check_login SP NUMBER SP R SP NUMBER CRLF 447 1.4 deraadt { 448 1.42 lukem if ($2) 449 1.42 lukem reply(202, "ALLO command ignored."); 450 1.1 cgd } 451 1.23 lukem 452 1.56 lukem | RNTO SP pathname CRLF 453 1.4 deraadt { 454 1.56 lukem if (check_write($3, 0)) { 455 1.42 lukem if (fromname) { 456 1.56 lukem renamecmd(fromname, $3); 457 1.78 lukem REASSIGN(fromname, NULL); 458 1.42 lukem } else { 459 1.42 lukem reply(503, "Bad sequence of commands."); 460 1.42 lukem } 461 1.1 cgd } 462 1.56 lukem if ($3 != NULL) 463 1.56 lukem free($3); 464 1.1 cgd } 465 1.23 lukem 466 1.42 lukem | ABOR check_login CRLF 467 1.4 deraadt { 468 1.60 aidan if (is_oob) 469 1.60 aidan abor(); 470 1.60 aidan else if ($2) 471 1.42 lukem reply(225, "ABOR command successful."); 472 1.1 cgd } 473 1.23 lukem 474 1.56 lukem | DELE SP pathname CRLF 475 1.4 deraadt { 476 1.56 lukem if (check_write($3, 0)) 477 1.56 lukem delete($3); 478 1.56 lukem if ($3 != NULL) 479 1.56 lukem free($3); 480 1.1 cgd } 481 1.23 lukem 482 1.56 lukem | RMD SP pathname CRLF 483 1.4 deraadt { 484 1.56 lukem if (check_write($3, 0)) 485 1.56 lukem removedir($3); 486 1.56 lukem if ($3 != NULL) 487 1.56 lukem free($3); 488 1.1 cgd } 489 1.1 cgd 490 1.56 lukem | MKD SP pathname CRLF 491 1.4 deraadt { 492 1.56 lukem if (check_write($3, 0)) 493 1.56 lukem makedir($3); 494 1.56 lukem if ($3 != NULL) 495 1.56 lukem free($3); 496 1.1 cgd } 497 1.23 lukem 498 1.23 lukem | PWD check_login CRLF 499 1.23 lukem { 500 1.23 lukem if ($2) 501 1.23 lukem pwd(); 502 1.23 lukem } 503 1.23 lukem 504 1.23 lukem | LIST check_login CRLF 505 1.23 lukem { 506 1.89 lukem const char *argv[] = { INTERNAL_LS, "-lgA", NULL }; 507 1.40 lukem 508 1.83 ginsbach if (CURCLASS_FLAGS_ISSET(hidesymlinks)) 509 1.83 ginsbach argv[1] = "-LlgA"; 510 1.23 lukem if ($2) 511 1.40 lukem retrieve(argv, ""); 512 1.23 lukem } 513 1.23 lukem 514 1.23 lukem | LIST check_login SP pathname CRLF 515 1.4 deraadt { 516 1.89 lukem const char *argv[] = { INTERNAL_LS, "-lgA", NULL, NULL }; 517 1.40 lukem 518 1.83 ginsbach if (CURCLASS_FLAGS_ISSET(hidesymlinks)) 519 1.83 ginsbach argv[1] = "-LlgA"; 520 1.40 lukem if ($2 && $4 != NULL) { 521 1.40 lukem argv[2] = $4; 522 1.40 lukem retrieve(argv, $4); 523 1.40 lukem } 524 1.1 cgd if ($4 != NULL) 525 1.4 deraadt free($4); 526 1.1 cgd } 527 1.23 lukem 528 1.23 lukem | NLST check_login CRLF 529 1.4 deraadt { 530 1.1 cgd if ($2) 531 1.23 lukem send_file_list("."); 532 1.1 cgd } 533 1.23 lukem 534 1.51 lukem | NLST check_login SP pathname CRLF 535 1.4 deraadt { 536 1.42 lukem if ($2) 537 1.23 lukem send_file_list($4); 538 1.42 lukem free($4); 539 1.1 cgd } 540 1.23 lukem 541 1.4 deraadt | SITE SP HELP CRLF 542 1.4 deraadt { 543 1.22 lukem help(sitetab, NULL); 544 1.1 cgd } 545 1.23 lukem 546 1.56 lukem | SITE SP CHMOD SP octal_number SP pathname CRLF 547 1.4 deraadt { 548 1.56 lukem if (check_write($7, 0)) { 549 1.79 lukem if (($5 == -1) || ($5 > 0777)) 550 1.1 cgd reply(501, 551 1.1 cgd "CHMOD: Mode value must be between 0 and 0777"); 552 1.56 lukem else if (chmod($7, $5) < 0) 553 1.56 lukem perror_reply(550, $7); 554 1.1 cgd else 555 1.1 cgd reply(200, "CHMOD command successful."); 556 1.1 cgd } 557 1.56 lukem if ($7 != NULL) 558 1.56 lukem free($7); 559 1.1 cgd } 560 1.23 lukem 561 1.41 lukem | SITE SP HELP SP STRING CRLF 562 1.41 lukem { 563 1.41 lukem help(sitetab, $5); 564 1.42 lukem free($5); 565 1.41 lukem } 566 1.41 lukem 567 1.42 lukem | SITE SP IDLE check_login CRLF 568 1.4 deraadt { 569 1.42 lukem if ($4) { 570 1.42 lukem reply(200, 571 1.72 lukem "Current IDLE time limit is " LLF 572 1.72 lukem " seconds; max " LLF, 573 1.72 lukem (LLT)curclass.timeout, 574 1.72 lukem (LLT)curclass.maxtimeout); 575 1.42 lukem } 576 1.1 cgd } 577 1.23 lukem 578 1.42 lukem | SITE SP IDLE check_login SP NUMBER CRLF 579 1.4 deraadt { 580 1.42 lukem if ($4) { 581 1.70 lukem if ($6.i < 30 || $6.i > curclass.maxtimeout) { 582 1.42 lukem reply(501, 583 1.72 lukem "IDLE time limit must be between 30 and " 584 1.72 lukem LLF " seconds", 585 1.72 lukem (LLT)curclass.maxtimeout); 586 1.42 lukem } else { 587 1.70 lukem curclass.timeout = $6.i; 588 1.42 lukem (void) alarm(curclass.timeout); 589 1.42 lukem reply(200, 590 1.72 lukem "IDLE time limit set to " 591 1.72 lukem LLF " seconds", 592 1.72 lukem (LLT)curclass.timeout); 593 1.42 lukem } 594 1.1 cgd } 595 1.1 cgd } 596 1.23 lukem 597 1.42 lukem | SITE SP RATEGET check_login CRLF 598 1.41 lukem { 599 1.42 lukem if ($4) { 600 1.56 lukem reply(200, 601 1.56 lukem "Current RATEGET is " LLF " bytes/sec", 602 1.56 lukem (LLT)curclass.rateget); 603 1.42 lukem } 604 1.41 lukem } 605 1.41 lukem 606 1.42 lukem | SITE SP RATEGET check_login SP STRING CRLF 607 1.41 lukem { 608 1.72 lukem char errbuf[100]; 609 1.42 lukem char *p = $6; 610 1.56 lukem LLT rate; 611 1.41 lukem 612 1.42 lukem if ($4) { 613 1.72 lukem rate = strsuftollx("RATEGET", p, 0, 614 1.72 lukem curclass.maxrateget 615 1.72 lukem ? curclass.maxrateget 616 1.72 lukem : LLTMAX, errbuf, sizeof(errbuf)); 617 1.72 lukem if (errbuf[0]) 618 1.72 lukem reply(501, "%s", errbuf); 619 1.42 lukem else { 620 1.42 lukem curclass.rateget = rate; 621 1.42 lukem reply(200, 622 1.56 lukem "RATEGET set to " LLF " bytes/sec", 623 1.56 lukem (LLT)curclass.rateget); 624 1.42 lukem } 625 1.41 lukem } 626 1.42 lukem free($6); 627 1.41 lukem } 628 1.41 lukem 629 1.42 lukem | SITE SP RATEPUT check_login CRLF 630 1.41 lukem { 631 1.42 lukem if ($4) { 632 1.56 lukem reply(200, 633 1.56 lukem "Current RATEPUT is " LLF " bytes/sec", 634 1.56 lukem (LLT)curclass.rateput); 635 1.42 lukem } 636 1.41 lukem } 637 1.41 lukem 638 1.42 lukem | SITE SP RATEPUT check_login SP STRING CRLF 639 1.41 lukem { 640 1.72 lukem char errbuf[100]; 641 1.42 lukem char *p = $6; 642 1.56 lukem LLT rate; 643 1.41 lukem 644 1.42 lukem if ($4) { 645 1.72 lukem rate = strsuftollx("RATEPUT", p, 0, 646 1.72 lukem curclass.maxrateput 647 1.72 lukem ? curclass.maxrateput 648 1.72 lukem : LLTMAX, errbuf, sizeof(errbuf)); 649 1.72 lukem if (errbuf[0]) 650 1.72 lukem reply(501, "%s", errbuf); 651 1.42 lukem else { 652 1.42 lukem curclass.rateput = rate; 653 1.42 lukem reply(200, 654 1.56 lukem "RATEPUT set to " LLF " bytes/sec", 655 1.56 lukem (LLT)curclass.rateput); 656 1.42 lukem } 657 1.41 lukem } 658 1.42 lukem free($6); 659 1.41 lukem } 660 1.41 lukem 661 1.41 lukem | SITE SP UMASK check_login CRLF 662 1.41 lukem { 663 1.41 lukem int oldmask; 664 1.41 lukem 665 1.41 lukem if ($4) { 666 1.41 lukem oldmask = umask(0); 667 1.41 lukem (void) umask(oldmask); 668 1.41 lukem reply(200, "Current UMASK is %03o", oldmask); 669 1.41 lukem } 670 1.41 lukem } 671 1.41 lukem 672 1.56 lukem | SITE SP UMASK check_login SP octal_number CRLF 673 1.41 lukem { 674 1.41 lukem int oldmask; 675 1.41 lukem 676 1.67 lukem if ($4 && check_write("", 0)) { 677 1.41 lukem if (($6 == -1) || ($6 > 0777)) { 678 1.41 lukem reply(501, "Bad UMASK value"); 679 1.41 lukem } else { 680 1.41 lukem oldmask = umask($6); 681 1.41 lukem reply(200, 682 1.41 lukem "UMASK set to %03o (was %03o)", 683 1.41 lukem $6, oldmask); 684 1.41 lukem } 685 1.41 lukem } 686 1.41 lukem } 687 1.41 lukem 688 1.23 lukem | SYST CRLF 689 1.23 lukem { 690 1.52 lukem if (EMPTYSTR(version)) 691 1.52 lukem reply(215, "UNIX Type: L%d", NBBY); 692 1.52 lukem else 693 1.52 lukem reply(215, "UNIX Type: L%d Version: %s", NBBY, 694 1.52 lukem version); 695 1.23 lukem } 696 1.23 lukem 697 1.23 lukem | STAT check_login SP pathname CRLF 698 1.4 deraadt { 699 1.1 cgd if ($2 && $4 != NULL) 700 1.23 lukem statfilecmd($4); 701 1.1 cgd if ($4 != NULL) 702 1.4 deraadt free($4); 703 1.1 cgd } 704 1.23 lukem 705 1.23 lukem | STAT CRLF 706 1.23 lukem { 707 1.60 aidan if (is_oob) 708 1.60 aidan statxfer(); 709 1.60 aidan else 710 1.60 aidan statcmd(); 711 1.23 lukem } 712 1.23 lukem 713 1.23 lukem | HELP CRLF 714 1.23 lukem { 715 1.23 lukem help(cmdtab, NULL); 716 1.23 lukem } 717 1.23 lukem 718 1.23 lukem | HELP SP STRING CRLF 719 1.23 lukem { 720 1.23 lukem char *cp = $3; 721 1.23 lukem 722 1.23 lukem if (strncasecmp(cp, "SITE", 4) == 0) { 723 1.23 lukem cp = $3 + 4; 724 1.23 lukem if (*cp == ' ') 725 1.23 lukem cp++; 726 1.23 lukem if (*cp) 727 1.23 lukem help(sitetab, cp); 728 1.23 lukem else 729 1.23 lukem help(sitetab, NULL); 730 1.23 lukem } else 731 1.23 lukem help(cmdtab, $3); 732 1.42 lukem free($3); 733 1.23 lukem } 734 1.23 lukem 735 1.23 lukem | NOOP CRLF 736 1.23 lukem { 737 1.23 lukem reply(200, "NOOP command successful."); 738 1.23 lukem } 739 1.23 lukem 740 1.25 lukem /* RFC 2228 */ 741 1.25 lukem | AUTH SP mechanism_name CRLF 742 1.25 lukem { 743 1.25 lukem reply(502, "RFC 2228 authentication not implemented."); 744 1.42 lukem free($3); 745 1.25 lukem } 746 1.25 lukem 747 1.25 lukem | ADAT SP base64data CRLF 748 1.25 lukem { 749 1.25 lukem reply(503, 750 1.25 lukem "Please set authentication state with AUTH."); 751 1.42 lukem free($3); 752 1.25 lukem } 753 1.25 lukem 754 1.25 lukem | PROT SP prot_code CRLF 755 1.25 lukem { 756 1.25 lukem reply(503, 757 1.25 lukem "Please set protection buffer size with PBSZ."); 758 1.42 lukem free($3); 759 1.25 lukem } 760 1.25 lukem 761 1.25 lukem | PBSZ SP decimal_integer CRLF 762 1.25 lukem { 763 1.25 lukem reply(503, 764 1.25 lukem "Please set authentication state with AUTH."); 765 1.25 lukem } 766 1.25 lukem 767 1.25 lukem | CCC CRLF 768 1.25 lukem { 769 1.25 lukem reply(533, "No protection enabled."); 770 1.25 lukem } 771 1.25 lukem 772 1.25 lukem | MIC SP base64data CRLF 773 1.25 lukem { 774 1.25 lukem reply(502, "RFC 2228 authentication not implemented."); 775 1.42 lukem free($3); 776 1.25 lukem } 777 1.25 lukem 778 1.25 lukem | CONF SP base64data CRLF 779 1.25 lukem { 780 1.25 lukem reply(502, "RFC 2228 authentication not implemented."); 781 1.42 lukem free($3); 782 1.25 lukem } 783 1.25 lukem 784 1.25 lukem | ENC SP base64data CRLF 785 1.25 lukem { 786 1.25 lukem reply(502, "RFC 2228 authentication not implemented."); 787 1.42 lukem free($3); 788 1.25 lukem } 789 1.25 lukem 790 1.23 lukem /* RFC 2389 */ 791 1.23 lukem | FEAT CRLF 792 1.23 lukem { 793 1.47 lukem 794 1.47 lukem feat(); 795 1.23 lukem } 796 1.23 lukem 797 1.23 lukem | OPTS SP STRING CRLF 798 1.4 deraadt { 799 1.23 lukem 800 1.23 lukem opts($3); 801 1.42 lukem free($3); 802 1.1 cgd } 803 1.1 cgd 804 1.23 lukem 805 1.85 lukem /* RFC 3659 */ 806 1.23 lukem 807 1.1 cgd /* 808 1.1 cgd * Return size of file in a format suitable for 809 1.1 cgd * using with RESTART (we just count bytes). 810 1.1 cgd */ 811 1.4 deraadt | SIZE check_login SP pathname CRLF 812 1.4 deraadt { 813 1.1 cgd if ($2 && $4 != NULL) 814 1.4 deraadt sizecmd($4); 815 1.1 cgd if ($4 != NULL) 816 1.4 deraadt free($4); 817 1.1 cgd } 818 1.1 cgd 819 1.1 cgd /* 820 1.1 cgd * Return modification time of file as an ISO 3307 821 1.1 cgd * style time. E.g. YYYYMMDDHHMMSS or YYYYMMDDHHMMSS.xxx 822 1.1 cgd * where xxx is the fractional second (of any precision, 823 1.1 cgd * not necessarily 3 digits) 824 1.1 cgd */ 825 1.4 deraadt | MDTM check_login SP pathname CRLF 826 1.4 deraadt { 827 1.1 cgd if ($2 && $4 != NULL) { 828 1.1 cgd struct stat stbuf; 829 1.4 deraadt if (stat($4, &stbuf) < 0) 830 1.22 lukem perror_reply(550, $4); 831 1.4 deraadt else if (!S_ISREG(stbuf.st_mode)) { 832 1.4 deraadt reply(550, "%s: not a plain file.", $4); 833 1.1 cgd } else { 834 1.4 deraadt struct tm *t; 835 1.47 lukem 836 1.1 cgd t = gmtime(&stbuf.st_mtime); 837 1.1 cgd reply(213, 838 1.7 jtc "%04d%02d%02d%02d%02d%02d", 839 1.18 lukem TM_YEAR_BASE + t->tm_year, 840 1.7 jtc t->tm_mon+1, t->tm_mday, 841 1.1 cgd t->tm_hour, t->tm_min, t->tm_sec); 842 1.1 cgd } 843 1.1 cgd } 844 1.1 cgd if ($4 != NULL) 845 1.4 deraadt free($4); 846 1.1 cgd } 847 1.23 lukem 848 1.47 lukem | MLST check_login SP pathname CRLF 849 1.47 lukem { 850 1.47 lukem if ($2 && $4 != NULL) 851 1.47 lukem mlst($4); 852 1.47 lukem if ($4 != NULL) 853 1.47 lukem free($4); 854 1.47 lukem } 855 1.47 lukem 856 1.48 lukem | MLST check_login CRLF 857 1.47 lukem { 858 1.95 shm if ($2) 859 1.95 shm mlst(NULL); 860 1.47 lukem } 861 1.47 lukem 862 1.47 lukem | MLSD check_login SP pathname CRLF 863 1.47 lukem { 864 1.47 lukem if ($2 && $4 != NULL) 865 1.47 lukem mlsd($4); 866 1.47 lukem if ($4 != NULL) 867 1.47 lukem free($4); 868 1.47 lukem } 869 1.47 lukem 870 1.48 lukem | MLSD check_login CRLF 871 1.47 lukem { 872 1.95 shm if ($2) 873 1.95 shm mlsd(NULL); 874 1.47 lukem } 875 1.47 lukem 876 1.4 deraadt | error CRLF 877 1.4 deraadt { 878 1.1 cgd yyerrok; 879 1.1 cgd } 880 1.1 cgd ; 881 1.21 lukem 882 1.4 deraadt rcmd 883 1.70 lukem : REST check_login SP NUMBER CRLF 884 1.23 lukem { 885 1.42 lukem if ($2) { 886 1.78 lukem REASSIGN(fromname, NULL); 887 1.74 lukem restart_point = (off_t)$4.ll; 888 1.55 lukem reply(350, 889 1.55 lukem "Restarting at " LLF ". Send STORE or RETRIEVE to initiate transfer.", 890 1.55 lukem (LLT)restart_point); 891 1.42 lukem } 892 1.23 lukem } 893 1.42 lukem 894 1.56 lukem | RNFR SP pathname CRLF 895 1.4 deraadt { 896 1.1 cgd restart_point = (off_t) 0; 897 1.78 lukem if (check_write($3, 0)) { 898 1.78 lukem REASSIGN(fromname, NULL); 899 1.56 lukem fromname = renamefrom($3); 900 1.78 lukem } 901 1.56 lukem if ($3 != NULL) 902 1.56 lukem free($3); 903 1.1 cgd } 904 1.1 cgd ; 905 1.4 deraadt 906 1.4 deraadt username 907 1.4 deraadt : STRING 908 1.1 cgd ; 909 1.1 cgd 910 1.4 deraadt password 911 1.4 deraadt : /* empty */ 912 1.4 deraadt { 913 1.4 deraadt $$ = (char *)calloc(1, sizeof(char)); 914 1.1 cgd } 915 1.23 lukem 916 1.4 deraadt | STRING 917 1.1 cgd ; 918 1.1 cgd 919 1.4 deraadt byte_size 920 1.4 deraadt : NUMBER 921 1.70 lukem { 922 1.70 lukem $$ = $1.i; 923 1.70 lukem } 924 1.1 cgd ; 925 1.1 cgd 926 1.4 deraadt host_port 927 1.4 deraadt : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 928 1.1 cgd NUMBER COMMA NUMBER 929 1.4 deraadt { 930 1.4 deraadt char *a, *p; 931 1.1 cgd 932 1.55 lukem memset(&data_dest, 0, sizeof(data_dest)); 933 1.32 itojun data_dest.su_len = sizeof(struct sockaddr_in); 934 1.32 itojun data_dest.su_family = AF_INET; 935 1.55 lukem p = (char *)&data_dest.su_port; 936 1.70 lukem p[0] = $9.i; p[1] = $11.i; 937 1.55 lukem a = (char *)&data_dest.su_addr; 938 1.70 lukem a[0] = $1.i; a[1] = $3.i; a[2] = $5.i; a[3] = $7.i; 939 1.1 cgd } 940 1.1 cgd ; 941 1.1 cgd 942 1.34 itojun host_long_port4 943 1.34 itojun : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 944 1.34 itojun NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 945 1.34 itojun NUMBER 946 1.34 itojun { 947 1.34 itojun char *a, *p; 948 1.34 itojun 949 1.55 lukem memset(&data_dest, 0, sizeof(data_dest)); 950 1.55 lukem data_dest.su_len = sizeof(struct sockaddr_in); 951 1.34 itojun data_dest.su_family = AF_INET; 952 1.34 itojun p = (char *)&data_dest.su_port; 953 1.70 lukem p[0] = $15.i; p[1] = $17.i; 954 1.55 lukem a = (char *)&data_dest.su_addr; 955 1.70 lukem a[0] = $5.i; a[1] = $7.i; a[2] = $9.i; a[3] = $11.i; 956 1.35 itojun 957 1.35 itojun /* reject invalid LPRT command */ 958 1.70 lukem if ($1.i != 4 || $3.i != 4 || $13.i != 2) 959 1.35 itojun memset(&data_dest, 0, sizeof(data_dest)); 960 1.34 itojun } 961 1.34 itojun ; 962 1.34 itojun 963 1.34 itojun host_long_port6 964 1.32 itojun : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 965 1.32 itojun NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 966 1.32 itojun NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 967 1.32 itojun NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 968 1.32 itojun NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 969 1.32 itojun NUMBER 970 1.32 itojun { 971 1.53 christos #ifdef INET6 972 1.91 christos unsigned char buf[16]; 973 1.32 itojun 974 1.91 christos (void)memset(&data_dest, 0, sizeof(data_dest)); 975 1.55 lukem data_dest.su_len = sizeof(struct sockaddr_in6); 976 1.32 itojun data_dest.su_family = AF_INET6; 977 1.91 christos buf[0] = $39.i; buf[1] = $41.i; 978 1.91 christos (void)memcpy(&data_dest.su_port, buf, 979 1.92 joerg sizeof(data_dest.su_port)); 980 1.91 christos buf[0] = $5.i; buf[1] = $7.i; 981 1.91 christos buf[2] = $9.i; buf[3] = $11.i; 982 1.91 christos buf[4] = $13.i; buf[5] = $15.i; 983 1.91 christos buf[6] = $17.i; buf[7] = $19.i; 984 1.91 christos buf[8] = $21.i; buf[9] = $23.i; 985 1.91 christos buf[10] = $25.i; buf[11] = $27.i; 986 1.91 christos buf[12] = $29.i; buf[13] = $31.i; 987 1.91 christos buf[14] = $33.i; buf[15] = $35.i; 988 1.91 christos (void)memcpy(&data_dest.si_su.su_sin6.sin6_addr, 989 1.91 christos buf, sizeof(data_dest.si_su.su_sin6.sin6_addr)); 990 1.37 itojun if (his_addr.su_family == AF_INET6) { 991 1.59 lukem /* XXX: more sanity checks! */ 992 1.55 lukem data_dest.su_scope_id = his_addr.su_scope_id; 993 1.37 itojun } 994 1.53 christos #else 995 1.53 christos memset(&data_dest, 0, sizeof(data_dest)); 996 1.55 lukem #endif /* INET6 */ 997 1.35 itojun /* reject invalid LPRT command */ 998 1.75 lukem if ($1.i != 6 || $3.i != 16 || $37.i != 2) 999 1.35 itojun memset(&data_dest, 0, sizeof(data_dest)); 1000 1.32 itojun } 1001 1.32 itojun ; 1002 1.32 itojun 1003 1.4 deraadt form_code 1004 1.4 deraadt : N 1005 1.4 deraadt { 1006 1.4 deraadt $$ = FORM_N; 1007 1.4 deraadt } 1008 1.23 lukem 1009 1.4 deraadt | T 1010 1.4 deraadt { 1011 1.4 deraadt $$ = FORM_T; 1012 1.4 deraadt } 1013 1.23 lukem 1014 1.4 deraadt | C 1015 1.4 deraadt { 1016 1.4 deraadt $$ = FORM_C; 1017 1.4 deraadt } 1018 1.1 cgd ; 1019 1.1 cgd 1020 1.4 deraadt type_code 1021 1.4 deraadt : A 1022 1.4 deraadt { 1023 1.4 deraadt cmd_type = TYPE_A; 1024 1.4 deraadt cmd_form = FORM_N; 1025 1.4 deraadt } 1026 1.23 lukem 1027 1.4 deraadt | A SP form_code 1028 1.4 deraadt { 1029 1.4 deraadt cmd_type = TYPE_A; 1030 1.4 deraadt cmd_form = $3; 1031 1.4 deraadt } 1032 1.23 lukem 1033 1.4 deraadt | E 1034 1.4 deraadt { 1035 1.4 deraadt cmd_type = TYPE_E; 1036 1.4 deraadt cmd_form = FORM_N; 1037 1.4 deraadt } 1038 1.23 lukem 1039 1.4 deraadt | E SP form_code 1040 1.4 deraadt { 1041 1.4 deraadt cmd_type = TYPE_E; 1042 1.4 deraadt cmd_form = $3; 1043 1.4 deraadt } 1044 1.23 lukem 1045 1.4 deraadt | I 1046 1.4 deraadt { 1047 1.4 deraadt cmd_type = TYPE_I; 1048 1.4 deraadt } 1049 1.23 lukem 1050 1.4 deraadt | L 1051 1.4 deraadt { 1052 1.4 deraadt cmd_type = TYPE_L; 1053 1.4 deraadt cmd_bytesz = NBBY; 1054 1.4 deraadt } 1055 1.23 lukem 1056 1.4 deraadt | L SP byte_size 1057 1.4 deraadt { 1058 1.4 deraadt cmd_type = TYPE_L; 1059 1.4 deraadt cmd_bytesz = $3; 1060 1.4 deraadt } 1061 1.23 lukem 1062 1.4 deraadt /* this is for a bug in the BBN ftp */ 1063 1.4 deraadt | L byte_size 1064 1.4 deraadt { 1065 1.4 deraadt cmd_type = TYPE_L; 1066 1.4 deraadt cmd_bytesz = $2; 1067 1.4 deraadt } 1068 1.1 cgd ; 1069 1.1 cgd 1070 1.4 deraadt struct_code 1071 1.4 deraadt : F 1072 1.4 deraadt { 1073 1.4 deraadt $$ = STRU_F; 1074 1.4 deraadt } 1075 1.23 lukem 1076 1.4 deraadt | R 1077 1.4 deraadt { 1078 1.4 deraadt $$ = STRU_R; 1079 1.4 deraadt } 1080 1.23 lukem 1081 1.4 deraadt | P 1082 1.4 deraadt { 1083 1.4 deraadt $$ = STRU_P; 1084 1.4 deraadt } 1085 1.1 cgd ; 1086 1.1 cgd 1087 1.4 deraadt mode_code 1088 1.4 deraadt : S 1089 1.4 deraadt { 1090 1.4 deraadt $$ = MODE_S; 1091 1.4 deraadt } 1092 1.23 lukem 1093 1.4 deraadt | B 1094 1.4 deraadt { 1095 1.4 deraadt $$ = MODE_B; 1096 1.4 deraadt } 1097 1.23 lukem 1098 1.4 deraadt | C 1099 1.4 deraadt { 1100 1.4 deraadt $$ = MODE_C; 1101 1.4 deraadt } 1102 1.1 cgd ; 1103 1.1 cgd 1104 1.4 deraadt pathname 1105 1.4 deraadt : pathstring 1106 1.4 deraadt { 1107 1.4 deraadt /* 1108 1.4 deraadt * Problem: this production is used for all pathname 1109 1.4 deraadt * processing, but only gives a 550 error reply. 1110 1.9 lukem * This is a valid reply in some cases but not in 1111 1.9 lukem * others. 1112 1.4 deraadt */ 1113 1.4 deraadt if (logged_in && $1 && *$1 == '~') { 1114 1.64 lukem char *path, *home, *result; 1115 1.64 lukem size_t len; 1116 1.4 deraadt 1117 1.64 lukem path = strchr($1 + 1, '/'); 1118 1.64 lukem if (path != NULL) 1119 1.64 lukem *path++ = '\0'; 1120 1.9 lukem if ($1[1] == '\0') 1121 1.64 lukem home = homedir; 1122 1.9 lukem else { 1123 1.66 lukem struct passwd *hpw; 1124 1.64 lukem 1125 1.66 lukem if ((hpw = getpwnam($1 + 1)) != NULL) 1126 1.66 lukem home = hpw->pw_dir; 1127 1.64 lukem else 1128 1.64 lukem home = $1; 1129 1.64 lukem } 1130 1.64 lukem len = strlen(home) + 1; 1131 1.64 lukem if (path != NULL) 1132 1.64 lukem len += strlen(path) + 1; 1133 1.64 lukem if ((result = malloc(len)) == NULL) 1134 1.64 lukem fatal("Local resource failure: malloc"); 1135 1.64 lukem strlcpy(result, home, len); 1136 1.64 lukem if (path != NULL) { 1137 1.64 lukem strlcat(result, "/", len); 1138 1.64 lukem strlcat(result, path, len); 1139 1.4 deraadt } 1140 1.64 lukem $$ = result; 1141 1.4 deraadt free($1); 1142 1.4 deraadt } else 1143 1.4 deraadt $$ = $1; 1144 1.4 deraadt } 1145 1.1 cgd ; 1146 1.1 cgd 1147 1.4 deraadt pathstring 1148 1.4 deraadt : STRING 1149 1.1 cgd ; 1150 1.1 cgd 1151 1.4 deraadt octal_number 1152 1.4 deraadt : NUMBER 1153 1.4 deraadt { 1154 1.4 deraadt int ret, dec, multby, digit; 1155 1.1 cgd 1156 1.4 deraadt /* 1157 1.4 deraadt * Convert a number that was read as decimal number 1158 1.4 deraadt * to what it would be if it had been read as octal. 1159 1.4 deraadt */ 1160 1.70 lukem dec = $1.i; 1161 1.4 deraadt multby = 1; 1162 1.4 deraadt ret = 0; 1163 1.4 deraadt while (dec) { 1164 1.4 deraadt digit = dec%10; 1165 1.4 deraadt if (digit > 7) { 1166 1.4 deraadt ret = -1; 1167 1.4 deraadt break; 1168 1.4 deraadt } 1169 1.4 deraadt ret += digit * multby; 1170 1.4 deraadt multby *= 8; 1171 1.4 deraadt dec /= 10; 1172 1.1 cgd } 1173 1.4 deraadt $$ = ret; 1174 1.1 cgd } 1175 1.1 cgd ; 1176 1.1 cgd 1177 1.25 lukem mechanism_name 1178 1.25 lukem : STRING 1179 1.25 lukem ; 1180 1.25 lukem 1181 1.25 lukem base64data 1182 1.25 lukem : STRING 1183 1.25 lukem ; 1184 1.25 lukem 1185 1.25 lukem prot_code 1186 1.25 lukem : STRING 1187 1.25 lukem ; 1188 1.25 lukem 1189 1.25 lukem decimal_integer 1190 1.25 lukem : NUMBER 1191 1.70 lukem { 1192 1.70 lukem $$ = $1.i; 1193 1.70 lukem } 1194 1.25 lukem ; 1195 1.25 lukem 1196 1.4 deraadt check_login 1197 1.4 deraadt : /* empty */ 1198 1.4 deraadt { 1199 1.4 deraadt if (logged_in) 1200 1.4 deraadt $$ = 1; 1201 1.4 deraadt else { 1202 1.4 deraadt reply(530, "Please login with USER and PASS."); 1203 1.4 deraadt $$ = 0; 1204 1.22 lukem hasyyerrored = 1; 1205 1.4 deraadt } 1206 1.1 cgd } 1207 1.1 cgd ; 1208 1.21 lukem 1209 1.1 cgd %% 1210 1.1 cgd 1211 1.1 cgd #define CMD 0 /* beginning of command */ 1212 1.1 cgd #define ARGS 1 /* expect miscellaneous arguments */ 1213 1.1 cgd #define STR1 2 /* expect SP followed by STRING */ 1214 1.1 cgd #define STR2 3 /* expect STRING */ 1215 1.1 cgd #define OSTR 4 /* optional SP then STRING */ 1216 1.1 cgd #define ZSTR1 5 /* SP then optional STRING */ 1217 1.1 cgd #define ZSTR2 6 /* optional STRING after SP */ 1218 1.1 cgd #define SITECMD 7 /* SITE command */ 1219 1.1 cgd #define NSTR 8 /* Number followed by a string */ 1220 1.21 lukem #define NOARGS 9 /* No arguments allowed */ 1221 1.60 aidan #define EOLN 10 /* End of line */ 1222 1.1 cgd 1223 1.21 lukem struct tab cmdtab[] = { 1224 1.21 lukem /* From RFC 959, in order defined (5.3.1) */ 1225 1.89 lukem { "USER", USER, STR1, 1, "<sp> username", 0, }, 1226 1.89 lukem { "PASS", PASS, ZSTR1, 1, "<sp> password", 0, }, 1227 1.89 lukem { "ACCT", ACCT, STR1, 0, "(specify account)", 0, }, 1228 1.89 lukem { "CWD", CWD, OSTR, 1, "[ <sp> directory-name ]", 0, }, 1229 1.89 lukem { "CDUP", CDUP, NOARGS, 1, "(change to parent directory)", 0, }, 1230 1.89 lukem { "SMNT", SMNT, ARGS, 0, "(structure mount)", 0, }, 1231 1.89 lukem { "QUIT", QUIT, NOARGS, 1, "(terminate service)", 0, }, 1232 1.89 lukem { "REIN", REIN, NOARGS, 0, "(reinitialize server state)", 0, }, 1233 1.89 lukem { "PORT", PORT, ARGS, 1, "<sp> b0, b1, b2, b3, b4, b5", 0, }, 1234 1.89 lukem { "LPRT", LPRT, ARGS, 1, "<sp> af, hal, h1, h2, h3,..., pal, p1, p2...", 0, }, 1235 1.89 lukem { "EPRT", EPRT, STR1, 1, "<sp> |af|addr|port|", 0, }, 1236 1.89 lukem { "PASV", PASV, NOARGS, 1, "(set server in passive mode)", 0, }, 1237 1.89 lukem { "LPSV", LPSV, ARGS, 1, "(set server in passive mode)", 0, }, 1238 1.89 lukem { "EPSV", EPSV, ARGS, 1, "[<sp> af|ALL]", 0, }, 1239 1.89 lukem { "TYPE", TYPE, ARGS, 1, "<sp> [ A | E | I | L ]", 0, }, 1240 1.89 lukem { "STRU", STRU, ARGS, 1, "(specify file structure)", 0, }, 1241 1.89 lukem { "MODE", MODE, ARGS, 1, "(specify transfer mode)", 0, }, 1242 1.89 lukem { "RETR", RETR, STR1, 1, "<sp> file-name", 0, }, 1243 1.89 lukem { "STOR", STOR, STR1, 1, "<sp> file-name", 0, }, 1244 1.89 lukem { "STOU", STOU, STR1, 1, "<sp> file-name", 0, }, 1245 1.89 lukem { "APPE", APPE, STR1, 1, "<sp> file-name", 0, }, 1246 1.89 lukem { "ALLO", ALLO, ARGS, 1, "allocate storage (vacuously)", 0, }, 1247 1.89 lukem { "REST", REST, ARGS, 1, "<sp> offset (restart command)", 0, }, 1248 1.89 lukem { "RNFR", RNFR, STR1, 1, "<sp> file-name", 0, }, 1249 1.89 lukem { "RNTO", RNTO, STR1, 1, "<sp> file-name", 0, }, 1250 1.89 lukem { "ABOR", ABOR, NOARGS, 4, "(abort operation)", 0, }, 1251 1.89 lukem { "DELE", DELE, STR1, 1, "<sp> file-name", 0, }, 1252 1.89 lukem { "RMD", RMD, STR1, 1, "<sp> path-name", 0, }, 1253 1.89 lukem { "MKD", MKD, STR1, 1, "<sp> path-name", 0, }, 1254 1.89 lukem { "PWD", PWD, NOARGS, 1, "(return current directory)", 0, }, 1255 1.89 lukem { "LIST", LIST, OSTR, 1, "[ <sp> path-name ]", 0, }, 1256 1.89 lukem { "NLST", NLST, OSTR, 1, "[ <sp> path-name ]", 0, }, 1257 1.89 lukem { "SITE", SITE, SITECMD, 1, "site-cmd [ <sp> arguments ]", 0, }, 1258 1.89 lukem { "SYST", SYST, NOARGS, 1, "(get type of operating system)", 0, }, 1259 1.89 lukem { "STAT", STAT, OSTR, 4, "[ <sp> path-name ]", 0, }, 1260 1.89 lukem { "HELP", HELP, OSTR, 1, "[ <sp> <string> ]", 0, }, 1261 1.89 lukem { "NOOP", NOOP, NOARGS, 2, "", 0, }, 1262 1.23 lukem 1263 1.25 lukem /* From RFC 2228, in order defined */ 1264 1.89 lukem { "AUTH", AUTH, STR1, 1, "<sp> mechanism-name", 0, }, 1265 1.89 lukem { "ADAT", ADAT, STR1, 1, "<sp> base-64-data", 0, }, 1266 1.89 lukem { "PROT", PROT, STR1, 1, "<sp> prot-code", 0, }, 1267 1.89 lukem { "PBSZ", PBSZ, ARGS, 1, "<sp> decimal-integer", 0, }, 1268 1.89 lukem { "CCC", CCC, NOARGS, 1, "(Disable data protection)", 0, }, 1269 1.89 lukem { "MIC", MIC, STR1, 4, "<sp> base64data", 0, }, 1270 1.89 lukem { "CONF", CONF, STR1, 4, "<sp> base64data", 0, }, 1271 1.89 lukem { "ENC", ENC, STR1, 4, "<sp> base64data", 0, }, 1272 1.25 lukem 1273 1.25 lukem /* From RFC 2389, in order defined */ 1274 1.89 lukem { "FEAT", FEAT, NOARGS, 1, "(display extended features)", 0, }, 1275 1.89 lukem { "OPTS", OPTS, STR1, 1, "<sp> command [ <sp> options ]", 0, }, 1276 1.23 lukem 1277 1.85 lukem /* From RFC 3659, in order defined */ 1278 1.89 lukem { "MDTM", MDTM, OSTR, 1, "<sp> path-name", 0, }, 1279 1.89 lukem { "SIZE", SIZE, OSTR, 1, "<sp> path-name", 0, }, 1280 1.89 lukem { "MLST", MLST, OSTR, 2, "[ <sp> path-name ]", 0, }, 1281 1.89 lukem { "MLSD", MLSD, OSTR, 1, "[ <sp> directory-name ]", 0, }, 1282 1.21 lukem 1283 1.21 lukem /* obsolete commands */ 1284 1.89 lukem { "MAIL", MAIL, OSTR, 0, "(mail to user)", 0, }, 1285 1.89 lukem { "MLFL", MLFL, OSTR, 0, "(mail file)", 0, }, 1286 1.89 lukem { "MRCP", MRCP, STR1, 0, "(mail recipient)", 0, }, 1287 1.89 lukem { "MRSQ", MRSQ, OSTR, 0, "(mail recipient scheme question)", 0, }, 1288 1.89 lukem { "MSAM", MSAM, OSTR, 0, "(mail send to terminal and mailbox)", 0, }, 1289 1.89 lukem { "MSND", MSND, OSTR, 0, "(mail send to terminal)", 0, }, 1290 1.89 lukem { "MSOM", MSOM, OSTR, 0, "(mail send to terminal or mailbox)", 0, }, 1291 1.89 lukem { "XCUP", CDUP, NOARGS, 1, "(change to parent directory)", 0, }, 1292 1.89 lukem { "XCWD", CWD, OSTR, 1, "[ <sp> directory-name ]", 0, }, 1293 1.89 lukem { "XMKD", MKD, STR1, 1, "<sp> path-name", 0, }, 1294 1.89 lukem { "XPWD", PWD, NOARGS, 1, "(return current directory)", 0, }, 1295 1.89 lukem { "XRMD", RMD, STR1, 1, "<sp> path-name", 0, }, 1296 1.21 lukem 1297 1.89 lukem { NULL, 0, 0, 0, 0, 0, } 1298 1.1 cgd }; 1299 1.1 cgd 1300 1.1 cgd struct tab sitetab[] = { 1301 1.89 lukem { "CHMOD", CHMOD, NSTR, 1, "<sp> mode <sp> file-name", 0, }, 1302 1.89 lukem { "HELP", HELP, OSTR, 1, "[ <sp> <string> ]", 0, }, 1303 1.89 lukem { "IDLE", IDLE, ARGS, 1, "[ <sp> maximum-idle-time ]", 0, }, 1304 1.89 lukem { "RATEGET", RATEGET,OSTR, 1, "[ <sp> get-throttle-rate ]", 0, }, 1305 1.89 lukem { "RATEPUT", RATEPUT,OSTR, 1, "[ <sp> put-throttle-rate ]", 0, }, 1306 1.89 lukem { "UMASK", UMASK, ARGS, 1, "[ <sp> umask ]", 0, }, 1307 1.89 lukem { NULL, 0, 0, 0, 0, 0, } 1308 1.1 cgd }; 1309 1.1 cgd 1310 1.56 lukem /* 1311 1.56 lukem * Check if a filename is allowed to be modified (isupload == 0) or 1312 1.56 lukem * uploaded (isupload == 1), and if necessary, check the filename is `sane'. 1313 1.67 lukem * If the filename is NULL, fail. 1314 1.67 lukem * If the filename is "", don't do the sane name check. 1315 1.56 lukem */ 1316 1.56 lukem static int 1317 1.56 lukem check_write(const char *file, int isupload) 1318 1.56 lukem { 1319 1.56 lukem if (file == NULL) 1320 1.56 lukem return (0); 1321 1.56 lukem if (! logged_in) { 1322 1.56 lukem reply(530, "Please login with USER and PASS."); 1323 1.56 lukem return (0); 1324 1.56 lukem } 1325 1.56 lukem /* checking modify */ 1326 1.56 lukem if (! isupload && ! CURCLASS_FLAGS_ISSET(modify)) { 1327 1.56 lukem reply(502, "No permission to use this command."); 1328 1.56 lukem return (0); 1329 1.56 lukem } 1330 1.56 lukem /* checking upload */ 1331 1.56 lukem if (isupload && ! CURCLASS_FLAGS_ISSET(upload)) { 1332 1.56 lukem reply(502, "No permission to use this command."); 1333 1.56 lukem return (0); 1334 1.56 lukem } 1335 1.67 lukem 1336 1.56 lukem /* checking sanenames */ 1337 1.67 lukem if (file[0] != '\0' && CURCLASS_FLAGS_ISSET(sanenames)) { 1338 1.56 lukem const char *p; 1339 1.56 lukem 1340 1.56 lukem if (file[0] == '.') 1341 1.56 lukem goto insane_name; 1342 1.56 lukem for (p = file; *p; p++) { 1343 1.81 dsl if (isalnum((unsigned char)*p) || *p == '-' || *p == '+' || 1344 1.56 lukem *p == ',' || *p == '.' || *p == '_') 1345 1.56 lukem continue; 1346 1.56 lukem insane_name: 1347 1.56 lukem reply(553, "File name `%s' not allowed.", file); 1348 1.56 lukem return (0); 1349 1.56 lukem } 1350 1.56 lukem } 1351 1.56 lukem return (1); 1352 1.56 lukem } 1353 1.56 lukem 1354 1.47 lukem struct tab * 1355 1.46 lukem lookup(struct tab *p, const char *cmd) 1356 1.1 cgd { 1357 1.1 cgd 1358 1.1 cgd for (; p->name != NULL; p++) 1359 1.23 lukem if (strcasecmp(cmd, p->name) == 0) 1360 1.1 cgd return (p); 1361 1.1 cgd return (0); 1362 1.1 cgd } 1363 1.1 cgd 1364 1.1 cgd #include <arpa/telnet.h> 1365 1.1 cgd 1366 1.1 cgd /* 1367 1.90 roy * get_line - a hacked up version of fgets to ignore TELNET escape codes. 1368 1.88 lukem * `s' is the buffer to read into. 1369 1.88 lukem * `n' is the 1 less than the size of the buffer, to allow trailing NUL 1370 1.88 lukem * `iop' is the FILE to read from. 1371 1.88 lukem * Returns 0 on success, -1 on EOF, -2 if the command was too long. 1372 1.1 cgd */ 1373 1.88 lukem int 1374 1.90 roy get_line(char *s, int n, FILE *iop) 1375 1.1 cgd { 1376 1.4 deraadt int c; 1377 1.21 lukem char *cs; 1378 1.1 cgd 1379 1.1 cgd cs = s; 1380 1.1 cgd /* tmpline may contain saved command from urgent mode interruption */ 1381 1.1 cgd for (c = 0; tmpline[c] != '\0' && --n > 0; ++c) { 1382 1.1 cgd *cs++ = tmpline[c]; 1383 1.1 cgd if (tmpline[c] == '\n') { 1384 1.1 cgd *cs++ = '\0'; 1385 1.84 christos if (ftpd_debug) 1386 1.1 cgd syslog(LOG_DEBUG, "command: %s", s); 1387 1.1 cgd tmpline[0] = '\0'; 1388 1.88 lukem return(0); 1389 1.1 cgd } 1390 1.1 cgd if (c == 0) 1391 1.1 cgd tmpline[0] = '\0'; 1392 1.1 cgd } 1393 1.1 cgd while ((c = getc(iop)) != EOF) { 1394 1.27 lukem total_bytes++; 1395 1.27 lukem total_bytes_in++; 1396 1.1 cgd c &= 0377; 1397 1.1 cgd if (c == IAC) { 1398 1.1 cgd if ((c = getc(iop)) != EOF) { 1399 1.27 lukem total_bytes++; 1400 1.27 lukem total_bytes_in++; 1401 1.1 cgd c &= 0377; 1402 1.1 cgd switch (c) { 1403 1.1 cgd case WILL: 1404 1.1 cgd case WONT: 1405 1.1 cgd c = getc(iop); 1406 1.27 lukem total_bytes++; 1407 1.27 lukem total_bytes_in++; 1408 1.48 lukem cprintf(stdout, "%c%c%c", IAC, DONT, 0377&c); 1409 1.1 cgd (void) fflush(stdout); 1410 1.1 cgd continue; 1411 1.1 cgd case DO: 1412 1.1 cgd case DONT: 1413 1.1 cgd c = getc(iop); 1414 1.27 lukem total_bytes++; 1415 1.27 lukem total_bytes_in++; 1416 1.48 lukem cprintf(stdout, "%c%c%c", IAC, WONT, 0377&c); 1417 1.1 cgd (void) fflush(stdout); 1418 1.1 cgd continue; 1419 1.1 cgd case IAC: 1420 1.1 cgd break; 1421 1.1 cgd default: 1422 1.1 cgd continue; /* ignore command */ 1423 1.1 cgd } 1424 1.1 cgd } 1425 1.1 cgd } 1426 1.1 cgd *cs++ = c; 1427 1.88 lukem if (--n <= 0) { 1428 1.88 lukem /* 1429 1.88 lukem * If command doesn't fit into buffer, discard the 1430 1.88 lukem * rest of the command and indicate truncation. 1431 1.88 lukem * This prevents the command to be split up into 1432 1.88 lukem * multiple commands. 1433 1.88 lukem */ 1434 1.88 lukem if (ftpd_debug) 1435 1.88 lukem syslog(LOG_DEBUG, 1436 1.88 lukem "command too long, last char: %d", c); 1437 1.88 lukem while (c != '\n' && (c = getc(iop)) != EOF) 1438 1.88 lukem continue; 1439 1.88 lukem return (-2); 1440 1.88 lukem } 1441 1.88 lukem if (c == '\n') 1442 1.1 cgd break; 1443 1.1 cgd } 1444 1.1 cgd if (c == EOF && cs == s) 1445 1.88 lukem return (-1); 1446 1.1 cgd *cs++ = '\0'; 1447 1.84 christos if (ftpd_debug) { 1448 1.58 lukem if ((curclass.type != CLASS_GUEST && 1449 1.58 lukem strncasecmp(s, "PASS ", 5) == 0) || 1450 1.58 lukem strncasecmp(s, "ACCT ", 5) == 0) { 1451 1.4 deraadt /* Don't syslog passwords */ 1452 1.58 lukem syslog(LOG_DEBUG, "command: %.4s ???", s); 1453 1.4 deraadt } else { 1454 1.21 lukem char *cp; 1455 1.21 lukem int len; 1456 1.4 deraadt 1457 1.4 deraadt /* Don't syslog trailing CR-LF */ 1458 1.4 deraadt len = strlen(s); 1459 1.4 deraadt cp = s + len - 1; 1460 1.4 deraadt while (cp >= s && (*cp == '\n' || *cp == '\r')) { 1461 1.4 deraadt --cp; 1462 1.4 deraadt --len; 1463 1.4 deraadt } 1464 1.4 deraadt syslog(LOG_DEBUG, "command: %.*s", len, s); 1465 1.4 deraadt } 1466 1.4 deraadt } 1467 1.88 lukem return (0); 1468 1.1 cgd } 1469 1.1 cgd 1470 1.60 aidan void 1471 1.60 aidan ftp_handle_line(char *cp) 1472 1.60 aidan { 1473 1.62 lukem 1474 1.60 aidan cmdp = cp; 1475 1.60 aidan yyparse(); 1476 1.60 aidan } 1477 1.60 aidan 1478 1.60 aidan void 1479 1.60 aidan ftp_loop(void) 1480 1.60 aidan { 1481 1.88 lukem int ret; 1482 1.62 lukem 1483 1.60 aidan while (1) { 1484 1.60 aidan (void) alarm(curclass.timeout); 1485 1.90 roy ret = get_line(cbuf, sizeof(cbuf)-1, stdin); 1486 1.88 lukem (void) alarm(0); 1487 1.88 lukem if (ret == -1) { 1488 1.60 aidan reply(221, "You could at least say goodbye."); 1489 1.60 aidan dologout(0); 1490 1.88 lukem } else if (ret == -2) { 1491 1.88 lukem reply(500, "Command too long."); 1492 1.88 lukem } else { 1493 1.88 lukem ftp_handle_line(cbuf); 1494 1.60 aidan } 1495 1.60 aidan } 1496 1.60 aidan /*NOTREACHED*/ 1497 1.60 aidan } 1498 1.60 aidan 1499 1.76 lukem int 1500 1.46 lukem yylex(void) 1501 1.1 cgd { 1502 1.1 cgd static int cpos, state; 1503 1.4 deraadt char *cp, *cp2; 1504 1.4 deraadt struct tab *p; 1505 1.22 lukem int n; 1506 1.4 deraadt char c; 1507 1.1 cgd 1508 1.23 lukem switch (state) { 1509 1.1 cgd 1510 1.23 lukem case CMD: 1511 1.23 lukem hasyyerrored = 0; 1512 1.60 aidan if ((cp = strchr(cmdp, '\r'))) { 1513 1.42 lukem *cp = '\0'; 1514 1.86 lukem #if defined(HAVE_SETPROCTITLE) 1515 1.60 aidan if (strncasecmp(cmdp, "PASS", 4) != 0 && 1516 1.60 aidan strncasecmp(cmdp, "ACCT", 4) != 0) 1517 1.60 aidan setproctitle("%s: %s", proctitle, cmdp); 1518 1.86 lukem #endif /* defined(HAVE_SETPROCTITLE) */ 1519 1.23 lukem *cp++ = '\n'; 1520 1.23 lukem *cp = '\0'; 1521 1.23 lukem } 1522 1.60 aidan if ((cp = strpbrk(cmdp, " \n"))) 1523 1.60 aidan cpos = cp - cmdp; 1524 1.23 lukem if (cpos == 0) 1525 1.23 lukem cpos = 4; 1526 1.60 aidan c = cmdp[cpos]; 1527 1.60 aidan cmdp[cpos] = '\0'; 1528 1.60 aidan p = lookup(cmdtab, cmdp); 1529 1.60 aidan cmdp[cpos] = c; 1530 1.23 lukem if (p != NULL) { 1531 1.60 aidan if (is_oob && ! CMD_OOB(p)) { 1532 1.60 aidan /* command will be handled in-band */ 1533 1.60 aidan return (0); 1534 1.60 aidan } else if (! CMD_IMPLEMENTED(p)) { 1535 1.23 lukem reply(502, "%s command not implemented.", 1536 1.23 lukem p->name); 1537 1.23 lukem hasyyerrored = 1; 1538 1.23 lukem break; 1539 1.23 lukem } 1540 1.23 lukem state = p->state; 1541 1.89 lukem yylval.cs = p->name; 1542 1.23 lukem return (p->token); 1543 1.23 lukem } 1544 1.23 lukem break; 1545 1.23 lukem 1546 1.23 lukem case SITECMD: 1547 1.60 aidan if (cmdp[cpos] == ' ') { 1548 1.23 lukem cpos++; 1549 1.23 lukem return (SP); 1550 1.23 lukem } 1551 1.60 aidan cp = &cmdp[cpos]; 1552 1.23 lukem if ((cp2 = strpbrk(cp, " \n"))) 1553 1.60 aidan cpos = cp2 - cmdp; 1554 1.60 aidan c = cmdp[cpos]; 1555 1.60 aidan cmdp[cpos] = '\0'; 1556 1.23 lukem p = lookup(sitetab, cp); 1557 1.60 aidan cmdp[cpos] = c; 1558 1.23 lukem if (p != NULL) { 1559 1.47 lukem if (!CMD_IMPLEMENTED(p)) { 1560 1.23 lukem reply(502, "SITE %s command not implemented.", 1561 1.23 lukem p->name); 1562 1.23 lukem hasyyerrored = 1; 1563 1.23 lukem break; 1564 1.23 lukem } 1565 1.23 lukem state = p->state; 1566 1.89 lukem yylval.cs = p->name; 1567 1.23 lukem return (p->token); 1568 1.23 lukem } 1569 1.23 lukem break; 1570 1.23 lukem 1571 1.23 lukem case OSTR: 1572 1.60 aidan if (cmdp[cpos] == '\n') { 1573 1.60 aidan state = EOLN; 1574 1.23 lukem return (CRLF); 1575 1.23 lukem } 1576 1.23 lukem /* FALLTHROUGH */ 1577 1.23 lukem 1578 1.23 lukem case STR1: 1579 1.23 lukem case ZSTR1: 1580 1.23 lukem dostr1: 1581 1.60 aidan if (cmdp[cpos] == ' ') { 1582 1.23 lukem cpos++; 1583 1.39 tron state = state == OSTR ? STR2 : state+1; 1584 1.23 lukem return (SP); 1585 1.23 lukem } 1586 1.23 lukem break; 1587 1.23 lukem 1588 1.23 lukem case ZSTR2: 1589 1.60 aidan if (cmdp[cpos] == '\n') { 1590 1.60 aidan state = EOLN; 1591 1.23 lukem return (CRLF); 1592 1.23 lukem } 1593 1.23 lukem /* FALLTHROUGH */ 1594 1.23 lukem 1595 1.23 lukem case STR2: 1596 1.60 aidan cp = &cmdp[cpos]; 1597 1.23 lukem n = strlen(cp); 1598 1.23 lukem cpos += n - 1; 1599 1.23 lukem /* 1600 1.23 lukem * Make sure the string is nonempty and \n terminated. 1601 1.23 lukem */ 1602 1.60 aidan if (n > 1 && cmdp[cpos] == '\n') { 1603 1.60 aidan cmdp[cpos] = '\0'; 1604 1.84 christos yylval.s = ftpd_strdup(cp); 1605 1.60 aidan cmdp[cpos] = '\n'; 1606 1.23 lukem state = ARGS; 1607 1.23 lukem return (STRING); 1608 1.23 lukem } 1609 1.23 lukem break; 1610 1.23 lukem 1611 1.23 lukem case NSTR: 1612 1.60 aidan if (cmdp[cpos] == ' ') { 1613 1.23 lukem cpos++; 1614 1.23 lukem return (SP); 1615 1.23 lukem } 1616 1.81 dsl if (isdigit((unsigned char)cmdp[cpos])) { 1617 1.60 aidan cp = &cmdp[cpos]; 1618 1.81 dsl while (isdigit((unsigned char)cmdp[++cpos])) 1619 1.23 lukem ; 1620 1.60 aidan c = cmdp[cpos]; 1621 1.60 aidan cmdp[cpos] = '\0'; 1622 1.70 lukem yylval.u.i = atoi(cp); 1623 1.60 aidan cmdp[cpos] = c; 1624 1.23 lukem state = STR1; 1625 1.23 lukem return (NUMBER); 1626 1.23 lukem } 1627 1.23 lukem state = STR1; 1628 1.23 lukem goto dostr1; 1629 1.1 cgd 1630 1.23 lukem case ARGS: 1631 1.81 dsl if (isdigit((unsigned char)cmdp[cpos])) { 1632 1.60 aidan cp = &cmdp[cpos]; 1633 1.81 dsl while (isdigit((unsigned char)cmdp[++cpos])) 1634 1.23 lukem ; 1635 1.60 aidan c = cmdp[cpos]; 1636 1.60 aidan cmdp[cpos] = '\0'; 1637 1.70 lukem yylval.u.i = atoi(cp); 1638 1.93 plunky yylval.u.ll = STRTOLL(cp, NULL, 10); 1639 1.60 aidan cmdp[cpos] = c; 1640 1.23 lukem return (NUMBER); 1641 1.32 itojun } 1642 1.60 aidan if (strncasecmp(&cmdp[cpos], "ALL", 3) == 0 1643 1.81 dsl && !isalnum((unsigned char)cmdp[cpos + 3])) { 1644 1.32 itojun cpos += 3; 1645 1.80 lukem return (ALL); 1646 1.23 lukem } 1647 1.60 aidan switch (cmdp[cpos++]) { 1648 1.23 lukem 1649 1.23 lukem case '\n': 1650 1.60 aidan state = EOLN; 1651 1.23 lukem return (CRLF); 1652 1.23 lukem 1653 1.23 lukem case ' ': 1654 1.23 lukem return (SP); 1655 1.23 lukem 1656 1.23 lukem case ',': 1657 1.23 lukem return (COMMA); 1658 1.23 lukem 1659 1.23 lukem case 'A': 1660 1.23 lukem case 'a': 1661 1.23 lukem return (A); 1662 1.23 lukem 1663 1.23 lukem case 'B': 1664 1.23 lukem case 'b': 1665 1.23 lukem return (B); 1666 1.23 lukem 1667 1.23 lukem case 'C': 1668 1.23 lukem case 'c': 1669 1.23 lukem return (C); 1670 1.23 lukem 1671 1.23 lukem case 'E': 1672 1.23 lukem case 'e': 1673 1.23 lukem return (E); 1674 1.23 lukem 1675 1.23 lukem case 'F': 1676 1.23 lukem case 'f': 1677 1.23 lukem return (F); 1678 1.23 lukem 1679 1.23 lukem case 'I': 1680 1.23 lukem case 'i': 1681 1.23 lukem return (I); 1682 1.1 cgd 1683 1.23 lukem case 'L': 1684 1.23 lukem case 'l': 1685 1.23 lukem return (L); 1686 1.1 cgd 1687 1.23 lukem case 'N': 1688 1.23 lukem case 'n': 1689 1.23 lukem return (N); 1690 1.1 cgd 1691 1.23 lukem case 'P': 1692 1.23 lukem case 'p': 1693 1.23 lukem return (P); 1694 1.1 cgd 1695 1.23 lukem case 'R': 1696 1.23 lukem case 'r': 1697 1.23 lukem return (R); 1698 1.1 cgd 1699 1.23 lukem case 'S': 1700 1.23 lukem case 's': 1701 1.23 lukem return (S); 1702 1.1 cgd 1703 1.23 lukem case 'T': 1704 1.23 lukem case 't': 1705 1.23 lukem return (T); 1706 1.1 cgd 1707 1.23 lukem } 1708 1.23 lukem break; 1709 1.21 lukem 1710 1.23 lukem case NOARGS: 1711 1.60 aidan if (cmdp[cpos] == '\n') { 1712 1.60 aidan state = EOLN; 1713 1.23 lukem return (CRLF); 1714 1.1 cgd } 1715 1.60 aidan c = cmdp[cpos]; 1716 1.60 aidan cmdp[cpos] = '\0'; 1717 1.60 aidan reply(501, "'%s' command does not take any arguments.", cmdp); 1718 1.23 lukem hasyyerrored = 1; 1719 1.60 aidan cmdp[cpos] = c; 1720 1.23 lukem break; 1721 1.23 lukem 1722 1.60 aidan case EOLN: 1723 1.60 aidan state = CMD; 1724 1.60 aidan return (0); 1725 1.60 aidan 1726 1.23 lukem default: 1727 1.23 lukem fatal("Unknown state in scanner."); 1728 1.1 cgd } 1729 1.23 lukem yyerror(NULL); 1730 1.23 lukem state = CMD; 1731 1.80 lukem return (0); 1732 1.1 cgd } 1733 1.1 cgd 1734 1.22 lukem /* ARGSUSED */ 1735 1.22 lukem void 1736 1.89 lukem yyerror(const char *s) 1737 1.22 lukem { 1738 1.22 lukem char *cp; 1739 1.22 lukem 1740 1.60 aidan if (hasyyerrored || is_oob) 1741 1.22 lukem return; 1742 1.60 aidan if ((cp = strchr(cmdp,'\n')) != NULL) 1743 1.22 lukem *cp = '\0'; 1744 1.60 aidan reply(500, "'%s': command not understood.", cmdp); 1745 1.22 lukem hasyyerrored = 1; 1746 1.22 lukem } 1747 1.22 lukem 1748 1.4 deraadt static void 1749 1.46 lukem help(struct tab *ctab, const char *s) 1750 1.1 cgd { 1751 1.4 deraadt struct tab *c; 1752 1.4 deraadt int width, NCMDS; 1753 1.89 lukem const char *htype; 1754 1.1 cgd 1755 1.1 cgd if (ctab == sitetab) 1756 1.66 lukem htype = "SITE "; 1757 1.1 cgd else 1758 1.66 lukem htype = ""; 1759 1.1 cgd width = 0, NCMDS = 0; 1760 1.1 cgd for (c = ctab; c->name != NULL; c++) { 1761 1.1 cgd int len = strlen(c->name); 1762 1.1 cgd 1763 1.1 cgd if (len > width) 1764 1.1 cgd width = len; 1765 1.1 cgd NCMDS++; 1766 1.1 cgd } 1767 1.1 cgd width = (width + 8) &~ 7; 1768 1.1 cgd if (s == 0) { 1769 1.4 deraadt int i, j, w; 1770 1.1 cgd int columns, lines; 1771 1.1 cgd 1772 1.49 sommerfe reply(-214, "%s", ""); 1773 1.66 lukem reply(0, "The following %scommands are recognized.", htype); 1774 1.48 lukem reply(0, "(`-' = not implemented, `+' = supports options)"); 1775 1.1 cgd columns = 76 / width; 1776 1.1 cgd if (columns == 0) 1777 1.1 cgd columns = 1; 1778 1.1 cgd lines = (NCMDS + columns - 1) / columns; 1779 1.1 cgd for (i = 0; i < lines; i++) { 1780 1.48 lukem cprintf(stdout, " "); 1781 1.1 cgd for (j = 0; j < columns; j++) { 1782 1.1 cgd c = ctab + j * lines + i; 1783 1.48 lukem cprintf(stdout, "%s", c->name); 1784 1.23 lukem w = strlen(c->name); 1785 1.47 lukem if (! CMD_IMPLEMENTED(c)) { 1786 1.48 lukem CPUTC('-', stdout); 1787 1.23 lukem w++; 1788 1.23 lukem } 1789 1.47 lukem if (CMD_HAS_OPTIONS(c)) { 1790 1.48 lukem CPUTC('+', stdout); 1791 1.23 lukem w++; 1792 1.23 lukem } 1793 1.1 cgd if (c + lines >= &ctab[NCMDS]) 1794 1.1 cgd break; 1795 1.1 cgd while (w < width) { 1796 1.48 lukem CPUTC(' ', stdout); 1797 1.1 cgd w++; 1798 1.1 cgd } 1799 1.1 cgd } 1800 1.48 lukem cprintf(stdout, "\r\n"); 1801 1.1 cgd } 1802 1.1 cgd (void) fflush(stdout); 1803 1.1 cgd reply(214, "Direct comments to ftp-bugs@%s.", hostname); 1804 1.1 cgd return; 1805 1.1 cgd } 1806 1.1 cgd c = lookup(ctab, s); 1807 1.1 cgd if (c == (struct tab *)0) { 1808 1.71 darrenr reply(502, "Unknown command '%s'.", s); 1809 1.1 cgd return; 1810 1.1 cgd } 1811 1.47 lukem if (CMD_IMPLEMENTED(c)) 1812 1.66 lukem reply(214, "Syntax: %s%s %s", htype, c->name, c->help); 1813 1.1 cgd else 1814 1.71 darrenr reply(504, "%s%-*s\t%s; not implemented.", htype, width, 1815 1.1 cgd c->name, c->help); 1816 1.52 lukem } 1817 1.52 lukem 1818 1.52 lukem /* 1819 1.52 lukem * Check that the structures used for a PORT, LPRT or EPRT command are 1820 1.52 lukem * valid (data_dest, his_addr), and if necessary, detect ftp bounce attacks. 1821 1.52 lukem * If family != -1 check that his_addr.su_family == family. 1822 1.52 lukem */ 1823 1.52 lukem static void 1824 1.52 lukem port_check(const char *cmd, int family) 1825 1.52 lukem { 1826 1.61 itojun char h1[NI_MAXHOST], h2[NI_MAXHOST]; 1827 1.61 itojun char s1[NI_MAXHOST], s2[NI_MAXHOST]; 1828 1.61 itojun const int niflags = NI_NUMERICHOST | NI_NUMERICSERV; 1829 1.52 lukem 1830 1.52 lukem if (epsvall) { 1831 1.52 lukem reply(501, "%s disallowed after EPSV ALL", cmd); 1832 1.52 lukem return; 1833 1.52 lukem } 1834 1.52 lukem 1835 1.52 lukem if (family != -1 && his_addr.su_family != family) { 1836 1.52 lukem port_check_fail: 1837 1.52 lukem reply(500, "Illegal %s command rejected", cmd); 1838 1.52 lukem return; 1839 1.52 lukem } 1840 1.52 lukem 1841 1.52 lukem if (data_dest.su_family != his_addr.su_family) 1842 1.52 lukem goto port_check_fail; 1843 1.52 lukem 1844 1.52 lukem /* be paranoid, if told so */ 1845 1.56 lukem if (CURCLASS_FLAGS_ISSET(checkportcmd)) { 1846 1.61 itojun #ifdef INET6 1847 1.61 itojun /* 1848 1.61 itojun * be paranoid, there are getnameinfo implementation that does 1849 1.61 itojun * not present scopeid portion 1850 1.61 itojun */ 1851 1.61 itojun if (data_dest.su_family == AF_INET6 && 1852 1.61 itojun data_dest.su_scope_id != his_addr.su_scope_id) 1853 1.52 lukem goto port_check_fail; 1854 1.53 christos #endif 1855 1.61 itojun 1856 1.61 itojun if (getnameinfo((struct sockaddr *)&data_dest, data_dest.su_len, 1857 1.61 itojun h1, sizeof(h1), s1, sizeof(s1), niflags)) 1858 1.61 itojun goto port_check_fail; 1859 1.61 itojun if (getnameinfo((struct sockaddr *)&his_addr, his_addr.su_len, 1860 1.61 itojun h2, sizeof(h2), s2, sizeof(s2), niflags)) 1861 1.61 itojun goto port_check_fail; 1862 1.61 itojun 1863 1.61 itojun if (atoi(s1) < IPPORT_RESERVED || strcmp(h1, h2) != 0) 1864 1.52 lukem goto port_check_fail; 1865 1.52 lukem } 1866 1.52 lukem 1867 1.52 lukem usedefault = 0; 1868 1.52 lukem if (pdata >= 0) { 1869 1.52 lukem (void) close(pdata); 1870 1.52 lukem pdata = -1; 1871 1.52 lukem } 1872 1.52 lukem reply(200, "%s command successful.", cmd); 1873 1.23 lukem } 1874