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