ftpcmd.y revision 103949
11592Srgrimes/* 21592Srgrimes * Copyright (c) 1985, 1988, 1993, 1994 31592Srgrimes * The Regents of the University of California. All rights reserved. 41592Srgrimes * 51592Srgrimes * Redistribution and use in source and binary forms, with or without 61592Srgrimes * modification, are permitted provided that the following conditions 71592Srgrimes * are met: 81592Srgrimes * 1. Redistributions of source code must retain the above copyright 91592Srgrimes * notice, this list of conditions and the following disclaimer. 101592Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111592Srgrimes * notice, this list of conditions and the following disclaimer in the 121592Srgrimes * documentation and/or other materials provided with the distribution. 131592Srgrimes * 3. All advertising materials mentioning features or use of this software 141592Srgrimes * must display the following acknowledgement: 151592Srgrimes * This product includes software developed by the University of 161592Srgrimes * California, Berkeley and its contributors. 171592Srgrimes * 4. Neither the name of the University nor the names of its contributors 181592Srgrimes * may be used to endorse or promote products derived from this software 191592Srgrimes * without specific prior written permission. 201592Srgrimes * 211592Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221592Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231592Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241592Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251592Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261592Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271592Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281592Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291592Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301592Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311592Srgrimes * SUCH DAMAGE. 321592Srgrimes * 331592Srgrimes * @(#)ftpcmd.y 8.3 (Berkeley) 4/6/94 341592Srgrimes */ 351592Srgrimes 361592Srgrimes/* 371592Srgrimes * Grammar for FTP commands. 381592Srgrimes * See RFC 959. 391592Srgrimes */ 401592Srgrimes 411592Srgrimes%{ 421592Srgrimes 431592Srgrimes#ifndef lint 4431329Scharnier#if 0 451592Srgrimesstatic char sccsid[] = "@(#)ftpcmd.y 8.3 (Berkeley) 4/6/94"; 4631329Scharnier#endif 4731329Scharnierstatic const char rcsid[] = 4850476Speter "$FreeBSD: head/libexec/ftpd/ftpcmd.y 103949 2002-09-25 04:06:37Z mike $"; 491592Srgrimes#endif /* not lint */ 501592Srgrimes 511592Srgrimes#include <sys/param.h> 521592Srgrimes#include <sys/socket.h> 531592Srgrimes#include <sys/stat.h> 541592Srgrimes 551592Srgrimes#include <netinet/in.h> 561592Srgrimes#include <arpa/ftp.h> 571592Srgrimes 581592Srgrimes#include <ctype.h> 591592Srgrimes#include <errno.h> 601592Srgrimes#include <glob.h> 6192090Smaxim#include <libutil.h> 6292272Smaxim#include <limits.h> 6392090Smaxim#include <md5.h> 6456668Sshin#include <netdb.h> 651592Srgrimes#include <pwd.h> 661592Srgrimes#include <signal.h> 671592Srgrimes#include <stdio.h> 681592Srgrimes#include <stdlib.h> 691592Srgrimes#include <string.h> 701592Srgrimes#include <syslog.h> 711592Srgrimes#include <time.h> 721592Srgrimes#include <unistd.h> 731592Srgrimes 741592Srgrimes#include "extern.h" 751592Srgrimes 7656668Sshinextern union sockunion data_dest, his_addr; 771592Srgrimesextern int logged_in; 781592Srgrimesextern struct passwd *pw; 791592Srgrimesextern int guest; 8017435Spstextern int paranoid; 811592Srgrimesextern int logging; 821592Srgrimesextern int type; 831592Srgrimesextern int form; 8476096Smarkmextern int ftpdebug; 851592Srgrimesextern int timeout; 861592Srgrimesextern int maxtimeout; 871592Srgrimesextern int pdata; 8827650Sdavidnextern char *hostname; 8927650Sdavidnextern char remotehost[]; 901592Srgrimesextern char proctitle[]; 911592Srgrimesextern int usedefault; 921592Srgrimesextern int transflag; 931592Srgrimesextern char tmpline[]; 9470102Sphkextern int readonly; 9570102Sphkextern int noepsv; 9682460Snikextern int noretr; 9782796Ssheldonhextern int noguestretr; 98100684Syarextern char *typenames[]; /* defined in <arpa/ftp.h> included from ftpd.c */ 991592Srgrimes 1001592Srgrimesoff_t restart_point; 1011592Srgrimes 1021592Srgrimesstatic int cmd_type; 1031592Srgrimesstatic int cmd_form; 1041592Srgrimesstatic int cmd_bytesz; 10589935Syarstatic int state; 1061592Srgrimeschar cbuf[512]; 10788935Sdwmalonechar *fromname = (char *) 0; 1081592Srgrimes 10956668Sshinextern int epsvall; 11056668Sshin 1111592Srgrimes%} 1121592Srgrimes 1131592Srgrimes%union { 11492272Smaxim struct { 11592272Smaxim off_t o; 11692272Smaxim int i; 11792272Smaxim } u; 1181592Srgrimes char *s; 1191592Srgrimes} 1201592Srgrimes 1211592Srgrimes%token 1221592Srgrimes A B C E F I 1231592Srgrimes L N P R S T 12456668Sshin ALL 1251592Srgrimes 1261592Srgrimes SP CRLF COMMA 1271592Srgrimes 1281592Srgrimes USER PASS ACCT REIN QUIT PORT 1291592Srgrimes PASV TYPE STRU MODE RETR STOR 1301592Srgrimes APPE MLFL MAIL MSND MSOM MSAM 1311592Srgrimes MRSQ MRCP ALLO REST RNFR RNTO 1321592Srgrimes ABOR DELE CWD LIST NLST SITE 1331592Srgrimes STAT HELP NOOP MKD RMD PWD 1341592Srgrimes CDUP STOU SMNT SYST SIZE MDTM 13556668Sshin LPRT LPSV EPRT EPSV 1361592Srgrimes 13775535Sphk UMASK IDLE CHMOD MDFIVE 1381592Srgrimes 139102565Syar LEXERR NOTIMPL 1401592Srgrimes 1411592Srgrimes%token <s> STRING 14292272Smaxim%token <u> NUMBER 1431592Srgrimes 14492272Smaxim%type <u.i> check_login octal_number byte_size 14592272Smaxim%type <u.i> check_login_ro check_login_epsv 14692272Smaxim%type <u.i> struct_code mode_code type_code form_code 14775567Speter%type <s> pathstring pathname password username 148102565Syar%type <s> ALL NOTIMPL 1491592Srgrimes 1501592Srgrimes%start cmd_list 1511592Srgrimes 1521592Srgrimes%% 1531592Srgrimes 1541592Srgrimescmd_list 1551592Srgrimes : /* empty */ 1561592Srgrimes | cmd_list cmd 1571592Srgrimes { 15888935Sdwmalone if (fromname) 15988935Sdwmalone free(fromname); 1601592Srgrimes fromname = (char *) 0; 1611592Srgrimes restart_point = (off_t) 0; 1621592Srgrimes } 1631592Srgrimes | cmd_list rcmd 1641592Srgrimes ; 1651592Srgrimes 1661592Srgrimescmd 1671592Srgrimes : USER SP username CRLF 1681592Srgrimes { 1691592Srgrimes user($3); 1701592Srgrimes free($3); 1711592Srgrimes } 1721592Srgrimes | PASS SP password CRLF 1731592Srgrimes { 1741592Srgrimes pass($3); 1751592Srgrimes free($3); 1761592Srgrimes } 17775556Sgreen | PASS CRLF 17875556Sgreen { 17975556Sgreen pass(""); 18075556Sgreen } 18117433Spst | PORT check_login SP host_port CRLF 1821592Srgrimes { 18356668Sshin if (epsvall) { 18456668Sshin reply(501, "no PORT allowed after EPSV ALL"); 18556668Sshin goto port_done; 18656668Sshin } 18756668Sshin if (!$2) 18856668Sshin goto port_done; 18956668Sshin if (port_check("PORT") == 1) 19056668Sshin goto port_done; 19156668Sshin#ifdef INET6 19256668Sshin if ((his_addr.su_family != AF_INET6 || 19356668Sshin !IN6_IS_ADDR_V4MAPPED(&his_addr.su_sin6.sin6_addr))) { 19456668Sshin /* shoud never happen */ 19556668Sshin usedefault = 1; 19656668Sshin reply(500, "Invalid address rejected."); 19756668Sshin goto port_done; 19856668Sshin } 19956668Sshin port_check_v6("pcmd"); 20056668Sshin#endif 20156668Sshin port_done: 20256668Sshin } 20356668Sshin | LPRT check_login SP host_long_port CRLF 20456668Sshin { 20556668Sshin if (epsvall) { 20656668Sshin reply(501, "no LPRT allowed after EPSV ALL"); 20756668Sshin goto lprt_done; 20856668Sshin } 20956668Sshin if (!$2) 21056668Sshin goto lprt_done; 21156668Sshin if (port_check("LPRT") == 1) 21256668Sshin goto lprt_done; 21356668Sshin#ifdef INET6 21456668Sshin if (his_addr.su_family != AF_INET6) { 21556668Sshin usedefault = 1; 21656668Sshin reply(500, "Invalid address rejected."); 21756668Sshin goto lprt_done; 21856668Sshin } 21956668Sshin if (port_check_v6("LPRT") == 1) 22056668Sshin goto lprt_done; 22156668Sshin#endif 22256668Sshin lprt_done: 22356668Sshin } 22456668Sshin | EPRT check_login SP STRING CRLF 22556668Sshin { 22656668Sshin char delim; 22756668Sshin char *tmp = NULL; 22856668Sshin char *p, *q; 22956668Sshin char *result[3]; 23056668Sshin struct addrinfo hints; 23156668Sshin struct addrinfo *res; 23256668Sshin int i; 23356668Sshin 23456668Sshin if (epsvall) { 23556668Sshin reply(501, "no EPRT allowed after EPSV ALL"); 23656668Sshin goto eprt_done; 23756668Sshin } 23856668Sshin if (!$2) 23956668Sshin goto eprt_done; 24056668Sshin 24156668Sshin memset(&data_dest, 0, sizeof(data_dest)); 24256668Sshin tmp = strdup($4); 24376096Smarkm if (ftpdebug) 24456668Sshin syslog(LOG_DEBUG, "%s", tmp); 24556668Sshin if (!tmp) { 24676096Smarkm fatalerror("not enough core"); 24756668Sshin /*NOTREACHED*/ 24856668Sshin } 24956668Sshin p = tmp; 25056668Sshin delim = p[0]; 25156668Sshin p++; 25256668Sshin memset(result, 0, sizeof(result)); 25356668Sshin for (i = 0; i < 3; i++) { 25456668Sshin q = strchr(p, delim); 25556668Sshin if (!q || *q != delim) { 25656668Sshin parsefail: 25756668Sshin reply(500, 25856668Sshin "Invalid argument, rejected."); 25956668Sshin if (tmp) 26056668Sshin free(tmp); 26117433Spst usedefault = 1; 26256668Sshin goto eprt_done; 26317433Spst } 26456668Sshin *q++ = '\0'; 26556668Sshin result[i] = p; 26676096Smarkm if (ftpdebug) 26756668Sshin syslog(LOG_DEBUG, "%d: %s", i, p); 26856668Sshin p = q; 2691592Srgrimes } 27056668Sshin 27156668Sshin /* some more sanity check */ 27256668Sshin p = result[0]; 27356668Sshin while (*p) { 27456668Sshin if (!isdigit(*p)) 27556668Sshin goto parsefail; 27656668Sshin p++; 27756668Sshin } 27856668Sshin p = result[2]; 27956668Sshin while (*p) { 28056668Sshin if (!isdigit(*p)) 28156668Sshin goto parsefail; 28256668Sshin p++; 28356668Sshin } 28456668Sshin 28556668Sshin /* grab address */ 28656668Sshin memset(&hints, 0, sizeof(hints)); 28756668Sshin if (atoi(result[0]) == 1) 28856668Sshin hints.ai_family = PF_INET; 28956668Sshin#ifdef INET6 29056668Sshin else if (atoi(result[0]) == 2) 29156668Sshin hints.ai_family = PF_INET6; 29256668Sshin#endif 29356668Sshin else 29456668Sshin hints.ai_family = PF_UNSPEC; /*XXX*/ 29556668Sshin hints.ai_socktype = SOCK_STREAM; 29656668Sshin i = getaddrinfo(result[1], result[2], &hints, &res); 29756668Sshin if (i) 29856668Sshin goto parsefail; 29956668Sshin memcpy(&data_dest, res->ai_addr, res->ai_addrlen); 30056668Sshin#ifdef INET6 30156668Sshin if (his_addr.su_family == AF_INET6 30256668Sshin && data_dest.su_family == AF_INET6) { 30356668Sshin /* XXX more sanity checks! */ 30456668Sshin data_dest.su_sin6.sin6_scope_id = 30556668Sshin his_addr.su_sin6.sin6_scope_id; 30656668Sshin } 30756668Sshin#endif 30856668Sshin free(tmp); 30956668Sshin tmp = NULL; 31056668Sshin 31156668Sshin if (port_check("EPRT") == 1) 31256668Sshin goto eprt_done; 31356668Sshin#ifdef INET6 31456668Sshin if (his_addr.su_family != AF_INET6) { 31556668Sshin usedefault = 1; 31656668Sshin reply(500, "Invalid address rejected."); 31756668Sshin goto eprt_done; 31856668Sshin } 31956668Sshin if (port_check_v6("EPRT") == 1) 32056668Sshin goto eprt_done; 32156668Sshin#endif 32288935Sdwmalone eprt_done: 32388935Sdwmalone free($4); 3241592Srgrimes } 32517433Spst | PASV check_login CRLF 3261592Srgrimes { 32756668Sshin if (epsvall) 32856668Sshin reply(501, "no PASV allowed after EPSV ALL"); 32956668Sshin else if ($2) 33017433Spst passive(); 3311592Srgrimes } 33256668Sshin | LPSV check_login CRLF 33356668Sshin { 33456668Sshin if (epsvall) 33556668Sshin reply(501, "no LPSV allowed after EPSV ALL"); 33656668Sshin else if ($2) 33756668Sshin long_passive("LPSV", PF_UNSPEC); 33856668Sshin } 33970102Sphk | EPSV check_login_epsv SP NUMBER CRLF 34056668Sshin { 34156668Sshin if ($2) { 34256668Sshin int pf; 34392272Smaxim switch ($4.i) { 34456668Sshin case 1: 34556668Sshin pf = PF_INET; 34656668Sshin break; 34756668Sshin#ifdef INET6 34856668Sshin case 2: 34956668Sshin pf = PF_INET6; 35056668Sshin break; 35156668Sshin#endif 35256668Sshin default: 35356668Sshin pf = -1; /*junk value*/ 35456668Sshin break; 35556668Sshin } 35656668Sshin long_passive("EPSV", pf); 35756668Sshin } 35856668Sshin } 35970102Sphk | EPSV check_login_epsv SP ALL CRLF 36056668Sshin { 36156668Sshin if ($2) { 36256668Sshin reply(200, 36356668Sshin "EPSV ALL command successful."); 36456668Sshin epsvall++; 36556668Sshin } 36656668Sshin } 36770102Sphk | EPSV check_login_epsv CRLF 36856668Sshin { 36956668Sshin if ($2) 37056668Sshin long_passive("EPSV", PF_UNSPEC); 37156668Sshin } 37271278Sjedgar | TYPE check_login SP type_code CRLF 3731592Srgrimes { 37471278Sjedgar if ($2) { 37571278Sjedgar switch (cmd_type) { 3761592Srgrimes 37771278Sjedgar case TYPE_A: 37871278Sjedgar if (cmd_form == FORM_N) { 37971278Sjedgar reply(200, "Type set to A."); 38071278Sjedgar type = cmd_type; 38171278Sjedgar form = cmd_form; 38271278Sjedgar } else 38371278Sjedgar reply(504, "Form must be N."); 38471278Sjedgar break; 3851592Srgrimes 38671278Sjedgar case TYPE_E: 38771278Sjedgar reply(504, "Type E not implemented."); 38871278Sjedgar break; 3891592Srgrimes 39071278Sjedgar case TYPE_I: 39171278Sjedgar reply(200, "Type set to I."); 39271278Sjedgar type = cmd_type; 39371278Sjedgar break; 3941592Srgrimes 39571278Sjedgar case TYPE_L: 396103949Smike#if CHAR_BIT == 8 39771278Sjedgar if (cmd_bytesz == 8) { 39871278Sjedgar reply(200, 39971278Sjedgar "Type set to L (byte size 8)."); 40071278Sjedgar type = cmd_type; 40171278Sjedgar } else 40271278Sjedgar reply(504, "Byte size must be 8."); 403103949Smike#else /* CHAR_BIT == 8 */ 404103949Smike UNIMPLEMENTED for CHAR_BIT != 8 405103949Smike#endif /* CHAR_BIT == 8 */ 40671278Sjedgar } 4071592Srgrimes } 4081592Srgrimes } 40971278Sjedgar | STRU check_login SP struct_code CRLF 4101592Srgrimes { 41171278Sjedgar if ($2) { 41271278Sjedgar switch ($4) { 4131592Srgrimes 41471278Sjedgar case STRU_F: 41571278Sjedgar reply(200, "STRU F ok."); 41671278Sjedgar break; 4171592Srgrimes 41871278Sjedgar default: 41971278Sjedgar reply(504, "Unimplemented STRU type."); 42071278Sjedgar } 4211592Srgrimes } 4221592Srgrimes } 42371278Sjedgar | MODE check_login SP mode_code CRLF 4241592Srgrimes { 42571278Sjedgar if ($2) { 42671278Sjedgar switch ($4) { 4271592Srgrimes 42871278Sjedgar case MODE_S: 42971278Sjedgar reply(200, "MODE S ok."); 43071278Sjedgar break; 43171278Sjedgar 43271278Sjedgar default: 43371278Sjedgar reply(502, "Unimplemented MODE type."); 43471278Sjedgar } 4351592Srgrimes } 4361592Srgrimes } 43771278Sjedgar | ALLO check_login SP NUMBER CRLF 4381592Srgrimes { 43971278Sjedgar if ($2) { 44071278Sjedgar reply(202, "ALLO command ignored."); 44171278Sjedgar } 4421592Srgrimes } 44371278Sjedgar | ALLO check_login SP NUMBER SP R SP NUMBER CRLF 4441592Srgrimes { 44571278Sjedgar if ($2) { 44671278Sjedgar reply(202, "ALLO command ignored."); 44771278Sjedgar } 4481592Srgrimes } 4491592Srgrimes | RETR check_login SP pathname CRLF 4501592Srgrimes { 45182796Ssheldonh if (noretr || (guest && noguestretr)) 45282460Snik reply(500, "RETR command is disabled"); 45382460Snik else if ($2 && $4 != NULL) 4541592Srgrimes retrieve((char *) 0, $4); 45582460Snik 4561592Srgrimes if ($4 != NULL) 4571592Srgrimes free($4); 4581592Srgrimes } 45970102Sphk | STOR check_login_ro SP pathname CRLF 4601592Srgrimes { 4611592Srgrimes if ($2 && $4 != NULL) 4621592Srgrimes store($4, "w", 0); 4631592Srgrimes if ($4 != NULL) 4641592Srgrimes free($4); 4651592Srgrimes } 46670102Sphk | APPE check_login_ro SP pathname CRLF 4671592Srgrimes { 4681592Srgrimes if ($2 && $4 != NULL) 4691592Srgrimes store($4, "a", 0); 4701592Srgrimes if ($4 != NULL) 4711592Srgrimes free($4); 4721592Srgrimes } 4731592Srgrimes | NLST check_login CRLF 4741592Srgrimes { 4751592Srgrimes if ($2) 4761592Srgrimes send_file_list("."); 4771592Srgrimes } 478101395Syar | NLST check_login SP pathstring CRLF 4791592Srgrimes { 480101395Syar if ($2) 4811592Srgrimes send_file_list($4); 482101395Syar free($4); 4831592Srgrimes } 4841592Srgrimes | LIST check_login CRLF 4851592Srgrimes { 4861592Srgrimes if ($2) 4871592Srgrimes retrieve("/bin/ls -lgA", ""); 4881592Srgrimes } 48975567Speter | LIST check_login SP pathstring CRLF 4901592Srgrimes { 491101395Syar if ($2) 4921592Srgrimes retrieve("/bin/ls -lgA %s", $4); 493101395Syar free($4); 4941592Srgrimes } 4951592Srgrimes | STAT check_login SP pathname CRLF 4961592Srgrimes { 4971592Srgrimes if ($2 && $4 != NULL) 4981592Srgrimes statfilecmd($4); 4991592Srgrimes if ($4 != NULL) 5001592Srgrimes free($4); 5011592Srgrimes } 50271278Sjedgar | STAT check_login CRLF 5031592Srgrimes { 50471278Sjedgar if ($2) { 50571278Sjedgar statcmd(); 50671278Sjedgar } 5071592Srgrimes } 50870102Sphk | DELE check_login_ro SP pathname CRLF 5091592Srgrimes { 5101592Srgrimes if ($2 && $4 != NULL) 5111592Srgrimes delete($4); 5121592Srgrimes if ($4 != NULL) 5131592Srgrimes free($4); 5141592Srgrimes } 51570102Sphk | RNTO check_login_ro SP pathname CRLF 5161592Srgrimes { 517101379Syar if ($2 && $4 != NULL) { 51817433Spst if (fromname) { 51917433Spst renamecmd(fromname, $4); 52017433Spst free(fromname); 52117433Spst fromname = (char *) 0; 52217433Spst } else { 52317433Spst reply(503, "Bad sequence of commands."); 52417433Spst } 5251592Srgrimes } 526101379Syar if ($4 != NULL) 527101379Syar free($4); 5281592Srgrimes } 52971278Sjedgar | ABOR check_login CRLF 5301592Srgrimes { 53171278Sjedgar if ($2) 53271278Sjedgar reply(225, "ABOR command successful."); 5331592Srgrimes } 5341592Srgrimes | CWD check_login CRLF 5351592Srgrimes { 53669234Sdanny if ($2) { 53769234Sdanny if (guest) 53869234Sdanny cwd("/"); 53969234Sdanny else 54069234Sdanny cwd(pw->pw_dir); 54169234Sdanny } 5421592Srgrimes } 5431592Srgrimes | CWD check_login SP pathname CRLF 5441592Srgrimes { 5451592Srgrimes if ($2 && $4 != NULL) 5461592Srgrimes cwd($4); 5471592Srgrimes if ($4 != NULL) 5481592Srgrimes free($4); 5491592Srgrimes } 5501592Srgrimes | HELP CRLF 5511592Srgrimes { 5521592Srgrimes help(cmdtab, (char *) 0); 5531592Srgrimes } 5541592Srgrimes | HELP SP STRING CRLF 5551592Srgrimes { 5561592Srgrimes char *cp = $3; 5571592Srgrimes 5581592Srgrimes if (strncasecmp(cp, "SITE", 4) == 0) { 5591592Srgrimes cp = $3 + 4; 5601592Srgrimes if (*cp == ' ') 5611592Srgrimes cp++; 5621592Srgrimes if (*cp) 5631592Srgrimes help(sitetab, cp); 5641592Srgrimes else 5651592Srgrimes help(sitetab, (char *) 0); 5661592Srgrimes } else 5671592Srgrimes help(cmdtab, $3); 56888935Sdwmalone free($3); 5691592Srgrimes } 5701592Srgrimes | NOOP CRLF 5711592Srgrimes { 5721592Srgrimes reply(200, "NOOP command successful."); 5731592Srgrimes } 57470102Sphk | MKD check_login_ro SP pathname CRLF 5751592Srgrimes { 5761592Srgrimes if ($2 && $4 != NULL) 5771592Srgrimes makedir($4); 5781592Srgrimes if ($4 != NULL) 5791592Srgrimes free($4); 5801592Srgrimes } 58170102Sphk | RMD check_login_ro SP pathname CRLF 5821592Srgrimes { 5831592Srgrimes if ($2 && $4 != NULL) 5841592Srgrimes removedir($4); 5851592Srgrimes if ($4 != NULL) 5861592Srgrimes free($4); 5871592Srgrimes } 5881592Srgrimes | PWD check_login CRLF 5891592Srgrimes { 5901592Srgrimes if ($2) 5911592Srgrimes pwd(); 5921592Srgrimes } 5931592Srgrimes | CDUP check_login CRLF 5941592Srgrimes { 5951592Srgrimes if ($2) 5961592Srgrimes cwd(".."); 5971592Srgrimes } 5981592Srgrimes | SITE SP HELP CRLF 5991592Srgrimes { 6001592Srgrimes help(sitetab, (char *) 0); 6011592Srgrimes } 6021592Srgrimes | SITE SP HELP SP STRING CRLF 6031592Srgrimes { 6041592Srgrimes help(sitetab, $5); 60588935Sdwmalone free($5); 6061592Srgrimes } 60775535Sphk | SITE SP MDFIVE check_login SP pathname CRLF 60875535Sphk { 60975535Sphk char p[64], *q; 61075535Sphk 611101379Syar if ($4 && $6) { 61275535Sphk q = MD5File($6, p); 61375535Sphk if (q != NULL) 61475535Sphk reply(200, "MD5(%s) = %s", $6, p); 61575535Sphk else 61675535Sphk perror_reply(550, $6); 61775535Sphk } 61888935Sdwmalone if ($6) 61988935Sdwmalone free($6); 62075535Sphk } 6211592Srgrimes | SITE SP UMASK check_login CRLF 6221592Srgrimes { 6231592Srgrimes int oldmask; 6241592Srgrimes 6251592Srgrimes if ($4) { 6261592Srgrimes oldmask = umask(0); 6271592Srgrimes (void) umask(oldmask); 6281592Srgrimes reply(200, "Current UMASK is %03o", oldmask); 6291592Srgrimes } 6301592Srgrimes } 6311592Srgrimes | SITE SP UMASK check_login SP octal_number CRLF 6321592Srgrimes { 6331592Srgrimes int oldmask; 6341592Srgrimes 6351592Srgrimes if ($4) { 6361592Srgrimes if (($6 == -1) || ($6 > 0777)) { 6371592Srgrimes reply(501, "Bad UMASK value"); 6381592Srgrimes } else { 6391592Srgrimes oldmask = umask($6); 6401592Srgrimes reply(200, 6411592Srgrimes "UMASK set to %03o (was %03o)", 6421592Srgrimes $6, oldmask); 6431592Srgrimes } 6441592Srgrimes } 6451592Srgrimes } 64670102Sphk | SITE SP CHMOD check_login_ro SP octal_number SP pathname CRLF 6471592Srgrimes { 6481592Srgrimes if ($4 && ($8 != NULL)) { 649101378Syar if (($6 == -1 ) || ($6 > 0777)) 650101378Syar reply(501, "Bad mode value"); 6511592Srgrimes else if (chmod($8, $6) < 0) 6521592Srgrimes perror_reply(550, $8); 6531592Srgrimes else 6541592Srgrimes reply(200, "CHMOD command successful."); 6551592Srgrimes } 6561592Srgrimes if ($8 != NULL) 6571592Srgrimes free($8); 6581592Srgrimes } 65971278Sjedgar | SITE SP check_login IDLE CRLF 6601592Srgrimes { 66171278Sjedgar if ($3) 66271278Sjedgar reply(200, 66371278Sjedgar "Current IDLE time limit is %d seconds; max %d", 66471278Sjedgar timeout, maxtimeout); 6651592Srgrimes } 66671278Sjedgar | SITE SP check_login IDLE SP NUMBER CRLF 6671592Srgrimes { 66871278Sjedgar if ($3) { 66992272Smaxim if ($6.i < 30 || $6.i > maxtimeout) { 67071278Sjedgar reply(501, 67171278Sjedgar "Maximum IDLE time must be between 30 and %d seconds", 67271278Sjedgar maxtimeout); 67371278Sjedgar } else { 67492272Smaxim timeout = $6.i; 67571278Sjedgar (void) alarm((unsigned) timeout); 67671278Sjedgar reply(200, 67771278Sjedgar "Maximum IDLE time set to %d seconds", 67871278Sjedgar timeout); 67971278Sjedgar } 6801592Srgrimes } 6811592Srgrimes } 68270102Sphk | STOU check_login_ro SP pathname CRLF 6831592Srgrimes { 6841592Srgrimes if ($2 && $4 != NULL) 6851592Srgrimes store($4, "w", 1); 6861592Srgrimes if ($4 != NULL) 6871592Srgrimes free($4); 6881592Srgrimes } 68971278Sjedgar | SYST check_login CRLF 6901592Srgrimes { 69171278Sjedgar if ($2) 6921592Srgrimes#ifdef unix 6931592Srgrimes#ifdef BSD 6941592Srgrimes reply(215, "UNIX Type: L%d Version: BSD-%d", 695103949Smike CHAR_BIT, BSD); 6961592Srgrimes#else /* BSD */ 697103949Smike reply(215, "UNIX Type: L%d", CHAR_BIT); 6981592Srgrimes#endif /* BSD */ 6991592Srgrimes#else /* unix */ 700103949Smike reply(215, "UNKNOWN Type: L%d", CHAR_BIT); 7011592Srgrimes#endif /* unix */ 7021592Srgrimes } 7031592Srgrimes 7041592Srgrimes /* 7051592Srgrimes * SIZE is not in RFC959, but Postel has blessed it and 7061592Srgrimes * it will be in the updated RFC. 7071592Srgrimes * 7081592Srgrimes * Return size of file in a format suitable for 7091592Srgrimes * using with RESTART (we just count bytes). 7101592Srgrimes */ 7111592Srgrimes | SIZE check_login SP pathname CRLF 7121592Srgrimes { 7131592Srgrimes if ($2 && $4 != NULL) 7141592Srgrimes sizecmd($4); 7151592Srgrimes if ($4 != NULL) 7161592Srgrimes free($4); 7171592Srgrimes } 7181592Srgrimes 7191592Srgrimes /* 7201592Srgrimes * MDTM is not in RFC959, but Postel has blessed it and 7211592Srgrimes * it will be in the updated RFC. 7221592Srgrimes * 7231592Srgrimes * Return modification time of file as an ISO 3307 7241592Srgrimes * style time. E.g. YYYYMMDDHHMMSS or YYYYMMDDHHMMSS.xxx 7251592Srgrimes * where xxx is the fractional second (of any precision, 7261592Srgrimes * not necessarily 3 digits) 7271592Srgrimes */ 7281592Srgrimes | MDTM check_login SP pathname CRLF 7291592Srgrimes { 7301592Srgrimes if ($2 && $4 != NULL) { 7311592Srgrimes struct stat stbuf; 7321592Srgrimes if (stat($4, &stbuf) < 0) 7331592Srgrimes reply(550, "%s: %s", 7341592Srgrimes $4, strerror(errno)); 7351592Srgrimes else if (!S_ISREG(stbuf.st_mode)) { 7361592Srgrimes reply(550, "%s: not a plain file.", $4); 7371592Srgrimes } else { 7381592Srgrimes struct tm *t; 7391592Srgrimes t = gmtime(&stbuf.st_mtime); 7401592Srgrimes reply(213, 74117435Spst "%04d%02d%02d%02d%02d%02d", 74217435Spst 1900 + t->tm_year, 74317435Spst t->tm_mon+1, t->tm_mday, 7441592Srgrimes t->tm_hour, t->tm_min, t->tm_sec); 7451592Srgrimes } 7461592Srgrimes } 7471592Srgrimes if ($4 != NULL) 7481592Srgrimes free($4); 7491592Srgrimes } 7501592Srgrimes | QUIT CRLF 7511592Srgrimes { 7521592Srgrimes reply(221, "Goodbye."); 7531592Srgrimes dologout(0); 7541592Srgrimes } 755102565Syar | NOTIMPL 756102565Syar { 757102565Syar nack($1); 758102565Syar } 75989935Syar | error 7601592Srgrimes { 76189935Syar yyclearin; /* discard lookahead data */ 76289935Syar yyerrok; /* clear error condition */ 763102565Syar state = CMD; /* reset lexer state */ 7641592Srgrimes } 7651592Srgrimes ; 7661592Srgrimesrcmd 76770102Sphk : RNFR check_login_ro SP pathname CRLF 7681592Srgrimes { 7691592Srgrimes restart_point = (off_t) 0; 7701592Srgrimes if ($2 && $4) { 77188935Sdwmalone if (fromname) 77288935Sdwmalone free(fromname); 77388935Sdwmalone fromname = (char *) 0; 77488935Sdwmalone if (renamefrom($4)) 77588935Sdwmalone fromname = $4; 77688935Sdwmalone else 7771592Srgrimes free($4); 77888935Sdwmalone } else if ($4) { 77988935Sdwmalone free($4); 7801592Srgrimes } 7811592Srgrimes } 78292272Smaxim | REST check_login SP NUMBER CRLF 7831592Srgrimes { 78471278Sjedgar if ($2) { 78588935Sdwmalone if (fromname) 78688935Sdwmalone free(fromname); 78771278Sjedgar fromname = (char *) 0; 78892272Smaxim restart_point = $4.o; 78992272Smaxim reply(350, "Restarting at %llu. %s", 79071278Sjedgar restart_point, 79171278Sjedgar "Send STORE or RETRIEVE to initiate transfer."); 79271278Sjedgar } 7931592Srgrimes } 7941592Srgrimes ; 7951592Srgrimes 7961592Srgrimesusername 7971592Srgrimes : STRING 7981592Srgrimes ; 7991592Srgrimes 8001592Srgrimespassword 8011592Srgrimes : /* empty */ 8021592Srgrimes { 8031592Srgrimes $$ = (char *)calloc(1, sizeof(char)); 8041592Srgrimes } 8051592Srgrimes | STRING 8061592Srgrimes ; 8071592Srgrimes 8081592Srgrimesbyte_size 8091592Srgrimes : NUMBER 81092272Smaxim { 81192272Smaxim $$ = $1.i; 81292272Smaxim } 8131592Srgrimes ; 8141592Srgrimes 8151592Srgrimeshost_port 8161592Srgrimes : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 8171592Srgrimes NUMBER COMMA NUMBER 8181592Srgrimes { 8191592Srgrimes char *a, *p; 8201592Srgrimes 82156668Sshin data_dest.su_len = sizeof(struct sockaddr_in); 82256668Sshin data_dest.su_family = AF_INET; 82356668Sshin p = (char *)&data_dest.su_sin.sin_port; 82492272Smaxim p[0] = $9.i; p[1] = $11.i; 82556668Sshin a = (char *)&data_dest.su_sin.sin_addr; 82692272Smaxim a[0] = $1.i; a[1] = $3.i; a[2] = $5.i; a[3] = $7.i; 8271592Srgrimes } 8281592Srgrimes ; 8291592Srgrimes 83056668Sshinhost_long_port 83156668Sshin : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 83256668Sshin NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 83356668Sshin NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 83456668Sshin NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 83556668Sshin NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 83656668Sshin NUMBER 83756668Sshin { 83856668Sshin char *a, *p; 83956668Sshin 84056668Sshin memset(&data_dest, 0, sizeof(data_dest)); 84156668Sshin data_dest.su_len = sizeof(struct sockaddr_in6); 84256668Sshin data_dest.su_family = AF_INET6; 84356668Sshin p = (char *)&data_dest.su_port; 84492272Smaxim p[0] = $39.i; p[1] = $41.i; 84556668Sshin a = (char *)&data_dest.su_sin6.sin6_addr; 84692272Smaxim a[0] = $5.i; a[1] = $7.i; a[2] = $9.i; a[3] = $11.i; 84792272Smaxim a[4] = $13.i; a[5] = $15.i; a[6] = $17.i; a[7] = $19.i; 84892272Smaxim a[8] = $21.i; a[9] = $23.i; a[10] = $25.i; a[11] = $27.i; 84992272Smaxim a[12] = $29.i; a[13] = $31.i; a[14] = $33.i; a[15] = $35.i; 85056668Sshin if (his_addr.su_family == AF_INET6) { 85156668Sshin /* XXX more sanity checks! */ 85256668Sshin data_dest.su_sin6.sin6_scope_id = 85356668Sshin his_addr.su_sin6.sin6_scope_id; 85456668Sshin } 85592272Smaxim if ($1.i != 6 || $3.i != 16 || $37.i != 2) 85656668Sshin memset(&data_dest, 0, sizeof(data_dest)); 85756668Sshin } 85856668Sshin | NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 85956668Sshin NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 86056668Sshin NUMBER 86156668Sshin { 86256668Sshin char *a, *p; 86356668Sshin 86456668Sshin memset(&data_dest, 0, sizeof(data_dest)); 86556668Sshin data_dest.su_sin.sin_len = sizeof(struct sockaddr_in); 86656668Sshin data_dest.su_family = AF_INET; 86756668Sshin p = (char *)&data_dest.su_port; 86892272Smaxim p[0] = $15.i; p[1] = $17.i; 86956668Sshin a = (char *)&data_dest.su_sin.sin_addr; 87092272Smaxim a[0] = $5.i; a[1] = $7.i; a[2] = $9.i; a[3] = $11.i; 87192272Smaxim if ($1.i != 4 || $3.i != 4 || $13.i != 2) 87256668Sshin memset(&data_dest, 0, sizeof(data_dest)); 87356668Sshin } 87456668Sshin ; 87556668Sshin 8761592Srgrimesform_code 8771592Srgrimes : N 8781592Srgrimes { 8791592Srgrimes $$ = FORM_N; 8801592Srgrimes } 8811592Srgrimes | T 8821592Srgrimes { 8831592Srgrimes $$ = FORM_T; 8841592Srgrimes } 8851592Srgrimes | C 8861592Srgrimes { 8871592Srgrimes $$ = FORM_C; 8881592Srgrimes } 8891592Srgrimes ; 8901592Srgrimes 8911592Srgrimestype_code 8921592Srgrimes : A 8931592Srgrimes { 8941592Srgrimes cmd_type = TYPE_A; 8951592Srgrimes cmd_form = FORM_N; 8961592Srgrimes } 8971592Srgrimes | A SP form_code 8981592Srgrimes { 8991592Srgrimes cmd_type = TYPE_A; 9001592Srgrimes cmd_form = $3; 9011592Srgrimes } 9021592Srgrimes | E 9031592Srgrimes { 9041592Srgrimes cmd_type = TYPE_E; 9051592Srgrimes cmd_form = FORM_N; 9061592Srgrimes } 9071592Srgrimes | E SP form_code 9081592Srgrimes { 9091592Srgrimes cmd_type = TYPE_E; 9101592Srgrimes cmd_form = $3; 9111592Srgrimes } 9121592Srgrimes | I 9131592Srgrimes { 9141592Srgrimes cmd_type = TYPE_I; 9151592Srgrimes } 9161592Srgrimes | L 9171592Srgrimes { 9181592Srgrimes cmd_type = TYPE_L; 919103949Smike cmd_bytesz = CHAR_BIT; 9201592Srgrimes } 9211592Srgrimes | L SP byte_size 9221592Srgrimes { 9231592Srgrimes cmd_type = TYPE_L; 9241592Srgrimes cmd_bytesz = $3; 9251592Srgrimes } 9261592Srgrimes /* this is for a bug in the BBN ftp */ 9271592Srgrimes | L byte_size 9281592Srgrimes { 9291592Srgrimes cmd_type = TYPE_L; 9301592Srgrimes cmd_bytesz = $2; 9311592Srgrimes } 9321592Srgrimes ; 9331592Srgrimes 9341592Srgrimesstruct_code 9351592Srgrimes : F 9361592Srgrimes { 9371592Srgrimes $$ = STRU_F; 9381592Srgrimes } 9391592Srgrimes | R 9401592Srgrimes { 9411592Srgrimes $$ = STRU_R; 9421592Srgrimes } 9431592Srgrimes | P 9441592Srgrimes { 9451592Srgrimes $$ = STRU_P; 9461592Srgrimes } 9471592Srgrimes ; 9481592Srgrimes 9491592Srgrimesmode_code 9501592Srgrimes : S 9511592Srgrimes { 9521592Srgrimes $$ = MODE_S; 9531592Srgrimes } 9541592Srgrimes | B 9551592Srgrimes { 9561592Srgrimes $$ = MODE_B; 9571592Srgrimes } 9581592Srgrimes | C 9591592Srgrimes { 9601592Srgrimes $$ = MODE_C; 9611592Srgrimes } 9621592Srgrimes ; 9631592Srgrimes 9641592Srgrimespathname 9651592Srgrimes : pathstring 9661592Srgrimes { 9671592Srgrimes /* 9681592Srgrimes * Problem: this production is used for all pathname 9691592Srgrimes * processing, but only gives a 550 error reply. 9701592Srgrimes * This is a valid reply in some cases but not in others. 9711592Srgrimes */ 97275567Speter if (logged_in && $1) { 9731592Srgrimes glob_t gl; 9741592Srgrimes int flags = 975100222Smikeh GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE; 9761592Srgrimes 9771592Srgrimes memset(&gl, 0, sizeof(gl)); 97875560Sjedgar flags |= GLOB_MAXPATH; 97975560Sjedgar gl.gl_matchc = MAXGLOBARGS; 9801592Srgrimes if (glob($1, flags, NULL, &gl) || 9811592Srgrimes gl.gl_pathc == 0) { 982101380Syar reply(550, "wildcard expansion error"); 9831592Srgrimes $$ = NULL; 98475567Speter } else if (gl.gl_pathc > 1) { 98575567Speter reply(550, "ambiguous"); 98675567Speter $$ = NULL; 9871592Srgrimes } else { 9881592Srgrimes $$ = strdup(gl.gl_pathv[0]); 9891592Srgrimes } 9901592Srgrimes globfree(&gl); 9911592Srgrimes free($1); 9921592Srgrimes } else 9931592Srgrimes $$ = $1; 9941592Srgrimes } 9951592Srgrimes ; 9961592Srgrimes 9971592Srgrimespathstring 9981592Srgrimes : STRING 9991592Srgrimes ; 10001592Srgrimes 10011592Srgrimesoctal_number 10021592Srgrimes : NUMBER 10031592Srgrimes { 10041592Srgrimes int ret, dec, multby, digit; 10051592Srgrimes 10061592Srgrimes /* 10071592Srgrimes * Convert a number that was read as decimal number 10081592Srgrimes * to what it would be if it had been read as octal. 10091592Srgrimes */ 101092272Smaxim dec = $1.i; 10111592Srgrimes multby = 1; 10121592Srgrimes ret = 0; 10131592Srgrimes while (dec) { 10141592Srgrimes digit = dec%10; 10151592Srgrimes if (digit > 7) { 10161592Srgrimes ret = -1; 10171592Srgrimes break; 10181592Srgrimes } 10191592Srgrimes ret += digit * multby; 10201592Srgrimes multby *= 8; 10211592Srgrimes dec /= 10; 10221592Srgrimes } 10231592Srgrimes $$ = ret; 10241592Srgrimes } 10251592Srgrimes ; 10261592Srgrimes 10271592Srgrimes 10281592Srgrimescheck_login 10291592Srgrimes : /* empty */ 10301592Srgrimes { 103170102Sphk $$ = check_login1(); 10321592Srgrimes } 10331592Srgrimes ; 10341592Srgrimes 103570102Sphkcheck_login_epsv 103670102Sphk : /* empty */ 103770102Sphk { 103870102Sphk if (noepsv) { 103970102Sphk reply(500, "EPSV command disabled"); 104070102Sphk $$ = 0; 104170102Sphk } 104270102Sphk else 104370102Sphk $$ = check_login1(); 104470102Sphk } 104570102Sphk ; 104670102Sphk 104770102Sphkcheck_login_ro 104870102Sphk : /* empty */ 104970102Sphk { 105070102Sphk if (readonly) { 105172710Sdes reply(550, "Permission denied."); 105270102Sphk $$ = 0; 105370102Sphk } 105470102Sphk else 105570102Sphk $$ = check_login1(); 105670102Sphk } 105770102Sphk ; 105870102Sphk 10591592Srgrimes%% 10601592Srgrimes 10611592Srgrimes#define CMD 0 /* beginning of command */ 10621592Srgrimes#define ARGS 1 /* expect miscellaneous arguments */ 10631592Srgrimes#define STR1 2 /* expect SP followed by STRING */ 10641592Srgrimes#define STR2 3 /* expect STRING */ 10651592Srgrimes#define OSTR 4 /* optional SP then STRING */ 106675556Sgreen#define ZSTR1 5 /* optional SP then optional STRING */ 10671592Srgrimes#define ZSTR2 6 /* optional STRING after SP */ 10681592Srgrimes#define SITECMD 7 /* SITE command */ 10691592Srgrimes#define NSTR 8 /* Number followed by a string */ 10701592Srgrimes 107175560Sjedgar#define MAXGLOBARGS 1000 107275560Sjedgar 1073101034Syar#define MAXASIZE 10240 /* Deny ASCII SIZE on files larger than that */ 1074101034Syar 10751592Srgrimesstruct tab { 10761592Srgrimes char *name; 10771592Srgrimes short token; 10781592Srgrimes short state; 10791592Srgrimes short implemented; /* 1 if command is implemented */ 10801592Srgrimes char *help; 10811592Srgrimes}; 10821592Srgrimes 10831592Srgrimesstruct tab cmdtab[] = { /* In order defined in RFC 765 */ 10841592Srgrimes { "USER", USER, STR1, 1, "<sp> username" }, 108575556Sgreen { "PASS", PASS, ZSTR1, 1, "[<sp> [password]]" }, 10861592Srgrimes { "ACCT", ACCT, STR1, 0, "(specify account)" }, 10871592Srgrimes { "SMNT", SMNT, ARGS, 0, "(structure mount)" }, 10881592Srgrimes { "REIN", REIN, ARGS, 0, "(reinitialize server state)" }, 10891592Srgrimes { "QUIT", QUIT, ARGS, 1, "(terminate service)", }, 1090101806Syar { "PORT", PORT, ARGS, 1, "<sp> b0, b1, b2, b3, b4, b5" }, 109156668Sshin { "LPRT", LPRT, ARGS, 1, "<sp> af, hal, h1, h2, h3,..., pal, p1, p2..." }, 109256668Sshin { "EPRT", EPRT, STR1, 1, "<sp> |af|addr|port|" }, 10931592Srgrimes { "PASV", PASV, ARGS, 1, "(set server in passive mode)" }, 109456668Sshin { "LPSV", LPSV, ARGS, 1, "(set server in passive mode)" }, 109556668Sshin { "EPSV", EPSV, ARGS, 1, "[<sp> af|ALL]" }, 1096101806Syar { "TYPE", TYPE, ARGS, 1, "<sp> { A | E | I | L }" }, 10971592Srgrimes { "STRU", STRU, ARGS, 1, "(specify file structure)" }, 10981592Srgrimes { "MODE", MODE, ARGS, 1, "(specify transfer mode)" }, 10991592Srgrimes { "RETR", RETR, STR1, 1, "<sp> file-name" }, 11001592Srgrimes { "STOR", STOR, STR1, 1, "<sp> file-name" }, 11011592Srgrimes { "APPE", APPE, STR1, 1, "<sp> file-name" }, 11021592Srgrimes { "MLFL", MLFL, OSTR, 0, "(mail file)" }, 11031592Srgrimes { "MAIL", MAIL, OSTR, 0, "(mail to user)" }, 11041592Srgrimes { "MSND", MSND, OSTR, 0, "(mail send to terminal)" }, 11051592Srgrimes { "MSOM", MSOM, OSTR, 0, "(mail send to terminal or mailbox)" }, 11061592Srgrimes { "MSAM", MSAM, OSTR, 0, "(mail send to terminal and mailbox)" }, 11071592Srgrimes { "MRSQ", MRSQ, OSTR, 0, "(mail recipient scheme question)" }, 11081592Srgrimes { "MRCP", MRCP, STR1, 0, "(mail recipient)" }, 11091592Srgrimes { "ALLO", ALLO, ARGS, 1, "allocate storage (vacuously)" }, 11101592Srgrimes { "REST", REST, ARGS, 1, "<sp> offset (restart command)" }, 11111592Srgrimes { "RNFR", RNFR, STR1, 1, "<sp> file-name" }, 11121592Srgrimes { "RNTO", RNTO, STR1, 1, "<sp> file-name" }, 11131592Srgrimes { "ABOR", ABOR, ARGS, 1, "(abort operation)" }, 11141592Srgrimes { "DELE", DELE, STR1, 1, "<sp> file-name" }, 11151592Srgrimes { "CWD", CWD, OSTR, 1, "[ <sp> directory-name ]" }, 11161592Srgrimes { "XCWD", CWD, OSTR, 1, "[ <sp> directory-name ]" }, 11171592Srgrimes { "LIST", LIST, OSTR, 1, "[ <sp> path-name ]" }, 11181592Srgrimes { "NLST", NLST, OSTR, 1, "[ <sp> path-name ]" }, 11191592Srgrimes { "SITE", SITE, SITECMD, 1, "site-cmd [ <sp> arguments ]" }, 11201592Srgrimes { "SYST", SYST, ARGS, 1, "(get type of operating system)" }, 11211592Srgrimes { "STAT", STAT, OSTR, 1, "[ <sp> path-name ]" }, 11221592Srgrimes { "HELP", HELP, OSTR, 1, "[ <sp> <string> ]" }, 11231592Srgrimes { "NOOP", NOOP, ARGS, 1, "" }, 11241592Srgrimes { "MKD", MKD, STR1, 1, "<sp> path-name" }, 11251592Srgrimes { "XMKD", MKD, STR1, 1, "<sp> path-name" }, 11261592Srgrimes { "RMD", RMD, STR1, 1, "<sp> path-name" }, 11271592Srgrimes { "XRMD", RMD, STR1, 1, "<sp> path-name" }, 11281592Srgrimes { "PWD", PWD, ARGS, 1, "(return current directory)" }, 11291592Srgrimes { "XPWD", PWD, ARGS, 1, "(return current directory)" }, 11301592Srgrimes { "CDUP", CDUP, ARGS, 1, "(change to parent directory)" }, 11311592Srgrimes { "XCUP", CDUP, ARGS, 1, "(change to parent directory)" }, 11321592Srgrimes { "STOU", STOU, STR1, 1, "<sp> file-name" }, 11331592Srgrimes { "SIZE", SIZE, OSTR, 1, "<sp> path-name" }, 11341592Srgrimes { "MDTM", MDTM, OSTR, 1, "<sp> path-name" }, 11351592Srgrimes { NULL, 0, 0, 0, 0 } 11361592Srgrimes}; 11371592Srgrimes 11381592Srgrimesstruct tab sitetab[] = { 113975535Sphk { "MD5", MDFIVE, STR1, 1, "[ <sp> file-name ]" }, 11401592Srgrimes { "UMASK", UMASK, ARGS, 1, "[ <sp> umask ]" }, 11411592Srgrimes { "IDLE", IDLE, ARGS, 1, "[ <sp> maximum-idle-time ]" }, 11421592Srgrimes { "CHMOD", CHMOD, NSTR, 1, "<sp> mode <sp> file-name" }, 11431592Srgrimes { "HELP", HELP, OSTR, 1, "[ <sp> <string> ]" }, 11441592Srgrimes { NULL, 0, 0, 0, 0 } 11451592Srgrimes}; 11461592Srgrimes 114790148Simpstatic char *copy(char *); 114890148Simpstatic void help(struct tab *, char *); 11491592Srgrimesstatic struct tab * 115090148Simp lookup(struct tab *, char *); 115190148Simpstatic int port_check(const char *); 115290148Simpstatic int port_check_v6(const char *); 115390148Simpstatic void sizecmd(char *); 115490148Simpstatic void toolong(int); 115590148Simpstatic void v4map_data_dest(void); 115690148Simpstatic int yylex(void); 11571592Srgrimes 11581592Srgrimesstatic struct tab * 115990148Simplookup(struct tab *p, char *cmd) 11601592Srgrimes{ 11611592Srgrimes 11621592Srgrimes for (; p->name != NULL; p++) 11631592Srgrimes if (strcmp(cmd, p->name) == 0) 11641592Srgrimes return (p); 11651592Srgrimes return (0); 11661592Srgrimes} 11671592Srgrimes 11681592Srgrimes#include <arpa/telnet.h> 11691592Srgrimes 11701592Srgrimes/* 11711592Srgrimes * getline - a hacked up version of fgets to ignore TELNET escape codes. 11721592Srgrimes */ 11731592Srgrimeschar * 117490148Simpgetline(char *s, int n, FILE *iop) 11751592Srgrimes{ 11761592Srgrimes int c; 11771592Srgrimes register char *cs; 11781592Srgrimes 11791592Srgrimes cs = s; 11801592Srgrimes/* tmpline may contain saved command from urgent mode interruption */ 11811592Srgrimes for (c = 0; tmpline[c] != '\0' && --n > 0; ++c) { 11821592Srgrimes *cs++ = tmpline[c]; 11831592Srgrimes if (tmpline[c] == '\n') { 11841592Srgrimes *cs++ = '\0'; 118576096Smarkm if (ftpdebug) 11861592Srgrimes syslog(LOG_DEBUG, "command: %s", s); 11871592Srgrimes tmpline[0] = '\0'; 11881592Srgrimes return(s); 11891592Srgrimes } 11901592Srgrimes if (c == 0) 11911592Srgrimes tmpline[0] = '\0'; 11921592Srgrimes } 11931592Srgrimes while ((c = getc(iop)) != EOF) { 11941592Srgrimes c &= 0377; 11951592Srgrimes if (c == IAC) { 11961592Srgrimes if ((c = getc(iop)) != EOF) { 11971592Srgrimes c &= 0377; 11981592Srgrimes switch (c) { 11991592Srgrimes case WILL: 12001592Srgrimes case WONT: 12011592Srgrimes c = getc(iop); 12021592Srgrimes printf("%c%c%c", IAC, DONT, 0377&c); 12031592Srgrimes (void) fflush(stdout); 12041592Srgrimes continue; 12051592Srgrimes case DO: 12061592Srgrimes case DONT: 12071592Srgrimes c = getc(iop); 12081592Srgrimes printf("%c%c%c", IAC, WONT, 0377&c); 12091592Srgrimes (void) fflush(stdout); 12101592Srgrimes continue; 12111592Srgrimes case IAC: 12121592Srgrimes break; 12131592Srgrimes default: 12141592Srgrimes continue; /* ignore command */ 12151592Srgrimes } 12161592Srgrimes } 12171592Srgrimes } 12181592Srgrimes *cs++ = c; 12191592Srgrimes if (--n <= 0 || c == '\n') 12201592Srgrimes break; 12211592Srgrimes } 12221592Srgrimes if (c == EOF && cs == s) 12231592Srgrimes return (NULL); 12241592Srgrimes *cs++ = '\0'; 122576096Smarkm if (ftpdebug) { 12261592Srgrimes if (!guest && strncasecmp("pass ", s, 5) == 0) { 12271592Srgrimes /* Don't syslog passwords */ 12281592Srgrimes syslog(LOG_DEBUG, "command: %.5s ???", s); 12291592Srgrimes } else { 12301592Srgrimes register char *cp; 12311592Srgrimes register int len; 12321592Srgrimes 12331592Srgrimes /* Don't syslog trailing CR-LF */ 12341592Srgrimes len = strlen(s); 12351592Srgrimes cp = s + len - 1; 12361592Srgrimes while (cp >= s && (*cp == '\n' || *cp == '\r')) { 12371592Srgrimes --cp; 12381592Srgrimes --len; 12391592Srgrimes } 12401592Srgrimes syslog(LOG_DEBUG, "command: %.*s", len, s); 12411592Srgrimes } 12421592Srgrimes } 12431592Srgrimes return (s); 12441592Srgrimes} 12451592Srgrimes 12461592Srgrimesstatic void 124790148Simptoolong(int signo) 12481592Srgrimes{ 12491592Srgrimes 12501592Srgrimes reply(421, 12511592Srgrimes "Timeout (%d seconds): closing control connection.", timeout); 12521592Srgrimes if (logging) 12531592Srgrimes syslog(LOG_INFO, "User %s timed out after %d seconds", 12541592Srgrimes (pw ? pw -> pw_name : "unknown"), timeout); 12551592Srgrimes dologout(1); 12561592Srgrimes} 12571592Srgrimes 12581592Srgrimesstatic int 125990148Simpyylex(void) 12601592Srgrimes{ 126189935Syar static int cpos; 12621592Srgrimes char *cp, *cp2; 12631592Srgrimes struct tab *p; 12641592Srgrimes int n; 12651592Srgrimes char c; 12661592Srgrimes 12671592Srgrimes for (;;) { 12681592Srgrimes switch (state) { 12691592Srgrimes 12701592Srgrimes case CMD: 12711592Srgrimes (void) signal(SIGALRM, toolong); 12721592Srgrimes (void) alarm((unsigned) timeout); 12731592Srgrimes if (getline(cbuf, sizeof(cbuf)-1, stdin) == NULL) { 12741592Srgrimes reply(221, "You could at least say goodbye."); 12751592Srgrimes dologout(0); 12761592Srgrimes } 12771592Srgrimes (void) alarm(0); 12781592Srgrimes#ifdef SETPROCTITLE 127929574Sphk if (strncasecmp(cbuf, "PASS", 4) != 0) 12801592Srgrimes setproctitle("%s: %s", proctitle, cbuf); 12811592Srgrimes#endif /* SETPROCTITLE */ 12821592Srgrimes if ((cp = strchr(cbuf, '\r'))) { 12831592Srgrimes *cp++ = '\n'; 12841592Srgrimes *cp = '\0'; 12851592Srgrimes } 12861592Srgrimes if ((cp = strpbrk(cbuf, " \n"))) 12871592Srgrimes cpos = cp - cbuf; 12881592Srgrimes if (cpos == 0) 12891592Srgrimes cpos = 4; 12901592Srgrimes c = cbuf[cpos]; 12911592Srgrimes cbuf[cpos] = '\0'; 12921592Srgrimes upper(cbuf); 12931592Srgrimes p = lookup(cmdtab, cbuf); 12941592Srgrimes cbuf[cpos] = c; 12953776Spst if (p != 0) { 1296102565Syar yylval.s = p->name; 1297102565Syar if (!p->implemented) 1298102565Syar return (NOTIMPL); /* state remains CMD */ 12991592Srgrimes state = p->state; 13001592Srgrimes return (p->token); 13011592Srgrimes } 13021592Srgrimes break; 13031592Srgrimes 13041592Srgrimes case SITECMD: 13051592Srgrimes if (cbuf[cpos] == ' ') { 13061592Srgrimes cpos++; 13071592Srgrimes return (SP); 13081592Srgrimes } 13091592Srgrimes cp = &cbuf[cpos]; 13101592Srgrimes if ((cp2 = strpbrk(cp, " \n"))) 13111592Srgrimes cpos = cp2 - cbuf; 13121592Srgrimes c = cbuf[cpos]; 13131592Srgrimes cbuf[cpos] = '\0'; 13141592Srgrimes upper(cp); 13151592Srgrimes p = lookup(sitetab, cp); 13161592Srgrimes cbuf[cpos] = c; 13173777Spst if (guest == 0 && p != 0) { 1318102565Syar yylval.s = p->name; 1319102565Syar if (!p->implemented) { 13201592Srgrimes state = CMD; 1321102565Syar return (NOTIMPL); 13221592Srgrimes } 13231592Srgrimes state = p->state; 13241592Srgrimes return (p->token); 13251592Srgrimes } 13261592Srgrimes state = CMD; 13271592Srgrimes break; 13281592Srgrimes 132975556Sgreen case ZSTR1: 13301592Srgrimes case OSTR: 13311592Srgrimes if (cbuf[cpos] == '\n') { 13321592Srgrimes state = CMD; 13331592Srgrimes return (CRLF); 13341592Srgrimes } 13351592Srgrimes /* FALLTHROUGH */ 13361592Srgrimes 13371592Srgrimes case STR1: 13381592Srgrimes dostr1: 13391592Srgrimes if (cbuf[cpos] == ' ') { 13401592Srgrimes cpos++; 134151979Salfred state = state == OSTR ? STR2 : state+1; 13421592Srgrimes return (SP); 13431592Srgrimes } 13441592Srgrimes break; 13451592Srgrimes 13461592Srgrimes case ZSTR2: 13471592Srgrimes if (cbuf[cpos] == '\n') { 13481592Srgrimes state = CMD; 13491592Srgrimes return (CRLF); 13501592Srgrimes } 13511592Srgrimes /* FALLTHROUGH */ 13521592Srgrimes 13531592Srgrimes case STR2: 13541592Srgrimes cp = &cbuf[cpos]; 13551592Srgrimes n = strlen(cp); 13561592Srgrimes cpos += n - 1; 13571592Srgrimes /* 13581592Srgrimes * Make sure the string is nonempty and \n terminated. 13591592Srgrimes */ 13601592Srgrimes if (n > 1 && cbuf[cpos] == '\n') { 13611592Srgrimes cbuf[cpos] = '\0'; 13621592Srgrimes yylval.s = copy(cp); 13631592Srgrimes cbuf[cpos] = '\n'; 13641592Srgrimes state = ARGS; 13651592Srgrimes return (STRING); 13661592Srgrimes } 13671592Srgrimes break; 13681592Srgrimes 13691592Srgrimes case NSTR: 13701592Srgrimes if (cbuf[cpos] == ' ') { 13711592Srgrimes cpos++; 13721592Srgrimes return (SP); 13731592Srgrimes } 13741592Srgrimes if (isdigit(cbuf[cpos])) { 13751592Srgrimes cp = &cbuf[cpos]; 13761592Srgrimes while (isdigit(cbuf[++cpos])) 13771592Srgrimes ; 13781592Srgrimes c = cbuf[cpos]; 13791592Srgrimes cbuf[cpos] = '\0'; 138092272Smaxim yylval.u.i = atoi(cp); 13811592Srgrimes cbuf[cpos] = c; 13821592Srgrimes state = STR1; 13831592Srgrimes return (NUMBER); 13841592Srgrimes } 13851592Srgrimes state = STR1; 13861592Srgrimes goto dostr1; 13871592Srgrimes 13881592Srgrimes case ARGS: 13891592Srgrimes if (isdigit(cbuf[cpos])) { 13901592Srgrimes cp = &cbuf[cpos]; 13911592Srgrimes while (isdigit(cbuf[++cpos])) 13921592Srgrimes ; 13931592Srgrimes c = cbuf[cpos]; 13941592Srgrimes cbuf[cpos] = '\0'; 139592272Smaxim yylval.u.i = atoi(cp); 139692272Smaxim yylval.u.o = strtoull(cp, (char **)NULL, 10); 13971592Srgrimes cbuf[cpos] = c; 13981592Srgrimes return (NUMBER); 13991592Srgrimes } 140056668Sshin if (strncasecmp(&cbuf[cpos], "ALL", 3) == 0 140156668Sshin && !isalnum(cbuf[cpos + 3])) { 140256668Sshin cpos += 3; 140356668Sshin return ALL; 140456668Sshin } 14051592Srgrimes switch (cbuf[cpos++]) { 14061592Srgrimes 14071592Srgrimes case '\n': 14081592Srgrimes state = CMD; 14091592Srgrimes return (CRLF); 14101592Srgrimes 14111592Srgrimes case ' ': 14121592Srgrimes return (SP); 14131592Srgrimes 14141592Srgrimes case ',': 14151592Srgrimes return (COMMA); 14161592Srgrimes 14171592Srgrimes case 'A': 14181592Srgrimes case 'a': 14191592Srgrimes return (A); 14201592Srgrimes 14211592Srgrimes case 'B': 14221592Srgrimes case 'b': 14231592Srgrimes return (B); 14241592Srgrimes 14251592Srgrimes case 'C': 14261592Srgrimes case 'c': 14271592Srgrimes return (C); 14281592Srgrimes 14291592Srgrimes case 'E': 14301592Srgrimes case 'e': 14311592Srgrimes return (E); 14321592Srgrimes 14331592Srgrimes case 'F': 14341592Srgrimes case 'f': 14351592Srgrimes return (F); 14361592Srgrimes 14371592Srgrimes case 'I': 14381592Srgrimes case 'i': 14391592Srgrimes return (I); 14401592Srgrimes 14411592Srgrimes case 'L': 14421592Srgrimes case 'l': 14431592Srgrimes return (L); 14441592Srgrimes 14451592Srgrimes case 'N': 14461592Srgrimes case 'n': 14471592Srgrimes return (N); 14481592Srgrimes 14491592Srgrimes case 'P': 14501592Srgrimes case 'p': 14511592Srgrimes return (P); 14521592Srgrimes 14531592Srgrimes case 'R': 14541592Srgrimes case 'r': 14551592Srgrimes return (R); 14561592Srgrimes 14571592Srgrimes case 'S': 14581592Srgrimes case 's': 14591592Srgrimes return (S); 14601592Srgrimes 14611592Srgrimes case 'T': 14621592Srgrimes case 't': 14631592Srgrimes return (T); 14641592Srgrimes 14651592Srgrimes } 14661592Srgrimes break; 14671592Srgrimes 14681592Srgrimes default: 146976096Smarkm fatalerror("Unknown state in scanner."); 14701592Srgrimes } 14711592Srgrimes state = CMD; 147289935Syar return (LEXERR); 14731592Srgrimes } 14741592Srgrimes} 14751592Srgrimes 14761592Srgrimesvoid 147790148Simpupper(char *s) 14781592Srgrimes{ 14791592Srgrimes while (*s != '\0') { 14801592Srgrimes if (islower(*s)) 14811592Srgrimes *s = toupper(*s); 14821592Srgrimes s++; 14831592Srgrimes } 14841592Srgrimes} 14851592Srgrimes 14861592Srgrimesstatic char * 148790148Simpcopy(char *s) 14881592Srgrimes{ 14891592Srgrimes char *p; 14901592Srgrimes 14911592Srgrimes p = malloc((unsigned) strlen(s) + 1); 14921592Srgrimes if (p == NULL) 149376096Smarkm fatalerror("Ran out of memory."); 14941592Srgrimes (void) strcpy(p, s); 14951592Srgrimes return (p); 14961592Srgrimes} 14971592Srgrimes 14981592Srgrimesstatic void 149990148Simphelp(struct tab *ctab, char *s) 15001592Srgrimes{ 15011592Srgrimes struct tab *c; 15021592Srgrimes int width, NCMDS; 15031592Srgrimes char *type; 15041592Srgrimes 15051592Srgrimes if (ctab == sitetab) 15061592Srgrimes type = "SITE "; 15071592Srgrimes else 15081592Srgrimes type = ""; 15091592Srgrimes width = 0, NCMDS = 0; 15101592Srgrimes for (c = ctab; c->name != NULL; c++) { 15111592Srgrimes int len = strlen(c->name); 15121592Srgrimes 15131592Srgrimes if (len > width) 15141592Srgrimes width = len; 15151592Srgrimes NCMDS++; 15161592Srgrimes } 15171592Srgrimes width = (width + 8) &~ 7; 15181592Srgrimes if (s == 0) { 15191592Srgrimes int i, j, w; 15201592Srgrimes int columns, lines; 15211592Srgrimes 15221592Srgrimes lreply(214, "The following %scommands are recognized %s.", 15231592Srgrimes type, "(* =>'s unimplemented)"); 15241592Srgrimes columns = 76 / width; 15251592Srgrimes if (columns == 0) 15261592Srgrimes columns = 1; 15271592Srgrimes lines = (NCMDS + columns - 1) / columns; 15281592Srgrimes for (i = 0; i < lines; i++) { 15291592Srgrimes printf(" "); 15301592Srgrimes for (j = 0; j < columns; j++) { 15311592Srgrimes c = ctab + j * lines + i; 15321592Srgrimes printf("%s%c", c->name, 15331592Srgrimes c->implemented ? ' ' : '*'); 15341592Srgrimes if (c + lines >= &ctab[NCMDS]) 15351592Srgrimes break; 15361592Srgrimes w = strlen(c->name) + 1; 15371592Srgrimes while (w < width) { 15381592Srgrimes putchar(' '); 15391592Srgrimes w++; 15401592Srgrimes } 15411592Srgrimes } 15421592Srgrimes printf("\r\n"); 15431592Srgrimes } 15441592Srgrimes (void) fflush(stdout); 15451592Srgrimes reply(214, "Direct comments to ftp-bugs@%s.", hostname); 15461592Srgrimes return; 15471592Srgrimes } 15481592Srgrimes upper(s); 15491592Srgrimes c = lookup(ctab, s); 15501592Srgrimes if (c == (struct tab *)0) { 15511592Srgrimes reply(502, "Unknown command %s.", s); 15521592Srgrimes return; 15531592Srgrimes } 15541592Srgrimes if (c->implemented) 15551592Srgrimes reply(214, "Syntax: %s%s %s", type, c->name, c->help); 15561592Srgrimes else 15571592Srgrimes reply(214, "%s%-*s\t%s; unimplemented.", type, width, 15581592Srgrimes c->name, c->help); 15591592Srgrimes} 15601592Srgrimes 15611592Srgrimesstatic void 156290148Simpsizecmd(char *filename) 15631592Srgrimes{ 15641592Srgrimes switch (type) { 15651592Srgrimes case TYPE_L: 15661592Srgrimes case TYPE_I: { 15671592Srgrimes struct stat stbuf; 156863350Sdes if (stat(filename, &stbuf) < 0) 156963350Sdes perror_reply(550, filename); 157063350Sdes else if (!S_ISREG(stbuf.st_mode)) 15711592Srgrimes reply(550, "%s: not a plain file.", filename); 15721592Srgrimes else 15731592Srgrimes reply(213, "%qu", stbuf.st_size); 15741592Srgrimes break; } 15751592Srgrimes case TYPE_A: { 15761592Srgrimes FILE *fin; 15771592Srgrimes int c; 15781592Srgrimes off_t count; 15791592Srgrimes struct stat stbuf; 15801592Srgrimes fin = fopen(filename, "r"); 15811592Srgrimes if (fin == NULL) { 15821592Srgrimes perror_reply(550, filename); 15831592Srgrimes return; 15841592Srgrimes } 158563350Sdes if (fstat(fileno(fin), &stbuf) < 0) { 158663350Sdes perror_reply(550, filename); 158763350Sdes (void) fclose(fin); 158863350Sdes return; 158963350Sdes } else if (!S_ISREG(stbuf.st_mode)) { 15901592Srgrimes reply(550, "%s: not a plain file.", filename); 15911592Srgrimes (void) fclose(fin); 15921592Srgrimes return; 1593101034Syar } else if (stbuf.st_size > MAXASIZE) { 1594101034Syar reply(550, "%s: too large for type A SIZE.", filename); 1595101034Syar (void) fclose(fin); 1596101034Syar return; 15971592Srgrimes } 15981592Srgrimes 15991592Srgrimes count = 0; 16001592Srgrimes while((c=getc(fin)) != EOF) { 16011592Srgrimes if (c == '\n') /* will get expanded to \r\n */ 16021592Srgrimes count++; 16031592Srgrimes count++; 16041592Srgrimes } 16051592Srgrimes (void) fclose(fin); 16061592Srgrimes 16071592Srgrimes reply(213, "%qd", count); 16081592Srgrimes break; } 16091592Srgrimes default: 1610100684Syar reply(504, "SIZE not implemented for type %s.", 1611100684Syar typenames[type]); 16121592Srgrimes } 16131592Srgrimes} 161456668Sshin 161556668Sshin/* Return 1, if port check is done. Return 0, if not yet. */ 161656668Sshinstatic int 161790148Simpport_check(const char *pcmd) 161856668Sshin{ 161956668Sshin if (his_addr.su_family == AF_INET) { 162056668Sshin if (data_dest.su_family != AF_INET) { 162156668Sshin usedefault = 1; 162256668Sshin reply(500, "Invalid address rejected."); 162356668Sshin return 1; 162456668Sshin } 162556668Sshin if (paranoid && 162656668Sshin ((ntohs(data_dest.su_port) < IPPORT_RESERVED) || 162756668Sshin memcmp(&data_dest.su_sin.sin_addr, 162856668Sshin &his_addr.su_sin.sin_addr, 162956668Sshin sizeof(data_dest.su_sin.sin_addr)))) { 163056668Sshin usedefault = 1; 163156668Sshin reply(500, "Illegal PORT range rejected."); 163256668Sshin } else { 163356668Sshin usedefault = 0; 163456668Sshin if (pdata >= 0) { 163556668Sshin (void) close(pdata); 163656668Sshin pdata = -1; 163756668Sshin } 163856668Sshin reply(200, "%s command successful.", pcmd); 163956668Sshin } 164056668Sshin return 1; 164156668Sshin } 164256668Sshin return 0; 164356668Sshin} 164456668Sshin 164570102Sphkstatic int 164690148Simpcheck_login1(void) 164770102Sphk{ 164870102Sphk if (logged_in) 164970102Sphk return 1; 165070102Sphk else { 165170102Sphk reply(530, "Please login with USER and PASS."); 165270102Sphk return 0; 165370102Sphk } 165470102Sphk} 165570102Sphk 165656668Sshin#ifdef INET6 165756668Sshin/* Return 1, if port check is done. Return 0, if not yet. */ 165856668Sshinstatic int 165990148Simpport_check_v6(const char *pcmd) 166056668Sshin{ 166156668Sshin if (his_addr.su_family == AF_INET6) { 166256668Sshin if (IN6_IS_ADDR_V4MAPPED(&his_addr.su_sin6.sin6_addr)) 166356668Sshin /* Convert data_dest into v4 mapped sockaddr.*/ 166456668Sshin v4map_data_dest(); 166556668Sshin if (data_dest.su_family != AF_INET6) { 166656668Sshin usedefault = 1; 166756668Sshin reply(500, "Invalid address rejected."); 166856668Sshin return 1; 166956668Sshin } 167056668Sshin if (paranoid && 167156668Sshin ((ntohs(data_dest.su_port) < IPPORT_RESERVED) || 167256668Sshin memcmp(&data_dest.su_sin6.sin6_addr, 167356668Sshin &his_addr.su_sin6.sin6_addr, 167456668Sshin sizeof(data_dest.su_sin6.sin6_addr)))) { 167556668Sshin usedefault = 1; 167656668Sshin reply(500, "Illegal PORT range rejected."); 167756668Sshin } else { 167856668Sshin usedefault = 0; 167956668Sshin if (pdata >= 0) { 168056668Sshin (void) close(pdata); 168156668Sshin pdata = -1; 168256668Sshin } 168356668Sshin reply(200, "%s command successful.", pcmd); 168456668Sshin } 168556668Sshin return 1; 168656668Sshin } 168756668Sshin return 0; 168856668Sshin} 168956668Sshin 169056668Sshinstatic void 169190148Simpv4map_data_dest(void) 169256668Sshin{ 169356668Sshin struct in_addr savedaddr; 169456668Sshin int savedport; 169556668Sshin 169656668Sshin if (data_dest.su_family != AF_INET) { 169756668Sshin usedefault = 1; 169856668Sshin reply(500, "Invalid address rejected."); 169956668Sshin return; 170056668Sshin } 170156668Sshin 170256668Sshin savedaddr = data_dest.su_sin.sin_addr; 170356668Sshin savedport = data_dest.su_port; 170456668Sshin 170556668Sshin memset(&data_dest, 0, sizeof(data_dest)); 170656668Sshin data_dest.su_sin6.sin6_len = sizeof(struct sockaddr_in6); 170756668Sshin data_dest.su_sin6.sin6_family = AF_INET6; 170856668Sshin data_dest.su_sin6.sin6_port = savedport; 170956668Sshin memset((caddr_t)&data_dest.su_sin6.sin6_addr.s6_addr[10], 0xff, 2); 171056668Sshin memcpy((caddr_t)&data_dest.su_sin6.sin6_addr.s6_addr[12], 171156668Sshin (caddr_t)&savedaddr, sizeof(savedaddr)); 171256668Sshin} 171356668Sshin#endif 1714