| 1 | /* $NetBSD: ftpcmd.y,v 1.6 1995/06/03 22:46:45 mycroft Exp $ */
|
|---|
| 2 |
|
|---|
| 3 | /*
|
|---|
| 4 | * Copyright (c) 1985, 1988, 1993, 1994
|
|---|
| 5 | * The Regents of the University of California. All rights reserved.
|
|---|
| 6 | *
|
|---|
| 7 | * Redistribution and use in source and binary forms, with or without
|
|---|
| 8 | * modification, are permitted provided that the following conditions
|
|---|
| 9 | * are met:
|
|---|
| 10 | * 1. Redistributions of source code must retain the above copyright
|
|---|
| 11 | * notice, this list of conditions and the following disclaimer.
|
|---|
| 12 | * 2. Redistributions in binary form must reproduce the above copyright
|
|---|
| 13 | * notice, this list of conditions and the following disclaimer in the
|
|---|
| 14 | * documentation and/or other materials provided with the distribution.
|
|---|
| 15 | * 3. All advertising materials mentioning features or use of this software
|
|---|
| 16 | * must display the following acknowledgement:
|
|---|
| 17 | * This product includes software developed by the University of
|
|---|
| 18 | * California, Berkeley and its contributors.
|
|---|
| 19 | * 4. Neither the name of the University nor the names of its contributors
|
|---|
| 20 | * may be used to endorse or promote products derived from this software
|
|---|
| 21 | * without specific prior written permission.
|
|---|
| 22 | *
|
|---|
| 23 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|---|
| 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|---|
| 25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|---|
| 26 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|---|
| 27 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|---|
| 28 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|---|
| 29 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|---|
| 30 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|---|
| 31 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|---|
| 32 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|---|
| 33 | * SUCH DAMAGE.
|
|---|
| 34 | *
|
|---|
| 35 | * @(#)ftpcmd.y 8.3 (Berkeley) 4/6/94
|
|---|
| 36 | */
|
|---|
| 37 |
|
|---|
| 38 | /*
|
|---|
| 39 | * Grammar for FTP commands.
|
|---|
| 40 | * See RFC 959.
|
|---|
| 41 | */
|
|---|
| 42 |
|
|---|
| 43 | %{
|
|---|
| 44 |
|
|---|
| 45 | #include "ftpd_locl.h"
|
|---|
| 46 | RCSID("$Id$");
|
|---|
| 47 |
|
|---|
| 48 | off_t restart_point;
|
|---|
| 49 |
|
|---|
| 50 | static int hasyyerrored;
|
|---|
| 51 |
|
|---|
| 52 |
|
|---|
| 53 | static int cmd_type;
|
|---|
| 54 | static int cmd_form;
|
|---|
| 55 | static int cmd_bytesz;
|
|---|
| 56 | char cbuf[64*1024];
|
|---|
| 57 | char *fromname;
|
|---|
| 58 |
|
|---|
| 59 | struct tab {
|
|---|
| 60 | char *name;
|
|---|
| 61 | short token;
|
|---|
| 62 | short state;
|
|---|
| 63 | short implemented; /* 1 if command is implemented */
|
|---|
| 64 | char *help;
|
|---|
| 65 | };
|
|---|
| 66 |
|
|---|
| 67 | extern struct tab cmdtab[];
|
|---|
| 68 | extern struct tab sitetab[];
|
|---|
| 69 |
|
|---|
| 70 | static char *copy (char *);
|
|---|
| 71 | static void help (struct tab *, char *);
|
|---|
| 72 | static struct tab *
|
|---|
| 73 | lookup (struct tab *, char *);
|
|---|
| 74 | static void sizecmd (char *);
|
|---|
| 75 | static RETSIGTYPE toolong (int);
|
|---|
| 76 | static int yylex (void);
|
|---|
| 77 |
|
|---|
| 78 | /* This is for bison */
|
|---|
| 79 |
|
|---|
| 80 | #if !defined(alloca) && !defined(HAVE_ALLOCA)
|
|---|
| 81 | #define alloca(x) malloc(x)
|
|---|
| 82 | #endif
|
|---|
| 83 |
|
|---|
| 84 | %}
|
|---|
| 85 |
|
|---|
| 86 | %union {
|
|---|
| 87 | int i;
|
|---|
| 88 | char *s;
|
|---|
| 89 | }
|
|---|
| 90 |
|
|---|
| 91 | %token
|
|---|
| 92 | A B C E F I
|
|---|
| 93 | L N P R S T
|
|---|
| 94 |
|
|---|
| 95 | SP CRLF COMMA
|
|---|
| 96 |
|
|---|
| 97 | USER PASS ACCT REIN QUIT PORT
|
|---|
| 98 | PASV TYPE STRU MODE RETR STOR
|
|---|
| 99 | APPE MLFL MAIL MSND MSOM MSAM
|
|---|
| 100 | MRSQ MRCP ALLO REST RNFR RNTO
|
|---|
| 101 | ABOR DELE CWD LIST NLST SITE
|
|---|
| 102 | sTAT HELP NOOP MKD RMD PWD
|
|---|
| 103 | CDUP STOU SMNT SYST SIZE MDTM
|
|---|
| 104 | EPRT EPSV
|
|---|
| 105 |
|
|---|
| 106 | UMASK IDLE CHMOD
|
|---|
| 107 |
|
|---|
| 108 | AUTH ADAT PROT PBSZ CCC MIC
|
|---|
| 109 | CONF ENC
|
|---|
| 110 |
|
|---|
| 111 | KAUTH KLIST KDESTROY KRBTKFILE AFSLOG
|
|---|
| 112 | LOCATE URL
|
|---|
| 113 |
|
|---|
| 114 | FEAT OPTS
|
|---|
| 115 |
|
|---|
| 116 | LEXERR
|
|---|
| 117 |
|
|---|
| 118 | %token <s> STRING
|
|---|
| 119 | %token <i> NUMBER
|
|---|
| 120 |
|
|---|
| 121 | %type <i> check_login check_login_no_guest check_secure octal_number byte_size
|
|---|
| 122 | %type <i> struct_code mode_code type_code form_code
|
|---|
| 123 | %type <s> pathstring pathname password username
|
|---|
| 124 |
|
|---|
| 125 | %start cmd_list
|
|---|
| 126 |
|
|---|
| 127 | %%
|
|---|
| 128 |
|
|---|
| 129 | cmd_list
|
|---|
| 130 | : /* empty */
|
|---|
| 131 | | cmd_list cmd
|
|---|
| 132 | {
|
|---|
| 133 | fromname = (char *) 0;
|
|---|
| 134 | restart_point = (off_t) 0;
|
|---|
| 135 | }
|
|---|
| 136 | | cmd_list rcmd
|
|---|
| 137 | ;
|
|---|
| 138 |
|
|---|
| 139 | cmd
|
|---|
| 140 | : USER SP username CRLF check_secure
|
|---|
| 141 | {
|
|---|
| 142 | if ($5)
|
|---|
| 143 | user($3);
|
|---|
| 144 | free($3);
|
|---|
| 145 | }
|
|---|
| 146 | | PASS SP password CRLF check_secure
|
|---|
| 147 | {
|
|---|
| 148 | if ($5)
|
|---|
| 149 | pass($3);
|
|---|
| 150 | memset ($3, 0, strlen($3));
|
|---|
| 151 | free($3);
|
|---|
| 152 | }
|
|---|
| 153 |
|
|---|
| 154 | | PORT SP host_port CRLF check_secure
|
|---|
| 155 | {
|
|---|
| 156 | if ($5) {
|
|---|
| 157 | if (paranoid &&
|
|---|
| 158 | (data_dest->sa_family != his_addr->sa_family ||
|
|---|
| 159 | (socket_get_port(data_dest) < IPPORT_RESERVED) ||
|
|---|
| 160 | memcmp(socket_get_address(data_dest),
|
|---|
| 161 | socket_get_address(his_addr),
|
|---|
| 162 | socket_addr_size(his_addr)) != 0)) {
|
|---|
| 163 | usedefault = 1;
|
|---|
| 164 | reply(500, "Illegal PORT range rejected.");
|
|---|
| 165 | } else {
|
|---|
| 166 | usedefault = 0;
|
|---|
| 167 | if (pdata >= 0) {
|
|---|
| 168 | close(pdata);
|
|---|
| 169 | pdata = -1;
|
|---|
| 170 | }
|
|---|
| 171 | reply(200, "PORT command successful.");
|
|---|
| 172 | }
|
|---|
| 173 | }
|
|---|
| 174 | }
|
|---|
| 175 | | EPRT SP STRING CRLF check_secure
|
|---|
| 176 | {
|
|---|
| 177 | if ($5)
|
|---|
| 178 | eprt ($3);
|
|---|
| 179 | free ($3);
|
|---|
| 180 | }
|
|---|
| 181 | | PASV CRLF check_login
|
|---|
| 182 | {
|
|---|
| 183 | if($3)
|
|---|
| 184 | pasv ();
|
|---|
| 185 | }
|
|---|
| 186 | | EPSV CRLF check_login
|
|---|
| 187 | {
|
|---|
| 188 | if($3)
|
|---|
| 189 | epsv (NULL);
|
|---|
| 190 | }
|
|---|
| 191 | | EPSV SP STRING CRLF check_login
|
|---|
| 192 | {
|
|---|
| 193 | if($5)
|
|---|
| 194 | epsv ($3);
|
|---|
| 195 | free ($3);
|
|---|
| 196 | }
|
|---|
| 197 | | TYPE SP type_code CRLF check_secure
|
|---|
| 198 | {
|
|---|
| 199 | if ($5) {
|
|---|
| 200 | switch (cmd_type) {
|
|---|
| 201 |
|
|---|
| 202 | case TYPE_A:
|
|---|
| 203 | if (cmd_form == FORM_N) {
|
|---|
| 204 | reply(200, "Type set to A.");
|
|---|
| 205 | type = cmd_type;
|
|---|
| 206 | form = cmd_form;
|
|---|
| 207 | } else
|
|---|
| 208 | reply(504, "Form must be N.");
|
|---|
| 209 | break;
|
|---|
| 210 |
|
|---|
| 211 | case TYPE_E:
|
|---|
| 212 | reply(504, "Type E not implemented.");
|
|---|
| 213 | break;
|
|---|
| 214 |
|
|---|
| 215 | case TYPE_I:
|
|---|
| 216 | reply(200, "Type set to I.");
|
|---|
| 217 | type = cmd_type;
|
|---|
| 218 | break;
|
|---|
| 219 |
|
|---|
| 220 | case TYPE_L:
|
|---|
| 221 | #if NBBY == 8
|
|---|
| 222 | if (cmd_bytesz == 8) {
|
|---|
| 223 | reply(200,
|
|---|
| 224 | "Type set to L (byte size 8).");
|
|---|
| 225 | type = cmd_type;
|
|---|
| 226 | } else
|
|---|
| 227 | reply(504, "Byte size must be 8.");
|
|---|
| 228 | #else /* NBBY == 8 */
|
|---|
| 229 | UNIMPLEMENTED for NBBY != 8
|
|---|
| 230 | #endif /* NBBY == 8 */
|
|---|
| 231 | }
|
|---|
| 232 | }
|
|---|
| 233 | }
|
|---|
| 234 | | STRU SP struct_code CRLF check_secure
|
|---|
| 235 | {
|
|---|
| 236 | if ($5) {
|
|---|
| 237 | switch ($3) {
|
|---|
| 238 |
|
|---|
| 239 | case STRU_F:
|
|---|
| 240 | reply(200, "STRU F ok.");
|
|---|
| 241 | break;
|
|---|
| 242 |
|
|---|
| 243 | default:
|
|---|
| 244 | reply(504, "Unimplemented STRU type.");
|
|---|
| 245 | }
|
|---|
| 246 | }
|
|---|
| 247 | }
|
|---|
| 248 | | MODE SP mode_code CRLF check_secure
|
|---|
| 249 | {
|
|---|
| 250 | if ($5) {
|
|---|
| 251 | switch ($3) {
|
|---|
| 252 |
|
|---|
| 253 | case MODE_S:
|
|---|
| 254 | reply(200, "MODE S ok.");
|
|---|
| 255 | break;
|
|---|
| 256 |
|
|---|
| 257 | default:
|
|---|
| 258 | reply(502, "Unimplemented MODE type.");
|
|---|
| 259 | }
|
|---|
| 260 | }
|
|---|
| 261 | }
|
|---|
| 262 | | ALLO SP NUMBER CRLF check_secure
|
|---|
| 263 | {
|
|---|
| 264 | if ($5) {
|
|---|
| 265 | reply(202, "ALLO command ignored.");
|
|---|
| 266 | }
|
|---|
| 267 | }
|
|---|
| 268 | | ALLO SP NUMBER SP R SP NUMBER CRLF check_secure
|
|---|
| 269 | {
|
|---|
| 270 | if ($9) {
|
|---|
| 271 | reply(202, "ALLO command ignored.");
|
|---|
| 272 | }
|
|---|
| 273 | }
|
|---|
| 274 | | RETR SP pathname CRLF check_login
|
|---|
| 275 | {
|
|---|
| 276 | char *name = $3;
|
|---|
| 277 |
|
|---|
| 278 | if ($5 && name != NULL)
|
|---|
| 279 | retrieve(0, name);
|
|---|
| 280 | if (name != NULL)
|
|---|
| 281 | free(name);
|
|---|
| 282 | }
|
|---|
| 283 | | STOR SP pathname CRLF check_login
|
|---|
| 284 | {
|
|---|
| 285 | char *name = $3;
|
|---|
| 286 |
|
|---|
| 287 | if ($5 && name != NULL)
|
|---|
| 288 | do_store(name, "w", 0);
|
|---|
| 289 | if (name != NULL)
|
|---|
| 290 | free(name);
|
|---|
| 291 | }
|
|---|
| 292 | | APPE SP pathname CRLF check_login
|
|---|
| 293 | {
|
|---|
| 294 | char *name = $3;
|
|---|
| 295 |
|
|---|
| 296 | if ($5 && name != NULL)
|
|---|
| 297 | do_store(name, "a", 0);
|
|---|
| 298 | if (name != NULL)
|
|---|
| 299 | free(name);
|
|---|
| 300 | }
|
|---|
| 301 | | NLST CRLF check_login
|
|---|
| 302 | {
|
|---|
| 303 | if ($3)
|
|---|
| 304 | send_file_list(".");
|
|---|
| 305 | }
|
|---|
| 306 | | NLST SP STRING CRLF check_login
|
|---|
| 307 | {
|
|---|
| 308 | char *name = $3;
|
|---|
| 309 |
|
|---|
| 310 | if ($5 && name != NULL)
|
|---|
| 311 | send_file_list(name);
|
|---|
| 312 | if (name != NULL)
|
|---|
| 313 | free(name);
|
|---|
| 314 | }
|
|---|
| 315 | | LIST CRLF check_login
|
|---|
| 316 | {
|
|---|
| 317 | if($3)
|
|---|
| 318 | list_file(".");
|
|---|
| 319 | }
|
|---|
| 320 | | LIST SP pathname CRLF check_login
|
|---|
| 321 | {
|
|---|
| 322 | if($5)
|
|---|
| 323 | list_file($3);
|
|---|
| 324 | free($3);
|
|---|
| 325 | }
|
|---|
| 326 | | sTAT SP pathname CRLF check_login
|
|---|
| 327 | {
|
|---|
| 328 | if ($5 && $3 != NULL)
|
|---|
| 329 | statfilecmd($3);
|
|---|
| 330 | if ($3 != NULL)
|
|---|
| 331 | free($3);
|
|---|
| 332 | }
|
|---|
| 333 | | sTAT CRLF check_secure
|
|---|
| 334 | {
|
|---|
| 335 | if ($3)
|
|---|
| 336 | statcmd();
|
|---|
| 337 | }
|
|---|
| 338 | | DELE SP pathname CRLF check_login_no_guest
|
|---|
| 339 | {
|
|---|
| 340 | if ($5 && $3 != NULL)
|
|---|
| 341 | do_delete($3);
|
|---|
| 342 | if ($3 != NULL)
|
|---|
| 343 | free($3);
|
|---|
| 344 | }
|
|---|
| 345 | | RNTO SP pathname CRLF check_login_no_guest
|
|---|
| 346 | {
|
|---|
| 347 | if($5){
|
|---|
| 348 | if (fromname) {
|
|---|
| 349 | renamecmd(fromname, $3);
|
|---|
| 350 | free(fromname);
|
|---|
| 351 | fromname = (char *) 0;
|
|---|
| 352 | } else {
|
|---|
| 353 | reply(503, "Bad sequence of commands.");
|
|---|
| 354 | }
|
|---|
| 355 | }
|
|---|
| 356 | if ($3 != NULL)
|
|---|
| 357 | free($3);
|
|---|
| 358 | }
|
|---|
| 359 | | ABOR CRLF check_secure
|
|---|
| 360 | {
|
|---|
| 361 | if ($3)
|
|---|
| 362 | reply(225, "ABOR command successful.");
|
|---|
| 363 | }
|
|---|
| 364 | | CWD CRLF check_login
|
|---|
| 365 | {
|
|---|
| 366 | if ($3) {
|
|---|
| 367 | const char *path = pw->pw_dir;
|
|---|
| 368 | if (dochroot || guest)
|
|---|
| 369 | path = "/";
|
|---|
| 370 | cwd(path);
|
|---|
| 371 | }
|
|---|
| 372 | }
|
|---|
| 373 | | CWD SP pathname CRLF check_login
|
|---|
| 374 | {
|
|---|
| 375 | if ($5 && $3 != NULL)
|
|---|
| 376 | cwd($3);
|
|---|
| 377 | if ($3 != NULL)
|
|---|
| 378 | free($3);
|
|---|
| 379 | }
|
|---|
| 380 | | HELP CRLF check_secure
|
|---|
| 381 | {
|
|---|
| 382 | if ($3)
|
|---|
| 383 | help(cmdtab, (char *) 0);
|
|---|
| 384 | }
|
|---|
| 385 | | HELP SP STRING CRLF check_secure
|
|---|
| 386 | {
|
|---|
| 387 | if ($5) {
|
|---|
| 388 | char *cp = $3;
|
|---|
| 389 |
|
|---|
| 390 | if (strncasecmp(cp, "SITE", 4) == 0) {
|
|---|
| 391 | cp = $3 + 4;
|
|---|
| 392 | if (*cp == ' ')
|
|---|
| 393 | cp++;
|
|---|
| 394 | if (*cp)
|
|---|
| 395 | help(sitetab, cp);
|
|---|
| 396 | else
|
|---|
| 397 | help(sitetab, (char *) 0);
|
|---|
| 398 | } else
|
|---|
| 399 | help(cmdtab, $3);
|
|---|
| 400 | }
|
|---|
| 401 | }
|
|---|
| 402 | | NOOP CRLF check_secure
|
|---|
| 403 | {
|
|---|
| 404 | if ($3)
|
|---|
| 405 | reply(200, "NOOP command successful.");
|
|---|
| 406 | }
|
|---|
| 407 | | MKD SP pathname CRLF check_login
|
|---|
| 408 | {
|
|---|
| 409 | if ($5 && $3 != NULL)
|
|---|
| 410 | makedir($3);
|
|---|
| 411 | if ($3 != NULL)
|
|---|
| 412 | free($3);
|
|---|
| 413 | }
|
|---|
| 414 | | RMD SP pathname CRLF check_login_no_guest
|
|---|
| 415 | {
|
|---|
| 416 | if ($5 && $3 != NULL)
|
|---|
| 417 | removedir($3);
|
|---|
| 418 | if ($3 != NULL)
|
|---|
| 419 | free($3);
|
|---|
| 420 | }
|
|---|
| 421 | | PWD CRLF check_login
|
|---|
| 422 | {
|
|---|
| 423 | if ($3)
|
|---|
| 424 | pwd();
|
|---|
| 425 | }
|
|---|
| 426 | | CDUP CRLF check_login
|
|---|
| 427 | {
|
|---|
| 428 | if ($3)
|
|---|
| 429 | cwd("..");
|
|---|
| 430 | }
|
|---|
| 431 | | FEAT CRLF check_secure
|
|---|
| 432 | {
|
|---|
| 433 | if ($3) {
|
|---|
| 434 | lreply(211, "Supported features:");
|
|---|
| 435 | lreply(0, " MDTM");
|
|---|
| 436 | lreply(0, " REST STREAM");
|
|---|
| 437 | lreply(0, " SIZE");
|
|---|
| 438 | reply(211, "End");
|
|---|
| 439 | }
|
|---|
| 440 | }
|
|---|
| 441 | | OPTS SP STRING CRLF check_secure
|
|---|
| 442 | {
|
|---|
| 443 | if ($5)
|
|---|
| 444 | reply(501, "Bad options");
|
|---|
| 445 | free ($3);
|
|---|
| 446 | }
|
|---|
| 447 |
|
|---|
| 448 | | SITE SP HELP CRLF check_secure
|
|---|
| 449 | {
|
|---|
| 450 | if ($5)
|
|---|
| 451 | help(sitetab, (char *) 0);
|
|---|
| 452 | }
|
|---|
| 453 | | SITE SP HELP SP STRING CRLF check_secure
|
|---|
| 454 | {
|
|---|
| 455 | if ($7)
|
|---|
| 456 | help(sitetab, $5);
|
|---|
| 457 | }
|
|---|
| 458 | | SITE SP UMASK CRLF check_login
|
|---|
| 459 | {
|
|---|
| 460 | if ($5) {
|
|---|
| 461 | int oldmask = umask(0);
|
|---|
| 462 | umask(oldmask);
|
|---|
| 463 | reply(200, "Current UMASK is %03o", oldmask);
|
|---|
| 464 | }
|
|---|
| 465 | }
|
|---|
| 466 | | SITE SP UMASK SP octal_number CRLF check_login_no_guest
|
|---|
| 467 | {
|
|---|
| 468 | if ($7) {
|
|---|
| 469 | if (($5 == -1) || ($5 > 0777)) {
|
|---|
| 470 | reply(501, "Bad UMASK value");
|
|---|
| 471 | } else {
|
|---|
| 472 | int oldmask = umask($5);
|
|---|
| 473 | reply(200,
|
|---|
| 474 | "UMASK set to %03o (was %03o)",
|
|---|
| 475 | $5, oldmask);
|
|---|
| 476 | }
|
|---|
| 477 | }
|
|---|
| 478 | }
|
|---|
| 479 | | SITE SP CHMOD SP octal_number SP pathname CRLF check_login_no_guest
|
|---|
| 480 | {
|
|---|
| 481 | if ($9 && $7 != NULL) {
|
|---|
| 482 | if ($5 > 0777)
|
|---|
| 483 | reply(501,
|
|---|
| 484 | "CHMOD: Mode value must be between 0 and 0777");
|
|---|
| 485 | else if (chmod($7, $5) < 0)
|
|---|
| 486 | perror_reply(550, $7);
|
|---|
| 487 | else
|
|---|
| 488 | reply(200, "CHMOD command successful.");
|
|---|
| 489 | }
|
|---|
| 490 | if ($7 != NULL)
|
|---|
| 491 | free($7);
|
|---|
| 492 | }
|
|---|
| 493 | | SITE SP IDLE CRLF check_secure
|
|---|
| 494 | {
|
|---|
| 495 | if ($5)
|
|---|
| 496 | reply(200,
|
|---|
| 497 | "Current IDLE time limit is %d seconds; max %d",
|
|---|
| 498 | ftpd_timeout, maxtimeout);
|
|---|
| 499 | }
|
|---|
| 500 | | SITE SP IDLE SP NUMBER CRLF check_secure
|
|---|
| 501 | {
|
|---|
| 502 | if ($7) {
|
|---|
| 503 | if ($5 < 30 || $5 > maxtimeout) {
|
|---|
| 504 | reply(501,
|
|---|
| 505 | "Maximum IDLE time must be between 30 and %d seconds",
|
|---|
| 506 | maxtimeout);
|
|---|
| 507 | } else {
|
|---|
| 508 | ftpd_timeout = $5;
|
|---|
| 509 | alarm((unsigned) ftpd_timeout);
|
|---|
| 510 | reply(200,
|
|---|
| 511 | "Maximum IDLE time set to %d seconds",
|
|---|
| 512 | ftpd_timeout);
|
|---|
| 513 | }
|
|---|
| 514 | }
|
|---|
| 515 | }
|
|---|
| 516 |
|
|---|
| 517 | | SITE SP KAUTH SP STRING CRLF check_login
|
|---|
| 518 | {
|
|---|
| 519 | reply(500, "Command not implemented.");
|
|---|
| 520 | }
|
|---|
| 521 | | SITE SP KLIST CRLF check_login
|
|---|
| 522 | {
|
|---|
| 523 | if($5)
|
|---|
| 524 | klist();
|
|---|
| 525 | }
|
|---|
| 526 | | SITE SP KDESTROY CRLF check_login
|
|---|
| 527 | {
|
|---|
| 528 | reply(500, "Command not implemented.");
|
|---|
| 529 | }
|
|---|
| 530 | | SITE SP KRBTKFILE SP STRING CRLF check_login
|
|---|
| 531 | {
|
|---|
| 532 | reply(500, "Command not implemented.");
|
|---|
| 533 | }
|
|---|
| 534 | | SITE SP AFSLOG CRLF check_login
|
|---|
| 535 | {
|
|---|
| 536 | #if defined(KRB5)
|
|---|
| 537 | if(guest)
|
|---|
| 538 | reply(500, "Can't be done as guest.");
|
|---|
| 539 | else if($5)
|
|---|
| 540 | afslog(NULL, 0);
|
|---|
| 541 | #else
|
|---|
| 542 | reply(500, "Command not implemented.");
|
|---|
| 543 | #endif
|
|---|
| 544 | }
|
|---|
| 545 | | SITE SP AFSLOG SP STRING CRLF check_login
|
|---|
| 546 | {
|
|---|
| 547 | #if defined(KRB5)
|
|---|
| 548 | if(guest)
|
|---|
| 549 | reply(500, "Can't be done as guest.");
|
|---|
| 550 | else if($7)
|
|---|
| 551 | afslog($5, 0);
|
|---|
| 552 | if($5)
|
|---|
| 553 | free($5);
|
|---|
| 554 | #else
|
|---|
| 555 | reply(500, "Command not implemented.");
|
|---|
| 556 | #endif
|
|---|
| 557 | }
|
|---|
| 558 | | SITE SP LOCATE SP STRING CRLF check_login
|
|---|
| 559 | {
|
|---|
| 560 | if($7 && $5 != NULL)
|
|---|
| 561 | find($5);
|
|---|
| 562 | if($5 != NULL)
|
|---|
| 563 | free($5);
|
|---|
| 564 | }
|
|---|
| 565 | | SITE SP URL CRLF check_secure
|
|---|
| 566 | {
|
|---|
| 567 | if ($5)
|
|---|
| 568 | reply(200, "http://www.pdc.kth.se/heimdal/");
|
|---|
| 569 | }
|
|---|
| 570 | | STOU SP pathname CRLF check_login
|
|---|
| 571 | {
|
|---|
| 572 | if ($5 && $3 != NULL)
|
|---|
| 573 | do_store($3, "w", 1);
|
|---|
| 574 | if ($3 != NULL)
|
|---|
| 575 | free($3);
|
|---|
| 576 | }
|
|---|
| 577 | | SYST CRLF check_secure
|
|---|
| 578 | {
|
|---|
| 579 | if ($3) {
|
|---|
| 580 | #if !defined(WIN32) && !defined(__EMX__) && !defined(__OS2__) && !defined(__CYGWIN32__)
|
|---|
| 581 | reply(215, "UNIX Type: L%d", NBBY);
|
|---|
| 582 | #else
|
|---|
| 583 | reply(215, "UNKNOWN Type: L%d", NBBY);
|
|---|
| 584 | #endif
|
|---|
| 585 | }
|
|---|
| 586 | }
|
|---|
| 587 |
|
|---|
| 588 | /*
|
|---|
| 589 | * SIZE is not in RFC959, but Postel has blessed it and
|
|---|
| 590 | * it will be in the updated RFC.
|
|---|
| 591 | *
|
|---|
| 592 | * Return size of file in a format suitable for
|
|---|
| 593 | * using with RESTART (we just count bytes).
|
|---|
| 594 | */
|
|---|
| 595 | | SIZE SP pathname CRLF check_login
|
|---|
| 596 | {
|
|---|
| 597 | if ($5 && $3 != NULL)
|
|---|
| 598 | sizecmd($3);
|
|---|
| 599 | if ($3 != NULL)
|
|---|
| 600 | free($3);
|
|---|
| 601 | }
|
|---|
| 602 |
|
|---|
| 603 | /*
|
|---|
| 604 | * MDTM is not in RFC959, but Postel has blessed it and
|
|---|
| 605 | * it will be in the updated RFC.
|
|---|
| 606 | *
|
|---|
| 607 | * Return modification time of file as an ISO 3307
|
|---|
| 608 | * style time. E.g. YYYYMMDDHHMMSS or YYYYMMDDHHMMSS.xxx
|
|---|
| 609 | * where xxx is the fractional second (of any precision,
|
|---|
| 610 | * not necessarily 3 digits)
|
|---|
| 611 | */
|
|---|
| 612 | | MDTM SP pathname CRLF check_login
|
|---|
| 613 | {
|
|---|
| 614 | if ($5 && $3 != NULL) {
|
|---|
| 615 | struct stat stbuf;
|
|---|
| 616 | if (stat($3, &stbuf) < 0)
|
|---|
| 617 | reply(550, "%s: %s",
|
|---|
| 618 | $3, strerror(errno));
|
|---|
| 619 | else if (!S_ISREG(stbuf.st_mode)) {
|
|---|
| 620 | reply(550,
|
|---|
| 621 | "%s: not a plain file.", $3);
|
|---|
| 622 | } else {
|
|---|
| 623 | struct tm *t;
|
|---|
| 624 | time_t mtime = stbuf.st_mtime;
|
|---|
| 625 |
|
|---|
| 626 | t = gmtime(&mtime);
|
|---|
| 627 | reply(213,
|
|---|
| 628 | "%04d%02d%02d%02d%02d%02d",
|
|---|
| 629 | t->tm_year + 1900,
|
|---|
| 630 | t->tm_mon + 1,
|
|---|
| 631 | t->tm_mday,
|
|---|
| 632 | t->tm_hour,
|
|---|
| 633 | t->tm_min,
|
|---|
| 634 | t->tm_sec);
|
|---|
| 635 | }
|
|---|
| 636 | }
|
|---|
| 637 | if ($3 != NULL)
|
|---|
| 638 | free($3);
|
|---|
| 639 | }
|
|---|
| 640 | | QUIT CRLF check_secure
|
|---|
| 641 | {
|
|---|
| 642 | if ($3) {
|
|---|
| 643 | reply(221, "Goodbye.");
|
|---|
| 644 | dologout(0);
|
|---|
| 645 | }
|
|---|
| 646 | }
|
|---|
| 647 | | error CRLF
|
|---|
| 648 | {
|
|---|
| 649 | yyerrok;
|
|---|
| 650 | }
|
|---|
| 651 | ;
|
|---|
| 652 | rcmd
|
|---|
| 653 | : RNFR SP pathname CRLF check_login_no_guest
|
|---|
| 654 | {
|
|---|
| 655 | restart_point = (off_t) 0;
|
|---|
| 656 | if ($5 && $3) {
|
|---|
| 657 | fromname = renamefrom($3);
|
|---|
| 658 | if (fromname == (char *) 0 && $3) {
|
|---|
| 659 | free($3);
|
|---|
| 660 | }
|
|---|
| 661 | }
|
|---|
| 662 | }
|
|---|
| 663 | | REST SP byte_size CRLF check_secure
|
|---|
| 664 | {
|
|---|
| 665 | if ($5) {
|
|---|
| 666 | fromname = (char *) 0;
|
|---|
| 667 | restart_point = $3; /* XXX $3 is only "int" */
|
|---|
| 668 | reply(350, "Restarting at %ld. %s",
|
|---|
| 669 | (long)restart_point,
|
|---|
| 670 | "Send STORE or RETRIEVE to initiate transfer.");
|
|---|
| 671 | }
|
|---|
| 672 | }
|
|---|
| 673 | | AUTH SP STRING CRLF
|
|---|
| 674 | {
|
|---|
| 675 | auth($3);
|
|---|
| 676 | free($3);
|
|---|
| 677 | }
|
|---|
| 678 | | ADAT SP STRING CRLF
|
|---|
| 679 | {
|
|---|
| 680 | adat($3);
|
|---|
| 681 | free($3);
|
|---|
| 682 | }
|
|---|
| 683 | | PBSZ SP NUMBER CRLF check_secure
|
|---|
| 684 | {
|
|---|
| 685 | if ($5)
|
|---|
| 686 | pbsz($3);
|
|---|
| 687 | }
|
|---|
| 688 | | PROT SP STRING CRLF check_secure
|
|---|
| 689 | {
|
|---|
| 690 | if ($5)
|
|---|
| 691 | prot($3);
|
|---|
| 692 | }
|
|---|
| 693 | | CCC CRLF check_secure
|
|---|
| 694 | {
|
|---|
| 695 | if ($3)
|
|---|
| 696 | ccc();
|
|---|
| 697 | }
|
|---|
| 698 | | MIC SP STRING CRLF
|
|---|
| 699 | {
|
|---|
| 700 | mec($3, prot_safe);
|
|---|
| 701 | free($3);
|
|---|
| 702 | }
|
|---|
| 703 | | CONF SP STRING CRLF
|
|---|
| 704 | {
|
|---|
| 705 | mec($3, prot_confidential);
|
|---|
| 706 | free($3);
|
|---|
| 707 | }
|
|---|
| 708 | | ENC SP STRING CRLF
|
|---|
| 709 | {
|
|---|
| 710 | mec($3, prot_private);
|
|---|
| 711 | free($3);
|
|---|
| 712 | }
|
|---|
| 713 | ;
|
|---|
| 714 |
|
|---|
| 715 | username
|
|---|
| 716 | : STRING
|
|---|
| 717 | ;
|
|---|
| 718 |
|
|---|
| 719 | password
|
|---|
| 720 | : /* empty */
|
|---|
| 721 | {
|
|---|
| 722 | $$ = (char *)calloc(1, sizeof(char));
|
|---|
| 723 | }
|
|---|
| 724 | | STRING
|
|---|
| 725 | ;
|
|---|
| 726 |
|
|---|
| 727 | byte_size
|
|---|
| 728 | : NUMBER
|
|---|
| 729 | ;
|
|---|
| 730 |
|
|---|
| 731 | host_port
|
|---|
| 732 | : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
|
|---|
| 733 | NUMBER COMMA NUMBER
|
|---|
| 734 | {
|
|---|
| 735 | struct sockaddr_in *sin4 = (struct sockaddr_in *)data_dest;
|
|---|
| 736 |
|
|---|
| 737 | sin4->sin_family = AF_INET;
|
|---|
| 738 | sin4->sin_port = htons($9 * 256 + $11);
|
|---|
| 739 | sin4->sin_addr.s_addr =
|
|---|
| 740 | htonl(($1 << 24) | ($3 << 16) | ($5 << 8) | $7);
|
|---|
| 741 | }
|
|---|
| 742 | ;
|
|---|
| 743 |
|
|---|
| 744 | form_code
|
|---|
| 745 | : N
|
|---|
| 746 | {
|
|---|
| 747 | $$ = FORM_N;
|
|---|
| 748 | }
|
|---|
| 749 | | T
|
|---|
| 750 | {
|
|---|
| 751 | $$ = FORM_T;
|
|---|
| 752 | }
|
|---|
| 753 | | C
|
|---|
| 754 | {
|
|---|
| 755 | $$ = FORM_C;
|
|---|
| 756 | }
|
|---|
| 757 | ;
|
|---|
| 758 |
|
|---|
| 759 | type_code
|
|---|
| 760 | : A
|
|---|
| 761 | {
|
|---|
| 762 | cmd_type = TYPE_A;
|
|---|
| 763 | cmd_form = FORM_N;
|
|---|
| 764 | }
|
|---|
| 765 | | A SP form_code
|
|---|
| 766 | {
|
|---|
| 767 | cmd_type = TYPE_A;
|
|---|
| 768 | cmd_form = $3;
|
|---|
| 769 | }
|
|---|
| 770 | | E
|
|---|
| 771 | {
|
|---|
| 772 | cmd_type = TYPE_E;
|
|---|
| 773 | cmd_form = FORM_N;
|
|---|
| 774 | }
|
|---|
| 775 | | E SP form_code
|
|---|
| 776 | {
|
|---|
| 777 | cmd_type = TYPE_E;
|
|---|
| 778 | cmd_form = $3;
|
|---|
| 779 | }
|
|---|
| 780 | | I
|
|---|
| 781 | {
|
|---|
| 782 | cmd_type = TYPE_I;
|
|---|
| 783 | }
|
|---|
| 784 | | L
|
|---|
| 785 | {
|
|---|
| 786 | cmd_type = TYPE_L;
|
|---|
| 787 | cmd_bytesz = NBBY;
|
|---|
| 788 | }
|
|---|
| 789 | | L SP byte_size
|
|---|
| 790 | {
|
|---|
| 791 | cmd_type = TYPE_L;
|
|---|
| 792 | cmd_bytesz = $3;
|
|---|
| 793 | }
|
|---|
| 794 | /* this is for a bug in the BBN ftp */
|
|---|
| 795 | | L byte_size
|
|---|
| 796 | {
|
|---|
| 797 | cmd_type = TYPE_L;
|
|---|
| 798 | cmd_bytesz = $2;
|
|---|
| 799 | }
|
|---|
| 800 | ;
|
|---|
| 801 |
|
|---|
| 802 | struct_code
|
|---|
| 803 | : F
|
|---|
| 804 | {
|
|---|
| 805 | $$ = STRU_F;
|
|---|
| 806 | }
|
|---|
| 807 | | R
|
|---|
| 808 | {
|
|---|
| 809 | $$ = STRU_R;
|
|---|
| 810 | }
|
|---|
| 811 | | P
|
|---|
| 812 | {
|
|---|
| 813 | $$ = STRU_P;
|
|---|
| 814 | }
|
|---|
| 815 | ;
|
|---|
| 816 |
|
|---|
| 817 | mode_code
|
|---|
| 818 | : S
|
|---|
| 819 | {
|
|---|
| 820 | $$ = MODE_S;
|
|---|
| 821 | }
|
|---|
| 822 | | B
|
|---|
| 823 | {
|
|---|
| 824 | $$ = MODE_B;
|
|---|
| 825 | }
|
|---|
| 826 | | C
|
|---|
| 827 | {
|
|---|
| 828 | $$ = MODE_C;
|
|---|
| 829 | }
|
|---|
| 830 | ;
|
|---|
| 831 |
|
|---|
| 832 | pathname
|
|---|
| 833 | : pathstring
|
|---|
| 834 | {
|
|---|
| 835 | /*
|
|---|
| 836 | * Problem: this production is used for all pathname
|
|---|
| 837 | * processing, but only gives a 550 error reply.
|
|---|
| 838 | * This is a valid reply in some cases but not in others.
|
|---|
| 839 | */
|
|---|
| 840 | if (logged_in && $1 && *$1 == '~') {
|
|---|
| 841 | glob_t gl;
|
|---|
| 842 | int flags =
|
|---|
| 843 | GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
|
|---|
| 844 |
|
|---|
| 845 | memset(&gl, 0, sizeof(gl));
|
|---|
| 846 | if (glob($1, flags, NULL, &gl) ||
|
|---|
| 847 | gl.gl_pathc == 0) {
|
|---|
| 848 | reply(550, "not found");
|
|---|
| 849 | $$ = NULL;
|
|---|
| 850 | } else {
|
|---|
| 851 | $$ = strdup(gl.gl_pathv[0]);
|
|---|
| 852 | }
|
|---|
| 853 | globfree(&gl);
|
|---|
| 854 | free($1);
|
|---|
| 855 | } else
|
|---|
| 856 | $$ = $1;
|
|---|
| 857 | }
|
|---|
| 858 | ;
|
|---|
| 859 |
|
|---|
| 860 | pathstring
|
|---|
| 861 | : STRING
|
|---|
| 862 | ;
|
|---|
| 863 |
|
|---|
| 864 | octal_number
|
|---|
| 865 | : NUMBER
|
|---|
| 866 | {
|
|---|
| 867 | int ret, dec, multby, digit;
|
|---|
| 868 |
|
|---|
| 869 | /*
|
|---|
| 870 | * Convert a number that was read as decimal number
|
|---|
| 871 | * to what it would be if it had been read as octal.
|
|---|
| 872 | */
|
|---|
| 873 | dec = $1;
|
|---|
| 874 | multby = 1;
|
|---|
| 875 | ret = 0;
|
|---|
| 876 | while (dec) {
|
|---|
| 877 | digit = dec%10;
|
|---|
| 878 | if (digit > 7) {
|
|---|
| 879 | ret = -1;
|
|---|
| 880 | break;
|
|---|
| 881 | }
|
|---|
| 882 | ret += digit * multby;
|
|---|
| 883 | multby *= 8;
|
|---|
| 884 | dec /= 10;
|
|---|
| 885 | }
|
|---|
| 886 | $$ = ret;
|
|---|
| 887 | }
|
|---|
| 888 | ;
|
|---|
| 889 |
|
|---|
| 890 |
|
|---|
| 891 | check_login_no_guest : check_login
|
|---|
| 892 | {
|
|---|
| 893 | $$ = $1 && !guest;
|
|---|
| 894 | if($1 && !$$)
|
|---|
| 895 | reply(550, "Permission denied");
|
|---|
| 896 | }
|
|---|
| 897 | ;
|
|---|
| 898 |
|
|---|
| 899 | check_login : check_secure
|
|---|
| 900 | {
|
|---|
| 901 | if($1) {
|
|---|
| 902 | if(($$ = logged_in) == 0)
|
|---|
| 903 | reply(530, "Please login with USER and PASS.");
|
|---|
| 904 | } else
|
|---|
| 905 | $$ = 0;
|
|---|
| 906 | }
|
|---|
| 907 | ;
|
|---|
| 908 |
|
|---|
| 909 | check_secure : /* empty */
|
|---|
| 910 | {
|
|---|
| 911 | $$ = 1;
|
|---|
| 912 | if(sec_complete && !ccc_passed && !secure_command()) {
|
|---|
| 913 | $$ = 0;
|
|---|
| 914 | reply(533, "Command protection level denied "
|
|---|
| 915 | "for paranoid reasons.");
|
|---|
| 916 | }
|
|---|
| 917 | }
|
|---|
| 918 | ;
|
|---|
| 919 |
|
|---|
| 920 | %%
|
|---|
| 921 |
|
|---|
| 922 | #define CMD 0 /* beginning of command */
|
|---|
| 923 | #define ARGS 1 /* expect miscellaneous arguments */
|
|---|
| 924 | #define STR1 2 /* expect SP followed by STRING */
|
|---|
| 925 | #define STR2 3 /* expect STRING */
|
|---|
| 926 | #define OSTR 4 /* optional SP then STRING */
|
|---|
| 927 | #define ZSTR1 5 /* SP then optional STRING */
|
|---|
| 928 | #define ZSTR2 6 /* optional STRING after SP */
|
|---|
| 929 | #define SITECMD 7 /* SITE command */
|
|---|
| 930 | #define NSTR 8 /* Number followed by a string */
|
|---|
| 931 |
|
|---|
| 932 | struct tab cmdtab[] = { /* In order defined in RFC 765 */
|
|---|
| 933 | { "USER", USER, STR1, 1, "<sp> username" },
|
|---|
| 934 | { "PASS", PASS, ZSTR1, 1, "<sp> password" },
|
|---|
| 935 | { "ACCT", ACCT, STR1, 0, "(specify account)" },
|
|---|
| 936 | { "SMNT", SMNT, ARGS, 0, "(structure mount)" },
|
|---|
| 937 | { "REIN", REIN, ARGS, 0, "(reinitialize server state)" },
|
|---|
| 938 | { "QUIT", QUIT, ARGS, 1, "(terminate service)", },
|
|---|
| 939 | { "PORT", PORT, ARGS, 1, "<sp> b0, b1, b2, b3, b4" },
|
|---|
| 940 | { "EPRT", EPRT, STR1, 1, "<sp> string" },
|
|---|
| 941 | { "PASV", PASV, ARGS, 1, "(set server in passive mode)" },
|
|---|
| 942 | { "EPSV", EPSV, OSTR, 1, "[<sp> foo]" },
|
|---|
| 943 | { "TYPE", TYPE, ARGS, 1, "<sp> [ A | E | I | L ]" },
|
|---|
| 944 | { "STRU", STRU, ARGS, 1, "(specify file structure)" },
|
|---|
| 945 | { "MODE", MODE, ARGS, 1, "(specify transfer mode)" },
|
|---|
| 946 | { "RETR", RETR, STR1, 1, "<sp> file-name" },
|
|---|
| 947 | { "STOR", STOR, STR1, 1, "<sp> file-name" },
|
|---|
| 948 | { "APPE", APPE, STR1, 1, "<sp> file-name" },
|
|---|
| 949 | { "MLFL", MLFL, OSTR, 0, "(mail file)" },
|
|---|
| 950 | { "MAIL", MAIL, OSTR, 0, "(mail to user)" },
|
|---|
| 951 | { "MSND", MSND, OSTR, 0, "(mail send to terminal)" },
|
|---|
| 952 | { "MSOM", MSOM, OSTR, 0, "(mail send to terminal or mailbox)" },
|
|---|
| 953 | { "MSAM", MSAM, OSTR, 0, "(mail send to terminal and mailbox)" },
|
|---|
| 954 | { "MRSQ", MRSQ, OSTR, 0, "(mail recipient scheme question)" },
|
|---|
| 955 | { "MRCP", MRCP, STR1, 0, "(mail recipient)" },
|
|---|
| 956 | { "ALLO", ALLO, ARGS, 1, "allocate storage (vacuously)" },
|
|---|
| 957 | { "REST", REST, ARGS, 1, "<sp> offset (restart command)" },
|
|---|
| 958 | { "RNFR", RNFR, STR1, 1, "<sp> file-name" },
|
|---|
| 959 | { "RNTO", RNTO, STR1, 1, "<sp> file-name" },
|
|---|
| 960 | { "ABOR", ABOR, ARGS, 1, "(abort operation)" },
|
|---|
| 961 | { "DELE", DELE, STR1, 1, "<sp> file-name" },
|
|---|
| 962 | { "CWD", CWD, OSTR, 1, "[ <sp> directory-name ]" },
|
|---|
| 963 | { "XCWD", CWD, OSTR, 1, "[ <sp> directory-name ]" },
|
|---|
| 964 | { "LIST", LIST, OSTR, 1, "[ <sp> path-name ]" },
|
|---|
| 965 | { "NLST", NLST, OSTR, 1, "[ <sp> path-name ]" },
|
|---|
| 966 | { "SITE", SITE, SITECMD, 1, "site-cmd [ <sp> arguments ]" },
|
|---|
| 967 | { "SYST", SYST, ARGS, 1, "(get type of operating system)" },
|
|---|
| 968 | { "STAT", sTAT, OSTR, 1, "[ <sp> path-name ]" },
|
|---|
| 969 | { "HELP", HELP, OSTR, 1, "[ <sp> <string> ]" },
|
|---|
| 970 | { "NOOP", NOOP, ARGS, 1, "" },
|
|---|
| 971 | { "MKD", MKD, STR1, 1, "<sp> path-name" },
|
|---|
| 972 | { "XMKD", MKD, STR1, 1, "<sp> path-name" },
|
|---|
| 973 | { "RMD", RMD, STR1, 1, "<sp> path-name" },
|
|---|
| 974 | { "XRMD", RMD, STR1, 1, "<sp> path-name" },
|
|---|
| 975 | { "PWD", PWD, ARGS, 1, "(return current directory)" },
|
|---|
| 976 | { "XPWD", PWD, ARGS, 1, "(return current directory)" },
|
|---|
| 977 | { "CDUP", CDUP, ARGS, 1, "(change to parent directory)" },
|
|---|
| 978 | { "XCUP", CDUP, ARGS, 1, "(change to parent directory)" },
|
|---|
| 979 | { "STOU", STOU, STR1, 1, "<sp> file-name" },
|
|---|
| 980 | { "SIZE", SIZE, OSTR, 1, "<sp> path-name" },
|
|---|
| 981 | { "MDTM", MDTM, OSTR, 1, "<sp> path-name" },
|
|---|
| 982 |
|
|---|
| 983 | /* extensions from RFC2228 */
|
|---|
| 984 | { "AUTH", AUTH, STR1, 1, "<sp> auth-type" },
|
|---|
| 985 | { "ADAT", ADAT, STR1, 1, "<sp> auth-data" },
|
|---|
| 986 | { "PBSZ", PBSZ, ARGS, 1, "<sp> buffer-size" },
|
|---|
| 987 | { "PROT", PROT, STR1, 1, "<sp> prot-level" },
|
|---|
| 988 | { "CCC", CCC, ARGS, 1, "" },
|
|---|
| 989 | { "MIC", MIC, STR1, 1, "<sp> integrity command" },
|
|---|
| 990 | { "CONF", CONF, STR1, 1, "<sp> confidentiality command" },
|
|---|
| 991 | { "ENC", ENC, STR1, 1, "<sp> privacy command" },
|
|---|
| 992 |
|
|---|
| 993 | /* RFC2389 */
|
|---|
| 994 | { "FEAT", FEAT, ARGS, 1, "" },
|
|---|
| 995 | { "OPTS", OPTS, ARGS, 1, "<sp> command [<sp> options]" },
|
|---|
| 996 |
|
|---|
| 997 | { NULL, 0, 0, 0, 0 }
|
|---|
| 998 | };
|
|---|
| 999 |
|
|---|
| 1000 | struct tab sitetab[] = {
|
|---|
| 1001 | { "UMASK", UMASK, ARGS, 1, "[ <sp> umask ]" },
|
|---|
| 1002 | { "IDLE", IDLE, ARGS, 1, "[ <sp> maximum-idle-time ]" },
|
|---|
| 1003 | { "CHMOD", CHMOD, NSTR, 1, "<sp> mode <sp> file-name" },
|
|---|
| 1004 | { "HELP", HELP, OSTR, 1, "[ <sp> <string> ]" },
|
|---|
| 1005 |
|
|---|
| 1006 | { "KAUTH", KAUTH, STR1, 1, "<sp> principal [ <sp> ticket ]" },
|
|---|
| 1007 | { "KLIST", KLIST, ARGS, 1, "(show ticket file)" },
|
|---|
| 1008 | { "KDESTROY", KDESTROY, ARGS, 1, "(destroy tickets)" },
|
|---|
| 1009 | { "KRBTKFILE", KRBTKFILE, STR1, 1, "<sp> ticket-file" },
|
|---|
| 1010 | { "AFSLOG", AFSLOG, OSTR, 1, "[<sp> cell]" },
|
|---|
| 1011 |
|
|---|
| 1012 | { "LOCATE", LOCATE, STR1, 1, "<sp> globexpr" },
|
|---|
| 1013 | { "FIND", LOCATE, STR1, 1, "<sp> globexpr" },
|
|---|
| 1014 |
|
|---|
| 1015 | { "URL", URL, ARGS, 1, "?" },
|
|---|
| 1016 |
|
|---|
| 1017 | { NULL, 0, 0, 0, 0 }
|
|---|
| 1018 | };
|
|---|
| 1019 |
|
|---|
| 1020 | static struct tab *
|
|---|
| 1021 | lookup(struct tab *p, char *cmd)
|
|---|
| 1022 | {
|
|---|
| 1023 |
|
|---|
| 1024 | for (; p->name != NULL; p++)
|
|---|
| 1025 | if (strcmp(cmd, p->name) == 0)
|
|---|
| 1026 | return (p);
|
|---|
| 1027 | return (0);
|
|---|
| 1028 | }
|
|---|
| 1029 |
|
|---|
| 1030 | /*
|
|---|
| 1031 | * ftpd_getline - a hacked up version of fgets to ignore TELNET escape codes.
|
|---|
| 1032 | */
|
|---|
| 1033 | char *
|
|---|
| 1034 | ftpd_getline(char *s, int n)
|
|---|
| 1035 | {
|
|---|
| 1036 | int c;
|
|---|
| 1037 | char *cs;
|
|---|
| 1038 |
|
|---|
| 1039 | cs = s;
|
|---|
| 1040 |
|
|---|
| 1041 | /* might still be data within the security MIC/CONF/ENC */
|
|---|
| 1042 | if(ftp_command){
|
|---|
| 1043 | strlcpy(s, ftp_command, n);
|
|---|
| 1044 | if (debug)
|
|---|
| 1045 | syslog(LOG_DEBUG, "command: %s", s);
|
|---|
| 1046 | return s;
|
|---|
| 1047 | }
|
|---|
| 1048 | while ((c = getc(stdin)) != EOF) {
|
|---|
| 1049 | c &= 0377;
|
|---|
| 1050 | if (c == IAC) {
|
|---|
| 1051 | if ((c = getc(stdin)) != EOF) {
|
|---|
| 1052 | c &= 0377;
|
|---|
| 1053 | switch (c) {
|
|---|
| 1054 | case WILL:
|
|---|
| 1055 | case WONT:
|
|---|
| 1056 | c = getc(stdin);
|
|---|
| 1057 | printf("%c%c%c", IAC, DONT, 0377&c);
|
|---|
| 1058 | fflush(stdout);
|
|---|
| 1059 | continue;
|
|---|
| 1060 | case DO:
|
|---|
| 1061 | case DONT:
|
|---|
| 1062 | c = getc(stdin);
|
|---|
| 1063 | printf("%c%c%c", IAC, WONT, 0377&c);
|
|---|
| 1064 | fflush(stdout);
|
|---|
| 1065 | continue;
|
|---|
| 1066 | case IAC:
|
|---|
| 1067 | break;
|
|---|
| 1068 | default:
|
|---|
| 1069 | continue; /* ignore command */
|
|---|
| 1070 | }
|
|---|
| 1071 | }
|
|---|
| 1072 | }
|
|---|
| 1073 | *cs++ = c;
|
|---|
| 1074 | if (--n <= 0 || c == '\n')
|
|---|
| 1075 | break;
|
|---|
| 1076 | }
|
|---|
| 1077 | if (c == EOF && cs == s)
|
|---|
| 1078 | return (NULL);
|
|---|
| 1079 | *cs++ = '\0';
|
|---|
| 1080 | if (debug) {
|
|---|
| 1081 | if (!guest && strncasecmp("pass ", s, 5) == 0) {
|
|---|
| 1082 | /* Don't syslog passwords */
|
|---|
| 1083 | syslog(LOG_DEBUG, "command: %.5s ???", s);
|
|---|
| 1084 | } else {
|
|---|
| 1085 | char *cp;
|
|---|
| 1086 | int len;
|
|---|
| 1087 |
|
|---|
| 1088 | /* Don't syslog trailing CR-LF */
|
|---|
| 1089 | len = strlen(s);
|
|---|
| 1090 | cp = s + len - 1;
|
|---|
| 1091 | while (cp >= s && (*cp == '\n' || *cp == '\r')) {
|
|---|
| 1092 | --cp;
|
|---|
| 1093 | --len;
|
|---|
| 1094 | }
|
|---|
| 1095 | syslog(LOG_DEBUG, "command: %.*s", len, s);
|
|---|
| 1096 | }
|
|---|
| 1097 | }
|
|---|
| 1098 | #ifdef XXX
|
|---|
| 1099 | fprintf(stderr, "%s\n", s);
|
|---|
| 1100 | #endif
|
|---|
| 1101 | return (s);
|
|---|
| 1102 | }
|
|---|
| 1103 |
|
|---|
| 1104 | static RETSIGTYPE
|
|---|
| 1105 | toolong(int signo)
|
|---|
| 1106 | {
|
|---|
| 1107 |
|
|---|
| 1108 | reply(421,
|
|---|
| 1109 | "Timeout (%d seconds): closing control connection.",
|
|---|
| 1110 | ftpd_timeout);
|
|---|
| 1111 | if (logging)
|
|---|
| 1112 | syslog(LOG_INFO, "User %s timed out after %d seconds",
|
|---|
| 1113 | (pw ? pw -> pw_name : "unknown"), ftpd_timeout);
|
|---|
| 1114 | dologout(1);
|
|---|
| 1115 | SIGRETURN(0);
|
|---|
| 1116 | }
|
|---|
| 1117 |
|
|---|
| 1118 | static int
|
|---|
| 1119 | yylex(void)
|
|---|
| 1120 | {
|
|---|
| 1121 | static int cpos, state;
|
|---|
| 1122 | char *cp, *cp2;
|
|---|
| 1123 | struct tab *p;
|
|---|
| 1124 | int n;
|
|---|
| 1125 | char c;
|
|---|
| 1126 |
|
|---|
| 1127 | for (;;) {
|
|---|
| 1128 | switch (state) {
|
|---|
| 1129 |
|
|---|
| 1130 | case CMD:
|
|---|
| 1131 | hasyyerrored = 0;
|
|---|
| 1132 |
|
|---|
| 1133 | signal(SIGALRM, toolong);
|
|---|
| 1134 | alarm((unsigned) ftpd_timeout);
|
|---|
| 1135 | if (ftpd_getline(cbuf, sizeof(cbuf)-1) == NULL) {
|
|---|
| 1136 | reply(221, "You could at least say goodbye.");
|
|---|
| 1137 | dologout(0);
|
|---|
| 1138 | }
|
|---|
| 1139 | alarm(0);
|
|---|
| 1140 | #ifdef HAVE_SETPROCTITLE
|
|---|
| 1141 | if (strncasecmp(cbuf, "PASS", 4) != 0)
|
|---|
| 1142 | setproctitle("%s: %s", proctitle, cbuf);
|
|---|
| 1143 | #endif /* HAVE_SETPROCTITLE */
|
|---|
| 1144 | if ((cp = strchr(cbuf, '\r'))) {
|
|---|
| 1145 | *cp++ = '\n';
|
|---|
| 1146 | *cp = '\0';
|
|---|
| 1147 | }
|
|---|
| 1148 | if ((cp = strpbrk(cbuf, " \n")))
|
|---|
| 1149 | cpos = cp - cbuf;
|
|---|
| 1150 | if (cpos == 0)
|
|---|
| 1151 | cpos = 4;
|
|---|
| 1152 | c = cbuf[cpos];
|
|---|
| 1153 | cbuf[cpos] = '\0';
|
|---|
| 1154 | strupr(cbuf);
|
|---|
| 1155 | p = lookup(cmdtab, cbuf);
|
|---|
| 1156 | cbuf[cpos] = c;
|
|---|
| 1157 | if (p != 0) {
|
|---|
| 1158 | if (p->implemented == 0) {
|
|---|
| 1159 | nack(p->name);
|
|---|
| 1160 | hasyyerrored = 1;
|
|---|
| 1161 | break;
|
|---|
| 1162 | }
|
|---|
| 1163 | state = p->state;
|
|---|
| 1164 | yylval.s = p->name;
|
|---|
| 1165 | return (p->token);
|
|---|
| 1166 | }
|
|---|
| 1167 | break;
|
|---|
| 1168 |
|
|---|
| 1169 | case SITECMD:
|
|---|
| 1170 | if (cbuf[cpos] == ' ') {
|
|---|
| 1171 | cpos++;
|
|---|
| 1172 | return (SP);
|
|---|
| 1173 | }
|
|---|
| 1174 | cp = &cbuf[cpos];
|
|---|
| 1175 | if ((cp2 = strpbrk(cp, " \n")))
|
|---|
| 1176 | cpos = cp2 - cbuf;
|
|---|
| 1177 | c = cbuf[cpos];
|
|---|
| 1178 | cbuf[cpos] = '\0';
|
|---|
| 1179 | strupr(cp);
|
|---|
| 1180 | p = lookup(sitetab, cp);
|
|---|
| 1181 | cbuf[cpos] = c;
|
|---|
| 1182 | if (p != 0) {
|
|---|
| 1183 | if (p->implemented == 0) {
|
|---|
| 1184 | state = CMD;
|
|---|
| 1185 | nack(p->name);
|
|---|
| 1186 | hasyyerrored = 1;
|
|---|
| 1187 | break;
|
|---|
| 1188 | }
|
|---|
| 1189 | state = p->state;
|
|---|
| 1190 | yylval.s = p->name;
|
|---|
| 1191 | return (p->token);
|
|---|
| 1192 | }
|
|---|
| 1193 | state = CMD;
|
|---|
| 1194 | break;
|
|---|
| 1195 |
|
|---|
| 1196 | case OSTR:
|
|---|
| 1197 | if (cbuf[cpos] == '\n') {
|
|---|
| 1198 | state = CMD;
|
|---|
| 1199 | return (CRLF);
|
|---|
| 1200 | }
|
|---|
| 1201 | /* FALLTHROUGH */
|
|---|
| 1202 |
|
|---|
| 1203 | case STR1:
|
|---|
| 1204 | case ZSTR1:
|
|---|
| 1205 | dostr1:
|
|---|
| 1206 | if (cbuf[cpos] == ' ') {
|
|---|
| 1207 | cpos++;
|
|---|
| 1208 | if(state == OSTR)
|
|---|
| 1209 | state = STR2;
|
|---|
| 1210 | else
|
|---|
| 1211 | state++;
|
|---|
| 1212 | return (SP);
|
|---|
| 1213 | }
|
|---|
| 1214 | break;
|
|---|
| 1215 |
|
|---|
| 1216 | case ZSTR2:
|
|---|
| 1217 | if (cbuf[cpos] == '\n') {
|
|---|
| 1218 | state = CMD;
|
|---|
| 1219 | return (CRLF);
|
|---|
| 1220 | }
|
|---|
| 1221 | /* FALLTHROUGH */
|
|---|
| 1222 |
|
|---|
| 1223 | case STR2:
|
|---|
| 1224 | cp = &cbuf[cpos];
|
|---|
| 1225 | n = strlen(cp);
|
|---|
| 1226 | cpos += n - 1;
|
|---|
| 1227 | /*
|
|---|
| 1228 | * Make sure the string is nonempty and \n terminated.
|
|---|
| 1229 | */
|
|---|
| 1230 | if (n > 1 && cbuf[cpos] == '\n') {
|
|---|
| 1231 | cbuf[cpos] = '\0';
|
|---|
| 1232 | yylval.s = copy(cp);
|
|---|
| 1233 | cbuf[cpos] = '\n';
|
|---|
| 1234 | state = ARGS;
|
|---|
| 1235 | return (STRING);
|
|---|
| 1236 | }
|
|---|
| 1237 | break;
|
|---|
| 1238 |
|
|---|
| 1239 | case NSTR:
|
|---|
| 1240 | if (cbuf[cpos] == ' ') {
|
|---|
| 1241 | cpos++;
|
|---|
| 1242 | return (SP);
|
|---|
| 1243 | }
|
|---|
| 1244 | if (isdigit((unsigned char)cbuf[cpos])) {
|
|---|
| 1245 | cp = &cbuf[cpos];
|
|---|
| 1246 | while (isdigit((unsigned char)cbuf[++cpos]))
|
|---|
| 1247 | ;
|
|---|
| 1248 | c = cbuf[cpos];
|
|---|
| 1249 | cbuf[cpos] = '\0';
|
|---|
| 1250 | yylval.i = atoi(cp);
|
|---|
| 1251 | cbuf[cpos] = c;
|
|---|
| 1252 | state = STR1;
|
|---|
| 1253 | return (NUMBER);
|
|---|
| 1254 | }
|
|---|
| 1255 | state = STR1;
|
|---|
| 1256 | goto dostr1;
|
|---|
| 1257 |
|
|---|
| 1258 | case ARGS:
|
|---|
| 1259 | if (isdigit((unsigned char)cbuf[cpos])) {
|
|---|
| 1260 | cp = &cbuf[cpos];
|
|---|
| 1261 | while (isdigit((unsigned char)cbuf[++cpos]))
|
|---|
| 1262 | ;
|
|---|
| 1263 | c = cbuf[cpos];
|
|---|
| 1264 | cbuf[cpos] = '\0';
|
|---|
| 1265 | yylval.i = atoi(cp);
|
|---|
| 1266 | cbuf[cpos] = c;
|
|---|
| 1267 | return (NUMBER);
|
|---|
| 1268 | }
|
|---|
| 1269 | switch (cbuf[cpos++]) {
|
|---|
| 1270 |
|
|---|
| 1271 | case '\n':
|
|---|
| 1272 | state = CMD;
|
|---|
| 1273 | return (CRLF);
|
|---|
| 1274 |
|
|---|
| 1275 | case ' ':
|
|---|
| 1276 | return (SP);
|
|---|
| 1277 |
|
|---|
| 1278 | case ',':
|
|---|
| 1279 | return (COMMA);
|
|---|
| 1280 |
|
|---|
| 1281 | case 'A':
|
|---|
| 1282 | case 'a':
|
|---|
| 1283 | return (A);
|
|---|
| 1284 |
|
|---|
| 1285 | case 'B':
|
|---|
| 1286 | case 'b':
|
|---|
| 1287 | return (B);
|
|---|
| 1288 |
|
|---|
| 1289 | case 'C':
|
|---|
| 1290 | case 'c':
|
|---|
| 1291 | return (C);
|
|---|
| 1292 |
|
|---|
| 1293 | case 'E':
|
|---|
| 1294 | case 'e':
|
|---|
| 1295 | return (E);
|
|---|
| 1296 |
|
|---|
| 1297 | case 'F':
|
|---|
| 1298 | case 'f':
|
|---|
| 1299 | return (F);
|
|---|
| 1300 |
|
|---|
| 1301 | case 'I':
|
|---|
| 1302 | case 'i':
|
|---|
| 1303 | return (I);
|
|---|
| 1304 |
|
|---|
| 1305 | case 'L':
|
|---|
| 1306 | case 'l':
|
|---|
| 1307 | return (L);
|
|---|
| 1308 |
|
|---|
| 1309 | case 'N':
|
|---|
| 1310 | case 'n':
|
|---|
| 1311 | return (N);
|
|---|
| 1312 |
|
|---|
| 1313 | case 'P':
|
|---|
| 1314 | case 'p':
|
|---|
| 1315 | return (P);
|
|---|
| 1316 |
|
|---|
| 1317 | case 'R':
|
|---|
| 1318 | case 'r':
|
|---|
| 1319 | return (R);
|
|---|
| 1320 |
|
|---|
| 1321 | case 'S':
|
|---|
| 1322 | case 's':
|
|---|
| 1323 | return (S);
|
|---|
| 1324 |
|
|---|
| 1325 | case 'T':
|
|---|
| 1326 | case 't':
|
|---|
| 1327 | return (T);
|
|---|
| 1328 |
|
|---|
| 1329 | }
|
|---|
| 1330 | break;
|
|---|
| 1331 |
|
|---|
| 1332 | default:
|
|---|
| 1333 | fatal("Unknown state in scanner.");
|
|---|
| 1334 | }
|
|---|
| 1335 | yyerror(NULL);
|
|---|
| 1336 | state = CMD;
|
|---|
| 1337 | return (0);
|
|---|
| 1338 | }
|
|---|
| 1339 | }
|
|---|
| 1340 |
|
|---|
| 1341 | /* ARGSUSED */
|
|---|
| 1342 | void
|
|---|
| 1343 | yyerror(char *s)
|
|---|
| 1344 | {
|
|---|
| 1345 | char *cp;
|
|---|
| 1346 |
|
|---|
| 1347 | if (hasyyerrored)
|
|---|
| 1348 | return;
|
|---|
| 1349 |
|
|---|
| 1350 | if ((cp = strchr(cbuf,'\n')))
|
|---|
| 1351 | *cp = '\0';
|
|---|
| 1352 | reply(500, "'%s': command not understood.", cbuf);
|
|---|
| 1353 | hasyyerrored = 1;
|
|---|
| 1354 | }
|
|---|
| 1355 |
|
|---|
| 1356 | static char *
|
|---|
| 1357 | copy(char *s)
|
|---|
| 1358 | {
|
|---|
| 1359 | char *p;
|
|---|
| 1360 |
|
|---|
| 1361 | p = strdup(s);
|
|---|
| 1362 | if (p == NULL)
|
|---|
| 1363 | fatal("Ran out of memory.");
|
|---|
| 1364 | return p;
|
|---|
| 1365 | }
|
|---|
| 1366 |
|
|---|
| 1367 | static void
|
|---|
| 1368 | help(struct tab *ctab, char *s)
|
|---|
| 1369 | {
|
|---|
| 1370 | struct tab *c;
|
|---|
| 1371 | int width, NCMDS;
|
|---|
| 1372 | char *t;
|
|---|
| 1373 | char buf[1024];
|
|---|
| 1374 |
|
|---|
| 1375 | if (ctab == sitetab)
|
|---|
| 1376 | t = "SITE ";
|
|---|
| 1377 | else
|
|---|
| 1378 | t = "";
|
|---|
| 1379 | width = 0, NCMDS = 0;
|
|---|
| 1380 | for (c = ctab; c->name != NULL; c++) {
|
|---|
| 1381 | int len = strlen(c->name);
|
|---|
| 1382 |
|
|---|
| 1383 | if (len > width)
|
|---|
| 1384 | width = len;
|
|---|
| 1385 | NCMDS++;
|
|---|
| 1386 | }
|
|---|
| 1387 | width = (width + 8) &~ 7;
|
|---|
| 1388 | if (s == 0) {
|
|---|
| 1389 | int i, j, w;
|
|---|
| 1390 | int columns, lines;
|
|---|
| 1391 |
|
|---|
| 1392 | lreply(214, "The following %scommands are recognized %s.",
|
|---|
| 1393 | t, "(* =>'s unimplemented)");
|
|---|
| 1394 | columns = 76 / width;
|
|---|
| 1395 | if (columns == 0)
|
|---|
| 1396 | columns = 1;
|
|---|
| 1397 | lines = (NCMDS + columns - 1) / columns;
|
|---|
| 1398 | for (i = 0; i < lines; i++) {
|
|---|
| 1399 | strlcpy (buf, " ", sizeof(buf));
|
|---|
| 1400 | for (j = 0; j < columns; j++) {
|
|---|
| 1401 | c = ctab + j * lines + i;
|
|---|
| 1402 | snprintf (buf + strlen(buf),
|
|---|
| 1403 | sizeof(buf) - strlen(buf),
|
|---|
| 1404 | "%s%c",
|
|---|
| 1405 | c->name,
|
|---|
| 1406 | c->implemented ? ' ' : '*');
|
|---|
| 1407 | if (c + lines >= &ctab[NCMDS])
|
|---|
| 1408 | break;
|
|---|
| 1409 | w = strlen(c->name) + 1;
|
|---|
| 1410 | while (w < width) {
|
|---|
| 1411 | strlcat (buf,
|
|---|
| 1412 | " ",
|
|---|
| 1413 | sizeof(buf));
|
|---|
| 1414 | w++;
|
|---|
| 1415 | }
|
|---|
| 1416 | }
|
|---|
| 1417 | lreply(214, "%s", buf);
|
|---|
| 1418 | }
|
|---|
| 1419 | reply(214, "Direct comments to kth-krb-bugs@pdc.kth.se");
|
|---|
| 1420 | return;
|
|---|
| 1421 | }
|
|---|
| 1422 | strupr(s);
|
|---|
| 1423 | c = lookup(ctab, s);
|
|---|
| 1424 | if (c == (struct tab *)0) {
|
|---|
| 1425 | reply(502, "Unknown command %s.", s);
|
|---|
| 1426 | return;
|
|---|
| 1427 | }
|
|---|
| 1428 | if (c->implemented)
|
|---|
| 1429 | reply(214, "Syntax: %s%s %s", t, c->name, c->help);
|
|---|
| 1430 | else
|
|---|
| 1431 | reply(214, "%s%-*s\t%s; unimplemented.", t, width,
|
|---|
| 1432 | c->name, c->help);
|
|---|
| 1433 | }
|
|---|
| 1434 |
|
|---|
| 1435 | static void
|
|---|
| 1436 | sizecmd(char *filename)
|
|---|
| 1437 | {
|
|---|
| 1438 | switch (type) {
|
|---|
| 1439 | case TYPE_L:
|
|---|
| 1440 | case TYPE_I: {
|
|---|
| 1441 | struct stat stbuf;
|
|---|
| 1442 | if (stat(filename, &stbuf) < 0 || !S_ISREG(stbuf.st_mode))
|
|---|
| 1443 | reply(550, "%s: not a plain file.", filename);
|
|---|
| 1444 | else
|
|---|
| 1445 | reply(213, "%lu", (unsigned long)stbuf.st_size);
|
|---|
| 1446 | break;
|
|---|
| 1447 | }
|
|---|
| 1448 | case TYPE_A: {
|
|---|
| 1449 | FILE *fin;
|
|---|
| 1450 | int c;
|
|---|
| 1451 | size_t count;
|
|---|
| 1452 | struct stat stbuf;
|
|---|
| 1453 | fin = fopen(filename, "r");
|
|---|
| 1454 | if (fin == NULL) {
|
|---|
| 1455 | perror_reply(550, filename);
|
|---|
| 1456 | return;
|
|---|
| 1457 | }
|
|---|
| 1458 | if (fstat(fileno(fin), &stbuf) < 0 || !S_ISREG(stbuf.st_mode)) {
|
|---|
| 1459 | reply(550, "%s: not a plain file.", filename);
|
|---|
| 1460 | fclose(fin);
|
|---|
| 1461 | return;
|
|---|
| 1462 | }
|
|---|
| 1463 |
|
|---|
| 1464 | count = 0;
|
|---|
| 1465 | while((c=getc(fin)) != EOF) {
|
|---|
| 1466 | if (c == '\n') /* will get expanded to \r\n */
|
|---|
| 1467 | count++;
|
|---|
| 1468 | count++;
|
|---|
| 1469 | }
|
|---|
| 1470 | fclose(fin);
|
|---|
| 1471 |
|
|---|
| 1472 | reply(213, "%lu", (unsigned long)count);
|
|---|
| 1473 | break;
|
|---|
| 1474 | }
|
|---|
| 1475 | default:
|
|---|
| 1476 | reply(504, "SIZE not implemented for Type %c.", "?AEIL"[type]);
|
|---|
| 1477 | }
|
|---|
| 1478 | }
|
|---|