ftpcmd.y revision 109380
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 109380 2003-01-16 13:27:58Z yar $"; 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" 75109380Syar#include "pathnames.h" 761592Srgrimes 7756668Sshinextern union sockunion data_dest, his_addr; 781592Srgrimesextern int logged_in; 791592Srgrimesextern struct passwd *pw; 801592Srgrimesextern int guest; 8117435Spstextern int paranoid; 821592Srgrimesextern int logging; 831592Srgrimesextern int type; 841592Srgrimesextern int form; 8576096Smarkmextern int ftpdebug; 861592Srgrimesextern int timeout; 871592Srgrimesextern int maxtimeout; 881592Srgrimesextern int pdata; 8927650Sdavidnextern char *hostname; 9027650Sdavidnextern char remotehost[]; 911592Srgrimesextern char proctitle[]; 921592Srgrimesextern int usedefault; 931592Srgrimesextern int transflag; 941592Srgrimesextern char tmpline[]; 9570102Sphkextern int readonly; 9670102Sphkextern int noepsv; 9782460Snikextern int noretr; 9882796Ssheldonhextern int noguestretr; 99100684Syarextern char *typenames[]; /* defined in <arpa/ftp.h> included from ftpd.c */ 1001592Srgrimes 1011592Srgrimesoff_t restart_point; 1021592Srgrimes 1031592Srgrimesstatic int cmd_type; 1041592Srgrimesstatic int cmd_form; 1051592Srgrimesstatic int cmd_bytesz; 10689935Syarstatic int state; 1071592Srgrimeschar cbuf[512]; 10888935Sdwmalonechar *fromname = (char *) 0; 1091592Srgrimes 11056668Sshinextern int epsvall; 11156668Sshin 1121592Srgrimes%} 1131592Srgrimes 1141592Srgrimes%union { 11592272Smaxim struct { 11692272Smaxim off_t o; 11792272Smaxim int i; 11892272Smaxim } u; 1191592Srgrimes char *s; 1201592Srgrimes} 1211592Srgrimes 1221592Srgrimes%token 1231592Srgrimes A B C E F I 1241592Srgrimes L N P R S T 12556668Sshin ALL 1261592Srgrimes 1271592Srgrimes SP CRLF COMMA 1281592Srgrimes 1291592Srgrimes USER PASS ACCT REIN QUIT PORT 1301592Srgrimes PASV TYPE STRU MODE RETR STOR 1311592Srgrimes APPE MLFL MAIL MSND MSOM MSAM 1321592Srgrimes MRSQ MRCP ALLO REST RNFR RNTO 1331592Srgrimes ABOR DELE CWD LIST NLST SITE 1341592Srgrimes STAT HELP NOOP MKD RMD PWD 1351592Srgrimes CDUP STOU SMNT SYST SIZE MDTM 13656668Sshin LPRT LPSV EPRT EPSV 1371592Srgrimes 13875535Sphk UMASK IDLE CHMOD MDFIVE 1391592Srgrimes 140102565Syar LEXERR NOTIMPL 1411592Srgrimes 1421592Srgrimes%token <s> STRING 14392272Smaxim%token <u> NUMBER 1441592Srgrimes 14592272Smaxim%type <u.i> check_login octal_number byte_size 14692272Smaxim%type <u.i> check_login_ro check_login_epsv 14792272Smaxim%type <u.i> struct_code mode_code type_code form_code 14875567Speter%type <s> pathstring pathname password username 149102565Syar%type <s> ALL NOTIMPL 1501592Srgrimes 1511592Srgrimes%start cmd_list 1521592Srgrimes 1531592Srgrimes%% 1541592Srgrimes 1551592Srgrimescmd_list 1561592Srgrimes : /* empty */ 1571592Srgrimes | cmd_list cmd 1581592Srgrimes { 15988935Sdwmalone if (fromname) 16088935Sdwmalone free(fromname); 1611592Srgrimes fromname = (char *) 0; 1621592Srgrimes restart_point = (off_t) 0; 1631592Srgrimes } 1641592Srgrimes | cmd_list rcmd 1651592Srgrimes ; 1661592Srgrimes 1671592Srgrimescmd 1681592Srgrimes : USER SP username CRLF 1691592Srgrimes { 1701592Srgrimes user($3); 1711592Srgrimes free($3); 1721592Srgrimes } 1731592Srgrimes | PASS SP password CRLF 1741592Srgrimes { 1751592Srgrimes pass($3); 1761592Srgrimes free($3); 1771592Srgrimes } 17875556Sgreen | PASS CRLF 17975556Sgreen { 18075556Sgreen pass(""); 18175556Sgreen } 18217433Spst | PORT check_login SP host_port CRLF 1831592Srgrimes { 18456668Sshin if (epsvall) { 18556668Sshin reply(501, "no PORT allowed after EPSV ALL"); 18656668Sshin goto port_done; 18756668Sshin } 18856668Sshin if (!$2) 18956668Sshin goto port_done; 19056668Sshin if (port_check("PORT") == 1) 19156668Sshin goto port_done; 19256668Sshin#ifdef INET6 19356668Sshin if ((his_addr.su_family != AF_INET6 || 19456668Sshin !IN6_IS_ADDR_V4MAPPED(&his_addr.su_sin6.sin6_addr))) { 19556668Sshin /* shoud never happen */ 19656668Sshin usedefault = 1; 19756668Sshin reply(500, "Invalid address rejected."); 19856668Sshin goto port_done; 19956668Sshin } 20056668Sshin port_check_v6("pcmd"); 20156668Sshin#endif 20256668Sshin port_done: 20356668Sshin } 20456668Sshin | LPRT check_login SP host_long_port CRLF 20556668Sshin { 20656668Sshin if (epsvall) { 20756668Sshin reply(501, "no LPRT allowed after EPSV ALL"); 20856668Sshin goto lprt_done; 20956668Sshin } 21056668Sshin if (!$2) 21156668Sshin goto lprt_done; 21256668Sshin if (port_check("LPRT") == 1) 21356668Sshin goto lprt_done; 21456668Sshin#ifdef INET6 21556668Sshin if (his_addr.su_family != AF_INET6) { 21656668Sshin usedefault = 1; 21756668Sshin reply(500, "Invalid address rejected."); 21856668Sshin goto lprt_done; 21956668Sshin } 22056668Sshin if (port_check_v6("LPRT") == 1) 22156668Sshin goto lprt_done; 22256668Sshin#endif 22356668Sshin lprt_done: 22456668Sshin } 22556668Sshin | EPRT check_login SP STRING CRLF 22656668Sshin { 22756668Sshin char delim; 22856668Sshin char *tmp = NULL; 22956668Sshin char *p, *q; 23056668Sshin char *result[3]; 23156668Sshin struct addrinfo hints; 23256668Sshin struct addrinfo *res; 23356668Sshin int i; 23456668Sshin 23556668Sshin if (epsvall) { 23656668Sshin reply(501, "no EPRT allowed after EPSV ALL"); 23756668Sshin goto eprt_done; 23856668Sshin } 23956668Sshin if (!$2) 24056668Sshin goto eprt_done; 24156668Sshin 24256668Sshin memset(&data_dest, 0, sizeof(data_dest)); 24356668Sshin tmp = strdup($4); 24476096Smarkm if (ftpdebug) 24556668Sshin syslog(LOG_DEBUG, "%s", tmp); 24656668Sshin if (!tmp) { 24776096Smarkm fatalerror("not enough core"); 24856668Sshin /*NOTREACHED*/ 24956668Sshin } 25056668Sshin p = tmp; 25156668Sshin delim = p[0]; 25256668Sshin p++; 25356668Sshin memset(result, 0, sizeof(result)); 25456668Sshin for (i = 0; i < 3; i++) { 25556668Sshin q = strchr(p, delim); 25656668Sshin if (!q || *q != delim) { 25756668Sshin parsefail: 25856668Sshin reply(500, 25956668Sshin "Invalid argument, rejected."); 26056668Sshin if (tmp) 26156668Sshin free(tmp); 26217433Spst usedefault = 1; 26356668Sshin goto eprt_done; 26417433Spst } 26556668Sshin *q++ = '\0'; 26656668Sshin result[i] = p; 26776096Smarkm if (ftpdebug) 26856668Sshin syslog(LOG_DEBUG, "%d: %s", i, p); 26956668Sshin p = q; 2701592Srgrimes } 27156668Sshin 27256668Sshin /* some more sanity check */ 27356668Sshin p = result[0]; 27456668Sshin while (*p) { 27556668Sshin if (!isdigit(*p)) 27656668Sshin goto parsefail; 27756668Sshin p++; 27856668Sshin } 27956668Sshin p = result[2]; 28056668Sshin while (*p) { 28156668Sshin if (!isdigit(*p)) 28256668Sshin goto parsefail; 28356668Sshin p++; 28456668Sshin } 28556668Sshin 28656668Sshin /* grab address */ 28756668Sshin memset(&hints, 0, sizeof(hints)); 28856668Sshin if (atoi(result[0]) == 1) 28956668Sshin hints.ai_family = PF_INET; 29056668Sshin#ifdef INET6 29156668Sshin else if (atoi(result[0]) == 2) 29256668Sshin hints.ai_family = PF_INET6; 29356668Sshin#endif 29456668Sshin else 29556668Sshin hints.ai_family = PF_UNSPEC; /*XXX*/ 29656668Sshin hints.ai_socktype = SOCK_STREAM; 29756668Sshin i = getaddrinfo(result[1], result[2], &hints, &res); 29856668Sshin if (i) 29956668Sshin goto parsefail; 30056668Sshin memcpy(&data_dest, res->ai_addr, res->ai_addrlen); 30156668Sshin#ifdef INET6 30256668Sshin if (his_addr.su_family == AF_INET6 30356668Sshin && data_dest.su_family == AF_INET6) { 30456668Sshin /* XXX more sanity checks! */ 30556668Sshin data_dest.su_sin6.sin6_scope_id = 30656668Sshin his_addr.su_sin6.sin6_scope_id; 30756668Sshin } 30856668Sshin#endif 30956668Sshin free(tmp); 31056668Sshin tmp = NULL; 31156668Sshin 31256668Sshin if (port_check("EPRT") == 1) 31356668Sshin goto eprt_done; 31456668Sshin#ifdef INET6 31556668Sshin if (his_addr.su_family != AF_INET6) { 31656668Sshin usedefault = 1; 31756668Sshin reply(500, "Invalid address rejected."); 31856668Sshin goto eprt_done; 31956668Sshin } 32056668Sshin if (port_check_v6("EPRT") == 1) 32156668Sshin goto eprt_done; 32256668Sshin#endif 32388935Sdwmalone eprt_done: 32488935Sdwmalone free($4); 3251592Srgrimes } 32617433Spst | PASV check_login CRLF 3271592Srgrimes { 32856668Sshin if (epsvall) 32956668Sshin reply(501, "no PASV allowed after EPSV ALL"); 33056668Sshin else if ($2) 33117433Spst passive(); 3321592Srgrimes } 33356668Sshin | LPSV check_login CRLF 33456668Sshin { 33556668Sshin if (epsvall) 33656668Sshin reply(501, "no LPSV allowed after EPSV ALL"); 33756668Sshin else if ($2) 33856668Sshin long_passive("LPSV", PF_UNSPEC); 33956668Sshin } 34070102Sphk | EPSV check_login_epsv SP NUMBER CRLF 34156668Sshin { 34256668Sshin if ($2) { 34356668Sshin int pf; 34492272Smaxim switch ($4.i) { 34556668Sshin case 1: 34656668Sshin pf = PF_INET; 34756668Sshin break; 34856668Sshin#ifdef INET6 34956668Sshin case 2: 35056668Sshin pf = PF_INET6; 35156668Sshin break; 35256668Sshin#endif 35356668Sshin default: 35456668Sshin pf = -1; /*junk value*/ 35556668Sshin break; 35656668Sshin } 35756668Sshin long_passive("EPSV", pf); 35856668Sshin } 35956668Sshin } 36070102Sphk | EPSV check_login_epsv SP ALL CRLF 36156668Sshin { 36256668Sshin if ($2) { 36356668Sshin reply(200, 36456668Sshin "EPSV ALL command successful."); 36556668Sshin epsvall++; 36656668Sshin } 36756668Sshin } 36870102Sphk | EPSV check_login_epsv CRLF 36956668Sshin { 37056668Sshin if ($2) 37156668Sshin long_passive("EPSV", PF_UNSPEC); 37256668Sshin } 37371278Sjedgar | TYPE check_login SP type_code CRLF 3741592Srgrimes { 37571278Sjedgar if ($2) { 37671278Sjedgar switch (cmd_type) { 3771592Srgrimes 37871278Sjedgar case TYPE_A: 37971278Sjedgar if (cmd_form == FORM_N) { 38071278Sjedgar reply(200, "Type set to A."); 38171278Sjedgar type = cmd_type; 38271278Sjedgar form = cmd_form; 38371278Sjedgar } else 38471278Sjedgar reply(504, "Form must be N."); 38571278Sjedgar break; 3861592Srgrimes 38771278Sjedgar case TYPE_E: 38871278Sjedgar reply(504, "Type E not implemented."); 38971278Sjedgar break; 3901592Srgrimes 39171278Sjedgar case TYPE_I: 39271278Sjedgar reply(200, "Type set to I."); 39371278Sjedgar type = cmd_type; 39471278Sjedgar break; 3951592Srgrimes 39671278Sjedgar case TYPE_L: 397103949Smike#if CHAR_BIT == 8 39871278Sjedgar if (cmd_bytesz == 8) { 39971278Sjedgar reply(200, 40071278Sjedgar "Type set to L (byte size 8)."); 40171278Sjedgar type = cmd_type; 40271278Sjedgar } else 40371278Sjedgar reply(504, "Byte size must be 8."); 404103949Smike#else /* CHAR_BIT == 8 */ 405103949Smike UNIMPLEMENTED for CHAR_BIT != 8 406103949Smike#endif /* CHAR_BIT == 8 */ 40771278Sjedgar } 4081592Srgrimes } 4091592Srgrimes } 41071278Sjedgar | STRU check_login SP struct_code CRLF 4111592Srgrimes { 41271278Sjedgar if ($2) { 41371278Sjedgar switch ($4) { 4141592Srgrimes 41571278Sjedgar case STRU_F: 41671278Sjedgar reply(200, "STRU F ok."); 41771278Sjedgar break; 4181592Srgrimes 41971278Sjedgar default: 42071278Sjedgar reply(504, "Unimplemented STRU type."); 42171278Sjedgar } 4221592Srgrimes } 4231592Srgrimes } 42471278Sjedgar | MODE check_login SP mode_code CRLF 4251592Srgrimes { 42671278Sjedgar if ($2) { 42771278Sjedgar switch ($4) { 4281592Srgrimes 42971278Sjedgar case MODE_S: 43071278Sjedgar reply(200, "MODE S ok."); 43171278Sjedgar break; 43271278Sjedgar 43371278Sjedgar default: 43471278Sjedgar reply(502, "Unimplemented MODE type."); 43571278Sjedgar } 4361592Srgrimes } 4371592Srgrimes } 43871278Sjedgar | ALLO check_login SP NUMBER CRLF 4391592Srgrimes { 44071278Sjedgar if ($2) { 44171278Sjedgar reply(202, "ALLO command ignored."); 44271278Sjedgar } 4431592Srgrimes } 44471278Sjedgar | ALLO check_login SP NUMBER SP R SP NUMBER CRLF 4451592Srgrimes { 44671278Sjedgar if ($2) { 44771278Sjedgar reply(202, "ALLO command ignored."); 44871278Sjedgar } 4491592Srgrimes } 4501592Srgrimes | RETR check_login SP pathname CRLF 4511592Srgrimes { 45282796Ssheldonh if (noretr || (guest && noguestretr)) 45382460Snik reply(500, "RETR command is disabled"); 45482460Snik else if ($2 && $4 != NULL) 4551592Srgrimes retrieve((char *) 0, $4); 45682460Snik 4571592Srgrimes if ($4 != NULL) 4581592Srgrimes free($4); 4591592Srgrimes } 46070102Sphk | STOR check_login_ro SP pathname CRLF 4611592Srgrimes { 4621592Srgrimes if ($2 && $4 != NULL) 4631592Srgrimes store($4, "w", 0); 4641592Srgrimes if ($4 != NULL) 4651592Srgrimes free($4); 4661592Srgrimes } 46770102Sphk | APPE check_login_ro SP pathname CRLF 4681592Srgrimes { 4691592Srgrimes if ($2 && $4 != NULL) 4701592Srgrimes store($4, "a", 0); 4711592Srgrimes if ($4 != NULL) 4721592Srgrimes free($4); 4731592Srgrimes } 4741592Srgrimes | NLST check_login CRLF 4751592Srgrimes { 4761592Srgrimes if ($2) 4771592Srgrimes send_file_list("."); 4781592Srgrimes } 479101395Syar | NLST check_login SP pathstring CRLF 4801592Srgrimes { 481101395Syar if ($2) 4821592Srgrimes send_file_list($4); 483101395Syar free($4); 4841592Srgrimes } 4851592Srgrimes | LIST check_login CRLF 4861592Srgrimes { 4871592Srgrimes if ($2) 488109380Syar retrieve(_PATH_LS " -lgA", ""); 4891592Srgrimes } 49075567Speter | LIST check_login SP pathstring CRLF 4911592Srgrimes { 492101395Syar if ($2) 493109380Syar retrieve(_PATH_LS " -lgA %s", $4); 494101395Syar free($4); 4951592Srgrimes } 4961592Srgrimes | STAT check_login SP pathname CRLF 4971592Srgrimes { 4981592Srgrimes if ($2 && $4 != NULL) 4991592Srgrimes statfilecmd($4); 5001592Srgrimes if ($4 != NULL) 5011592Srgrimes free($4); 5021592Srgrimes } 50371278Sjedgar | STAT check_login CRLF 5041592Srgrimes { 50571278Sjedgar if ($2) { 50671278Sjedgar statcmd(); 50771278Sjedgar } 5081592Srgrimes } 50970102Sphk | DELE check_login_ro SP pathname CRLF 5101592Srgrimes { 5111592Srgrimes if ($2 && $4 != NULL) 5121592Srgrimes delete($4); 5131592Srgrimes if ($4 != NULL) 5141592Srgrimes free($4); 5151592Srgrimes } 51670102Sphk | RNTO check_login_ro SP pathname CRLF 5171592Srgrimes { 518101379Syar if ($2 && $4 != NULL) { 51917433Spst if (fromname) { 52017433Spst renamecmd(fromname, $4); 52117433Spst free(fromname); 52217433Spst fromname = (char *) 0; 52317433Spst } else { 52417433Spst reply(503, "Bad sequence of commands."); 52517433Spst } 5261592Srgrimes } 527101379Syar if ($4 != NULL) 528101379Syar free($4); 5291592Srgrimes } 53071278Sjedgar | ABOR check_login CRLF 5311592Srgrimes { 53271278Sjedgar if ($2) 53371278Sjedgar reply(225, "ABOR command successful."); 5341592Srgrimes } 5351592Srgrimes | CWD check_login CRLF 5361592Srgrimes { 53769234Sdanny if ($2) { 53869234Sdanny if (guest) 53969234Sdanny cwd("/"); 54069234Sdanny else 54169234Sdanny cwd(pw->pw_dir); 54269234Sdanny } 5431592Srgrimes } 5441592Srgrimes | CWD check_login SP pathname CRLF 5451592Srgrimes { 5461592Srgrimes if ($2 && $4 != NULL) 5471592Srgrimes cwd($4); 5481592Srgrimes if ($4 != NULL) 5491592Srgrimes free($4); 5501592Srgrimes } 5511592Srgrimes | HELP CRLF 5521592Srgrimes { 5531592Srgrimes help(cmdtab, (char *) 0); 5541592Srgrimes } 5551592Srgrimes | HELP SP STRING CRLF 5561592Srgrimes { 5571592Srgrimes char *cp = $3; 5581592Srgrimes 5591592Srgrimes if (strncasecmp(cp, "SITE", 4) == 0) { 5601592Srgrimes cp = $3 + 4; 5611592Srgrimes if (*cp == ' ') 5621592Srgrimes cp++; 5631592Srgrimes if (*cp) 5641592Srgrimes help(sitetab, cp); 5651592Srgrimes else 5661592Srgrimes help(sitetab, (char *) 0); 5671592Srgrimes } else 5681592Srgrimes help(cmdtab, $3); 56988935Sdwmalone free($3); 5701592Srgrimes } 5711592Srgrimes | NOOP CRLF 5721592Srgrimes { 5731592Srgrimes reply(200, "NOOP command successful."); 5741592Srgrimes } 57570102Sphk | MKD check_login_ro SP pathname CRLF 5761592Srgrimes { 5771592Srgrimes if ($2 && $4 != NULL) 5781592Srgrimes makedir($4); 5791592Srgrimes if ($4 != NULL) 5801592Srgrimes free($4); 5811592Srgrimes } 58270102Sphk | RMD check_login_ro SP pathname CRLF 5831592Srgrimes { 5841592Srgrimes if ($2 && $4 != NULL) 5851592Srgrimes removedir($4); 5861592Srgrimes if ($4 != NULL) 5871592Srgrimes free($4); 5881592Srgrimes } 5891592Srgrimes | PWD check_login CRLF 5901592Srgrimes { 5911592Srgrimes if ($2) 5921592Srgrimes pwd(); 5931592Srgrimes } 5941592Srgrimes | CDUP check_login CRLF 5951592Srgrimes { 5961592Srgrimes if ($2) 5971592Srgrimes cwd(".."); 5981592Srgrimes } 5991592Srgrimes | SITE SP HELP CRLF 6001592Srgrimes { 6011592Srgrimes help(sitetab, (char *) 0); 6021592Srgrimes } 6031592Srgrimes | SITE SP HELP SP STRING CRLF 6041592Srgrimes { 6051592Srgrimes help(sitetab, $5); 60688935Sdwmalone free($5); 6071592Srgrimes } 60875535Sphk | SITE SP MDFIVE check_login SP pathname CRLF 60975535Sphk { 61075535Sphk char p[64], *q; 61175535Sphk 612101379Syar if ($4 && $6) { 61375535Sphk q = MD5File($6, p); 61475535Sphk if (q != NULL) 61575535Sphk reply(200, "MD5(%s) = %s", $6, p); 61675535Sphk else 61775535Sphk perror_reply(550, $6); 61875535Sphk } 61988935Sdwmalone if ($6) 62088935Sdwmalone free($6); 62175535Sphk } 6221592Srgrimes | SITE SP UMASK check_login CRLF 6231592Srgrimes { 6241592Srgrimes int oldmask; 6251592Srgrimes 6261592Srgrimes if ($4) { 6271592Srgrimes oldmask = umask(0); 6281592Srgrimes (void) umask(oldmask); 6291592Srgrimes reply(200, "Current UMASK is %03o", oldmask); 6301592Srgrimes } 6311592Srgrimes } 6321592Srgrimes | SITE SP UMASK check_login SP octal_number CRLF 6331592Srgrimes { 6341592Srgrimes int oldmask; 6351592Srgrimes 6361592Srgrimes if ($4) { 6371592Srgrimes if (($6 == -1) || ($6 > 0777)) { 6381592Srgrimes reply(501, "Bad UMASK value"); 6391592Srgrimes } else { 6401592Srgrimes oldmask = umask($6); 6411592Srgrimes reply(200, 6421592Srgrimes "UMASK set to %03o (was %03o)", 6431592Srgrimes $6, oldmask); 6441592Srgrimes } 6451592Srgrimes } 6461592Srgrimes } 64770102Sphk | SITE SP CHMOD check_login_ro SP octal_number SP pathname CRLF 6481592Srgrimes { 6491592Srgrimes if ($4 && ($8 != NULL)) { 650101378Syar if (($6 == -1 ) || ($6 > 0777)) 651101378Syar reply(501, "Bad mode value"); 6521592Srgrimes else if (chmod($8, $6) < 0) 6531592Srgrimes perror_reply(550, $8); 6541592Srgrimes else 6551592Srgrimes reply(200, "CHMOD command successful."); 6561592Srgrimes } 6571592Srgrimes if ($8 != NULL) 6581592Srgrimes free($8); 6591592Srgrimes } 66071278Sjedgar | SITE SP check_login IDLE CRLF 6611592Srgrimes { 66271278Sjedgar if ($3) 66371278Sjedgar reply(200, 66471278Sjedgar "Current IDLE time limit is %d seconds; max %d", 66571278Sjedgar timeout, maxtimeout); 6661592Srgrimes } 66771278Sjedgar | SITE SP check_login IDLE SP NUMBER CRLF 6681592Srgrimes { 66971278Sjedgar if ($3) { 67092272Smaxim if ($6.i < 30 || $6.i > maxtimeout) { 67171278Sjedgar reply(501, 67271278Sjedgar "Maximum IDLE time must be between 30 and %d seconds", 67371278Sjedgar maxtimeout); 67471278Sjedgar } else { 67592272Smaxim timeout = $6.i; 67671278Sjedgar (void) alarm((unsigned) timeout); 67771278Sjedgar reply(200, 67871278Sjedgar "Maximum IDLE time set to %d seconds", 67971278Sjedgar timeout); 68071278Sjedgar } 6811592Srgrimes } 6821592Srgrimes } 68370102Sphk | STOU check_login_ro SP pathname CRLF 6841592Srgrimes { 6851592Srgrimes if ($2 && $4 != NULL) 6861592Srgrimes store($4, "w", 1); 6871592Srgrimes if ($4 != NULL) 6881592Srgrimes free($4); 6891592Srgrimes } 69071278Sjedgar | SYST check_login CRLF 6911592Srgrimes { 69271278Sjedgar if ($2) 6931592Srgrimes#ifdef unix 6941592Srgrimes#ifdef BSD 6951592Srgrimes reply(215, "UNIX Type: L%d Version: BSD-%d", 696103949Smike CHAR_BIT, BSD); 6971592Srgrimes#else /* BSD */ 698103949Smike reply(215, "UNIX Type: L%d", CHAR_BIT); 6991592Srgrimes#endif /* BSD */ 7001592Srgrimes#else /* unix */ 701103949Smike reply(215, "UNKNOWN Type: L%d", CHAR_BIT); 7021592Srgrimes#endif /* unix */ 7031592Srgrimes } 7041592Srgrimes 7051592Srgrimes /* 7061592Srgrimes * SIZE is not in RFC959, but Postel has blessed it and 7071592Srgrimes * it will be in the updated RFC. 7081592Srgrimes * 7091592Srgrimes * Return size of file in a format suitable for 7101592Srgrimes * using with RESTART (we just count bytes). 7111592Srgrimes */ 7121592Srgrimes | SIZE check_login SP pathname CRLF 7131592Srgrimes { 7141592Srgrimes if ($2 && $4 != NULL) 7151592Srgrimes sizecmd($4); 7161592Srgrimes if ($4 != NULL) 7171592Srgrimes free($4); 7181592Srgrimes } 7191592Srgrimes 7201592Srgrimes /* 7211592Srgrimes * MDTM is not in RFC959, but Postel has blessed it and 7221592Srgrimes * it will be in the updated RFC. 7231592Srgrimes * 7241592Srgrimes * Return modification time of file as an ISO 3307 7251592Srgrimes * style time. E.g. YYYYMMDDHHMMSS or YYYYMMDDHHMMSS.xxx 7261592Srgrimes * where xxx is the fractional second (of any precision, 7271592Srgrimes * not necessarily 3 digits) 7281592Srgrimes */ 7291592Srgrimes | MDTM check_login SP pathname CRLF 7301592Srgrimes { 7311592Srgrimes if ($2 && $4 != NULL) { 7321592Srgrimes struct stat stbuf; 7331592Srgrimes if (stat($4, &stbuf) < 0) 7341592Srgrimes reply(550, "%s: %s", 7351592Srgrimes $4, strerror(errno)); 7361592Srgrimes else if (!S_ISREG(stbuf.st_mode)) { 7371592Srgrimes reply(550, "%s: not a plain file.", $4); 7381592Srgrimes } else { 7391592Srgrimes struct tm *t; 7401592Srgrimes t = gmtime(&stbuf.st_mtime); 7411592Srgrimes reply(213, 74217435Spst "%04d%02d%02d%02d%02d%02d", 74317435Spst 1900 + t->tm_year, 74417435Spst t->tm_mon+1, t->tm_mday, 7451592Srgrimes t->tm_hour, t->tm_min, t->tm_sec); 7461592Srgrimes } 7471592Srgrimes } 7481592Srgrimes if ($4 != NULL) 7491592Srgrimes free($4); 7501592Srgrimes } 7511592Srgrimes | QUIT CRLF 7521592Srgrimes { 7531592Srgrimes reply(221, "Goodbye."); 7541592Srgrimes dologout(0); 7551592Srgrimes } 756102565Syar | NOTIMPL 757102565Syar { 758102565Syar nack($1); 759102565Syar } 76089935Syar | error 7611592Srgrimes { 76289935Syar yyclearin; /* discard lookahead data */ 76389935Syar yyerrok; /* clear error condition */ 764102565Syar state = CMD; /* reset lexer state */ 7651592Srgrimes } 7661592Srgrimes ; 7671592Srgrimesrcmd 76870102Sphk : RNFR check_login_ro SP pathname CRLF 7691592Srgrimes { 7701592Srgrimes restart_point = (off_t) 0; 7711592Srgrimes if ($2 && $4) { 77288935Sdwmalone if (fromname) 77388935Sdwmalone free(fromname); 77488935Sdwmalone fromname = (char *) 0; 77588935Sdwmalone if (renamefrom($4)) 77688935Sdwmalone fromname = $4; 77788935Sdwmalone else 7781592Srgrimes free($4); 77988935Sdwmalone } else if ($4) { 78088935Sdwmalone free($4); 7811592Srgrimes } 7821592Srgrimes } 78392272Smaxim | REST check_login SP NUMBER CRLF 7841592Srgrimes { 78571278Sjedgar if ($2) { 78688935Sdwmalone if (fromname) 78788935Sdwmalone free(fromname); 78871278Sjedgar fromname = (char *) 0; 78992272Smaxim restart_point = $4.o; 79092272Smaxim reply(350, "Restarting at %llu. %s", 79171278Sjedgar restart_point, 79271278Sjedgar "Send STORE or RETRIEVE to initiate transfer."); 79371278Sjedgar } 7941592Srgrimes } 7951592Srgrimes ; 7961592Srgrimes 7971592Srgrimesusername 7981592Srgrimes : STRING 7991592Srgrimes ; 8001592Srgrimes 8011592Srgrimespassword 8021592Srgrimes : /* empty */ 8031592Srgrimes { 8041592Srgrimes $$ = (char *)calloc(1, sizeof(char)); 8051592Srgrimes } 8061592Srgrimes | STRING 8071592Srgrimes ; 8081592Srgrimes 8091592Srgrimesbyte_size 8101592Srgrimes : NUMBER 81192272Smaxim { 81292272Smaxim $$ = $1.i; 81392272Smaxim } 8141592Srgrimes ; 8151592Srgrimes 8161592Srgrimeshost_port 8171592Srgrimes : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 8181592Srgrimes NUMBER COMMA NUMBER 8191592Srgrimes { 8201592Srgrimes char *a, *p; 8211592Srgrimes 82256668Sshin data_dest.su_len = sizeof(struct sockaddr_in); 82356668Sshin data_dest.su_family = AF_INET; 82456668Sshin p = (char *)&data_dest.su_sin.sin_port; 82592272Smaxim p[0] = $9.i; p[1] = $11.i; 82656668Sshin a = (char *)&data_dest.su_sin.sin_addr; 82792272Smaxim a[0] = $1.i; a[1] = $3.i; a[2] = $5.i; a[3] = $7.i; 8281592Srgrimes } 8291592Srgrimes ; 8301592Srgrimes 83156668Sshinhost_long_port 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 COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 83756668Sshin NUMBER 83856668Sshin { 83956668Sshin char *a, *p; 84056668Sshin 84156668Sshin memset(&data_dest, 0, sizeof(data_dest)); 84256668Sshin data_dest.su_len = sizeof(struct sockaddr_in6); 84356668Sshin data_dest.su_family = AF_INET6; 84456668Sshin p = (char *)&data_dest.su_port; 84592272Smaxim p[0] = $39.i; p[1] = $41.i; 84656668Sshin a = (char *)&data_dest.su_sin6.sin6_addr; 84792272Smaxim a[0] = $5.i; a[1] = $7.i; a[2] = $9.i; a[3] = $11.i; 84892272Smaxim a[4] = $13.i; a[5] = $15.i; a[6] = $17.i; a[7] = $19.i; 84992272Smaxim a[8] = $21.i; a[9] = $23.i; a[10] = $25.i; a[11] = $27.i; 85092272Smaxim a[12] = $29.i; a[13] = $31.i; a[14] = $33.i; a[15] = $35.i; 85156668Sshin if (his_addr.su_family == AF_INET6) { 85256668Sshin /* XXX more sanity checks! */ 85356668Sshin data_dest.su_sin6.sin6_scope_id = 85456668Sshin his_addr.su_sin6.sin6_scope_id; 85556668Sshin } 85692272Smaxim if ($1.i != 6 || $3.i != 16 || $37.i != 2) 85756668Sshin memset(&data_dest, 0, sizeof(data_dest)); 85856668Sshin } 85956668Sshin | NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 86056668Sshin NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 86156668Sshin NUMBER 86256668Sshin { 86356668Sshin char *a, *p; 86456668Sshin 86556668Sshin memset(&data_dest, 0, sizeof(data_dest)); 86656668Sshin data_dest.su_sin.sin_len = sizeof(struct sockaddr_in); 86756668Sshin data_dest.su_family = AF_INET; 86856668Sshin p = (char *)&data_dest.su_port; 86992272Smaxim p[0] = $15.i; p[1] = $17.i; 87056668Sshin a = (char *)&data_dest.su_sin.sin_addr; 87192272Smaxim a[0] = $5.i; a[1] = $7.i; a[2] = $9.i; a[3] = $11.i; 87292272Smaxim if ($1.i != 4 || $3.i != 4 || $13.i != 2) 87356668Sshin memset(&data_dest, 0, sizeof(data_dest)); 87456668Sshin } 87556668Sshin ; 87656668Sshin 8771592Srgrimesform_code 8781592Srgrimes : N 8791592Srgrimes { 8801592Srgrimes $$ = FORM_N; 8811592Srgrimes } 8821592Srgrimes | T 8831592Srgrimes { 8841592Srgrimes $$ = FORM_T; 8851592Srgrimes } 8861592Srgrimes | C 8871592Srgrimes { 8881592Srgrimes $$ = FORM_C; 8891592Srgrimes } 8901592Srgrimes ; 8911592Srgrimes 8921592Srgrimestype_code 8931592Srgrimes : A 8941592Srgrimes { 8951592Srgrimes cmd_type = TYPE_A; 8961592Srgrimes cmd_form = FORM_N; 8971592Srgrimes } 8981592Srgrimes | A SP form_code 8991592Srgrimes { 9001592Srgrimes cmd_type = TYPE_A; 9011592Srgrimes cmd_form = $3; 9021592Srgrimes } 9031592Srgrimes | E 9041592Srgrimes { 9051592Srgrimes cmd_type = TYPE_E; 9061592Srgrimes cmd_form = FORM_N; 9071592Srgrimes } 9081592Srgrimes | E SP form_code 9091592Srgrimes { 9101592Srgrimes cmd_type = TYPE_E; 9111592Srgrimes cmd_form = $3; 9121592Srgrimes } 9131592Srgrimes | I 9141592Srgrimes { 9151592Srgrimes cmd_type = TYPE_I; 9161592Srgrimes } 9171592Srgrimes | L 9181592Srgrimes { 9191592Srgrimes cmd_type = TYPE_L; 920103949Smike cmd_bytesz = CHAR_BIT; 9211592Srgrimes } 9221592Srgrimes | L SP byte_size 9231592Srgrimes { 9241592Srgrimes cmd_type = TYPE_L; 9251592Srgrimes cmd_bytesz = $3; 9261592Srgrimes } 9271592Srgrimes /* this is for a bug in the BBN ftp */ 9281592Srgrimes | L byte_size 9291592Srgrimes { 9301592Srgrimes cmd_type = TYPE_L; 9311592Srgrimes cmd_bytesz = $2; 9321592Srgrimes } 9331592Srgrimes ; 9341592Srgrimes 9351592Srgrimesstruct_code 9361592Srgrimes : F 9371592Srgrimes { 9381592Srgrimes $$ = STRU_F; 9391592Srgrimes } 9401592Srgrimes | R 9411592Srgrimes { 9421592Srgrimes $$ = STRU_R; 9431592Srgrimes } 9441592Srgrimes | P 9451592Srgrimes { 9461592Srgrimes $$ = STRU_P; 9471592Srgrimes } 9481592Srgrimes ; 9491592Srgrimes 9501592Srgrimesmode_code 9511592Srgrimes : S 9521592Srgrimes { 9531592Srgrimes $$ = MODE_S; 9541592Srgrimes } 9551592Srgrimes | B 9561592Srgrimes { 9571592Srgrimes $$ = MODE_B; 9581592Srgrimes } 9591592Srgrimes | C 9601592Srgrimes { 9611592Srgrimes $$ = MODE_C; 9621592Srgrimes } 9631592Srgrimes ; 9641592Srgrimes 9651592Srgrimespathname 9661592Srgrimes : pathstring 9671592Srgrimes { 9681592Srgrimes /* 9691592Srgrimes * Problem: this production is used for all pathname 9701592Srgrimes * processing, but only gives a 550 error reply. 9711592Srgrimes * This is a valid reply in some cases but not in others. 9721592Srgrimes */ 97375567Speter if (logged_in && $1) { 9741592Srgrimes glob_t gl; 9751592Srgrimes int flags = 976100222Smikeh GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE; 9771592Srgrimes 9781592Srgrimes memset(&gl, 0, sizeof(gl)); 97975560Sjedgar flags |= GLOB_MAXPATH; 98075560Sjedgar gl.gl_matchc = MAXGLOBARGS; 9811592Srgrimes if (glob($1, flags, NULL, &gl) || 9821592Srgrimes gl.gl_pathc == 0) { 983101380Syar reply(550, "wildcard expansion error"); 9841592Srgrimes $$ = NULL; 98575567Speter } else if (gl.gl_pathc > 1) { 98675567Speter reply(550, "ambiguous"); 98775567Speter $$ = NULL; 9881592Srgrimes } else { 9891592Srgrimes $$ = strdup(gl.gl_pathv[0]); 9901592Srgrimes } 9911592Srgrimes globfree(&gl); 9921592Srgrimes free($1); 9931592Srgrimes } else 9941592Srgrimes $$ = $1; 9951592Srgrimes } 9961592Srgrimes ; 9971592Srgrimes 9981592Srgrimespathstring 9991592Srgrimes : STRING 10001592Srgrimes ; 10011592Srgrimes 10021592Srgrimesoctal_number 10031592Srgrimes : NUMBER 10041592Srgrimes { 10051592Srgrimes int ret, dec, multby, digit; 10061592Srgrimes 10071592Srgrimes /* 10081592Srgrimes * Convert a number that was read as decimal number 10091592Srgrimes * to what it would be if it had been read as octal. 10101592Srgrimes */ 101192272Smaxim dec = $1.i; 10121592Srgrimes multby = 1; 10131592Srgrimes ret = 0; 10141592Srgrimes while (dec) { 10151592Srgrimes digit = dec%10; 10161592Srgrimes if (digit > 7) { 10171592Srgrimes ret = -1; 10181592Srgrimes break; 10191592Srgrimes } 10201592Srgrimes ret += digit * multby; 10211592Srgrimes multby *= 8; 10221592Srgrimes dec /= 10; 10231592Srgrimes } 10241592Srgrimes $$ = ret; 10251592Srgrimes } 10261592Srgrimes ; 10271592Srgrimes 10281592Srgrimes 10291592Srgrimescheck_login 10301592Srgrimes : /* empty */ 10311592Srgrimes { 103270102Sphk $$ = check_login1(); 10331592Srgrimes } 10341592Srgrimes ; 10351592Srgrimes 103670102Sphkcheck_login_epsv 103770102Sphk : /* empty */ 103870102Sphk { 103970102Sphk if (noepsv) { 104070102Sphk reply(500, "EPSV command disabled"); 104170102Sphk $$ = 0; 104270102Sphk } 104370102Sphk else 104470102Sphk $$ = check_login1(); 104570102Sphk } 104670102Sphk ; 104770102Sphk 104870102Sphkcheck_login_ro 104970102Sphk : /* empty */ 105070102Sphk { 105170102Sphk if (readonly) { 105272710Sdes reply(550, "Permission denied."); 105370102Sphk $$ = 0; 105470102Sphk } 105570102Sphk else 105670102Sphk $$ = check_login1(); 105770102Sphk } 105870102Sphk ; 105970102Sphk 10601592Srgrimes%% 10611592Srgrimes 10621592Srgrimes#define CMD 0 /* beginning of command */ 10631592Srgrimes#define ARGS 1 /* expect miscellaneous arguments */ 10641592Srgrimes#define STR1 2 /* expect SP followed by STRING */ 10651592Srgrimes#define STR2 3 /* expect STRING */ 10661592Srgrimes#define OSTR 4 /* optional SP then STRING */ 106775556Sgreen#define ZSTR1 5 /* optional SP then optional STRING */ 10681592Srgrimes#define ZSTR2 6 /* optional STRING after SP */ 10691592Srgrimes#define SITECMD 7 /* SITE command */ 10701592Srgrimes#define NSTR 8 /* Number followed by a string */ 10711592Srgrimes 107275560Sjedgar#define MAXGLOBARGS 1000 107375560Sjedgar 1074101034Syar#define MAXASIZE 10240 /* Deny ASCII SIZE on files larger than that */ 1075101034Syar 10761592Srgrimesstruct tab { 10771592Srgrimes char *name; 10781592Srgrimes short token; 10791592Srgrimes short state; 10801592Srgrimes short implemented; /* 1 if command is implemented */ 10811592Srgrimes char *help; 10821592Srgrimes}; 10831592Srgrimes 10841592Srgrimesstruct tab cmdtab[] = { /* In order defined in RFC 765 */ 10851592Srgrimes { "USER", USER, STR1, 1, "<sp> username" }, 108675556Sgreen { "PASS", PASS, ZSTR1, 1, "[<sp> [password]]" }, 10871592Srgrimes { "ACCT", ACCT, STR1, 0, "(specify account)" }, 10881592Srgrimes { "SMNT", SMNT, ARGS, 0, "(structure mount)" }, 10891592Srgrimes { "REIN", REIN, ARGS, 0, "(reinitialize server state)" }, 10901592Srgrimes { "QUIT", QUIT, ARGS, 1, "(terminate service)", }, 1091101806Syar { "PORT", PORT, ARGS, 1, "<sp> b0, b1, b2, b3, b4, b5" }, 109256668Sshin { "LPRT", LPRT, ARGS, 1, "<sp> af, hal, h1, h2, h3,..., pal, p1, p2..." }, 109356668Sshin { "EPRT", EPRT, STR1, 1, "<sp> |af|addr|port|" }, 10941592Srgrimes { "PASV", PASV, ARGS, 1, "(set server in passive mode)" }, 109556668Sshin { "LPSV", LPSV, ARGS, 1, "(set server in passive mode)" }, 109656668Sshin { "EPSV", EPSV, ARGS, 1, "[<sp> af|ALL]" }, 1097101806Syar { "TYPE", TYPE, ARGS, 1, "<sp> { A | E | I | L }" }, 10981592Srgrimes { "STRU", STRU, ARGS, 1, "(specify file structure)" }, 10991592Srgrimes { "MODE", MODE, ARGS, 1, "(specify transfer mode)" }, 11001592Srgrimes { "RETR", RETR, STR1, 1, "<sp> file-name" }, 11011592Srgrimes { "STOR", STOR, STR1, 1, "<sp> file-name" }, 11021592Srgrimes { "APPE", APPE, STR1, 1, "<sp> file-name" }, 11031592Srgrimes { "MLFL", MLFL, OSTR, 0, "(mail file)" }, 11041592Srgrimes { "MAIL", MAIL, OSTR, 0, "(mail to user)" }, 11051592Srgrimes { "MSND", MSND, OSTR, 0, "(mail send to terminal)" }, 11061592Srgrimes { "MSOM", MSOM, OSTR, 0, "(mail send to terminal or mailbox)" }, 11071592Srgrimes { "MSAM", MSAM, OSTR, 0, "(mail send to terminal and mailbox)" }, 11081592Srgrimes { "MRSQ", MRSQ, OSTR, 0, "(mail recipient scheme question)" }, 11091592Srgrimes { "MRCP", MRCP, STR1, 0, "(mail recipient)" }, 11101592Srgrimes { "ALLO", ALLO, ARGS, 1, "allocate storage (vacuously)" }, 11111592Srgrimes { "REST", REST, ARGS, 1, "<sp> offset (restart command)" }, 11121592Srgrimes { "RNFR", RNFR, STR1, 1, "<sp> file-name" }, 11131592Srgrimes { "RNTO", RNTO, STR1, 1, "<sp> file-name" }, 11141592Srgrimes { "ABOR", ABOR, ARGS, 1, "(abort operation)" }, 11151592Srgrimes { "DELE", DELE, STR1, 1, "<sp> file-name" }, 11161592Srgrimes { "CWD", CWD, OSTR, 1, "[ <sp> directory-name ]" }, 11171592Srgrimes { "XCWD", CWD, OSTR, 1, "[ <sp> directory-name ]" }, 11181592Srgrimes { "LIST", LIST, OSTR, 1, "[ <sp> path-name ]" }, 11191592Srgrimes { "NLST", NLST, OSTR, 1, "[ <sp> path-name ]" }, 11201592Srgrimes { "SITE", SITE, SITECMD, 1, "site-cmd [ <sp> arguments ]" }, 11211592Srgrimes { "SYST", SYST, ARGS, 1, "(get type of operating system)" }, 11221592Srgrimes { "STAT", STAT, OSTR, 1, "[ <sp> path-name ]" }, 11231592Srgrimes { "HELP", HELP, OSTR, 1, "[ <sp> <string> ]" }, 11241592Srgrimes { "NOOP", NOOP, ARGS, 1, "" }, 11251592Srgrimes { "MKD", MKD, STR1, 1, "<sp> path-name" }, 11261592Srgrimes { "XMKD", MKD, STR1, 1, "<sp> path-name" }, 11271592Srgrimes { "RMD", RMD, STR1, 1, "<sp> path-name" }, 11281592Srgrimes { "XRMD", RMD, STR1, 1, "<sp> path-name" }, 11291592Srgrimes { "PWD", PWD, ARGS, 1, "(return current directory)" }, 11301592Srgrimes { "XPWD", PWD, ARGS, 1, "(return current directory)" }, 11311592Srgrimes { "CDUP", CDUP, ARGS, 1, "(change to parent directory)" }, 11321592Srgrimes { "XCUP", CDUP, ARGS, 1, "(change to parent directory)" }, 11331592Srgrimes { "STOU", STOU, STR1, 1, "<sp> file-name" }, 11341592Srgrimes { "SIZE", SIZE, OSTR, 1, "<sp> path-name" }, 11351592Srgrimes { "MDTM", MDTM, OSTR, 1, "<sp> path-name" }, 11361592Srgrimes { NULL, 0, 0, 0, 0 } 11371592Srgrimes}; 11381592Srgrimes 11391592Srgrimesstruct tab sitetab[] = { 114075535Sphk { "MD5", MDFIVE, STR1, 1, "[ <sp> file-name ]" }, 11411592Srgrimes { "UMASK", UMASK, ARGS, 1, "[ <sp> umask ]" }, 11421592Srgrimes { "IDLE", IDLE, ARGS, 1, "[ <sp> maximum-idle-time ]" }, 11431592Srgrimes { "CHMOD", CHMOD, NSTR, 1, "<sp> mode <sp> file-name" }, 11441592Srgrimes { "HELP", HELP, OSTR, 1, "[ <sp> <string> ]" }, 11451592Srgrimes { NULL, 0, 0, 0, 0 } 11461592Srgrimes}; 11471592Srgrimes 114890148Simpstatic char *copy(char *); 114990148Simpstatic void help(struct tab *, char *); 11501592Srgrimesstatic struct tab * 115190148Simp lookup(struct tab *, char *); 115290148Simpstatic int port_check(const char *); 115390148Simpstatic int port_check_v6(const char *); 115490148Simpstatic void sizecmd(char *); 115590148Simpstatic void toolong(int); 115690148Simpstatic void v4map_data_dest(void); 115790148Simpstatic int yylex(void); 11581592Srgrimes 11591592Srgrimesstatic struct tab * 116090148Simplookup(struct tab *p, char *cmd) 11611592Srgrimes{ 11621592Srgrimes 11631592Srgrimes for (; p->name != NULL; p++) 11641592Srgrimes if (strcmp(cmd, p->name) == 0) 11651592Srgrimes return (p); 11661592Srgrimes return (0); 11671592Srgrimes} 11681592Srgrimes 11691592Srgrimes#include <arpa/telnet.h> 11701592Srgrimes 11711592Srgrimes/* 11721592Srgrimes * getline - a hacked up version of fgets to ignore TELNET escape codes. 11731592Srgrimes */ 11741592Srgrimeschar * 117590148Simpgetline(char *s, int n, FILE *iop) 11761592Srgrimes{ 11771592Srgrimes int c; 11781592Srgrimes register char *cs; 11791592Srgrimes 11801592Srgrimes cs = s; 11811592Srgrimes/* tmpline may contain saved command from urgent mode interruption */ 11821592Srgrimes for (c = 0; tmpline[c] != '\0' && --n > 0; ++c) { 11831592Srgrimes *cs++ = tmpline[c]; 11841592Srgrimes if (tmpline[c] == '\n') { 11851592Srgrimes *cs++ = '\0'; 118676096Smarkm if (ftpdebug) 11871592Srgrimes syslog(LOG_DEBUG, "command: %s", s); 11881592Srgrimes tmpline[0] = '\0'; 11891592Srgrimes return(s); 11901592Srgrimes } 11911592Srgrimes if (c == 0) 11921592Srgrimes tmpline[0] = '\0'; 11931592Srgrimes } 11941592Srgrimes while ((c = getc(iop)) != EOF) { 11951592Srgrimes c &= 0377; 11961592Srgrimes if (c == IAC) { 11971592Srgrimes if ((c = getc(iop)) != EOF) { 11981592Srgrimes c &= 0377; 11991592Srgrimes switch (c) { 12001592Srgrimes case WILL: 12011592Srgrimes case WONT: 12021592Srgrimes c = getc(iop); 12031592Srgrimes printf("%c%c%c", IAC, DONT, 0377&c); 12041592Srgrimes (void) fflush(stdout); 12051592Srgrimes continue; 12061592Srgrimes case DO: 12071592Srgrimes case DONT: 12081592Srgrimes c = getc(iop); 12091592Srgrimes printf("%c%c%c", IAC, WONT, 0377&c); 12101592Srgrimes (void) fflush(stdout); 12111592Srgrimes continue; 12121592Srgrimes case IAC: 12131592Srgrimes break; 12141592Srgrimes default: 12151592Srgrimes continue; /* ignore command */ 12161592Srgrimes } 12171592Srgrimes } 12181592Srgrimes } 12191592Srgrimes *cs++ = c; 12201592Srgrimes if (--n <= 0 || c == '\n') 12211592Srgrimes break; 12221592Srgrimes } 12231592Srgrimes if (c == EOF && cs == s) 12241592Srgrimes return (NULL); 12251592Srgrimes *cs++ = '\0'; 122676096Smarkm if (ftpdebug) { 12271592Srgrimes if (!guest && strncasecmp("pass ", s, 5) == 0) { 12281592Srgrimes /* Don't syslog passwords */ 12291592Srgrimes syslog(LOG_DEBUG, "command: %.5s ???", s); 12301592Srgrimes } else { 12311592Srgrimes register char *cp; 12321592Srgrimes register int len; 12331592Srgrimes 12341592Srgrimes /* Don't syslog trailing CR-LF */ 12351592Srgrimes len = strlen(s); 12361592Srgrimes cp = s + len - 1; 12371592Srgrimes while (cp >= s && (*cp == '\n' || *cp == '\r')) { 12381592Srgrimes --cp; 12391592Srgrimes --len; 12401592Srgrimes } 12411592Srgrimes syslog(LOG_DEBUG, "command: %.*s", len, s); 12421592Srgrimes } 12431592Srgrimes } 12441592Srgrimes return (s); 12451592Srgrimes} 12461592Srgrimes 12471592Srgrimesstatic void 124890148Simptoolong(int signo) 12491592Srgrimes{ 12501592Srgrimes 12511592Srgrimes reply(421, 12521592Srgrimes "Timeout (%d seconds): closing control connection.", timeout); 12531592Srgrimes if (logging) 12541592Srgrimes syslog(LOG_INFO, "User %s timed out after %d seconds", 12551592Srgrimes (pw ? pw -> pw_name : "unknown"), timeout); 12561592Srgrimes dologout(1); 12571592Srgrimes} 12581592Srgrimes 12591592Srgrimesstatic int 126090148Simpyylex(void) 12611592Srgrimes{ 126289935Syar static int cpos; 12631592Srgrimes char *cp, *cp2; 12641592Srgrimes struct tab *p; 12651592Srgrimes int n; 12661592Srgrimes char c; 12671592Srgrimes 12681592Srgrimes for (;;) { 12691592Srgrimes switch (state) { 12701592Srgrimes 12711592Srgrimes case CMD: 12721592Srgrimes (void) signal(SIGALRM, toolong); 12731592Srgrimes (void) alarm((unsigned) timeout); 12741592Srgrimes if (getline(cbuf, sizeof(cbuf)-1, stdin) == NULL) { 12751592Srgrimes reply(221, "You could at least say goodbye."); 12761592Srgrimes dologout(0); 12771592Srgrimes } 12781592Srgrimes (void) alarm(0); 12791592Srgrimes#ifdef SETPROCTITLE 128029574Sphk if (strncasecmp(cbuf, "PASS", 4) != 0) 12811592Srgrimes setproctitle("%s: %s", proctitle, cbuf); 12821592Srgrimes#endif /* SETPROCTITLE */ 12831592Srgrimes if ((cp = strchr(cbuf, '\r'))) { 12841592Srgrimes *cp++ = '\n'; 12851592Srgrimes *cp = '\0'; 12861592Srgrimes } 12871592Srgrimes if ((cp = strpbrk(cbuf, " \n"))) 12881592Srgrimes cpos = cp - cbuf; 12891592Srgrimes if (cpos == 0) 12901592Srgrimes cpos = 4; 12911592Srgrimes c = cbuf[cpos]; 12921592Srgrimes cbuf[cpos] = '\0'; 12931592Srgrimes upper(cbuf); 12941592Srgrimes p = lookup(cmdtab, cbuf); 12951592Srgrimes cbuf[cpos] = c; 12963776Spst if (p != 0) { 1297102565Syar yylval.s = p->name; 1298102565Syar if (!p->implemented) 1299102565Syar return (NOTIMPL); /* state remains CMD */ 13001592Srgrimes state = p->state; 13011592Srgrimes return (p->token); 13021592Srgrimes } 13031592Srgrimes break; 13041592Srgrimes 13051592Srgrimes case SITECMD: 13061592Srgrimes if (cbuf[cpos] == ' ') { 13071592Srgrimes cpos++; 13081592Srgrimes return (SP); 13091592Srgrimes } 13101592Srgrimes cp = &cbuf[cpos]; 13111592Srgrimes if ((cp2 = strpbrk(cp, " \n"))) 13121592Srgrimes cpos = cp2 - cbuf; 13131592Srgrimes c = cbuf[cpos]; 13141592Srgrimes cbuf[cpos] = '\0'; 13151592Srgrimes upper(cp); 13161592Srgrimes p = lookup(sitetab, cp); 13171592Srgrimes cbuf[cpos] = c; 13183777Spst if (guest == 0 && p != 0) { 1319102565Syar yylval.s = p->name; 1320102565Syar if (!p->implemented) { 13211592Srgrimes state = CMD; 1322102565Syar return (NOTIMPL); 13231592Srgrimes } 13241592Srgrimes state = p->state; 13251592Srgrimes return (p->token); 13261592Srgrimes } 13271592Srgrimes state = CMD; 13281592Srgrimes break; 13291592Srgrimes 133075556Sgreen case ZSTR1: 13311592Srgrimes case OSTR: 13321592Srgrimes if (cbuf[cpos] == '\n') { 13331592Srgrimes state = CMD; 13341592Srgrimes return (CRLF); 13351592Srgrimes } 13361592Srgrimes /* FALLTHROUGH */ 13371592Srgrimes 13381592Srgrimes case STR1: 13391592Srgrimes dostr1: 13401592Srgrimes if (cbuf[cpos] == ' ') { 13411592Srgrimes cpos++; 134251979Salfred state = state == OSTR ? STR2 : state+1; 13431592Srgrimes return (SP); 13441592Srgrimes } 13451592Srgrimes break; 13461592Srgrimes 13471592Srgrimes case ZSTR2: 13481592Srgrimes if (cbuf[cpos] == '\n') { 13491592Srgrimes state = CMD; 13501592Srgrimes return (CRLF); 13511592Srgrimes } 13521592Srgrimes /* FALLTHROUGH */ 13531592Srgrimes 13541592Srgrimes case STR2: 13551592Srgrimes cp = &cbuf[cpos]; 13561592Srgrimes n = strlen(cp); 13571592Srgrimes cpos += n - 1; 13581592Srgrimes /* 13591592Srgrimes * Make sure the string is nonempty and \n terminated. 13601592Srgrimes */ 13611592Srgrimes if (n > 1 && cbuf[cpos] == '\n') { 13621592Srgrimes cbuf[cpos] = '\0'; 13631592Srgrimes yylval.s = copy(cp); 13641592Srgrimes cbuf[cpos] = '\n'; 13651592Srgrimes state = ARGS; 13661592Srgrimes return (STRING); 13671592Srgrimes } 13681592Srgrimes break; 13691592Srgrimes 13701592Srgrimes case NSTR: 13711592Srgrimes if (cbuf[cpos] == ' ') { 13721592Srgrimes cpos++; 13731592Srgrimes return (SP); 13741592Srgrimes } 13751592Srgrimes if (isdigit(cbuf[cpos])) { 13761592Srgrimes cp = &cbuf[cpos]; 13771592Srgrimes while (isdigit(cbuf[++cpos])) 13781592Srgrimes ; 13791592Srgrimes c = cbuf[cpos]; 13801592Srgrimes cbuf[cpos] = '\0'; 138192272Smaxim yylval.u.i = atoi(cp); 13821592Srgrimes cbuf[cpos] = c; 13831592Srgrimes state = STR1; 13841592Srgrimes return (NUMBER); 13851592Srgrimes } 13861592Srgrimes state = STR1; 13871592Srgrimes goto dostr1; 13881592Srgrimes 13891592Srgrimes case ARGS: 13901592Srgrimes if (isdigit(cbuf[cpos])) { 13911592Srgrimes cp = &cbuf[cpos]; 13921592Srgrimes while (isdigit(cbuf[++cpos])) 13931592Srgrimes ; 13941592Srgrimes c = cbuf[cpos]; 13951592Srgrimes cbuf[cpos] = '\0'; 139692272Smaxim yylval.u.i = atoi(cp); 139792272Smaxim yylval.u.o = strtoull(cp, (char **)NULL, 10); 13981592Srgrimes cbuf[cpos] = c; 13991592Srgrimes return (NUMBER); 14001592Srgrimes } 140156668Sshin if (strncasecmp(&cbuf[cpos], "ALL", 3) == 0 140256668Sshin && !isalnum(cbuf[cpos + 3])) { 140356668Sshin cpos += 3; 140456668Sshin return ALL; 140556668Sshin } 14061592Srgrimes switch (cbuf[cpos++]) { 14071592Srgrimes 14081592Srgrimes case '\n': 14091592Srgrimes state = CMD; 14101592Srgrimes return (CRLF); 14111592Srgrimes 14121592Srgrimes case ' ': 14131592Srgrimes return (SP); 14141592Srgrimes 14151592Srgrimes case ',': 14161592Srgrimes return (COMMA); 14171592Srgrimes 14181592Srgrimes case 'A': 14191592Srgrimes case 'a': 14201592Srgrimes return (A); 14211592Srgrimes 14221592Srgrimes case 'B': 14231592Srgrimes case 'b': 14241592Srgrimes return (B); 14251592Srgrimes 14261592Srgrimes case 'C': 14271592Srgrimes case 'c': 14281592Srgrimes return (C); 14291592Srgrimes 14301592Srgrimes case 'E': 14311592Srgrimes case 'e': 14321592Srgrimes return (E); 14331592Srgrimes 14341592Srgrimes case 'F': 14351592Srgrimes case 'f': 14361592Srgrimes return (F); 14371592Srgrimes 14381592Srgrimes case 'I': 14391592Srgrimes case 'i': 14401592Srgrimes return (I); 14411592Srgrimes 14421592Srgrimes case 'L': 14431592Srgrimes case 'l': 14441592Srgrimes return (L); 14451592Srgrimes 14461592Srgrimes case 'N': 14471592Srgrimes case 'n': 14481592Srgrimes return (N); 14491592Srgrimes 14501592Srgrimes case 'P': 14511592Srgrimes case 'p': 14521592Srgrimes return (P); 14531592Srgrimes 14541592Srgrimes case 'R': 14551592Srgrimes case 'r': 14561592Srgrimes return (R); 14571592Srgrimes 14581592Srgrimes case 'S': 14591592Srgrimes case 's': 14601592Srgrimes return (S); 14611592Srgrimes 14621592Srgrimes case 'T': 14631592Srgrimes case 't': 14641592Srgrimes return (T); 14651592Srgrimes 14661592Srgrimes } 14671592Srgrimes break; 14681592Srgrimes 14691592Srgrimes default: 147076096Smarkm fatalerror("Unknown state in scanner."); 14711592Srgrimes } 14721592Srgrimes state = CMD; 147389935Syar return (LEXERR); 14741592Srgrimes } 14751592Srgrimes} 14761592Srgrimes 14771592Srgrimesvoid 147890148Simpupper(char *s) 14791592Srgrimes{ 14801592Srgrimes while (*s != '\0') { 14811592Srgrimes if (islower(*s)) 14821592Srgrimes *s = toupper(*s); 14831592Srgrimes s++; 14841592Srgrimes } 14851592Srgrimes} 14861592Srgrimes 14871592Srgrimesstatic char * 148890148Simpcopy(char *s) 14891592Srgrimes{ 14901592Srgrimes char *p; 14911592Srgrimes 14921592Srgrimes p = malloc((unsigned) strlen(s) + 1); 14931592Srgrimes if (p == NULL) 149476096Smarkm fatalerror("Ran out of memory."); 14951592Srgrimes (void) strcpy(p, s); 14961592Srgrimes return (p); 14971592Srgrimes} 14981592Srgrimes 14991592Srgrimesstatic void 150090148Simphelp(struct tab *ctab, char *s) 15011592Srgrimes{ 15021592Srgrimes struct tab *c; 15031592Srgrimes int width, NCMDS; 15041592Srgrimes char *type; 15051592Srgrimes 15061592Srgrimes if (ctab == sitetab) 15071592Srgrimes type = "SITE "; 15081592Srgrimes else 15091592Srgrimes type = ""; 15101592Srgrimes width = 0, NCMDS = 0; 15111592Srgrimes for (c = ctab; c->name != NULL; c++) { 15121592Srgrimes int len = strlen(c->name); 15131592Srgrimes 15141592Srgrimes if (len > width) 15151592Srgrimes width = len; 15161592Srgrimes NCMDS++; 15171592Srgrimes } 15181592Srgrimes width = (width + 8) &~ 7; 15191592Srgrimes if (s == 0) { 15201592Srgrimes int i, j, w; 15211592Srgrimes int columns, lines; 15221592Srgrimes 15231592Srgrimes lreply(214, "The following %scommands are recognized %s.", 15241592Srgrimes type, "(* =>'s unimplemented)"); 15251592Srgrimes columns = 76 / width; 15261592Srgrimes if (columns == 0) 15271592Srgrimes columns = 1; 15281592Srgrimes lines = (NCMDS + columns - 1) / columns; 15291592Srgrimes for (i = 0; i < lines; i++) { 15301592Srgrimes printf(" "); 15311592Srgrimes for (j = 0; j < columns; j++) { 15321592Srgrimes c = ctab + j * lines + i; 15331592Srgrimes printf("%s%c", c->name, 15341592Srgrimes c->implemented ? ' ' : '*'); 15351592Srgrimes if (c + lines >= &ctab[NCMDS]) 15361592Srgrimes break; 15371592Srgrimes w = strlen(c->name) + 1; 15381592Srgrimes while (w < width) { 15391592Srgrimes putchar(' '); 15401592Srgrimes w++; 15411592Srgrimes } 15421592Srgrimes } 15431592Srgrimes printf("\r\n"); 15441592Srgrimes } 15451592Srgrimes (void) fflush(stdout); 15461592Srgrimes reply(214, "Direct comments to ftp-bugs@%s.", hostname); 15471592Srgrimes return; 15481592Srgrimes } 15491592Srgrimes upper(s); 15501592Srgrimes c = lookup(ctab, s); 15511592Srgrimes if (c == (struct tab *)0) { 15521592Srgrimes reply(502, "Unknown command %s.", s); 15531592Srgrimes return; 15541592Srgrimes } 15551592Srgrimes if (c->implemented) 15561592Srgrimes reply(214, "Syntax: %s%s %s", type, c->name, c->help); 15571592Srgrimes else 15581592Srgrimes reply(214, "%s%-*s\t%s; unimplemented.", type, width, 15591592Srgrimes c->name, c->help); 15601592Srgrimes} 15611592Srgrimes 15621592Srgrimesstatic void 156390148Simpsizecmd(char *filename) 15641592Srgrimes{ 15651592Srgrimes switch (type) { 15661592Srgrimes case TYPE_L: 15671592Srgrimes case TYPE_I: { 15681592Srgrimes struct stat stbuf; 156963350Sdes if (stat(filename, &stbuf) < 0) 157063350Sdes perror_reply(550, filename); 157163350Sdes else if (!S_ISREG(stbuf.st_mode)) 15721592Srgrimes reply(550, "%s: not a plain file.", filename); 15731592Srgrimes else 15741592Srgrimes reply(213, "%qu", stbuf.st_size); 15751592Srgrimes break; } 15761592Srgrimes case TYPE_A: { 15771592Srgrimes FILE *fin; 15781592Srgrimes int c; 15791592Srgrimes off_t count; 15801592Srgrimes struct stat stbuf; 15811592Srgrimes fin = fopen(filename, "r"); 15821592Srgrimes if (fin == NULL) { 15831592Srgrimes perror_reply(550, filename); 15841592Srgrimes return; 15851592Srgrimes } 158663350Sdes if (fstat(fileno(fin), &stbuf) < 0) { 158763350Sdes perror_reply(550, filename); 158863350Sdes (void) fclose(fin); 158963350Sdes return; 159063350Sdes } else if (!S_ISREG(stbuf.st_mode)) { 15911592Srgrimes reply(550, "%s: not a plain file.", filename); 15921592Srgrimes (void) fclose(fin); 15931592Srgrimes return; 1594101034Syar } else if (stbuf.st_size > MAXASIZE) { 1595101034Syar reply(550, "%s: too large for type A SIZE.", filename); 1596101034Syar (void) fclose(fin); 1597101034Syar return; 15981592Srgrimes } 15991592Srgrimes 16001592Srgrimes count = 0; 16011592Srgrimes while((c=getc(fin)) != EOF) { 16021592Srgrimes if (c == '\n') /* will get expanded to \r\n */ 16031592Srgrimes count++; 16041592Srgrimes count++; 16051592Srgrimes } 16061592Srgrimes (void) fclose(fin); 16071592Srgrimes 16081592Srgrimes reply(213, "%qd", count); 16091592Srgrimes break; } 16101592Srgrimes default: 1611100684Syar reply(504, "SIZE not implemented for type %s.", 1612100684Syar typenames[type]); 16131592Srgrimes } 16141592Srgrimes} 161556668Sshin 161656668Sshin/* Return 1, if port check is done. Return 0, if not yet. */ 161756668Sshinstatic int 161890148Simpport_check(const char *pcmd) 161956668Sshin{ 162056668Sshin if (his_addr.su_family == AF_INET) { 162156668Sshin if (data_dest.su_family != AF_INET) { 162256668Sshin usedefault = 1; 162356668Sshin reply(500, "Invalid address rejected."); 162456668Sshin return 1; 162556668Sshin } 162656668Sshin if (paranoid && 162756668Sshin ((ntohs(data_dest.su_port) < IPPORT_RESERVED) || 162856668Sshin memcmp(&data_dest.su_sin.sin_addr, 162956668Sshin &his_addr.su_sin.sin_addr, 163056668Sshin sizeof(data_dest.su_sin.sin_addr)))) { 163156668Sshin usedefault = 1; 163256668Sshin reply(500, "Illegal PORT range rejected."); 163356668Sshin } else { 163456668Sshin usedefault = 0; 163556668Sshin if (pdata >= 0) { 163656668Sshin (void) close(pdata); 163756668Sshin pdata = -1; 163856668Sshin } 163956668Sshin reply(200, "%s command successful.", pcmd); 164056668Sshin } 164156668Sshin return 1; 164256668Sshin } 164356668Sshin return 0; 164456668Sshin} 164556668Sshin 164670102Sphkstatic int 164790148Simpcheck_login1(void) 164870102Sphk{ 164970102Sphk if (logged_in) 165070102Sphk return 1; 165170102Sphk else { 165270102Sphk reply(530, "Please login with USER and PASS."); 165370102Sphk return 0; 165470102Sphk } 165570102Sphk} 165670102Sphk 165756668Sshin#ifdef INET6 165856668Sshin/* Return 1, if port check is done. Return 0, if not yet. */ 165956668Sshinstatic int 166090148Simpport_check_v6(const char *pcmd) 166156668Sshin{ 166256668Sshin if (his_addr.su_family == AF_INET6) { 166356668Sshin if (IN6_IS_ADDR_V4MAPPED(&his_addr.su_sin6.sin6_addr)) 166456668Sshin /* Convert data_dest into v4 mapped sockaddr.*/ 166556668Sshin v4map_data_dest(); 166656668Sshin if (data_dest.su_family != AF_INET6) { 166756668Sshin usedefault = 1; 166856668Sshin reply(500, "Invalid address rejected."); 166956668Sshin return 1; 167056668Sshin } 167156668Sshin if (paranoid && 167256668Sshin ((ntohs(data_dest.su_port) < IPPORT_RESERVED) || 167356668Sshin memcmp(&data_dest.su_sin6.sin6_addr, 167456668Sshin &his_addr.su_sin6.sin6_addr, 167556668Sshin sizeof(data_dest.su_sin6.sin6_addr)))) { 167656668Sshin usedefault = 1; 167756668Sshin reply(500, "Illegal PORT range rejected."); 167856668Sshin } else { 167956668Sshin usedefault = 0; 168056668Sshin if (pdata >= 0) { 168156668Sshin (void) close(pdata); 168256668Sshin pdata = -1; 168356668Sshin } 168456668Sshin reply(200, "%s command successful.", pcmd); 168556668Sshin } 168656668Sshin return 1; 168756668Sshin } 168856668Sshin return 0; 168956668Sshin} 169056668Sshin 169156668Sshinstatic void 169290148Simpv4map_data_dest(void) 169356668Sshin{ 169456668Sshin struct in_addr savedaddr; 169556668Sshin int savedport; 169656668Sshin 169756668Sshin if (data_dest.su_family != AF_INET) { 169856668Sshin usedefault = 1; 169956668Sshin reply(500, "Invalid address rejected."); 170056668Sshin return; 170156668Sshin } 170256668Sshin 170356668Sshin savedaddr = data_dest.su_sin.sin_addr; 170456668Sshin savedport = data_dest.su_port; 170556668Sshin 170656668Sshin memset(&data_dest, 0, sizeof(data_dest)); 170756668Sshin data_dest.su_sin6.sin6_len = sizeof(struct sockaddr_in6); 170856668Sshin data_dest.su_sin6.sin6_family = AF_INET6; 170956668Sshin data_dest.su_sin6.sin6_port = savedport; 171056668Sshin memset((caddr_t)&data_dest.su_sin6.sin6_addr.s6_addr[10], 0xff, 2); 171156668Sshin memcpy((caddr_t)&data_dest.su_sin6.sin6_addr.s6_addr[12], 171256668Sshin (caddr_t)&savedaddr, sizeof(savedaddr)); 171356668Sshin} 171456668Sshin#endif 1715