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