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