ftpcmd.y revision 89935
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 89935 2002-01-28 19:28:14Z 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> 6156668Sshin#include <netdb.h> 621592Srgrimes#include <pwd.h> 631592Srgrimes#include <signal.h> 641592Srgrimes#include <stdio.h> 651592Srgrimes#include <stdlib.h> 661592Srgrimes#include <string.h> 671592Srgrimes#include <syslog.h> 681592Srgrimes#include <time.h> 691592Srgrimes#include <unistd.h> 7013139Speter#include <libutil.h> 7175535Sphk#include <md5.h> 721592Srgrimes 731592Srgrimes#include "extern.h" 741592Srgrimes 7556668Sshinextern union sockunion data_dest, his_addr; 761592Srgrimesextern int logged_in; 771592Srgrimesextern struct passwd *pw; 781592Srgrimesextern int guest; 7917435Spstextern int paranoid; 801592Srgrimesextern int logging; 811592Srgrimesextern int type; 821592Srgrimesextern int form; 8376096Smarkmextern int ftpdebug; 841592Srgrimesextern int timeout; 851592Srgrimesextern int maxtimeout; 861592Srgrimesextern int pdata; 8727650Sdavidnextern char *hostname; 8827650Sdavidnextern char remotehost[]; 891592Srgrimesextern char proctitle[]; 901592Srgrimesextern int usedefault; 911592Srgrimesextern int transflag; 921592Srgrimesextern char tmpline[]; 9370102Sphkextern int readonly; 9470102Sphkextern int noepsv; 9582460Snikextern int noretr; 9682796Ssheldonhextern int noguestretr; 971592Srgrimes 981592Srgrimesoff_t restart_point; 991592Srgrimes 1001592Srgrimesstatic int cmd_type; 1011592Srgrimesstatic int cmd_form; 1021592Srgrimesstatic int cmd_bytesz; 10389935Syarstatic int state; 1041592Srgrimeschar cbuf[512]; 10588935Sdwmalonechar *fromname = (char *) 0; 1061592Srgrimes 10756668Sshinextern int epsvall; 10856668Sshin 1091592Srgrimes%} 1101592Srgrimes 1111592Srgrimes%union { 1121592Srgrimes int i; 1131592Srgrimes char *s; 1141592Srgrimes} 1151592Srgrimes 1161592Srgrimes%token 1171592Srgrimes A B C E F I 1181592Srgrimes L N P R S T 11956668Sshin ALL 1201592Srgrimes 1211592Srgrimes SP CRLF COMMA 1221592Srgrimes 1231592Srgrimes USER PASS ACCT REIN QUIT PORT 1241592Srgrimes PASV TYPE STRU MODE RETR STOR 1251592Srgrimes APPE MLFL MAIL MSND MSOM MSAM 1261592Srgrimes MRSQ MRCP ALLO REST RNFR RNTO 1271592Srgrimes ABOR DELE CWD LIST NLST SITE 1281592Srgrimes STAT HELP NOOP MKD RMD PWD 1291592Srgrimes CDUP STOU SMNT SYST SIZE MDTM 13056668Sshin LPRT LPSV EPRT EPSV 1311592Srgrimes 13275535Sphk UMASK IDLE CHMOD MDFIVE 1331592Srgrimes 1341592Srgrimes LEXERR 1351592Srgrimes 1361592Srgrimes%token <s> STRING 1371592Srgrimes%token <i> NUMBER 1381592Srgrimes 1391592Srgrimes%type <i> check_login octal_number byte_size 14070102Sphk%type <i> check_login_ro octal_number byte_size 14170102Sphk%type <i> check_login_epsv octal_number byte_size 1421592Srgrimes%type <i> struct_code mode_code type_code form_code 14375567Speter%type <s> pathstring pathname password username 14456668Sshin%type <s> ALL 1451592Srgrimes 1461592Srgrimes%start cmd_list 1471592Srgrimes 1481592Srgrimes%% 1491592Srgrimes 1501592Srgrimescmd_list 1511592Srgrimes : /* empty */ 1521592Srgrimes | cmd_list cmd 1531592Srgrimes { 15488935Sdwmalone if (fromname) 15588935Sdwmalone free(fromname); 1561592Srgrimes fromname = (char *) 0; 1571592Srgrimes restart_point = (off_t) 0; 1581592Srgrimes } 1591592Srgrimes | cmd_list rcmd 1601592Srgrimes ; 1611592Srgrimes 1621592Srgrimescmd 1631592Srgrimes : USER SP username CRLF 1641592Srgrimes { 1651592Srgrimes user($3); 1661592Srgrimes free($3); 1671592Srgrimes } 1681592Srgrimes | PASS SP password CRLF 1691592Srgrimes { 1701592Srgrimes pass($3); 1711592Srgrimes free($3); 1721592Srgrimes } 17375556Sgreen | PASS CRLF 17475556Sgreen { 17575556Sgreen pass(""); 17675556Sgreen } 17717433Spst | PORT check_login SP host_port CRLF 1781592Srgrimes { 17956668Sshin if (epsvall) { 18056668Sshin reply(501, "no PORT allowed after EPSV ALL"); 18156668Sshin goto port_done; 18256668Sshin } 18356668Sshin if (!$2) 18456668Sshin goto port_done; 18556668Sshin if (port_check("PORT") == 1) 18656668Sshin goto port_done; 18756668Sshin#ifdef INET6 18856668Sshin if ((his_addr.su_family != AF_INET6 || 18956668Sshin !IN6_IS_ADDR_V4MAPPED(&his_addr.su_sin6.sin6_addr))) { 19056668Sshin /* shoud never happen */ 19156668Sshin usedefault = 1; 19256668Sshin reply(500, "Invalid address rejected."); 19356668Sshin goto port_done; 19456668Sshin } 19556668Sshin port_check_v6("pcmd"); 19656668Sshin#endif 19756668Sshin port_done: 19856668Sshin } 19956668Sshin | LPRT check_login SP host_long_port CRLF 20056668Sshin { 20156668Sshin if (epsvall) { 20256668Sshin reply(501, "no LPRT allowed after EPSV ALL"); 20356668Sshin goto lprt_done; 20456668Sshin } 20556668Sshin if (!$2) 20656668Sshin goto lprt_done; 20756668Sshin if (port_check("LPRT") == 1) 20856668Sshin goto lprt_done; 20956668Sshin#ifdef INET6 21056668Sshin if (his_addr.su_family != AF_INET6) { 21156668Sshin usedefault = 1; 21256668Sshin reply(500, "Invalid address rejected."); 21356668Sshin goto lprt_done; 21456668Sshin } 21556668Sshin if (port_check_v6("LPRT") == 1) 21656668Sshin goto lprt_done; 21756668Sshin#endif 21856668Sshin lprt_done: 21956668Sshin } 22056668Sshin | EPRT check_login SP STRING CRLF 22156668Sshin { 22256668Sshin char delim; 22356668Sshin char *tmp = NULL; 22456668Sshin char *p, *q; 22556668Sshin char *result[3]; 22656668Sshin struct addrinfo hints; 22756668Sshin struct addrinfo *res; 22856668Sshin int i; 22956668Sshin 23056668Sshin if (epsvall) { 23156668Sshin reply(501, "no EPRT allowed after EPSV ALL"); 23256668Sshin goto eprt_done; 23356668Sshin } 23456668Sshin if (!$2) 23556668Sshin goto eprt_done; 23656668Sshin 23756668Sshin memset(&data_dest, 0, sizeof(data_dest)); 23856668Sshin tmp = strdup($4); 23976096Smarkm if (ftpdebug) 24056668Sshin syslog(LOG_DEBUG, "%s", tmp); 24156668Sshin if (!tmp) { 24276096Smarkm fatalerror("not enough core"); 24356668Sshin /*NOTREACHED*/ 24456668Sshin } 24556668Sshin p = tmp; 24656668Sshin delim = p[0]; 24756668Sshin p++; 24856668Sshin memset(result, 0, sizeof(result)); 24956668Sshin for (i = 0; i < 3; i++) { 25056668Sshin q = strchr(p, delim); 25156668Sshin if (!q || *q != delim) { 25256668Sshin parsefail: 25356668Sshin reply(500, 25456668Sshin "Invalid argument, rejected."); 25556668Sshin if (tmp) 25656668Sshin free(tmp); 25717433Spst usedefault = 1; 25856668Sshin goto eprt_done; 25917433Spst } 26056668Sshin *q++ = '\0'; 26156668Sshin result[i] = p; 26276096Smarkm if (ftpdebug) 26356668Sshin syslog(LOG_DEBUG, "%d: %s", i, p); 26456668Sshin p = q; 2651592Srgrimes } 26656668Sshin 26756668Sshin /* some more sanity check */ 26856668Sshin p = result[0]; 26956668Sshin while (*p) { 27056668Sshin if (!isdigit(*p)) 27156668Sshin goto parsefail; 27256668Sshin p++; 27356668Sshin } 27456668Sshin p = result[2]; 27556668Sshin while (*p) { 27656668Sshin if (!isdigit(*p)) 27756668Sshin goto parsefail; 27856668Sshin p++; 27956668Sshin } 28056668Sshin 28156668Sshin /* grab address */ 28256668Sshin memset(&hints, 0, sizeof(hints)); 28356668Sshin if (atoi(result[0]) == 1) 28456668Sshin hints.ai_family = PF_INET; 28556668Sshin#ifdef INET6 28656668Sshin else if (atoi(result[0]) == 2) 28756668Sshin hints.ai_family = PF_INET6; 28856668Sshin#endif 28956668Sshin else 29056668Sshin hints.ai_family = PF_UNSPEC; /*XXX*/ 29156668Sshin hints.ai_socktype = SOCK_STREAM; 29256668Sshin i = getaddrinfo(result[1], result[2], &hints, &res); 29356668Sshin if (i) 29456668Sshin goto parsefail; 29556668Sshin memcpy(&data_dest, res->ai_addr, res->ai_addrlen); 29656668Sshin#ifdef INET6 29756668Sshin if (his_addr.su_family == AF_INET6 29856668Sshin && data_dest.su_family == AF_INET6) { 29956668Sshin /* XXX more sanity checks! */ 30056668Sshin data_dest.su_sin6.sin6_scope_id = 30156668Sshin his_addr.su_sin6.sin6_scope_id; 30256668Sshin } 30356668Sshin#endif 30456668Sshin free(tmp); 30556668Sshin tmp = NULL; 30656668Sshin 30756668Sshin if (port_check("EPRT") == 1) 30856668Sshin goto eprt_done; 30956668Sshin#ifdef INET6 31056668Sshin if (his_addr.su_family != AF_INET6) { 31156668Sshin usedefault = 1; 31256668Sshin reply(500, "Invalid address rejected."); 31356668Sshin goto eprt_done; 31456668Sshin } 31556668Sshin if (port_check_v6("EPRT") == 1) 31656668Sshin goto eprt_done; 31756668Sshin#endif 31888935Sdwmalone eprt_done: 31988935Sdwmalone free($4); 3201592Srgrimes } 32117433Spst | PASV check_login CRLF 3221592Srgrimes { 32356668Sshin if (epsvall) 32456668Sshin reply(501, "no PASV allowed after EPSV ALL"); 32556668Sshin else if ($2) 32617433Spst passive(); 3271592Srgrimes } 32856668Sshin | LPSV check_login CRLF 32956668Sshin { 33056668Sshin if (epsvall) 33156668Sshin reply(501, "no LPSV allowed after EPSV ALL"); 33256668Sshin else if ($2) 33356668Sshin long_passive("LPSV", PF_UNSPEC); 33456668Sshin } 33570102Sphk | EPSV check_login_epsv SP NUMBER CRLF 33656668Sshin { 33756668Sshin if ($2) { 33856668Sshin int pf; 33956668Sshin switch ($4) { 34056668Sshin case 1: 34156668Sshin pf = PF_INET; 34256668Sshin break; 34356668Sshin#ifdef INET6 34456668Sshin case 2: 34556668Sshin pf = PF_INET6; 34656668Sshin break; 34756668Sshin#endif 34856668Sshin default: 34956668Sshin pf = -1; /*junk value*/ 35056668Sshin break; 35156668Sshin } 35256668Sshin long_passive("EPSV", pf); 35356668Sshin } 35456668Sshin } 35570102Sphk | EPSV check_login_epsv SP ALL CRLF 35656668Sshin { 35756668Sshin if ($2) { 35856668Sshin reply(200, 35956668Sshin "EPSV ALL command successful."); 36056668Sshin epsvall++; 36156668Sshin } 36256668Sshin } 36370102Sphk | EPSV check_login_epsv CRLF 36456668Sshin { 36556668Sshin if ($2) 36656668Sshin long_passive("EPSV", PF_UNSPEC); 36756668Sshin } 36871278Sjedgar | TYPE check_login SP type_code CRLF 3691592Srgrimes { 37071278Sjedgar if ($2) { 37171278Sjedgar switch (cmd_type) { 3721592Srgrimes 37371278Sjedgar case TYPE_A: 37471278Sjedgar if (cmd_form == FORM_N) { 37571278Sjedgar reply(200, "Type set to A."); 37671278Sjedgar type = cmd_type; 37771278Sjedgar form = cmd_form; 37871278Sjedgar } else 37971278Sjedgar reply(504, "Form must be N."); 38071278Sjedgar break; 3811592Srgrimes 38271278Sjedgar case TYPE_E: 38371278Sjedgar reply(504, "Type E not implemented."); 38471278Sjedgar break; 3851592Srgrimes 38671278Sjedgar case TYPE_I: 38771278Sjedgar reply(200, "Type set to I."); 38871278Sjedgar type = cmd_type; 38971278Sjedgar break; 3901592Srgrimes 39171278Sjedgar case TYPE_L: 3921592Srgrimes#if NBBY == 8 39371278Sjedgar if (cmd_bytesz == 8) { 39471278Sjedgar reply(200, 39571278Sjedgar "Type set to L (byte size 8)."); 39671278Sjedgar type = cmd_type; 39771278Sjedgar } else 39871278Sjedgar reply(504, "Byte size must be 8."); 3991592Srgrimes#else /* NBBY == 8 */ 40071278Sjedgar UNIMPLEMENTED for NBBY != 8 4011592Srgrimes#endif /* NBBY == 8 */ 40271278Sjedgar } 4031592Srgrimes } 4041592Srgrimes } 40571278Sjedgar | STRU check_login SP struct_code CRLF 4061592Srgrimes { 40771278Sjedgar if ($2) { 40871278Sjedgar switch ($4) { 4091592Srgrimes 41071278Sjedgar case STRU_F: 41171278Sjedgar reply(200, "STRU F ok."); 41271278Sjedgar break; 4131592Srgrimes 41471278Sjedgar default: 41571278Sjedgar reply(504, "Unimplemented STRU type."); 41671278Sjedgar } 4171592Srgrimes } 4181592Srgrimes } 41971278Sjedgar | MODE check_login SP mode_code CRLF 4201592Srgrimes { 42171278Sjedgar if ($2) { 42271278Sjedgar switch ($4) { 4231592Srgrimes 42471278Sjedgar case MODE_S: 42571278Sjedgar reply(200, "MODE S ok."); 42671278Sjedgar break; 42771278Sjedgar 42871278Sjedgar default: 42971278Sjedgar reply(502, "Unimplemented MODE type."); 43071278Sjedgar } 4311592Srgrimes } 4321592Srgrimes } 43371278Sjedgar | ALLO check_login SP NUMBER CRLF 4341592Srgrimes { 43571278Sjedgar if ($2) { 43671278Sjedgar reply(202, "ALLO command ignored."); 43771278Sjedgar } 4381592Srgrimes } 43971278Sjedgar | ALLO check_login SP NUMBER SP R SP NUMBER CRLF 4401592Srgrimes { 44171278Sjedgar if ($2) { 44271278Sjedgar reply(202, "ALLO command ignored."); 44371278Sjedgar } 4441592Srgrimes } 4451592Srgrimes | RETR check_login SP pathname CRLF 4461592Srgrimes { 44782796Ssheldonh if (noretr || (guest && noguestretr)) 44882460Snik reply(500, "RETR command is disabled"); 44982460Snik else if ($2 && $4 != NULL) 4501592Srgrimes retrieve((char *) 0, $4); 45182460Snik 4521592Srgrimes if ($4 != NULL) 4531592Srgrimes free($4); 4541592Srgrimes } 45570102Sphk | STOR check_login_ro SP pathname CRLF 4561592Srgrimes { 4571592Srgrimes if ($2 && $4 != NULL) 4581592Srgrimes store($4, "w", 0); 4591592Srgrimes if ($4 != NULL) 4601592Srgrimes free($4); 4611592Srgrimes } 46270102Sphk | APPE check_login_ro SP pathname CRLF 4631592Srgrimes { 4641592Srgrimes if ($2 && $4 != NULL) 4651592Srgrimes store($4, "a", 0); 4661592Srgrimes if ($4 != NULL) 4671592Srgrimes free($4); 4681592Srgrimes } 4691592Srgrimes | NLST check_login CRLF 4701592Srgrimes { 4711592Srgrimes if ($2) 4721592Srgrimes send_file_list("."); 4731592Srgrimes } 4741592Srgrimes | NLST check_login SP STRING CRLF 4751592Srgrimes { 4761592Srgrimes if ($2 && $4 != NULL) 4771592Srgrimes send_file_list($4); 4781592Srgrimes if ($4 != NULL) 4791592Srgrimes free($4); 4801592Srgrimes } 4811592Srgrimes | LIST check_login CRLF 4821592Srgrimes { 4831592Srgrimes if ($2) 4841592Srgrimes retrieve("/bin/ls -lgA", ""); 4851592Srgrimes } 48675567Speter | LIST check_login SP pathstring CRLF 4871592Srgrimes { 4881592Srgrimes if ($2 && $4 != NULL) 4891592Srgrimes retrieve("/bin/ls -lgA %s", $4); 4901592Srgrimes if ($4 != NULL) 4911592Srgrimes free($4); 4921592Srgrimes } 4931592Srgrimes | STAT check_login SP pathname CRLF 4941592Srgrimes { 4951592Srgrimes if ($2 && $4 != NULL) 4961592Srgrimes statfilecmd($4); 4971592Srgrimes if ($4 != NULL) 4981592Srgrimes free($4); 4991592Srgrimes } 50071278Sjedgar | STAT check_login CRLF 5011592Srgrimes { 50271278Sjedgar if ($2) { 50371278Sjedgar statcmd(); 50471278Sjedgar } 5051592Srgrimes } 50670102Sphk | DELE check_login_ro SP pathname CRLF 5071592Srgrimes { 5081592Srgrimes if ($2 && $4 != NULL) 5091592Srgrimes delete($4); 5101592Srgrimes if ($4 != NULL) 5111592Srgrimes free($4); 5121592Srgrimes } 51370102Sphk | RNTO check_login_ro SP pathname CRLF 5141592Srgrimes { 51517433Spst if ($2) { 51617433Spst if (fromname) { 51717433Spst renamecmd(fromname, $4); 51817433Spst free(fromname); 51917433Spst fromname = (char *) 0; 52017433Spst } else { 52117433Spst reply(503, "Bad sequence of commands."); 52217433Spst } 5231592Srgrimes } 52417433Spst free($4); 5251592Srgrimes } 52671278Sjedgar | ABOR check_login CRLF 5271592Srgrimes { 52871278Sjedgar if ($2) 52971278Sjedgar reply(225, "ABOR command successful."); 5301592Srgrimes } 5311592Srgrimes | CWD check_login CRLF 5321592Srgrimes { 53369234Sdanny if ($2) { 53469234Sdanny if (guest) 53569234Sdanny cwd("/"); 53669234Sdanny else 53769234Sdanny cwd(pw->pw_dir); 53869234Sdanny } 5391592Srgrimes } 5401592Srgrimes | CWD check_login SP pathname CRLF 5411592Srgrimes { 5421592Srgrimes if ($2 && $4 != NULL) 5431592Srgrimes cwd($4); 5441592Srgrimes if ($4 != NULL) 5451592Srgrimes free($4); 5461592Srgrimes } 5471592Srgrimes | HELP CRLF 5481592Srgrimes { 5491592Srgrimes help(cmdtab, (char *) 0); 5501592Srgrimes } 5511592Srgrimes | HELP SP STRING CRLF 5521592Srgrimes { 5531592Srgrimes char *cp = $3; 5541592Srgrimes 5551592Srgrimes if (strncasecmp(cp, "SITE", 4) == 0) { 5561592Srgrimes cp = $3 + 4; 5571592Srgrimes if (*cp == ' ') 5581592Srgrimes cp++; 5591592Srgrimes if (*cp) 5601592Srgrimes help(sitetab, cp); 5611592Srgrimes else 5621592Srgrimes help(sitetab, (char *) 0); 5631592Srgrimes } else 5641592Srgrimes help(cmdtab, $3); 56588935Sdwmalone free($3); 5661592Srgrimes } 5671592Srgrimes | NOOP CRLF 5681592Srgrimes { 5691592Srgrimes reply(200, "NOOP command successful."); 5701592Srgrimes } 57170102Sphk | MKD check_login_ro SP pathname CRLF 5721592Srgrimes { 5731592Srgrimes if ($2 && $4 != NULL) 5741592Srgrimes makedir($4); 5751592Srgrimes if ($4 != NULL) 5761592Srgrimes free($4); 5771592Srgrimes } 57870102Sphk | RMD check_login_ro SP pathname CRLF 5791592Srgrimes { 5801592Srgrimes if ($2 && $4 != NULL) 5811592Srgrimes removedir($4); 5821592Srgrimes if ($4 != NULL) 5831592Srgrimes free($4); 5841592Srgrimes } 5851592Srgrimes | PWD check_login CRLF 5861592Srgrimes { 5871592Srgrimes if ($2) 5881592Srgrimes pwd(); 5891592Srgrimes } 5901592Srgrimes | CDUP check_login CRLF 5911592Srgrimes { 5921592Srgrimes if ($2) 5931592Srgrimes cwd(".."); 5941592Srgrimes } 5951592Srgrimes | SITE SP HELP CRLF 5961592Srgrimes { 5971592Srgrimes help(sitetab, (char *) 0); 5981592Srgrimes } 5991592Srgrimes | SITE SP HELP SP STRING CRLF 6001592Srgrimes { 6011592Srgrimes help(sitetab, $5); 60288935Sdwmalone free($5); 6031592Srgrimes } 60475535Sphk | SITE SP MDFIVE check_login SP pathname CRLF 60575535Sphk { 60675535Sphk char p[64], *q; 60775535Sphk 60875535Sphk if ($4) { 60975535Sphk q = MD5File($6, p); 61075535Sphk if (q != NULL) 61175535Sphk reply(200, "MD5(%s) = %s", $6, p); 61275535Sphk else 61375535Sphk perror_reply(550, $6); 61475535Sphk } 61588935Sdwmalone if ($6) 61688935Sdwmalone free($6); 61775535Sphk } 6181592Srgrimes | SITE SP UMASK check_login CRLF 6191592Srgrimes { 6201592Srgrimes int oldmask; 6211592Srgrimes 6221592Srgrimes if ($4) { 6231592Srgrimes oldmask = umask(0); 6241592Srgrimes (void) umask(oldmask); 6251592Srgrimes reply(200, "Current UMASK is %03o", oldmask); 6261592Srgrimes } 6271592Srgrimes } 6281592Srgrimes | SITE SP UMASK check_login SP octal_number CRLF 6291592Srgrimes { 6301592Srgrimes int oldmask; 6311592Srgrimes 6321592Srgrimes if ($4) { 6331592Srgrimes if (($6 == -1) || ($6 > 0777)) { 6341592Srgrimes reply(501, "Bad UMASK value"); 6351592Srgrimes } else { 6361592Srgrimes oldmask = umask($6); 6371592Srgrimes reply(200, 6381592Srgrimes "UMASK set to %03o (was %03o)", 6391592Srgrimes $6, oldmask); 6401592Srgrimes } 6411592Srgrimes } 6421592Srgrimes } 64370102Sphk | SITE SP CHMOD check_login_ro SP octal_number SP pathname CRLF 6441592Srgrimes { 6451592Srgrimes if ($4 && ($8 != NULL)) { 6461592Srgrimes if ($6 > 0777) 6471592Srgrimes reply(501, 6481592Srgrimes "CHMOD: Mode value must be between 0 and 0777"); 6491592Srgrimes else if (chmod($8, $6) < 0) 6501592Srgrimes perror_reply(550, $8); 6511592Srgrimes else 6521592Srgrimes reply(200, "CHMOD command successful."); 6531592Srgrimes } 6541592Srgrimes if ($8 != NULL) 6551592Srgrimes free($8); 6561592Srgrimes } 65771278Sjedgar | SITE SP check_login IDLE CRLF 6581592Srgrimes { 65971278Sjedgar if ($3) 66071278Sjedgar reply(200, 66171278Sjedgar "Current IDLE time limit is %d seconds; max %d", 66271278Sjedgar timeout, maxtimeout); 6631592Srgrimes } 66471278Sjedgar | SITE SP check_login IDLE SP NUMBER CRLF 6651592Srgrimes { 66671278Sjedgar if ($3) { 66771278Sjedgar if ($6 < 30 || $6 > maxtimeout) { 66871278Sjedgar reply(501, 66971278Sjedgar "Maximum IDLE time must be between 30 and %d seconds", 67071278Sjedgar maxtimeout); 67171278Sjedgar } else { 67271278Sjedgar timeout = $6; 67371278Sjedgar (void) alarm((unsigned) timeout); 67471278Sjedgar reply(200, 67571278Sjedgar "Maximum IDLE time set to %d seconds", 67671278Sjedgar timeout); 67771278Sjedgar } 6781592Srgrimes } 6791592Srgrimes } 68070102Sphk | STOU check_login_ro SP pathname CRLF 6811592Srgrimes { 6821592Srgrimes if ($2 && $4 != NULL) 6831592Srgrimes store($4, "w", 1); 6841592Srgrimes if ($4 != NULL) 6851592Srgrimes free($4); 6861592Srgrimes } 68771278Sjedgar | SYST check_login CRLF 6881592Srgrimes { 68971278Sjedgar if ($2) 6901592Srgrimes#ifdef unix 6911592Srgrimes#ifdef BSD 6921592Srgrimes reply(215, "UNIX Type: L%d Version: BSD-%d", 6931592Srgrimes NBBY, BSD); 6941592Srgrimes#else /* BSD */ 6951592Srgrimes reply(215, "UNIX Type: L%d", NBBY); 6961592Srgrimes#endif /* BSD */ 6971592Srgrimes#else /* unix */ 6981592Srgrimes reply(215, "UNKNOWN Type: L%d", NBBY); 6991592Srgrimes#endif /* unix */ 7001592Srgrimes } 7011592Srgrimes 7021592Srgrimes /* 7031592Srgrimes * SIZE is not in RFC959, but Postel has blessed it and 7041592Srgrimes * it will be in the updated RFC. 7051592Srgrimes * 7061592Srgrimes * Return size of file in a format suitable for 7071592Srgrimes * using with RESTART (we just count bytes). 7081592Srgrimes */ 7091592Srgrimes | SIZE check_login SP pathname CRLF 7101592Srgrimes { 7111592Srgrimes if ($2 && $4 != NULL) 7121592Srgrimes sizecmd($4); 7131592Srgrimes if ($4 != NULL) 7141592Srgrimes free($4); 7151592Srgrimes } 7161592Srgrimes 7171592Srgrimes /* 7181592Srgrimes * MDTM is not in RFC959, but Postel has blessed it and 7191592Srgrimes * it will be in the updated RFC. 7201592Srgrimes * 7211592Srgrimes * Return modification time of file as an ISO 3307 7221592Srgrimes * style time. E.g. YYYYMMDDHHMMSS or YYYYMMDDHHMMSS.xxx 7231592Srgrimes * where xxx is the fractional second (of any precision, 7241592Srgrimes * not necessarily 3 digits) 7251592Srgrimes */ 7261592Srgrimes | MDTM check_login SP pathname CRLF 7271592Srgrimes { 7281592Srgrimes if ($2 && $4 != NULL) { 7291592Srgrimes struct stat stbuf; 7301592Srgrimes if (stat($4, &stbuf) < 0) 7311592Srgrimes reply(550, "%s: %s", 7321592Srgrimes $4, strerror(errno)); 7331592Srgrimes else if (!S_ISREG(stbuf.st_mode)) { 7341592Srgrimes reply(550, "%s: not a plain file.", $4); 7351592Srgrimes } else { 7361592Srgrimes struct tm *t; 7371592Srgrimes t = gmtime(&stbuf.st_mtime); 7381592Srgrimes reply(213, 73917435Spst "%04d%02d%02d%02d%02d%02d", 74017435Spst 1900 + t->tm_year, 74117435Spst t->tm_mon+1, t->tm_mday, 7421592Srgrimes t->tm_hour, t->tm_min, t->tm_sec); 7431592Srgrimes } 7441592Srgrimes } 7451592Srgrimes if ($4 != NULL) 7461592Srgrimes free($4); 7471592Srgrimes } 7481592Srgrimes | QUIT CRLF 7491592Srgrimes { 7501592Srgrimes reply(221, "Goodbye."); 7511592Srgrimes dologout(0); 7521592Srgrimes } 75389935Syar | error 7541592Srgrimes { 75589935Syar yyclearin; /* discard lookahead data */ 75689935Syar yyerrok; /* clear error condition */ 75789935Syar state = 0; /* reset lexer state */ 7581592Srgrimes } 7591592Srgrimes ; 7601592Srgrimesrcmd 76170102Sphk : RNFR check_login_ro SP pathname CRLF 7621592Srgrimes { 7631592Srgrimes restart_point = (off_t) 0; 7641592Srgrimes if ($2 && $4) { 76588935Sdwmalone if (fromname) 76688935Sdwmalone free(fromname); 76788935Sdwmalone fromname = (char *) 0; 76888935Sdwmalone if (renamefrom($4)) 76988935Sdwmalone fromname = $4; 77088935Sdwmalone else 7711592Srgrimes free($4); 77288935Sdwmalone } else if ($4) { 77388935Sdwmalone free($4); 7741592Srgrimes } 7751592Srgrimes } 77671278Sjedgar | REST check_login SP byte_size CRLF 7771592Srgrimes { 77871278Sjedgar if ($2) { 77988935Sdwmalone if (fromname) 78088935Sdwmalone free(fromname); 78171278Sjedgar fromname = (char *) 0; 78271278Sjedgar restart_point = $4; /* XXX $4 is only "int" */ 78371278Sjedgar reply(350, "Restarting at %qd. %s", 78471278Sjedgar restart_point, 78571278Sjedgar "Send STORE or RETRIEVE to initiate transfer."); 78671278Sjedgar } 7871592Srgrimes } 7881592Srgrimes ; 7891592Srgrimes 7901592Srgrimesusername 7911592Srgrimes : STRING 7921592Srgrimes ; 7931592Srgrimes 7941592Srgrimespassword 7951592Srgrimes : /* empty */ 7961592Srgrimes { 7971592Srgrimes $$ = (char *)calloc(1, sizeof(char)); 7981592Srgrimes } 7991592Srgrimes | STRING 8001592Srgrimes ; 8011592Srgrimes 8021592Srgrimesbyte_size 8031592Srgrimes : NUMBER 8041592Srgrimes ; 8051592Srgrimes 8061592Srgrimeshost_port 8071592Srgrimes : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 8081592Srgrimes NUMBER COMMA NUMBER 8091592Srgrimes { 8101592Srgrimes char *a, *p; 8111592Srgrimes 81256668Sshin data_dest.su_len = sizeof(struct sockaddr_in); 81356668Sshin data_dest.su_family = AF_INET; 81456668Sshin p = (char *)&data_dest.su_sin.sin_port; 81517435Spst p[0] = $9; p[1] = $11; 81656668Sshin a = (char *)&data_dest.su_sin.sin_addr; 8171592Srgrimes a[0] = $1; a[1] = $3; a[2] = $5; a[3] = $7; 8181592Srgrimes } 8191592Srgrimes ; 8201592Srgrimes 82156668Sshinhost_long_port 82256668Sshin : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 82356668Sshin NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 82456668Sshin NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 82556668Sshin NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 82656668Sshin NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 82756668Sshin NUMBER 82856668Sshin { 82956668Sshin char *a, *p; 83056668Sshin 83156668Sshin memset(&data_dest, 0, sizeof(data_dest)); 83256668Sshin data_dest.su_len = sizeof(struct sockaddr_in6); 83356668Sshin data_dest.su_family = AF_INET6; 83456668Sshin p = (char *)&data_dest.su_port; 83556668Sshin p[0] = $39; p[1] = $41; 83656668Sshin a = (char *)&data_dest.su_sin6.sin6_addr; 83756668Sshin a[0] = $5; a[1] = $7; a[2] = $9; a[3] = $11; 83856668Sshin a[4] = $13; a[5] = $15; a[6] = $17; a[7] = $19; 83956668Sshin a[8] = $21; a[9] = $23; a[10] = $25; a[11] = $27; 84056668Sshin a[12] = $29; a[13] = $31; a[14] = $33; a[15] = $35; 84156668Sshin if (his_addr.su_family == AF_INET6) { 84256668Sshin /* XXX more sanity checks! */ 84356668Sshin data_dest.su_sin6.sin6_scope_id = 84456668Sshin his_addr.su_sin6.sin6_scope_id; 84556668Sshin } 84656668Sshin if ($1 != 6 || $3 != 16 || $37 != 2) 84756668Sshin memset(&data_dest, 0, sizeof(data_dest)); 84856668Sshin } 84956668Sshin | NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 85056668Sshin NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 85156668Sshin NUMBER 85256668Sshin { 85356668Sshin char *a, *p; 85456668Sshin 85556668Sshin memset(&data_dest, 0, sizeof(data_dest)); 85656668Sshin data_dest.su_sin.sin_len = sizeof(struct sockaddr_in); 85756668Sshin data_dest.su_family = AF_INET; 85856668Sshin p = (char *)&data_dest.su_port; 85956668Sshin p[0] = $15; p[1] = $17; 86056668Sshin a = (char *)&data_dest.su_sin.sin_addr; 86156668Sshin a[0] = $5; a[1] = $7; a[2] = $9; a[3] = $11; 86256668Sshin if ($1 != 4 || $3 != 4 || $13 != 2) 86356668Sshin memset(&data_dest, 0, sizeof(data_dest)); 86456668Sshin } 86556668Sshin ; 86656668Sshin 8671592Srgrimesform_code 8681592Srgrimes : N 8691592Srgrimes { 8701592Srgrimes $$ = FORM_N; 8711592Srgrimes } 8721592Srgrimes | T 8731592Srgrimes { 8741592Srgrimes $$ = FORM_T; 8751592Srgrimes } 8761592Srgrimes | C 8771592Srgrimes { 8781592Srgrimes $$ = FORM_C; 8791592Srgrimes } 8801592Srgrimes ; 8811592Srgrimes 8821592Srgrimestype_code 8831592Srgrimes : A 8841592Srgrimes { 8851592Srgrimes cmd_type = TYPE_A; 8861592Srgrimes cmd_form = FORM_N; 8871592Srgrimes } 8881592Srgrimes | A SP form_code 8891592Srgrimes { 8901592Srgrimes cmd_type = TYPE_A; 8911592Srgrimes cmd_form = $3; 8921592Srgrimes } 8931592Srgrimes | E 8941592Srgrimes { 8951592Srgrimes cmd_type = TYPE_E; 8961592Srgrimes cmd_form = FORM_N; 8971592Srgrimes } 8981592Srgrimes | E SP form_code 8991592Srgrimes { 9001592Srgrimes cmd_type = TYPE_E; 9011592Srgrimes cmd_form = $3; 9021592Srgrimes } 9031592Srgrimes | I 9041592Srgrimes { 9051592Srgrimes cmd_type = TYPE_I; 9061592Srgrimes } 9071592Srgrimes | L 9081592Srgrimes { 9091592Srgrimes cmd_type = TYPE_L; 9101592Srgrimes cmd_bytesz = NBBY; 9111592Srgrimes } 9121592Srgrimes | L SP byte_size 9131592Srgrimes { 9141592Srgrimes cmd_type = TYPE_L; 9151592Srgrimes cmd_bytesz = $3; 9161592Srgrimes } 9171592Srgrimes /* this is for a bug in the BBN ftp */ 9181592Srgrimes | L byte_size 9191592Srgrimes { 9201592Srgrimes cmd_type = TYPE_L; 9211592Srgrimes cmd_bytesz = $2; 9221592Srgrimes } 9231592Srgrimes ; 9241592Srgrimes 9251592Srgrimesstruct_code 9261592Srgrimes : F 9271592Srgrimes { 9281592Srgrimes $$ = STRU_F; 9291592Srgrimes } 9301592Srgrimes | R 9311592Srgrimes { 9321592Srgrimes $$ = STRU_R; 9331592Srgrimes } 9341592Srgrimes | P 9351592Srgrimes { 9361592Srgrimes $$ = STRU_P; 9371592Srgrimes } 9381592Srgrimes ; 9391592Srgrimes 9401592Srgrimesmode_code 9411592Srgrimes : S 9421592Srgrimes { 9431592Srgrimes $$ = MODE_S; 9441592Srgrimes } 9451592Srgrimes | B 9461592Srgrimes { 9471592Srgrimes $$ = MODE_B; 9481592Srgrimes } 9491592Srgrimes | C 9501592Srgrimes { 9511592Srgrimes $$ = MODE_C; 9521592Srgrimes } 9531592Srgrimes ; 9541592Srgrimes 9551592Srgrimespathname 9561592Srgrimes : pathstring 9571592Srgrimes { 9581592Srgrimes /* 9591592Srgrimes * Problem: this production is used for all pathname 9601592Srgrimes * processing, but only gives a 550 error reply. 9611592Srgrimes * This is a valid reply in some cases but not in others. 9621592Srgrimes */ 96375567Speter if (logged_in && $1) { 9641592Srgrimes glob_t gl; 9651592Srgrimes int flags = 9661592Srgrimes GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE; 9671592Srgrimes 9681592Srgrimes memset(&gl, 0, sizeof(gl)); 96975560Sjedgar flags |= GLOB_MAXPATH; 97075560Sjedgar gl.gl_matchc = MAXGLOBARGS; 9711592Srgrimes if (glob($1, flags, NULL, &gl) || 9721592Srgrimes gl.gl_pathc == 0) { 9731592Srgrimes reply(550, "not found"); 9741592Srgrimes $$ = NULL; 97575567Speter } else if (gl.gl_pathc > 1) { 97675567Speter reply(550, "ambiguous"); 97775567Speter $$ = NULL; 9781592Srgrimes } else { 9791592Srgrimes $$ = strdup(gl.gl_pathv[0]); 9801592Srgrimes } 9811592Srgrimes globfree(&gl); 9821592Srgrimes free($1); 9831592Srgrimes } else 9841592Srgrimes $$ = $1; 9851592Srgrimes } 9861592Srgrimes ; 9871592Srgrimes 9881592Srgrimespathstring 9891592Srgrimes : STRING 9901592Srgrimes ; 9911592Srgrimes 9921592Srgrimesoctal_number 9931592Srgrimes : NUMBER 9941592Srgrimes { 9951592Srgrimes int ret, dec, multby, digit; 9961592Srgrimes 9971592Srgrimes /* 9981592Srgrimes * Convert a number that was read as decimal number 9991592Srgrimes * to what it would be if it had been read as octal. 10001592Srgrimes */ 10011592Srgrimes dec = $1; 10021592Srgrimes multby = 1; 10031592Srgrimes ret = 0; 10041592Srgrimes while (dec) { 10051592Srgrimes digit = dec%10; 10061592Srgrimes if (digit > 7) { 10071592Srgrimes ret = -1; 10081592Srgrimes break; 10091592Srgrimes } 10101592Srgrimes ret += digit * multby; 10111592Srgrimes multby *= 8; 10121592Srgrimes dec /= 10; 10131592Srgrimes } 10141592Srgrimes $$ = ret; 10151592Srgrimes } 10161592Srgrimes ; 10171592Srgrimes 10181592Srgrimes 10191592Srgrimescheck_login 10201592Srgrimes : /* empty */ 10211592Srgrimes { 102270102Sphk $$ = check_login1(); 10231592Srgrimes } 10241592Srgrimes ; 10251592Srgrimes 102670102Sphkcheck_login_epsv 102770102Sphk : /* empty */ 102870102Sphk { 102970102Sphk if (noepsv) { 103070102Sphk reply(500, "EPSV command disabled"); 103170102Sphk $$ = 0; 103270102Sphk } 103370102Sphk else 103470102Sphk $$ = check_login1(); 103570102Sphk } 103670102Sphk ; 103770102Sphk 103870102Sphkcheck_login_ro 103970102Sphk : /* empty */ 104070102Sphk { 104170102Sphk if (readonly) { 104272710Sdes reply(550, "Permission denied."); 104370102Sphk $$ = 0; 104470102Sphk } 104570102Sphk else 104670102Sphk $$ = check_login1(); 104770102Sphk } 104870102Sphk ; 104970102Sphk 10501592Srgrimes%% 10511592Srgrimes 10521592Srgrimes#define CMD 0 /* beginning of command */ 10531592Srgrimes#define ARGS 1 /* expect miscellaneous arguments */ 10541592Srgrimes#define STR1 2 /* expect SP followed by STRING */ 10551592Srgrimes#define STR2 3 /* expect STRING */ 10561592Srgrimes#define OSTR 4 /* optional SP then STRING */ 105775556Sgreen#define ZSTR1 5 /* optional SP then optional STRING */ 10581592Srgrimes#define ZSTR2 6 /* optional STRING after SP */ 10591592Srgrimes#define SITECMD 7 /* SITE command */ 10601592Srgrimes#define NSTR 8 /* Number followed by a string */ 10611592Srgrimes 106275560Sjedgar#define MAXGLOBARGS 1000 106375560Sjedgar 10641592Srgrimesstruct tab { 10651592Srgrimes char *name; 10661592Srgrimes short token; 10671592Srgrimes short state; 10681592Srgrimes short implemented; /* 1 if command is implemented */ 10691592Srgrimes char *help; 10701592Srgrimes}; 10711592Srgrimes 10721592Srgrimesstruct tab cmdtab[] = { /* In order defined in RFC 765 */ 10731592Srgrimes { "USER", USER, STR1, 1, "<sp> username" }, 107475556Sgreen { "PASS", PASS, ZSTR1, 1, "[<sp> [password]]" }, 10751592Srgrimes { "ACCT", ACCT, STR1, 0, "(specify account)" }, 10761592Srgrimes { "SMNT", SMNT, ARGS, 0, "(structure mount)" }, 10771592Srgrimes { "REIN", REIN, ARGS, 0, "(reinitialize server state)" }, 10781592Srgrimes { "QUIT", QUIT, ARGS, 1, "(terminate service)", }, 10791592Srgrimes { "PORT", PORT, ARGS, 1, "<sp> b0, b1, b2, b3, b4" }, 108056668Sshin { "LPRT", LPRT, ARGS, 1, "<sp> af, hal, h1, h2, h3,..., pal, p1, p2..." }, 108156668Sshin { "EPRT", EPRT, STR1, 1, "<sp> |af|addr|port|" }, 10821592Srgrimes { "PASV", PASV, ARGS, 1, "(set server in passive mode)" }, 108356668Sshin { "LPSV", LPSV, ARGS, 1, "(set server in passive mode)" }, 108456668Sshin { "EPSV", EPSV, ARGS, 1, "[<sp> af|ALL]" }, 10851592Srgrimes { "TYPE", TYPE, ARGS, 1, "<sp> [ A | E | I | L ]" }, 10861592Srgrimes { "STRU", STRU, ARGS, 1, "(specify file structure)" }, 10871592Srgrimes { "MODE", MODE, ARGS, 1, "(specify transfer mode)" }, 10881592Srgrimes { "RETR", RETR, STR1, 1, "<sp> file-name" }, 10891592Srgrimes { "STOR", STOR, STR1, 1, "<sp> file-name" }, 10901592Srgrimes { "APPE", APPE, STR1, 1, "<sp> file-name" }, 10911592Srgrimes { "MLFL", MLFL, OSTR, 0, "(mail file)" }, 10921592Srgrimes { "MAIL", MAIL, OSTR, 0, "(mail to user)" }, 10931592Srgrimes { "MSND", MSND, OSTR, 0, "(mail send to terminal)" }, 10941592Srgrimes { "MSOM", MSOM, OSTR, 0, "(mail send to terminal or mailbox)" }, 10951592Srgrimes { "MSAM", MSAM, OSTR, 0, "(mail send to terminal and mailbox)" }, 10961592Srgrimes { "MRSQ", MRSQ, OSTR, 0, "(mail recipient scheme question)" }, 10971592Srgrimes { "MRCP", MRCP, STR1, 0, "(mail recipient)" }, 10981592Srgrimes { "ALLO", ALLO, ARGS, 1, "allocate storage (vacuously)" }, 10991592Srgrimes { "REST", REST, ARGS, 1, "<sp> offset (restart command)" }, 11001592Srgrimes { "RNFR", RNFR, STR1, 1, "<sp> file-name" }, 11011592Srgrimes { "RNTO", RNTO, STR1, 1, "<sp> file-name" }, 11021592Srgrimes { "ABOR", ABOR, ARGS, 1, "(abort operation)" }, 11031592Srgrimes { "DELE", DELE, STR1, 1, "<sp> file-name" }, 11041592Srgrimes { "CWD", CWD, OSTR, 1, "[ <sp> directory-name ]" }, 11051592Srgrimes { "XCWD", CWD, OSTR, 1, "[ <sp> directory-name ]" }, 11061592Srgrimes { "LIST", LIST, OSTR, 1, "[ <sp> path-name ]" }, 11071592Srgrimes { "NLST", NLST, OSTR, 1, "[ <sp> path-name ]" }, 11081592Srgrimes { "SITE", SITE, SITECMD, 1, "site-cmd [ <sp> arguments ]" }, 11091592Srgrimes { "SYST", SYST, ARGS, 1, "(get type of operating system)" }, 11101592Srgrimes { "STAT", STAT, OSTR, 1, "[ <sp> path-name ]" }, 11111592Srgrimes { "HELP", HELP, OSTR, 1, "[ <sp> <string> ]" }, 11121592Srgrimes { "NOOP", NOOP, ARGS, 1, "" }, 11131592Srgrimes { "MKD", MKD, STR1, 1, "<sp> path-name" }, 11141592Srgrimes { "XMKD", MKD, STR1, 1, "<sp> path-name" }, 11151592Srgrimes { "RMD", RMD, STR1, 1, "<sp> path-name" }, 11161592Srgrimes { "XRMD", RMD, STR1, 1, "<sp> path-name" }, 11171592Srgrimes { "PWD", PWD, ARGS, 1, "(return current directory)" }, 11181592Srgrimes { "XPWD", PWD, ARGS, 1, "(return current directory)" }, 11191592Srgrimes { "CDUP", CDUP, ARGS, 1, "(change to parent directory)" }, 11201592Srgrimes { "XCUP", CDUP, ARGS, 1, "(change to parent directory)" }, 11211592Srgrimes { "STOU", STOU, STR1, 1, "<sp> file-name" }, 11221592Srgrimes { "SIZE", SIZE, OSTR, 1, "<sp> path-name" }, 11231592Srgrimes { "MDTM", MDTM, OSTR, 1, "<sp> path-name" }, 11241592Srgrimes { NULL, 0, 0, 0, 0 } 11251592Srgrimes}; 11261592Srgrimes 11271592Srgrimesstruct tab sitetab[] = { 112875535Sphk { "MD5", MDFIVE, STR1, 1, "[ <sp> file-name ]" }, 11291592Srgrimes { "UMASK", UMASK, ARGS, 1, "[ <sp> umask ]" }, 11301592Srgrimes { "IDLE", IDLE, ARGS, 1, "[ <sp> maximum-idle-time ]" }, 11311592Srgrimes { "CHMOD", CHMOD, NSTR, 1, "<sp> mode <sp> file-name" }, 11321592Srgrimes { "HELP", HELP, OSTR, 1, "[ <sp> <string> ]" }, 11331592Srgrimes { NULL, 0, 0, 0, 0 } 11341592Srgrimes}; 11351592Srgrimes 11361592Srgrimesstatic char *copy __P((char *)); 11371592Srgrimesstatic void help __P((struct tab *, char *)); 11381592Srgrimesstatic struct tab * 11391592Srgrimes lookup __P((struct tab *, char *)); 114056668Sshinstatic int port_check __P((const char *)); 114156668Sshinstatic int port_check_v6 __P((const char *)); 11421592Srgrimesstatic void sizecmd __P((char *)); 11431592Srgrimesstatic void toolong __P((int)); 114456668Sshinstatic void v4map_data_dest __P((void)); 11451592Srgrimesstatic int yylex __P((void)); 11461592Srgrimes 11471592Srgrimesstatic struct tab * 11481592Srgrimeslookup(p, cmd) 11491592Srgrimes struct tab *p; 11501592Srgrimes char *cmd; 11511592Srgrimes{ 11521592Srgrimes 11531592Srgrimes for (; p->name != NULL; p++) 11541592Srgrimes if (strcmp(cmd, p->name) == 0) 11551592Srgrimes return (p); 11561592Srgrimes return (0); 11571592Srgrimes} 11581592Srgrimes 11591592Srgrimes#include <arpa/telnet.h> 11601592Srgrimes 11611592Srgrimes/* 11621592Srgrimes * getline - a hacked up version of fgets to ignore TELNET escape codes. 11631592Srgrimes */ 11641592Srgrimeschar * 11651592Srgrimesgetline(s, n, iop) 11661592Srgrimes char *s; 11671592Srgrimes int n; 11681592Srgrimes FILE *iop; 11691592Srgrimes{ 11701592Srgrimes int c; 11711592Srgrimes register char *cs; 11721592Srgrimes 11731592Srgrimes cs = s; 11741592Srgrimes/* tmpline may contain saved command from urgent mode interruption */ 11751592Srgrimes for (c = 0; tmpline[c] != '\0' && --n > 0; ++c) { 11761592Srgrimes *cs++ = tmpline[c]; 11771592Srgrimes if (tmpline[c] == '\n') { 11781592Srgrimes *cs++ = '\0'; 117976096Smarkm if (ftpdebug) 11801592Srgrimes syslog(LOG_DEBUG, "command: %s", s); 11811592Srgrimes tmpline[0] = '\0'; 11821592Srgrimes return(s); 11831592Srgrimes } 11841592Srgrimes if (c == 0) 11851592Srgrimes tmpline[0] = '\0'; 11861592Srgrimes } 11871592Srgrimes while ((c = getc(iop)) != EOF) { 11881592Srgrimes c &= 0377; 11891592Srgrimes if (c == IAC) { 11901592Srgrimes if ((c = getc(iop)) != EOF) { 11911592Srgrimes c &= 0377; 11921592Srgrimes switch (c) { 11931592Srgrimes case WILL: 11941592Srgrimes case WONT: 11951592Srgrimes c = getc(iop); 11961592Srgrimes printf("%c%c%c", IAC, DONT, 0377&c); 11971592Srgrimes (void) fflush(stdout); 11981592Srgrimes continue; 11991592Srgrimes case DO: 12001592Srgrimes case DONT: 12011592Srgrimes c = getc(iop); 12021592Srgrimes printf("%c%c%c", IAC, WONT, 0377&c); 12031592Srgrimes (void) fflush(stdout); 12041592Srgrimes continue; 12051592Srgrimes case IAC: 12061592Srgrimes break; 12071592Srgrimes default: 12081592Srgrimes continue; /* ignore command */ 12091592Srgrimes } 12101592Srgrimes } 12111592Srgrimes } 12121592Srgrimes *cs++ = c; 12131592Srgrimes if (--n <= 0 || c == '\n') 12141592Srgrimes break; 12151592Srgrimes } 12161592Srgrimes if (c == EOF && cs == s) 12171592Srgrimes return (NULL); 12181592Srgrimes *cs++ = '\0'; 121976096Smarkm if (ftpdebug) { 12201592Srgrimes if (!guest && strncasecmp("pass ", s, 5) == 0) { 12211592Srgrimes /* Don't syslog passwords */ 12221592Srgrimes syslog(LOG_DEBUG, "command: %.5s ???", s); 12231592Srgrimes } else { 12241592Srgrimes register char *cp; 12251592Srgrimes register int len; 12261592Srgrimes 12271592Srgrimes /* Don't syslog trailing CR-LF */ 12281592Srgrimes len = strlen(s); 12291592Srgrimes cp = s + len - 1; 12301592Srgrimes while (cp >= s && (*cp == '\n' || *cp == '\r')) { 12311592Srgrimes --cp; 12321592Srgrimes --len; 12331592Srgrimes } 12341592Srgrimes syslog(LOG_DEBUG, "command: %.*s", len, s); 12351592Srgrimes } 12361592Srgrimes } 12371592Srgrimes return (s); 12381592Srgrimes} 12391592Srgrimes 12401592Srgrimesstatic void 12411592Srgrimestoolong(signo) 12421592Srgrimes int signo; 12431592Srgrimes{ 12441592Srgrimes 12451592Srgrimes reply(421, 12461592Srgrimes "Timeout (%d seconds): closing control connection.", timeout); 12471592Srgrimes if (logging) 12481592Srgrimes syslog(LOG_INFO, "User %s timed out after %d seconds", 12491592Srgrimes (pw ? pw -> pw_name : "unknown"), timeout); 12501592Srgrimes dologout(1); 12511592Srgrimes} 12521592Srgrimes 12531592Srgrimesstatic int 12541592Srgrimesyylex() 12551592Srgrimes{ 125689935Syar static int cpos; 12571592Srgrimes char *cp, *cp2; 12581592Srgrimes struct tab *p; 12591592Srgrimes int n; 12601592Srgrimes char c; 12611592Srgrimes 12621592Srgrimes for (;;) { 12631592Srgrimes switch (state) { 12641592Srgrimes 12651592Srgrimes case CMD: 12661592Srgrimes (void) signal(SIGALRM, toolong); 12671592Srgrimes (void) alarm((unsigned) timeout); 12681592Srgrimes if (getline(cbuf, sizeof(cbuf)-1, stdin) == NULL) { 12691592Srgrimes reply(221, "You could at least say goodbye."); 12701592Srgrimes dologout(0); 12711592Srgrimes } 12721592Srgrimes (void) alarm(0); 12731592Srgrimes#ifdef SETPROCTITLE 127429574Sphk if (strncasecmp(cbuf, "PASS", 4) != 0) 12751592Srgrimes setproctitle("%s: %s", proctitle, cbuf); 12761592Srgrimes#endif /* SETPROCTITLE */ 12771592Srgrimes if ((cp = strchr(cbuf, '\r'))) { 12781592Srgrimes *cp++ = '\n'; 12791592Srgrimes *cp = '\0'; 12801592Srgrimes } 12811592Srgrimes if ((cp = strpbrk(cbuf, " \n"))) 12821592Srgrimes cpos = cp - cbuf; 12831592Srgrimes if (cpos == 0) 12841592Srgrimes cpos = 4; 12851592Srgrimes c = cbuf[cpos]; 12861592Srgrimes cbuf[cpos] = '\0'; 12871592Srgrimes upper(cbuf); 12881592Srgrimes p = lookup(cmdtab, cbuf); 12891592Srgrimes cbuf[cpos] = c; 12903776Spst if (p != 0) { 12911592Srgrimes if (p->implemented == 0) { 12921592Srgrimes nack(p->name); 129389935Syar return (LEXERR); 12941592Srgrimes } 12951592Srgrimes state = p->state; 12961592Srgrimes yylval.s = p->name; 12971592Srgrimes return (p->token); 12981592Srgrimes } 12991592Srgrimes break; 13001592Srgrimes 13011592Srgrimes case SITECMD: 13021592Srgrimes if (cbuf[cpos] == ' ') { 13031592Srgrimes cpos++; 13041592Srgrimes return (SP); 13051592Srgrimes } 13061592Srgrimes cp = &cbuf[cpos]; 13071592Srgrimes if ((cp2 = strpbrk(cp, " \n"))) 13081592Srgrimes cpos = cp2 - cbuf; 13091592Srgrimes c = cbuf[cpos]; 13101592Srgrimes cbuf[cpos] = '\0'; 13111592Srgrimes upper(cp); 13121592Srgrimes p = lookup(sitetab, cp); 13131592Srgrimes cbuf[cpos] = c; 13143777Spst if (guest == 0 && p != 0) { 13151592Srgrimes if (p->implemented == 0) { 13161592Srgrimes state = CMD; 13171592Srgrimes nack(p->name); 131889935Syar return (LEXERR); 13191592Srgrimes } 13201592Srgrimes state = p->state; 13211592Srgrimes yylval.s = p->name; 13221592Srgrimes return (p->token); 13231592Srgrimes } 13241592Srgrimes state = CMD; 13251592Srgrimes break; 13261592Srgrimes 132775556Sgreen case ZSTR1: 13281592Srgrimes case OSTR: 13291592Srgrimes if (cbuf[cpos] == '\n') { 13301592Srgrimes state = CMD; 13311592Srgrimes return (CRLF); 13321592Srgrimes } 13331592Srgrimes /* FALLTHROUGH */ 13341592Srgrimes 13351592Srgrimes case STR1: 13361592Srgrimes dostr1: 13371592Srgrimes if (cbuf[cpos] == ' ') { 13381592Srgrimes cpos++; 133951979Salfred state = state == OSTR ? STR2 : state+1; 13401592Srgrimes return (SP); 13411592Srgrimes } 13421592Srgrimes break; 13431592Srgrimes 13441592Srgrimes case ZSTR2: 13451592Srgrimes if (cbuf[cpos] == '\n') { 13461592Srgrimes state = CMD; 13471592Srgrimes return (CRLF); 13481592Srgrimes } 13491592Srgrimes /* FALLTHROUGH */ 13501592Srgrimes 13511592Srgrimes case STR2: 13521592Srgrimes cp = &cbuf[cpos]; 13531592Srgrimes n = strlen(cp); 13541592Srgrimes cpos += n - 1; 13551592Srgrimes /* 13561592Srgrimes * Make sure the string is nonempty and \n terminated. 13571592Srgrimes */ 13581592Srgrimes if (n > 1 && cbuf[cpos] == '\n') { 13591592Srgrimes cbuf[cpos] = '\0'; 13601592Srgrimes yylval.s = copy(cp); 13611592Srgrimes cbuf[cpos] = '\n'; 13621592Srgrimes state = ARGS; 13631592Srgrimes return (STRING); 13641592Srgrimes } 13651592Srgrimes break; 13661592Srgrimes 13671592Srgrimes case NSTR: 13681592Srgrimes if (cbuf[cpos] == ' ') { 13691592Srgrimes cpos++; 13701592Srgrimes return (SP); 13711592Srgrimes } 13721592Srgrimes if (isdigit(cbuf[cpos])) { 13731592Srgrimes cp = &cbuf[cpos]; 13741592Srgrimes while (isdigit(cbuf[++cpos])) 13751592Srgrimes ; 13761592Srgrimes c = cbuf[cpos]; 13771592Srgrimes cbuf[cpos] = '\0'; 13781592Srgrimes yylval.i = atoi(cp); 13791592Srgrimes cbuf[cpos] = c; 13801592Srgrimes state = STR1; 13811592Srgrimes return (NUMBER); 13821592Srgrimes } 13831592Srgrimes state = STR1; 13841592Srgrimes goto dostr1; 13851592Srgrimes 13861592Srgrimes case ARGS: 13871592Srgrimes if (isdigit(cbuf[cpos])) { 13881592Srgrimes cp = &cbuf[cpos]; 13891592Srgrimes while (isdigit(cbuf[++cpos])) 13901592Srgrimes ; 13911592Srgrimes c = cbuf[cpos]; 13921592Srgrimes cbuf[cpos] = '\0'; 13931592Srgrimes yylval.i = atoi(cp); 13941592Srgrimes cbuf[cpos] = c; 13951592Srgrimes return (NUMBER); 13961592Srgrimes } 139756668Sshin if (strncasecmp(&cbuf[cpos], "ALL", 3) == 0 139856668Sshin && !isalnum(cbuf[cpos + 3])) { 139956668Sshin cpos += 3; 140056668Sshin return ALL; 140156668Sshin } 14021592Srgrimes switch (cbuf[cpos++]) { 14031592Srgrimes 14041592Srgrimes case '\n': 14051592Srgrimes state = CMD; 14061592Srgrimes return (CRLF); 14071592Srgrimes 14081592Srgrimes case ' ': 14091592Srgrimes return (SP); 14101592Srgrimes 14111592Srgrimes case ',': 14121592Srgrimes return (COMMA); 14131592Srgrimes 14141592Srgrimes case 'A': 14151592Srgrimes case 'a': 14161592Srgrimes return (A); 14171592Srgrimes 14181592Srgrimes case 'B': 14191592Srgrimes case 'b': 14201592Srgrimes return (B); 14211592Srgrimes 14221592Srgrimes case 'C': 14231592Srgrimes case 'c': 14241592Srgrimes return (C); 14251592Srgrimes 14261592Srgrimes case 'E': 14271592Srgrimes case 'e': 14281592Srgrimes return (E); 14291592Srgrimes 14301592Srgrimes case 'F': 14311592Srgrimes case 'f': 14321592Srgrimes return (F); 14331592Srgrimes 14341592Srgrimes case 'I': 14351592Srgrimes case 'i': 14361592Srgrimes return (I); 14371592Srgrimes 14381592Srgrimes case 'L': 14391592Srgrimes case 'l': 14401592Srgrimes return (L); 14411592Srgrimes 14421592Srgrimes case 'N': 14431592Srgrimes case 'n': 14441592Srgrimes return (N); 14451592Srgrimes 14461592Srgrimes case 'P': 14471592Srgrimes case 'p': 14481592Srgrimes return (P); 14491592Srgrimes 14501592Srgrimes case 'R': 14511592Srgrimes case 'r': 14521592Srgrimes return (R); 14531592Srgrimes 14541592Srgrimes case 'S': 14551592Srgrimes case 's': 14561592Srgrimes return (S); 14571592Srgrimes 14581592Srgrimes case 'T': 14591592Srgrimes case 't': 14601592Srgrimes return (T); 14611592Srgrimes 14621592Srgrimes } 14631592Srgrimes break; 14641592Srgrimes 14651592Srgrimes default: 146676096Smarkm fatalerror("Unknown state in scanner."); 14671592Srgrimes } 14681592Srgrimes state = CMD; 146989935Syar return (LEXERR); 14701592Srgrimes } 14711592Srgrimes} 14721592Srgrimes 14731592Srgrimesvoid 14741592Srgrimesupper(s) 14751592Srgrimes char *s; 14761592Srgrimes{ 14771592Srgrimes while (*s != '\0') { 14781592Srgrimes if (islower(*s)) 14791592Srgrimes *s = toupper(*s); 14801592Srgrimes s++; 14811592Srgrimes } 14821592Srgrimes} 14831592Srgrimes 14841592Srgrimesstatic char * 14851592Srgrimescopy(s) 14861592Srgrimes char *s; 14871592Srgrimes{ 14881592Srgrimes char *p; 14891592Srgrimes 14901592Srgrimes p = malloc((unsigned) strlen(s) + 1); 14911592Srgrimes if (p == NULL) 149276096Smarkm fatalerror("Ran out of memory."); 14931592Srgrimes (void) strcpy(p, s); 14941592Srgrimes return (p); 14951592Srgrimes} 14961592Srgrimes 14971592Srgrimesstatic void 14981592Srgrimeshelp(ctab, s) 14991592Srgrimes struct tab *ctab; 15001592Srgrimes 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 15631592Srgrimessizecmd(filename) 15641592Srgrimes char *filename; 15651592Srgrimes{ 15661592Srgrimes switch (type) { 15671592Srgrimes case TYPE_L: 15681592Srgrimes case TYPE_I: { 15691592Srgrimes struct stat stbuf; 157063350Sdes if (stat(filename, &stbuf) < 0) 157163350Sdes perror_reply(550, filename); 157263350Sdes else if (!S_ISREG(stbuf.st_mode)) 15731592Srgrimes reply(550, "%s: not a plain file.", filename); 15741592Srgrimes else 15751592Srgrimes reply(213, "%qu", stbuf.st_size); 15761592Srgrimes break; } 15771592Srgrimes case TYPE_A: { 15781592Srgrimes FILE *fin; 15791592Srgrimes int c; 15801592Srgrimes off_t count; 15811592Srgrimes struct stat stbuf; 15821592Srgrimes fin = fopen(filename, "r"); 15831592Srgrimes if (fin == NULL) { 15841592Srgrimes perror_reply(550, filename); 15851592Srgrimes return; 15861592Srgrimes } 158763350Sdes if (fstat(fileno(fin), &stbuf) < 0) { 158863350Sdes perror_reply(550, filename); 158963350Sdes (void) fclose(fin); 159063350Sdes return; 159163350Sdes } else if (!S_ISREG(stbuf.st_mode)) { 15921592Srgrimes reply(550, "%s: not a plain file.", filename); 15931592Srgrimes (void) fclose(fin); 15941592Srgrimes return; 15951592Srgrimes } 15961592Srgrimes 15971592Srgrimes count = 0; 15981592Srgrimes while((c=getc(fin)) != EOF) { 15991592Srgrimes if (c == '\n') /* will get expanded to \r\n */ 16001592Srgrimes count++; 16011592Srgrimes count++; 16021592Srgrimes } 16031592Srgrimes (void) fclose(fin); 16041592Srgrimes 16051592Srgrimes reply(213, "%qd", count); 16061592Srgrimes break; } 16071592Srgrimes default: 16081592Srgrimes reply(504, "SIZE not implemented for Type %c.", "?AEIL"[type]); 16091592Srgrimes } 16101592Srgrimes} 161156668Sshin 161256668Sshin/* Return 1, if port check is done. Return 0, if not yet. */ 161356668Sshinstatic int 161456668Sshinport_check(pcmd) 161556668Sshin const char *pcmd; 161656668Sshin{ 161756668Sshin if (his_addr.su_family == AF_INET) { 161856668Sshin if (data_dest.su_family != AF_INET) { 161956668Sshin usedefault = 1; 162056668Sshin reply(500, "Invalid address rejected."); 162156668Sshin return 1; 162256668Sshin } 162356668Sshin if (paranoid && 162456668Sshin ((ntohs(data_dest.su_port) < IPPORT_RESERVED) || 162556668Sshin memcmp(&data_dest.su_sin.sin_addr, 162656668Sshin &his_addr.su_sin.sin_addr, 162756668Sshin sizeof(data_dest.su_sin.sin_addr)))) { 162856668Sshin usedefault = 1; 162956668Sshin reply(500, "Illegal PORT range rejected."); 163056668Sshin } else { 163156668Sshin usedefault = 0; 163256668Sshin if (pdata >= 0) { 163356668Sshin (void) close(pdata); 163456668Sshin pdata = -1; 163556668Sshin } 163656668Sshin reply(200, "%s command successful.", pcmd); 163756668Sshin } 163856668Sshin return 1; 163956668Sshin } 164056668Sshin return 0; 164156668Sshin} 164256668Sshin 164370102Sphkstatic int 164470102Sphkcheck_login1() 164570102Sphk{ 164670102Sphk if (logged_in) 164770102Sphk return 1; 164870102Sphk else { 164970102Sphk reply(530, "Please login with USER and PASS."); 165070102Sphk return 0; 165170102Sphk } 165270102Sphk} 165370102Sphk 165456668Sshin#ifdef INET6 165556668Sshin/* Return 1, if port check is done. Return 0, if not yet. */ 165656668Sshinstatic int 165756668Sshinport_check_v6(pcmd) 165856668Sshin const char *pcmd; 165956668Sshin{ 166056668Sshin if (his_addr.su_family == AF_INET6) { 166156668Sshin if (IN6_IS_ADDR_V4MAPPED(&his_addr.su_sin6.sin6_addr)) 166256668Sshin /* Convert data_dest into v4 mapped sockaddr.*/ 166356668Sshin v4map_data_dest(); 166456668Sshin if (data_dest.su_family != AF_INET6) { 166556668Sshin usedefault = 1; 166656668Sshin reply(500, "Invalid address rejected."); 166756668Sshin return 1; 166856668Sshin } 166956668Sshin if (paranoid && 167056668Sshin ((ntohs(data_dest.su_port) < IPPORT_RESERVED) || 167156668Sshin memcmp(&data_dest.su_sin6.sin6_addr, 167256668Sshin &his_addr.su_sin6.sin6_addr, 167356668Sshin sizeof(data_dest.su_sin6.sin6_addr)))) { 167456668Sshin usedefault = 1; 167556668Sshin reply(500, "Illegal PORT range rejected."); 167656668Sshin } else { 167756668Sshin usedefault = 0; 167856668Sshin if (pdata >= 0) { 167956668Sshin (void) close(pdata); 168056668Sshin pdata = -1; 168156668Sshin } 168256668Sshin reply(200, "%s command successful.", pcmd); 168356668Sshin } 168456668Sshin return 1; 168556668Sshin } 168656668Sshin return 0; 168756668Sshin} 168856668Sshin 168956668Sshinstatic void 169056668Sshinv4map_data_dest() 169156668Sshin{ 169256668Sshin struct in_addr savedaddr; 169356668Sshin int savedport; 169456668Sshin 169556668Sshin if (data_dest.su_family != AF_INET) { 169656668Sshin usedefault = 1; 169756668Sshin reply(500, "Invalid address rejected."); 169856668Sshin return; 169956668Sshin } 170056668Sshin 170156668Sshin savedaddr = data_dest.su_sin.sin_addr; 170256668Sshin savedport = data_dest.su_port; 170356668Sshin 170456668Sshin memset(&data_dest, 0, sizeof(data_dest)); 170556668Sshin data_dest.su_sin6.sin6_len = sizeof(struct sockaddr_in6); 170656668Sshin data_dest.su_sin6.sin6_family = AF_INET6; 170756668Sshin data_dest.su_sin6.sin6_port = savedport; 170856668Sshin memset((caddr_t)&data_dest.su_sin6.sin6_addr.s6_addr[10], 0xff, 2); 170956668Sshin memcpy((caddr_t)&data_dest.su_sin6.sin6_addr.s6_addr[12], 171056668Sshin (caddr_t)&savedaddr, sizeof(savedaddr)); 171156668Sshin} 171256668Sshin#endif 1713