ftpcmd.y revision 1.93 1 1.93 plunky /* $NetBSD: ftpcmd.y,v 1.93 2011/09/16 16:13:17 plunky 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.93 plunky __RCSID("$NetBSD: ftpcmd.y,v 1.93 2011/09/16 16:13:17 plunky 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.42 lukem 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.47 lukem mlst(NULL);
859 1.47 lukem }
860 1.47 lukem
861 1.47 lukem | MLSD check_login SP pathname CRLF
862 1.47 lukem {
863 1.47 lukem if ($2 && $4 != NULL)
864 1.47 lukem mlsd($4);
865 1.47 lukem if ($4 != NULL)
866 1.47 lukem free($4);
867 1.47 lukem }
868 1.47 lukem
869 1.48 lukem | MLSD check_login CRLF
870 1.47 lukem {
871 1.47 lukem mlsd(NULL);
872 1.47 lukem }
873 1.47 lukem
874 1.4 deraadt | error CRLF
875 1.4 deraadt {
876 1.1 cgd yyerrok;
877 1.1 cgd }
878 1.1 cgd ;
879 1.21 lukem
880 1.4 deraadt rcmd
881 1.70 lukem : REST check_login SP NUMBER CRLF
882 1.23 lukem {
883 1.42 lukem if ($2) {
884 1.78 lukem REASSIGN(fromname, NULL);
885 1.74 lukem restart_point = (off_t)$4.ll;
886 1.55 lukem reply(350,
887 1.55 lukem "Restarting at " LLF ". Send STORE or RETRIEVE to initiate transfer.",
888 1.55 lukem (LLT)restart_point);
889 1.42 lukem }
890 1.23 lukem }
891 1.42 lukem
892 1.56 lukem | RNFR SP pathname CRLF
893 1.4 deraadt {
894 1.1 cgd restart_point = (off_t) 0;
895 1.78 lukem if (check_write($3, 0)) {
896 1.78 lukem REASSIGN(fromname, NULL);
897 1.56 lukem fromname = renamefrom($3);
898 1.78 lukem }
899 1.56 lukem if ($3 != NULL)
900 1.56 lukem free($3);
901 1.1 cgd }
902 1.1 cgd ;
903 1.4 deraadt
904 1.4 deraadt username
905 1.4 deraadt : STRING
906 1.1 cgd ;
907 1.1 cgd
908 1.4 deraadt password
909 1.4 deraadt : /* empty */
910 1.4 deraadt {
911 1.4 deraadt $$ = (char *)calloc(1, sizeof(char));
912 1.1 cgd }
913 1.23 lukem
914 1.4 deraadt | STRING
915 1.1 cgd ;
916 1.1 cgd
917 1.4 deraadt byte_size
918 1.4 deraadt : NUMBER
919 1.70 lukem {
920 1.70 lukem $$ = $1.i;
921 1.70 lukem }
922 1.1 cgd ;
923 1.1 cgd
924 1.4 deraadt host_port
925 1.4 deraadt : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
926 1.1 cgd NUMBER COMMA NUMBER
927 1.4 deraadt {
928 1.4 deraadt char *a, *p;
929 1.1 cgd
930 1.55 lukem memset(&data_dest, 0, sizeof(data_dest));
931 1.32 itojun data_dest.su_len = sizeof(struct sockaddr_in);
932 1.32 itojun data_dest.su_family = AF_INET;
933 1.55 lukem p = (char *)&data_dest.su_port;
934 1.70 lukem p[0] = $9.i; p[1] = $11.i;
935 1.55 lukem a = (char *)&data_dest.su_addr;
936 1.70 lukem a[0] = $1.i; a[1] = $3.i; a[2] = $5.i; a[3] = $7.i;
937 1.1 cgd }
938 1.1 cgd ;
939 1.1 cgd
940 1.34 itojun host_long_port4
941 1.34 itojun : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
942 1.34 itojun NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
943 1.34 itojun NUMBER
944 1.34 itojun {
945 1.34 itojun char *a, *p;
946 1.34 itojun
947 1.55 lukem memset(&data_dest, 0, sizeof(data_dest));
948 1.55 lukem data_dest.su_len = sizeof(struct sockaddr_in);
949 1.34 itojun data_dest.su_family = AF_INET;
950 1.34 itojun p = (char *)&data_dest.su_port;
951 1.70 lukem p[0] = $15.i; p[1] = $17.i;
952 1.55 lukem a = (char *)&data_dest.su_addr;
953 1.70 lukem a[0] = $5.i; a[1] = $7.i; a[2] = $9.i; a[3] = $11.i;
954 1.35 itojun
955 1.35 itojun /* reject invalid LPRT command */
956 1.70 lukem if ($1.i != 4 || $3.i != 4 || $13.i != 2)
957 1.35 itojun memset(&data_dest, 0, sizeof(data_dest));
958 1.34 itojun }
959 1.34 itojun ;
960 1.34 itojun
961 1.34 itojun host_long_port6
962 1.32 itojun : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
963 1.32 itojun NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
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
968 1.32 itojun {
969 1.53 christos #ifdef INET6
970 1.91 christos unsigned char buf[16];
971 1.32 itojun
972 1.91 christos (void)memset(&data_dest, 0, sizeof(data_dest));
973 1.55 lukem data_dest.su_len = sizeof(struct sockaddr_in6);
974 1.32 itojun data_dest.su_family = AF_INET6;
975 1.91 christos buf[0] = $39.i; buf[1] = $41.i;
976 1.91 christos (void)memcpy(&data_dest.su_port, buf,
977 1.92 joerg sizeof(data_dest.su_port));
978 1.91 christos buf[0] = $5.i; buf[1] = $7.i;
979 1.91 christos buf[2] = $9.i; buf[3] = $11.i;
980 1.91 christos buf[4] = $13.i; buf[5] = $15.i;
981 1.91 christos buf[6] = $17.i; buf[7] = $19.i;
982 1.91 christos buf[8] = $21.i; buf[9] = $23.i;
983 1.91 christos buf[10] = $25.i; buf[11] = $27.i;
984 1.91 christos buf[12] = $29.i; buf[13] = $31.i;
985 1.91 christos buf[14] = $33.i; buf[15] = $35.i;
986 1.91 christos (void)memcpy(&data_dest.si_su.su_sin6.sin6_addr,
987 1.91 christos buf, sizeof(data_dest.si_su.su_sin6.sin6_addr));
988 1.37 itojun if (his_addr.su_family == AF_INET6) {
989 1.59 lukem /* XXX: more sanity checks! */
990 1.55 lukem data_dest.su_scope_id = his_addr.su_scope_id;
991 1.37 itojun }
992 1.53 christos #else
993 1.53 christos memset(&data_dest, 0, sizeof(data_dest));
994 1.55 lukem #endif /* INET6 */
995 1.35 itojun /* reject invalid LPRT command */
996 1.75 lukem if ($1.i != 6 || $3.i != 16 || $37.i != 2)
997 1.35 itojun memset(&data_dest, 0, sizeof(data_dest));
998 1.32 itojun }
999 1.32 itojun ;
1000 1.32 itojun
1001 1.4 deraadt form_code
1002 1.4 deraadt : N
1003 1.4 deraadt {
1004 1.4 deraadt $$ = FORM_N;
1005 1.4 deraadt }
1006 1.23 lukem
1007 1.4 deraadt | T
1008 1.4 deraadt {
1009 1.4 deraadt $$ = FORM_T;
1010 1.4 deraadt }
1011 1.23 lukem
1012 1.4 deraadt | C
1013 1.4 deraadt {
1014 1.4 deraadt $$ = FORM_C;
1015 1.4 deraadt }
1016 1.1 cgd ;
1017 1.1 cgd
1018 1.4 deraadt type_code
1019 1.4 deraadt : A
1020 1.4 deraadt {
1021 1.4 deraadt cmd_type = TYPE_A;
1022 1.4 deraadt cmd_form = FORM_N;
1023 1.4 deraadt }
1024 1.23 lukem
1025 1.4 deraadt | A SP form_code
1026 1.4 deraadt {
1027 1.4 deraadt cmd_type = TYPE_A;
1028 1.4 deraadt cmd_form = $3;
1029 1.4 deraadt }
1030 1.23 lukem
1031 1.4 deraadt | E
1032 1.4 deraadt {
1033 1.4 deraadt cmd_type = TYPE_E;
1034 1.4 deraadt cmd_form = FORM_N;
1035 1.4 deraadt }
1036 1.23 lukem
1037 1.4 deraadt | E SP form_code
1038 1.4 deraadt {
1039 1.4 deraadt cmd_type = TYPE_E;
1040 1.4 deraadt cmd_form = $3;
1041 1.4 deraadt }
1042 1.23 lukem
1043 1.4 deraadt | I
1044 1.4 deraadt {
1045 1.4 deraadt cmd_type = TYPE_I;
1046 1.4 deraadt }
1047 1.23 lukem
1048 1.4 deraadt | L
1049 1.4 deraadt {
1050 1.4 deraadt cmd_type = TYPE_L;
1051 1.4 deraadt cmd_bytesz = NBBY;
1052 1.4 deraadt }
1053 1.23 lukem
1054 1.4 deraadt | L SP byte_size
1055 1.4 deraadt {
1056 1.4 deraadt cmd_type = TYPE_L;
1057 1.4 deraadt cmd_bytesz = $3;
1058 1.4 deraadt }
1059 1.23 lukem
1060 1.4 deraadt /* this is for a bug in the BBN ftp */
1061 1.4 deraadt | L byte_size
1062 1.4 deraadt {
1063 1.4 deraadt cmd_type = TYPE_L;
1064 1.4 deraadt cmd_bytesz = $2;
1065 1.4 deraadt }
1066 1.1 cgd ;
1067 1.1 cgd
1068 1.4 deraadt struct_code
1069 1.4 deraadt : F
1070 1.4 deraadt {
1071 1.4 deraadt $$ = STRU_F;
1072 1.4 deraadt }
1073 1.23 lukem
1074 1.4 deraadt | R
1075 1.4 deraadt {
1076 1.4 deraadt $$ = STRU_R;
1077 1.4 deraadt }
1078 1.23 lukem
1079 1.4 deraadt | P
1080 1.4 deraadt {
1081 1.4 deraadt $$ = STRU_P;
1082 1.4 deraadt }
1083 1.1 cgd ;
1084 1.1 cgd
1085 1.4 deraadt mode_code
1086 1.4 deraadt : S
1087 1.4 deraadt {
1088 1.4 deraadt $$ = MODE_S;
1089 1.4 deraadt }
1090 1.23 lukem
1091 1.4 deraadt | B
1092 1.4 deraadt {
1093 1.4 deraadt $$ = MODE_B;
1094 1.4 deraadt }
1095 1.23 lukem
1096 1.4 deraadt | C
1097 1.4 deraadt {
1098 1.4 deraadt $$ = MODE_C;
1099 1.4 deraadt }
1100 1.1 cgd ;
1101 1.1 cgd
1102 1.4 deraadt pathname
1103 1.4 deraadt : pathstring
1104 1.4 deraadt {
1105 1.4 deraadt /*
1106 1.4 deraadt * Problem: this production is used for all pathname
1107 1.4 deraadt * processing, but only gives a 550 error reply.
1108 1.9 lukem * This is a valid reply in some cases but not in
1109 1.9 lukem * others.
1110 1.4 deraadt */
1111 1.4 deraadt if (logged_in && $1 && *$1 == '~') {
1112 1.64 lukem char *path, *home, *result;
1113 1.64 lukem size_t len;
1114 1.4 deraadt
1115 1.64 lukem path = strchr($1 + 1, '/');
1116 1.64 lukem if (path != NULL)
1117 1.64 lukem *path++ = '\0';
1118 1.9 lukem if ($1[1] == '\0')
1119 1.64 lukem home = homedir;
1120 1.9 lukem else {
1121 1.66 lukem struct passwd *hpw;
1122 1.64 lukem
1123 1.66 lukem if ((hpw = getpwnam($1 + 1)) != NULL)
1124 1.66 lukem home = hpw->pw_dir;
1125 1.64 lukem else
1126 1.64 lukem home = $1;
1127 1.64 lukem }
1128 1.64 lukem len = strlen(home) + 1;
1129 1.64 lukem if (path != NULL)
1130 1.64 lukem len += strlen(path) + 1;
1131 1.64 lukem if ((result = malloc(len)) == NULL)
1132 1.64 lukem fatal("Local resource failure: malloc");
1133 1.64 lukem strlcpy(result, home, len);
1134 1.64 lukem if (path != NULL) {
1135 1.64 lukem strlcat(result, "/", len);
1136 1.64 lukem strlcat(result, path, len);
1137 1.4 deraadt }
1138 1.64 lukem $$ = result;
1139 1.4 deraadt free($1);
1140 1.4 deraadt } else
1141 1.4 deraadt $$ = $1;
1142 1.4 deraadt }
1143 1.1 cgd ;
1144 1.1 cgd
1145 1.4 deraadt pathstring
1146 1.4 deraadt : STRING
1147 1.1 cgd ;
1148 1.1 cgd
1149 1.4 deraadt octal_number
1150 1.4 deraadt : NUMBER
1151 1.4 deraadt {
1152 1.4 deraadt int ret, dec, multby, digit;
1153 1.1 cgd
1154 1.4 deraadt /*
1155 1.4 deraadt * Convert a number that was read as decimal number
1156 1.4 deraadt * to what it would be if it had been read as octal.
1157 1.4 deraadt */
1158 1.70 lukem dec = $1.i;
1159 1.4 deraadt multby = 1;
1160 1.4 deraadt ret = 0;
1161 1.4 deraadt while (dec) {
1162 1.4 deraadt digit = dec%10;
1163 1.4 deraadt if (digit > 7) {
1164 1.4 deraadt ret = -1;
1165 1.4 deraadt break;
1166 1.4 deraadt }
1167 1.4 deraadt ret += digit * multby;
1168 1.4 deraadt multby *= 8;
1169 1.4 deraadt dec /= 10;
1170 1.1 cgd }
1171 1.4 deraadt $$ = ret;
1172 1.1 cgd }
1173 1.1 cgd ;
1174 1.1 cgd
1175 1.25 lukem mechanism_name
1176 1.25 lukem : STRING
1177 1.25 lukem ;
1178 1.25 lukem
1179 1.25 lukem base64data
1180 1.25 lukem : STRING
1181 1.25 lukem ;
1182 1.25 lukem
1183 1.25 lukem prot_code
1184 1.25 lukem : STRING
1185 1.25 lukem ;
1186 1.25 lukem
1187 1.25 lukem decimal_integer
1188 1.25 lukem : NUMBER
1189 1.70 lukem {
1190 1.70 lukem $$ = $1.i;
1191 1.70 lukem }
1192 1.25 lukem ;
1193 1.25 lukem
1194 1.4 deraadt check_login
1195 1.4 deraadt : /* empty */
1196 1.4 deraadt {
1197 1.4 deraadt if (logged_in)
1198 1.4 deraadt $$ = 1;
1199 1.4 deraadt else {
1200 1.4 deraadt reply(530, "Please login with USER and PASS.");
1201 1.4 deraadt $$ = 0;
1202 1.22 lukem hasyyerrored = 1;
1203 1.4 deraadt }
1204 1.1 cgd }
1205 1.1 cgd ;
1206 1.21 lukem
1207 1.1 cgd %%
1208 1.1 cgd
1209 1.1 cgd #define CMD 0 /* beginning of command */
1210 1.1 cgd #define ARGS 1 /* expect miscellaneous arguments */
1211 1.1 cgd #define STR1 2 /* expect SP followed by STRING */
1212 1.1 cgd #define STR2 3 /* expect STRING */
1213 1.1 cgd #define OSTR 4 /* optional SP then STRING */
1214 1.1 cgd #define ZSTR1 5 /* SP then optional STRING */
1215 1.1 cgd #define ZSTR2 6 /* optional STRING after SP */
1216 1.1 cgd #define SITECMD 7 /* SITE command */
1217 1.1 cgd #define NSTR 8 /* Number followed by a string */
1218 1.21 lukem #define NOARGS 9 /* No arguments allowed */
1219 1.60 aidan #define EOLN 10 /* End of line */
1220 1.1 cgd
1221 1.21 lukem struct tab cmdtab[] = {
1222 1.21 lukem /* From RFC 959, in order defined (5.3.1) */
1223 1.89 lukem { "USER", USER, STR1, 1, "<sp> username", 0, },
1224 1.89 lukem { "PASS", PASS, ZSTR1, 1, "<sp> password", 0, },
1225 1.89 lukem { "ACCT", ACCT, STR1, 0, "(specify account)", 0, },
1226 1.89 lukem { "CWD", CWD, OSTR, 1, "[ <sp> directory-name ]", 0, },
1227 1.89 lukem { "CDUP", CDUP, NOARGS, 1, "(change to parent directory)", 0, },
1228 1.89 lukem { "SMNT", SMNT, ARGS, 0, "(structure mount)", 0, },
1229 1.89 lukem { "QUIT", QUIT, NOARGS, 1, "(terminate service)", 0, },
1230 1.89 lukem { "REIN", REIN, NOARGS, 0, "(reinitialize server state)", 0, },
1231 1.89 lukem { "PORT", PORT, ARGS, 1, "<sp> b0, b1, b2, b3, b4, b5", 0, },
1232 1.89 lukem { "LPRT", LPRT, ARGS, 1, "<sp> af, hal, h1, h2, h3,..., pal, p1, p2...", 0, },
1233 1.89 lukem { "EPRT", EPRT, STR1, 1, "<sp> |af|addr|port|", 0, },
1234 1.89 lukem { "PASV", PASV, NOARGS, 1, "(set server in passive mode)", 0, },
1235 1.89 lukem { "LPSV", LPSV, ARGS, 1, "(set server in passive mode)", 0, },
1236 1.89 lukem { "EPSV", EPSV, ARGS, 1, "[<sp> af|ALL]", 0, },
1237 1.89 lukem { "TYPE", TYPE, ARGS, 1, "<sp> [ A | E | I | L ]", 0, },
1238 1.89 lukem { "STRU", STRU, ARGS, 1, "(specify file structure)", 0, },
1239 1.89 lukem { "MODE", MODE, ARGS, 1, "(specify transfer mode)", 0, },
1240 1.89 lukem { "RETR", RETR, STR1, 1, "<sp> file-name", 0, },
1241 1.89 lukem { "STOR", STOR, STR1, 1, "<sp> file-name", 0, },
1242 1.89 lukem { "STOU", STOU, STR1, 1, "<sp> file-name", 0, },
1243 1.89 lukem { "APPE", APPE, STR1, 1, "<sp> file-name", 0, },
1244 1.89 lukem { "ALLO", ALLO, ARGS, 1, "allocate storage (vacuously)", 0, },
1245 1.89 lukem { "REST", REST, ARGS, 1, "<sp> offset (restart command)", 0, },
1246 1.89 lukem { "RNFR", RNFR, STR1, 1, "<sp> file-name", 0, },
1247 1.89 lukem { "RNTO", RNTO, STR1, 1, "<sp> file-name", 0, },
1248 1.89 lukem { "ABOR", ABOR, NOARGS, 4, "(abort operation)", 0, },
1249 1.89 lukem { "DELE", DELE, STR1, 1, "<sp> file-name", 0, },
1250 1.89 lukem { "RMD", RMD, STR1, 1, "<sp> path-name", 0, },
1251 1.89 lukem { "MKD", MKD, STR1, 1, "<sp> path-name", 0, },
1252 1.89 lukem { "PWD", PWD, NOARGS, 1, "(return current directory)", 0, },
1253 1.89 lukem { "LIST", LIST, OSTR, 1, "[ <sp> path-name ]", 0, },
1254 1.89 lukem { "NLST", NLST, OSTR, 1, "[ <sp> path-name ]", 0, },
1255 1.89 lukem { "SITE", SITE, SITECMD, 1, "site-cmd [ <sp> arguments ]", 0, },
1256 1.89 lukem { "SYST", SYST, NOARGS, 1, "(get type of operating system)", 0, },
1257 1.89 lukem { "STAT", STAT, OSTR, 4, "[ <sp> path-name ]", 0, },
1258 1.89 lukem { "HELP", HELP, OSTR, 1, "[ <sp> <string> ]", 0, },
1259 1.89 lukem { "NOOP", NOOP, NOARGS, 2, "", 0, },
1260 1.23 lukem
1261 1.25 lukem /* From RFC 2228, in order defined */
1262 1.89 lukem { "AUTH", AUTH, STR1, 1, "<sp> mechanism-name", 0, },
1263 1.89 lukem { "ADAT", ADAT, STR1, 1, "<sp> base-64-data", 0, },
1264 1.89 lukem { "PROT", PROT, STR1, 1, "<sp> prot-code", 0, },
1265 1.89 lukem { "PBSZ", PBSZ, ARGS, 1, "<sp> decimal-integer", 0, },
1266 1.89 lukem { "CCC", CCC, NOARGS, 1, "(Disable data protection)", 0, },
1267 1.89 lukem { "MIC", MIC, STR1, 4, "<sp> base64data", 0, },
1268 1.89 lukem { "CONF", CONF, STR1, 4, "<sp> base64data", 0, },
1269 1.89 lukem { "ENC", ENC, STR1, 4, "<sp> base64data", 0, },
1270 1.25 lukem
1271 1.25 lukem /* From RFC 2389, in order defined */
1272 1.89 lukem { "FEAT", FEAT, NOARGS, 1, "(display extended features)", 0, },
1273 1.89 lukem { "OPTS", OPTS, STR1, 1, "<sp> command [ <sp> options ]", 0, },
1274 1.23 lukem
1275 1.85 lukem /* From RFC 3659, in order defined */
1276 1.89 lukem { "MDTM", MDTM, OSTR, 1, "<sp> path-name", 0, },
1277 1.89 lukem { "SIZE", SIZE, OSTR, 1, "<sp> path-name", 0, },
1278 1.89 lukem { "MLST", MLST, OSTR, 2, "[ <sp> path-name ]", 0, },
1279 1.89 lukem { "MLSD", MLSD, OSTR, 1, "[ <sp> directory-name ]", 0, },
1280 1.21 lukem
1281 1.21 lukem /* obsolete commands */
1282 1.89 lukem { "MAIL", MAIL, OSTR, 0, "(mail to user)", 0, },
1283 1.89 lukem { "MLFL", MLFL, OSTR, 0, "(mail file)", 0, },
1284 1.89 lukem { "MRCP", MRCP, STR1, 0, "(mail recipient)", 0, },
1285 1.89 lukem { "MRSQ", MRSQ, OSTR, 0, "(mail recipient scheme question)", 0, },
1286 1.89 lukem { "MSAM", MSAM, OSTR, 0, "(mail send to terminal and mailbox)", 0, },
1287 1.89 lukem { "MSND", MSND, OSTR, 0, "(mail send to terminal)", 0, },
1288 1.89 lukem { "MSOM", MSOM, OSTR, 0, "(mail send to terminal or mailbox)", 0, },
1289 1.89 lukem { "XCUP", CDUP, NOARGS, 1, "(change to parent directory)", 0, },
1290 1.89 lukem { "XCWD", CWD, OSTR, 1, "[ <sp> directory-name ]", 0, },
1291 1.89 lukem { "XMKD", MKD, STR1, 1, "<sp> path-name", 0, },
1292 1.89 lukem { "XPWD", PWD, NOARGS, 1, "(return current directory)", 0, },
1293 1.89 lukem { "XRMD", RMD, STR1, 1, "<sp> path-name", 0, },
1294 1.21 lukem
1295 1.89 lukem { NULL, 0, 0, 0, 0, 0, }
1296 1.1 cgd };
1297 1.1 cgd
1298 1.1 cgd struct tab sitetab[] = {
1299 1.89 lukem { "CHMOD", CHMOD, NSTR, 1, "<sp> mode <sp> file-name", 0, },
1300 1.89 lukem { "HELP", HELP, OSTR, 1, "[ <sp> <string> ]", 0, },
1301 1.89 lukem { "IDLE", IDLE, ARGS, 1, "[ <sp> maximum-idle-time ]", 0, },
1302 1.89 lukem { "RATEGET", RATEGET,OSTR, 1, "[ <sp> get-throttle-rate ]", 0, },
1303 1.89 lukem { "RATEPUT", RATEPUT,OSTR, 1, "[ <sp> put-throttle-rate ]", 0, },
1304 1.89 lukem { "UMASK", UMASK, ARGS, 1, "[ <sp> umask ]", 0, },
1305 1.89 lukem { NULL, 0, 0, 0, 0, 0, }
1306 1.1 cgd };
1307 1.1 cgd
1308 1.56 lukem /*
1309 1.56 lukem * Check if a filename is allowed to be modified (isupload == 0) or
1310 1.56 lukem * uploaded (isupload == 1), and if necessary, check the filename is `sane'.
1311 1.67 lukem * If the filename is NULL, fail.
1312 1.67 lukem * If the filename is "", don't do the sane name check.
1313 1.56 lukem */
1314 1.56 lukem static int
1315 1.56 lukem check_write(const char *file, int isupload)
1316 1.56 lukem {
1317 1.56 lukem if (file == NULL)
1318 1.56 lukem return (0);
1319 1.56 lukem if (! logged_in) {
1320 1.56 lukem reply(530, "Please login with USER and PASS.");
1321 1.56 lukem return (0);
1322 1.56 lukem }
1323 1.56 lukem /* checking modify */
1324 1.56 lukem if (! isupload && ! CURCLASS_FLAGS_ISSET(modify)) {
1325 1.56 lukem reply(502, "No permission to use this command.");
1326 1.56 lukem return (0);
1327 1.56 lukem }
1328 1.56 lukem /* checking upload */
1329 1.56 lukem if (isupload && ! CURCLASS_FLAGS_ISSET(upload)) {
1330 1.56 lukem reply(502, "No permission to use this command.");
1331 1.56 lukem return (0);
1332 1.56 lukem }
1333 1.67 lukem
1334 1.56 lukem /* checking sanenames */
1335 1.67 lukem if (file[0] != '\0' && CURCLASS_FLAGS_ISSET(sanenames)) {
1336 1.56 lukem const char *p;
1337 1.56 lukem
1338 1.56 lukem if (file[0] == '.')
1339 1.56 lukem goto insane_name;
1340 1.56 lukem for (p = file; *p; p++) {
1341 1.81 dsl if (isalnum((unsigned char)*p) || *p == '-' || *p == '+' ||
1342 1.56 lukem *p == ',' || *p == '.' || *p == '_')
1343 1.56 lukem continue;
1344 1.56 lukem insane_name:
1345 1.56 lukem reply(553, "File name `%s' not allowed.", file);
1346 1.56 lukem return (0);
1347 1.56 lukem }
1348 1.56 lukem }
1349 1.56 lukem return (1);
1350 1.56 lukem }
1351 1.56 lukem
1352 1.47 lukem struct tab *
1353 1.46 lukem lookup(struct tab *p, const char *cmd)
1354 1.1 cgd {
1355 1.1 cgd
1356 1.1 cgd for (; p->name != NULL; p++)
1357 1.23 lukem if (strcasecmp(cmd, p->name) == 0)
1358 1.1 cgd return (p);
1359 1.1 cgd return (0);
1360 1.1 cgd }
1361 1.1 cgd
1362 1.1 cgd #include <arpa/telnet.h>
1363 1.1 cgd
1364 1.1 cgd /*
1365 1.90 roy * get_line - a hacked up version of fgets to ignore TELNET escape codes.
1366 1.88 lukem * `s' is the buffer to read into.
1367 1.88 lukem * `n' is the 1 less than the size of the buffer, to allow trailing NUL
1368 1.88 lukem * `iop' is the FILE to read from.
1369 1.88 lukem * Returns 0 on success, -1 on EOF, -2 if the command was too long.
1370 1.1 cgd */
1371 1.88 lukem int
1372 1.90 roy get_line(char *s, int n, FILE *iop)
1373 1.1 cgd {
1374 1.4 deraadt int c;
1375 1.21 lukem char *cs;
1376 1.1 cgd
1377 1.1 cgd cs = s;
1378 1.1 cgd /* tmpline may contain saved command from urgent mode interruption */
1379 1.1 cgd for (c = 0; tmpline[c] != '\0' && --n > 0; ++c) {
1380 1.1 cgd *cs++ = tmpline[c];
1381 1.1 cgd if (tmpline[c] == '\n') {
1382 1.1 cgd *cs++ = '\0';
1383 1.84 christos if (ftpd_debug)
1384 1.1 cgd syslog(LOG_DEBUG, "command: %s", s);
1385 1.1 cgd tmpline[0] = '\0';
1386 1.88 lukem return(0);
1387 1.1 cgd }
1388 1.1 cgd if (c == 0)
1389 1.1 cgd tmpline[0] = '\0';
1390 1.1 cgd }
1391 1.1 cgd while ((c = getc(iop)) != EOF) {
1392 1.27 lukem total_bytes++;
1393 1.27 lukem total_bytes_in++;
1394 1.1 cgd c &= 0377;
1395 1.1 cgd if (c == IAC) {
1396 1.1 cgd if ((c = getc(iop)) != EOF) {
1397 1.27 lukem total_bytes++;
1398 1.27 lukem total_bytes_in++;
1399 1.1 cgd c &= 0377;
1400 1.1 cgd switch (c) {
1401 1.1 cgd case WILL:
1402 1.1 cgd case WONT:
1403 1.1 cgd c = getc(iop);
1404 1.27 lukem total_bytes++;
1405 1.27 lukem total_bytes_in++;
1406 1.48 lukem cprintf(stdout, "%c%c%c", IAC, DONT, 0377&c);
1407 1.1 cgd (void) fflush(stdout);
1408 1.1 cgd continue;
1409 1.1 cgd case DO:
1410 1.1 cgd case DONT:
1411 1.1 cgd c = getc(iop);
1412 1.27 lukem total_bytes++;
1413 1.27 lukem total_bytes_in++;
1414 1.48 lukem cprintf(stdout, "%c%c%c", IAC, WONT, 0377&c);
1415 1.1 cgd (void) fflush(stdout);
1416 1.1 cgd continue;
1417 1.1 cgd case IAC:
1418 1.1 cgd break;
1419 1.1 cgd default:
1420 1.1 cgd continue; /* ignore command */
1421 1.1 cgd }
1422 1.1 cgd }
1423 1.1 cgd }
1424 1.1 cgd *cs++ = c;
1425 1.88 lukem if (--n <= 0) {
1426 1.88 lukem /*
1427 1.88 lukem * If command doesn't fit into buffer, discard the
1428 1.88 lukem * rest of the command and indicate truncation.
1429 1.88 lukem * This prevents the command to be split up into
1430 1.88 lukem * multiple commands.
1431 1.88 lukem */
1432 1.88 lukem if (ftpd_debug)
1433 1.88 lukem syslog(LOG_DEBUG,
1434 1.88 lukem "command too long, last char: %d", c);
1435 1.88 lukem while (c != '\n' && (c = getc(iop)) != EOF)
1436 1.88 lukem continue;
1437 1.88 lukem return (-2);
1438 1.88 lukem }
1439 1.88 lukem if (c == '\n')
1440 1.1 cgd break;
1441 1.1 cgd }
1442 1.1 cgd if (c == EOF && cs == s)
1443 1.88 lukem return (-1);
1444 1.1 cgd *cs++ = '\0';
1445 1.84 christos if (ftpd_debug) {
1446 1.58 lukem if ((curclass.type != CLASS_GUEST &&
1447 1.58 lukem strncasecmp(s, "PASS ", 5) == 0) ||
1448 1.58 lukem strncasecmp(s, "ACCT ", 5) == 0) {
1449 1.4 deraadt /* Don't syslog passwords */
1450 1.58 lukem syslog(LOG_DEBUG, "command: %.4s ???", s);
1451 1.4 deraadt } else {
1452 1.21 lukem char *cp;
1453 1.21 lukem int len;
1454 1.4 deraadt
1455 1.4 deraadt /* Don't syslog trailing CR-LF */
1456 1.4 deraadt len = strlen(s);
1457 1.4 deraadt cp = s + len - 1;
1458 1.4 deraadt while (cp >= s && (*cp == '\n' || *cp == '\r')) {
1459 1.4 deraadt --cp;
1460 1.4 deraadt --len;
1461 1.4 deraadt }
1462 1.4 deraadt syslog(LOG_DEBUG, "command: %.*s", len, s);
1463 1.4 deraadt }
1464 1.4 deraadt }
1465 1.88 lukem return (0);
1466 1.1 cgd }
1467 1.1 cgd
1468 1.60 aidan void
1469 1.60 aidan ftp_handle_line(char *cp)
1470 1.60 aidan {
1471 1.62 lukem
1472 1.60 aidan cmdp = cp;
1473 1.60 aidan yyparse();
1474 1.60 aidan }
1475 1.60 aidan
1476 1.60 aidan void
1477 1.60 aidan ftp_loop(void)
1478 1.60 aidan {
1479 1.88 lukem int ret;
1480 1.62 lukem
1481 1.60 aidan while (1) {
1482 1.60 aidan (void) alarm(curclass.timeout);
1483 1.90 roy ret = get_line(cbuf, sizeof(cbuf)-1, stdin);
1484 1.88 lukem (void) alarm(0);
1485 1.88 lukem if (ret == -1) {
1486 1.60 aidan reply(221, "You could at least say goodbye.");
1487 1.60 aidan dologout(0);
1488 1.88 lukem } else if (ret == -2) {
1489 1.88 lukem reply(500, "Command too long.");
1490 1.88 lukem } else {
1491 1.88 lukem ftp_handle_line(cbuf);
1492 1.60 aidan }
1493 1.60 aidan }
1494 1.60 aidan /*NOTREACHED*/
1495 1.60 aidan }
1496 1.60 aidan
1497 1.76 lukem int
1498 1.46 lukem yylex(void)
1499 1.1 cgd {
1500 1.1 cgd static int cpos, state;
1501 1.4 deraadt char *cp, *cp2;
1502 1.4 deraadt struct tab *p;
1503 1.22 lukem int n;
1504 1.4 deraadt char c;
1505 1.1 cgd
1506 1.23 lukem switch (state) {
1507 1.1 cgd
1508 1.23 lukem case CMD:
1509 1.23 lukem hasyyerrored = 0;
1510 1.60 aidan if ((cp = strchr(cmdp, '\r'))) {
1511 1.42 lukem *cp = '\0';
1512 1.86 lukem #if defined(HAVE_SETPROCTITLE)
1513 1.60 aidan if (strncasecmp(cmdp, "PASS", 4) != 0 &&
1514 1.60 aidan strncasecmp(cmdp, "ACCT", 4) != 0)
1515 1.60 aidan setproctitle("%s: %s", proctitle, cmdp);
1516 1.86 lukem #endif /* defined(HAVE_SETPROCTITLE) */
1517 1.23 lukem *cp++ = '\n';
1518 1.23 lukem *cp = '\0';
1519 1.23 lukem }
1520 1.60 aidan if ((cp = strpbrk(cmdp, " \n")))
1521 1.60 aidan cpos = cp - cmdp;
1522 1.23 lukem if (cpos == 0)
1523 1.23 lukem cpos = 4;
1524 1.60 aidan c = cmdp[cpos];
1525 1.60 aidan cmdp[cpos] = '\0';
1526 1.60 aidan p = lookup(cmdtab, cmdp);
1527 1.60 aidan cmdp[cpos] = c;
1528 1.23 lukem if (p != NULL) {
1529 1.60 aidan if (is_oob && ! CMD_OOB(p)) {
1530 1.60 aidan /* command will be handled in-band */
1531 1.60 aidan return (0);
1532 1.60 aidan } else if (! CMD_IMPLEMENTED(p)) {
1533 1.23 lukem reply(502, "%s command not implemented.",
1534 1.23 lukem p->name);
1535 1.23 lukem hasyyerrored = 1;
1536 1.23 lukem break;
1537 1.23 lukem }
1538 1.23 lukem state = p->state;
1539 1.89 lukem yylval.cs = p->name;
1540 1.23 lukem return (p->token);
1541 1.23 lukem }
1542 1.23 lukem break;
1543 1.23 lukem
1544 1.23 lukem case SITECMD:
1545 1.60 aidan if (cmdp[cpos] == ' ') {
1546 1.23 lukem cpos++;
1547 1.23 lukem return (SP);
1548 1.23 lukem }
1549 1.60 aidan cp = &cmdp[cpos];
1550 1.23 lukem if ((cp2 = strpbrk(cp, " \n")))
1551 1.60 aidan cpos = cp2 - cmdp;
1552 1.60 aidan c = cmdp[cpos];
1553 1.60 aidan cmdp[cpos] = '\0';
1554 1.23 lukem p = lookup(sitetab, cp);
1555 1.60 aidan cmdp[cpos] = c;
1556 1.23 lukem if (p != NULL) {
1557 1.47 lukem if (!CMD_IMPLEMENTED(p)) {
1558 1.23 lukem reply(502, "SITE %s command not implemented.",
1559 1.23 lukem p->name);
1560 1.23 lukem hasyyerrored = 1;
1561 1.23 lukem break;
1562 1.23 lukem }
1563 1.23 lukem state = p->state;
1564 1.89 lukem yylval.cs = p->name;
1565 1.23 lukem return (p->token);
1566 1.23 lukem }
1567 1.23 lukem break;
1568 1.23 lukem
1569 1.23 lukem case OSTR:
1570 1.60 aidan if (cmdp[cpos] == '\n') {
1571 1.60 aidan state = EOLN;
1572 1.23 lukem return (CRLF);
1573 1.23 lukem }
1574 1.23 lukem /* FALLTHROUGH */
1575 1.23 lukem
1576 1.23 lukem case STR1:
1577 1.23 lukem case ZSTR1:
1578 1.23 lukem dostr1:
1579 1.60 aidan if (cmdp[cpos] == ' ') {
1580 1.23 lukem cpos++;
1581 1.39 tron state = state == OSTR ? STR2 : state+1;
1582 1.23 lukem return (SP);
1583 1.23 lukem }
1584 1.23 lukem break;
1585 1.23 lukem
1586 1.23 lukem case ZSTR2:
1587 1.60 aidan if (cmdp[cpos] == '\n') {
1588 1.60 aidan state = EOLN;
1589 1.23 lukem return (CRLF);
1590 1.23 lukem }
1591 1.23 lukem /* FALLTHROUGH */
1592 1.23 lukem
1593 1.23 lukem case STR2:
1594 1.60 aidan cp = &cmdp[cpos];
1595 1.23 lukem n = strlen(cp);
1596 1.23 lukem cpos += n - 1;
1597 1.23 lukem /*
1598 1.23 lukem * Make sure the string is nonempty and \n terminated.
1599 1.23 lukem */
1600 1.60 aidan if (n > 1 && cmdp[cpos] == '\n') {
1601 1.60 aidan cmdp[cpos] = '\0';
1602 1.84 christos yylval.s = ftpd_strdup(cp);
1603 1.60 aidan cmdp[cpos] = '\n';
1604 1.23 lukem state = ARGS;
1605 1.23 lukem return (STRING);
1606 1.23 lukem }
1607 1.23 lukem break;
1608 1.23 lukem
1609 1.23 lukem case NSTR:
1610 1.60 aidan if (cmdp[cpos] == ' ') {
1611 1.23 lukem cpos++;
1612 1.23 lukem return (SP);
1613 1.23 lukem }
1614 1.81 dsl if (isdigit((unsigned char)cmdp[cpos])) {
1615 1.60 aidan cp = &cmdp[cpos];
1616 1.81 dsl while (isdigit((unsigned char)cmdp[++cpos]))
1617 1.23 lukem ;
1618 1.60 aidan c = cmdp[cpos];
1619 1.60 aidan cmdp[cpos] = '\0';
1620 1.70 lukem yylval.u.i = atoi(cp);
1621 1.60 aidan cmdp[cpos] = c;
1622 1.23 lukem state = STR1;
1623 1.23 lukem return (NUMBER);
1624 1.23 lukem }
1625 1.23 lukem state = STR1;
1626 1.23 lukem goto dostr1;
1627 1.1 cgd
1628 1.23 lukem case ARGS:
1629 1.81 dsl if (isdigit((unsigned char)cmdp[cpos])) {
1630 1.60 aidan cp = &cmdp[cpos];
1631 1.81 dsl while (isdigit((unsigned char)cmdp[++cpos]))
1632 1.23 lukem ;
1633 1.60 aidan c = cmdp[cpos];
1634 1.60 aidan cmdp[cpos] = '\0';
1635 1.70 lukem yylval.u.i = atoi(cp);
1636 1.93 plunky yylval.u.ll = STRTOLL(cp, NULL, 10);
1637 1.60 aidan cmdp[cpos] = c;
1638 1.23 lukem return (NUMBER);
1639 1.32 itojun }
1640 1.60 aidan if (strncasecmp(&cmdp[cpos], "ALL", 3) == 0
1641 1.81 dsl && !isalnum((unsigned char)cmdp[cpos + 3])) {
1642 1.32 itojun cpos += 3;
1643 1.80 lukem return (ALL);
1644 1.23 lukem }
1645 1.60 aidan switch (cmdp[cpos++]) {
1646 1.23 lukem
1647 1.23 lukem case '\n':
1648 1.60 aidan state = EOLN;
1649 1.23 lukem return (CRLF);
1650 1.23 lukem
1651 1.23 lukem case ' ':
1652 1.23 lukem return (SP);
1653 1.23 lukem
1654 1.23 lukem case ',':
1655 1.23 lukem return (COMMA);
1656 1.23 lukem
1657 1.23 lukem case 'A':
1658 1.23 lukem case 'a':
1659 1.23 lukem return (A);
1660 1.23 lukem
1661 1.23 lukem case 'B':
1662 1.23 lukem case 'b':
1663 1.23 lukem return (B);
1664 1.23 lukem
1665 1.23 lukem case 'C':
1666 1.23 lukem case 'c':
1667 1.23 lukem return (C);
1668 1.23 lukem
1669 1.23 lukem case 'E':
1670 1.23 lukem case 'e':
1671 1.23 lukem return (E);
1672 1.23 lukem
1673 1.23 lukem case 'F':
1674 1.23 lukem case 'f':
1675 1.23 lukem return (F);
1676 1.23 lukem
1677 1.23 lukem case 'I':
1678 1.23 lukem case 'i':
1679 1.23 lukem return (I);
1680 1.1 cgd
1681 1.23 lukem case 'L':
1682 1.23 lukem case 'l':
1683 1.23 lukem return (L);
1684 1.1 cgd
1685 1.23 lukem case 'N':
1686 1.23 lukem case 'n':
1687 1.23 lukem return (N);
1688 1.1 cgd
1689 1.23 lukem case 'P':
1690 1.23 lukem case 'p':
1691 1.23 lukem return (P);
1692 1.1 cgd
1693 1.23 lukem case 'R':
1694 1.23 lukem case 'r':
1695 1.23 lukem return (R);
1696 1.1 cgd
1697 1.23 lukem case 'S':
1698 1.23 lukem case 's':
1699 1.23 lukem return (S);
1700 1.1 cgd
1701 1.23 lukem case 'T':
1702 1.23 lukem case 't':
1703 1.23 lukem return (T);
1704 1.1 cgd
1705 1.23 lukem }
1706 1.23 lukem break;
1707 1.21 lukem
1708 1.23 lukem case NOARGS:
1709 1.60 aidan if (cmdp[cpos] == '\n') {
1710 1.60 aidan state = EOLN;
1711 1.23 lukem return (CRLF);
1712 1.1 cgd }
1713 1.60 aidan c = cmdp[cpos];
1714 1.60 aidan cmdp[cpos] = '\0';
1715 1.60 aidan reply(501, "'%s' command does not take any arguments.", cmdp);
1716 1.23 lukem hasyyerrored = 1;
1717 1.60 aidan cmdp[cpos] = c;
1718 1.23 lukem break;
1719 1.23 lukem
1720 1.60 aidan case EOLN:
1721 1.60 aidan state = CMD;
1722 1.60 aidan return (0);
1723 1.60 aidan
1724 1.23 lukem default:
1725 1.23 lukem fatal("Unknown state in scanner.");
1726 1.1 cgd }
1727 1.23 lukem yyerror(NULL);
1728 1.23 lukem state = CMD;
1729 1.80 lukem return (0);
1730 1.1 cgd }
1731 1.1 cgd
1732 1.22 lukem /* ARGSUSED */
1733 1.22 lukem void
1734 1.89 lukem yyerror(const char *s)
1735 1.22 lukem {
1736 1.22 lukem char *cp;
1737 1.22 lukem
1738 1.60 aidan if (hasyyerrored || is_oob)
1739 1.22 lukem return;
1740 1.60 aidan if ((cp = strchr(cmdp,'\n')) != NULL)
1741 1.22 lukem *cp = '\0';
1742 1.60 aidan reply(500, "'%s': command not understood.", cmdp);
1743 1.22 lukem hasyyerrored = 1;
1744 1.22 lukem }
1745 1.22 lukem
1746 1.4 deraadt static void
1747 1.46 lukem help(struct tab *ctab, const char *s)
1748 1.1 cgd {
1749 1.4 deraadt struct tab *c;
1750 1.4 deraadt int width, NCMDS;
1751 1.89 lukem const char *htype;
1752 1.1 cgd
1753 1.1 cgd if (ctab == sitetab)
1754 1.66 lukem htype = "SITE ";
1755 1.1 cgd else
1756 1.66 lukem htype = "";
1757 1.1 cgd width = 0, NCMDS = 0;
1758 1.1 cgd for (c = ctab; c->name != NULL; c++) {
1759 1.1 cgd int len = strlen(c->name);
1760 1.1 cgd
1761 1.1 cgd if (len > width)
1762 1.1 cgd width = len;
1763 1.1 cgd NCMDS++;
1764 1.1 cgd }
1765 1.1 cgd width = (width + 8) &~ 7;
1766 1.1 cgd if (s == 0) {
1767 1.4 deraadt int i, j, w;
1768 1.1 cgd int columns, lines;
1769 1.1 cgd
1770 1.49 sommerfe reply(-214, "%s", "");
1771 1.66 lukem reply(0, "The following %scommands are recognized.", htype);
1772 1.48 lukem reply(0, "(`-' = not implemented, `+' = supports options)");
1773 1.1 cgd columns = 76 / width;
1774 1.1 cgd if (columns == 0)
1775 1.1 cgd columns = 1;
1776 1.1 cgd lines = (NCMDS + columns - 1) / columns;
1777 1.1 cgd for (i = 0; i < lines; i++) {
1778 1.48 lukem cprintf(stdout, " ");
1779 1.1 cgd for (j = 0; j < columns; j++) {
1780 1.1 cgd c = ctab + j * lines + i;
1781 1.48 lukem cprintf(stdout, "%s", c->name);
1782 1.23 lukem w = strlen(c->name);
1783 1.47 lukem if (! CMD_IMPLEMENTED(c)) {
1784 1.48 lukem CPUTC('-', stdout);
1785 1.23 lukem w++;
1786 1.23 lukem }
1787 1.47 lukem if (CMD_HAS_OPTIONS(c)) {
1788 1.48 lukem CPUTC('+', stdout);
1789 1.23 lukem w++;
1790 1.23 lukem }
1791 1.1 cgd if (c + lines >= &ctab[NCMDS])
1792 1.1 cgd break;
1793 1.1 cgd while (w < width) {
1794 1.48 lukem CPUTC(' ', stdout);
1795 1.1 cgd w++;
1796 1.1 cgd }
1797 1.1 cgd }
1798 1.48 lukem cprintf(stdout, "\r\n");
1799 1.1 cgd }
1800 1.1 cgd (void) fflush(stdout);
1801 1.1 cgd reply(214, "Direct comments to ftp-bugs@%s.", hostname);
1802 1.1 cgd return;
1803 1.1 cgd }
1804 1.1 cgd c = lookup(ctab, s);
1805 1.1 cgd if (c == (struct tab *)0) {
1806 1.71 darrenr reply(502, "Unknown command '%s'.", s);
1807 1.1 cgd return;
1808 1.1 cgd }
1809 1.47 lukem if (CMD_IMPLEMENTED(c))
1810 1.66 lukem reply(214, "Syntax: %s%s %s", htype, c->name, c->help);
1811 1.1 cgd else
1812 1.71 darrenr reply(504, "%s%-*s\t%s; not implemented.", htype, width,
1813 1.1 cgd c->name, c->help);
1814 1.52 lukem }
1815 1.52 lukem
1816 1.52 lukem /*
1817 1.52 lukem * Check that the structures used for a PORT, LPRT or EPRT command are
1818 1.52 lukem * valid (data_dest, his_addr), and if necessary, detect ftp bounce attacks.
1819 1.52 lukem * If family != -1 check that his_addr.su_family == family.
1820 1.52 lukem */
1821 1.52 lukem static void
1822 1.52 lukem port_check(const char *cmd, int family)
1823 1.52 lukem {
1824 1.61 itojun char h1[NI_MAXHOST], h2[NI_MAXHOST];
1825 1.61 itojun char s1[NI_MAXHOST], s2[NI_MAXHOST];
1826 1.61 itojun #ifdef NI_WITHSCOPEID
1827 1.61 itojun const int niflags = NI_NUMERICHOST | NI_NUMERICSERV | NI_WITHSCOPEID;
1828 1.61 itojun #else
1829 1.61 itojun const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
1830 1.61 itojun #endif
1831 1.52 lukem
1832 1.52 lukem if (epsvall) {
1833 1.52 lukem reply(501, "%s disallowed after EPSV ALL", cmd);
1834 1.52 lukem return;
1835 1.52 lukem }
1836 1.52 lukem
1837 1.52 lukem if (family != -1 && his_addr.su_family != family) {
1838 1.52 lukem port_check_fail:
1839 1.52 lukem reply(500, "Illegal %s command rejected", cmd);
1840 1.52 lukem return;
1841 1.52 lukem }
1842 1.52 lukem
1843 1.52 lukem if (data_dest.su_family != his_addr.su_family)
1844 1.52 lukem goto port_check_fail;
1845 1.52 lukem
1846 1.52 lukem /* be paranoid, if told so */
1847 1.56 lukem if (CURCLASS_FLAGS_ISSET(checkportcmd)) {
1848 1.61 itojun #ifdef INET6
1849 1.61 itojun /*
1850 1.61 itojun * be paranoid, there are getnameinfo implementation that does
1851 1.61 itojun * not present scopeid portion
1852 1.61 itojun */
1853 1.61 itojun if (data_dest.su_family == AF_INET6 &&
1854 1.61 itojun data_dest.su_scope_id != his_addr.su_scope_id)
1855 1.52 lukem goto port_check_fail;
1856 1.53 christos #endif
1857 1.61 itojun
1858 1.61 itojun if (getnameinfo((struct sockaddr *)&data_dest, data_dest.su_len,
1859 1.61 itojun h1, sizeof(h1), s1, sizeof(s1), niflags))
1860 1.61 itojun goto port_check_fail;
1861 1.61 itojun if (getnameinfo((struct sockaddr *)&his_addr, his_addr.su_len,
1862 1.61 itojun h2, sizeof(h2), s2, sizeof(s2), niflags))
1863 1.61 itojun goto port_check_fail;
1864 1.61 itojun
1865 1.61 itojun if (atoi(s1) < IPPORT_RESERVED || strcmp(h1, h2) != 0)
1866 1.52 lukem goto port_check_fail;
1867 1.52 lukem }
1868 1.52 lukem
1869 1.52 lukem usedefault = 0;
1870 1.52 lukem if (pdata >= 0) {
1871 1.52 lukem (void) close(pdata);
1872 1.52 lukem pdata = -1;
1873 1.52 lukem }
1874 1.52 lukem reply(200, "%s command successful.", cmd);
1875 1.23 lukem }
1876