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