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