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