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