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