Files
m241Neelima/components/ip_net2-6.9/ipappl/src/ipftps.c
T
2026-07-30 11:19:44 +05:30

5869 lines
160 KiB
C

/*
******************************************************************************
* SOURCE FILE
*
* Document no: @(#) $ipftps.c$ $RCSfile: ipftps.c,v $ $Revision: 1.84.10.45 $
* $Source: /home/interpeak/CVSRoot/ipappl/src/ipftps.c,v $
* $Author: lwang7 $
* $State: Exp $ $Locker: $
*
* INTERPEAK_COPYRIGHT_STRING
* Design and implementation by Ulf Olofsson <ulf@interpeak.se>
******************************************************************************
*/
/*
****************************************************************************
* 1 DESCRIPTION
****************************************************************************
*/
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
#include "ipftps_config.h"
/* Timeout when sending data to socket */
#define IPFTPS_SEND_TIMEOUT 30
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#define IPCOM_USE_CLIB_PROTO
#include <ipcom_clib.h>
#include <ipcom_clib2.h>
#include <ipcom_time.h>
#include <ipcom_os.h>
#include <ipcom_auth.h>
#include <ipcom_sock.h>
#include <ipcom_sock2.h>
#include <ipcom_err.h>
#include <ipcom_syslog.h>
#include <ipcom_list.h>
#include <ipcom_ipd.h>
#include <ipcom_sysvar.h>
#include "ipftps.h"
#ifdef IP_PORT_VXWORKS
#include <vxWorks.h>
#include <pathLib.h>
#include <iosLib.h>
#include <dirent.h>
#include <private/loginLibP.h>
#include <shellHook.h>
#endif
/*
****************************************************************************
* 4 DEFINES
****************************************************************************
*/
/* The definitions below can be used to change the priorities of the main and session processes */
#define IPFTPS_MAIN_PROC_PRIO IPCOM_PRIORITY_DEFAULT
#define IPFTPS_SESSION_PROC_PRIO IPCOM_PROC_PRIO_INHERIT
/*
****************************************************************************
* 5 TYPES
****************************************************************************
*/
/* Public data */
typedef struct
{
#ifdef IPCOM_USE_INET
Ipftps_sockcb sock4; /* Main IPv4 server socket */
#endif
#ifdef IPCOM_USE_INET6
Ipftps_sockcb sock6; /* Main IPv6 server socket */
#endif
int session_number; /* Current active session number */
int databuf_size; /* Data transfer buffer size */
Ipcom_mutex lock; /* mutex to protect FTPS global data */
Ip_fd pipe_fd[2]; /* pipe between daemon/session task */
}
Ipftps_data;
/*
****************************************************************************
* 6 EXTERN PROTOTYPES
****************************************************************************
*/
#ifdef IP_PORT_OSE5
extern int efs_donate_fd(int fd, Ip_pid_t to);
extern int efs_receive_fd(Ip_pid_t from);
#endif
#ifdef IPFTP_TLS
IP_EXTERN int ipftps_tls_enbale;
#endif
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
#define IPFTPS_C
#include "ipftps_h.h"
IP_STATIC int ipftps_filewrite_ascii(Ip_fd fd, char *buf, char *nbuf, int bufsize, Ip_bool *orphant);
IP_STATIC int ipftps_socketwrite_ascii(Ipftps_session *session, Ip_fd fd, char *buf, char *nbuf, int bufsize);
IP_STATIC int ipftps_dirindex(char *path, int idomin);
IP_STATIC int ipftps_dircmp(char *root, char *path);
IP_STATIC int ipftps_root_check(Ipftps_session *session, char **path);
IP_STATIC int ipftps_ls(Ipftps_session *session, Ip_fd fd, char *path1, char *path2);
IP_STATIC void ipftps_abor(Ipftps_session *session, int argc, char *argv[]);
IP_STATIC void ipftps_acct(Ipftps_session *session, int argc, char *argv[]);
IP_STATIC void ipftps_appe(Ipftps_session *session, int argc, char *argv[]);
IP_STATIC void ipftps_cdup(Ipftps_session *session, int argc, char *argv[]);
IP_STATIC void ipftps_cwd(Ipftps_session *session, int argc, char *argv[]);
IP_STATIC void ipftps_allo(Ipftps_session *session, int argc, char *argv[]);
IP_STATIC void ipftps_dele(Ipftps_session *session, int argc, char *argv[]);
IP_STATIC void ipftps_eprt(Ipftps_session *session, int argc, char *argv[]);
IP_STATIC void ipftps_epsv(Ipftps_session *session, int argc, char *argv[]);
IP_STATIC void ipftps_help(Ipftps_session *session, int argc, char *argv[]);
IP_STATIC void ipftps_list(Ipftps_session *session, int argc, char *argv[]);
IP_STATIC void ipftps_mkd(Ipftps_session *session, int argc, char *argv[]);
IP_STATIC void ipftps_mode(Ipftps_session *session, int argc, char *argv[]);
IP_STATIC void ipftps_nlst(Ipftps_session *session, int argc, char *argv[]);
IP_STATIC void ipftps_noop(Ipftps_session *session, int argc, char *argv[]);
IP_STATIC void ipftps_pass(Ipftps_session *session, int argc, char *argv[]);
IP_STATIC void ipftps_pasv(Ipftps_session *session, int argc, char *argv[]);
IP_STATIC void ipftps_port(Ipftps_session *session, int argc, char *argv[]);
IP_STATIC void ipftps_pwd(Ipftps_session *session, int argc, char *argv[]);
IP_STATIC void ipftps_quit(Ipftps_session *session, int argc, char *argv[]);
IP_STATIC void ipftps_retr(Ipftps_session *session, int argc, char *argv[]);
IP_STATIC void ipftps_rmd(Ipftps_session *session, int argc, char *argv[]);
IP_STATIC void ipftps_rnfr(Ipftps_session *session, int argc, char *argv[]);
IP_STATIC void ipftps_rnto(Ipftps_session *session, int argc, char *argv[]);
IP_STATIC void ipftps_stat(Ipftps_session *session, int argc, char *argv[]);
IP_STATIC void ipftps_stor(Ipftps_session *session, int argc, char *argv[]);
IP_STATIC void ipftps_stru(Ipftps_session *session, int argc, char *argv[]);
IP_STATIC void ipftps_syst(Ipftps_session *session, int argc, char *argv[]);
IP_STATIC void ipftps_type(Ipftps_session *session, int argc, char *argv[]);
IP_STATIC void ipftps_user(Ipftps_session *session, int argc, char *argv[]);
IP_STATIC void ipftps_size(Ipftps_session *session, int argc, char *argv[]);
IP_STATIC int ipftps_chdir(Ipftps_session *session, char *path);
IP_STATIC char* ipftps_wildcard_check(char *path, struct Ip_stat *st);
IP_STATIC int ipftps_pattern_check(char *pattern, char *name);
IP_STATIC const char *ipftps_ntop(union Ip_sockaddr_union *addr, char *dest, int len);
IP_STATIC void ipftps_perror(Ipftps_session *session, int no);
IP_STATIC int ipftps_dsock_open(Ipftps_session *session, int passive_open);
IP_STATIC void ipftps_dsock_close(Ipftps_session *session);
IP_STATIC int ipftps_write(Ipftps_session *session, Ip_fd fd, void *buf, int len);
IP_STATIC void ipftps_reply_sock(Ipftps_session *session, Ip_fd fd, const char *fmt, ...);
IP_STATIC void ipftps_reply(Ipftps_session *session, const char *fmt, ...);
IP_STATIC int ipftps_telnet(Ipftps_session *session);
IP_STATIC int ipftps_get_command(Ipftps_session *session);
IP_STATIC int ipftps_parse_command(Ipftps_session *session);
IP_STATIC int ipftps_async(Ipftps_session *session);
#ifdef IPFTP_TLS
IP_STATIC void ipftps_auth(Ipftps_session *session, int argc, char *argv[]);
IP_STATIC void ipftps_prot(Ipftps_session *session, int argc, char *argv[]);
IP_STATIC void ipftps_pbsz(Ipftps_session * session, int argc, char * argv [ ]);
IP_STATIC void ipftps_ccc(Ipftps_session *session, int argc, char *argv[]);
#endif
#ifdef IPFTPS_USE_TEST
IP_STATIC void
ipftps_xftp(Ipftps_session *session, int argc, char *argv[]);
#endif
IP_PUBLIC Ip_err ipftps_start(void);
IP_PUBLIC const char *ipftps_version(void);
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
/* List of commmands */
IP_STATIC const Ipftps_cmd ipftps_cmdlist[] =
{
/* Name Handler MinMaxLoginArgtypeDescription */
{"ABOR", ipftps_abor, 0, 0, 0, 1, "Abort data transfer"},
{"ACCT", ipftps_acct, 1, 1, 0, 1, "Select account"},
{"APPE", ipftps_appe, 1, 1, 1, 1, "Append to file"},
{"CDUP", ipftps_cdup, 0, 0, 0, 1, "Change to parent dir"},
{"CWD", ipftps_cwd, 1, 1, 1, 1, "Change directory"},
{"DELE", ipftps_dele, 1, 1, 1, 1, "Delete file"},
{"EPRT", ipftps_eprt, 3, 3, 0, 1, "Specify extended data port"},
{"EPSV", ipftps_epsv, 0, 1, 0, 1, "Enter extended passive mode"},
{"HELP", ipftps_help, 0, 1, 0, 0, "Help"},
{"LIST", ipftps_list, 0, 1, 1, 1, "List file(s)"},
{"MKD", ipftps_mkd, 1, 1, 1, 1, "Make directory"},
{"MODE", ipftps_mode, 1, 1, 0, 1, "Set transfer mode"},
{"NLST", ipftps_nlst, 0, 1, 1, 1, "List file name(s)"},
{"NOOP", ipftps_noop, 0, 0, 0, 1, "No operation"},
{"PASS", ipftps_pass, 1, 1, 0, 0, "Login password"},
{"PASV", ipftps_pasv, 0, 0, 0, 1, "Enter passive mode"},
{"PORT", ipftps_port, 6, 6, 0, 1, "Specify data port"},
{"PWD", ipftps_pwd, 0, 0, 0, 1, "Print current directory"},
{"QUIT", ipftps_quit, 0, 0, 0, 0, "Quit FTP session"},
{"RETR", ipftps_retr, 1, 1, 1, 1, "Retrieve file"},
{"RMD", ipftps_rmd, 1, 1, 1, 1, "Remove directory"},
{"RNFR", ipftps_rnfr, 1, 1, 1, 1, "Rename from"},
{"RNTO", ipftps_rnto, 1, 1, 1, 1, "Rename to"},
{"STAT", ipftps_stat, 0, 1, 1, 1, "Show current status"},
{"STOR", ipftps_stor, 1, 1, 1, 1, "Store file"},
{"STRU", ipftps_stru, 1, 1, 0, 1, "Set file structure"},
{"SYST", ipftps_syst, 0, 0, 0, 1, "Show system type"},
{"TYPE", ipftps_type, 1, 2, 0, 1, "Set representation type"},
{"USER", ipftps_user, 0, 1, 0, 0, "Login username"},
{"XCUP", ipftps_cdup, 0, 0, 0, 1, "Change to parent dir"},
{"XCWD", ipftps_cwd, 1, 1, 1, 1, "Change directory"},
{"ALLO", ipftps_allo, 1, 2, 0, 1, "Allocate storage"},
#ifdef IPFTPS_USE_TEST
{"XFTP", ipftps_xftp, 1, 4, 0, 0,"Internal test"},
#endif
{"XMKD", ipftps_mkd, 1, 1, 1, 1, "Make directory"},
{"XPWD", ipftps_pwd, 0, 0, 0, 1, "Print current directory"},
{"XRMD", ipftps_rmd, 1, 1, 1, 1, "Remove directory"},
{"SIZE", ipftps_size, 1, 1, 1, 1, "Get size of special file"},
#ifdef IPFTP_TLS
{"AUTH", ipftps_auth, 1, 1, 0, 0, "TLS auth"},
{"PROT", ipftps_prot, 1, 1, 0, 0, "TLS prot command"},
{"PBSZ", ipftps_pbsz, 1, 1, 0, 0, "pbsz command"},
{"CCC", ipftps_ccc, 0, 0, 0, 0, "CCC command"},
#endif
{0, 0, 0}
};
/*
*===========================================================================
* ipftps
*===========================================================================
* Global data.
*/
IP_STATIC Ipftps_data ipftps;
/*
****************************************************************************
* 9 LOCAL FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipftps_socketpair
*===========================================================================
* Description: Create a pair of connected sockets for FTP server daemon task.
* Parameters: domain - Address domain to use. The supported domains are
* IP_AF_INET and IP_AF_INET6.
* Returns: 0 = success, -1 = error.
*
*/
IP_STATIC int
ipftps_socketpair(int domain)
{
struct Ip_addrinfo *res = IP_NULL;
struct Ip_addrinfo hints;
int ret;
int i, l;
Ip_socklen_t namelen;
ipftps.pipe_fd[0] = IP_INVALID_SOCKET;
ipftps.pipe_fd[1] = IP_INVALID_SOCKET;
ipcom_memset(&hints, 0, sizeof(hints));
hints.ai_family = domain;
hints.ai_socktype = IP_SOCK_STREAM;
ret = ipcom_getaddrinfo(IP_NULL, "0", &hints, &res);
if (ret)
goto errout;
for (i = 0; i < 2; i++)
{
ipftps.pipe_fd[i] = ipcom_socket(res->ai_family, IP_SOCK_STREAM, 0);
if (ipftps.pipe_fd[i] < 0)
goto errout;
}
/* Bind to an ephemeral port */
if (ipcom_bind(ipftps.pipe_fd[0], res->ai_addr, (Ip_socklen_t)res->ai_addrlen) < 0)
goto errout;
/* Figure out which ephemeral port the stack selected */
namelen = (Ip_socklen_t)res->ai_addrlen;
if (ipcom_getsockname(ipftps.pipe_fd[0], res->ai_addr, &namelen) < 0)
goto errout;
if (ipcom_listen(ipftps.pipe_fd[0], 1) < 0)
goto errout;
if (ipcom_connect(ipftps.pipe_fd[1], res->ai_addr, (Ip_socklen_t)res->ai_addrlen) < 0)
goto errout;
l = ipftps.pipe_fd[0];
ipftps.pipe_fd[0] = ipcom_accept(l, IP_NULL, IP_NULL);
ipcom_socketclose(l);
if (ipftps.pipe_fd[0] < 0)
goto errout;
ipcom_freeaddrinfo(res);
return 0;
errout:
if (res != IP_NULL)
ipcom_freeaddrinfo(res);
for (i = 0; i < 2; i++)
if (ipftps.pipe_fd[i] >= 0)
ipcom_socketclose(ipftps.pipe_fd[i]);
return -1;
}
/*
*===========================================================================
* ipftps_filewrite_ascii
*===========================================================================
*
* Description:
* Write ASCII buffer to file.
*
* Parameters:
* fd File descriptor.
* buf Buffer.
* nbuf New buffer.
* bufsize Buffer size.
* orphant True if last buffer was terminated with '\r'.
*
* Returns:
* 0 if success, 1 otherwise.
*/
IP_STATIC int
ipftps_filewrite_ascii(Ip_fd fd, char *buf, char *nbuf, int bufsize,
Ip_bool *orphant)
{
char *cp = nbuf;
int begin;
int end;
int no;
/* Enter '\r' if not followed by '\n' */
if (*orphant && buf[0] != '\n')
{
/* Output missing '\r' */
*cp++ = '\r';
}
*orphant = 0;
/* Loop for entire buffer */
for (begin = end = 0; end < bufsize; end++)
{
if (buf[end] == '\r')
{
if (end == (bufsize - 1))
{
/* '\r' at end of buffer, remember */
*orphant = 1;
}
else if (buf[end + 1] != '\n')
{
/* Not followed by '\n' - ignore */
continue;
}
/* Enter everything up to '\r' */
no = end - begin;
ipcom_memcpy(cp, &buf[begin], no);
cp += no;
/* Continue at '\n' */
begin = end + 1;
}
}
/* Enter last part */
no = end - begin;
ipcom_memcpy(cp, &buf[begin], no);
cp += no;
/* Write to file */
no = (int)(cp - nbuf);
if (ipcom_filewrite(fd, nbuf, no) != no)
{
return 1;
}
return 0;
}
/*
*===========================================================================
* ipftps_socketwrite_ascii
*===========================================================================
*
* Description:
* Write ASCII buffer to socket.
*
* Parameters:
* session Session descriptor.
* fd File descriptor.
* buf Buffer.
* nbuf New buffer.
* bufsize Buffer size.
*
* Returns:
* 0 if success, 1 otherwise.
*/
IP_STATIC int
ipftps_socketwrite_ascii(Ipftps_session *session, Ip_fd fd, char *buf, char *nbuf, int bufsize)
{
char *cp = nbuf;
int begin;
int end;
int no;
#ifdef IPFTP_TLS
int ret;
#endif
#ifndef IPFTP_TLS
(void)session;
#endif
/* Loop for entire buffer */
for (begin = end = 0; end < bufsize; end++)
{
if (buf[end] == '\n')
{
/* Enter everything up to '\n' */
no = end - begin;
ipcom_memcpy(cp, &buf[begin], no);
cp += no;
/* Enter newline */
*cp++ = '\r';
*cp++ = '\n';
/* Continue after '\n' */
begin = end + 1;
}
}
/* Enter last part */
no = end - begin;
ipcom_memcpy(cp, &buf[begin], no);
cp += no;
/* Write to socket */
no = (int)(cp - nbuf);
#ifdef IPFTP_TLS
if((ipftps_tls_enbale == IP_TRUE)
&& ((ret = ipftps_tls_send(session,fd,nbuf,no)) != 2))
{
return ret;
}
else
#endif
if (ipcom_socketwrite(fd, nbuf, no) != no)
{
return 1;
}
return 0;
}
/*
*===========================================================================
* ipftps_dirindex
*===========================================================================
*
* Description:
* Calculate level of directory path.
*
* Parameters:
* path Directory path.
* idomin Min flag.
*
* Returns:
* Final subdirectory level if idomin == 0,
* minimum subdirectory level if idomin == 1.
*/
IP_STATIC int
ipftps_dirindex(char *path, int idomin)
{
int level = 0;
int min = 0;
char *start;
char *stop;
char *cp;
cp = path;
while (*cp != '\0')
{
char c;
start = cp;
cp += ipcom_strcspn(cp, IPFTPS_DIRSEP);
stop = cp;
cp += ipcom_strspn(cp, IPFTPS_DIRSEP);
c = *stop;
*stop = '\0';
if (ipcom_strcmp(start, "..") == 0)
{
level--;
}
else if (*start != '\0' && ipcom_strcmp(start, ".") != 0)
{
level++;
}
*stop = c;
if (level < min)
{
min = level;
}
}
return (idomin ? min : level);
}
/*
*===========================================================================
* ipftps_dircmp
*===========================================================================
*
* Description:
* Check if dir is OK wrt root.
*
* Parameters:
* root Directory root.
* path Directory path.
*
* Returns:
* 0 if OK, 1 otherwise.
*/
IP_STATIC int
ipftps_dircmp(char *root, char *path)
{
Ip_size_t len;
int i;
len = ipcom_strlen(root);
for (i = 0; i < (int)len; i++)
{
if ((ipcom_strchr(IPFTPS_DIRSEP, root[i]) &&
ipcom_strchr(IPFTPS_DIRSEP, path[i])) ||
root[i] == path[i])
{
/* OK so far */
}
else
{
return 1;
}
}
return 0;
}
/*
*===========================================================================
* ipftps_root_check
*===========================================================================
*
* Description:
* Check if path valid, and prepare for its use in next command.
*
* Parameters:
* session Session descriptor.
* path Directory path.
*
* Returns:
* 0 if path OK, 1 otherwise.
*/
IP_STATIC int
ipftps_root_check(Ipftps_session *session, char **path)
{
char *newpath = *path;
Ip_size_t len;
/* If the input *path is a root path, using path directly without changing
session->cwd to be session->root. Eg: session->root is /ram0. And *path is
/test_dir/test.txt. Then the absolute path will be /ram0/test_dir/test.txt */
Ip_bool root_path = IP_FALSE;
/* Device or drive letter? */
if (newpath != *path)
{
/* Empty session root is required to change drive/device */
if (session->root[0] != '\0')
{
return 1;
}
newpath = *path;
}
else if (ipcom_strchr(IPFTPS_DIRSEP, *newpath) != IP_NULL)
{
char *orgpath = newpath;
/*
** Absolute path, remove initial slash
** to make it relative to root.
*/
if (*++newpath == '\0')
{
*--newpath = '.';
}
/* Check for trespassing */
if (ipftps_dirindex(newpath, 1) < 0)
{
/* Peeked above root */
return 1;
}
if (session->root[0] == '\0' ||
(ipcom_strchr(IPFTPS_DIRSEP, session->root[0]) != IP_NULL && session->root[1] == '\0'))
{
/*
** Session root is /, and it may not be safe to cd there
** since the file system may have its root at e.g. /ram.
** Use the absolute path directly.
*/
if (newpath == orgpath)
{
*newpath = '/';
}
else
{
newpath = orgpath;
}
}
else /* Session root is /ram0 */
{
root_path = IP_TRUE;
}
}
else
{
/* Check for trespassing */
if ((ipftps_dirindex(session->cwd, 0) + ipftps_dirindex(newpath, 1)) <
ipftps_dirindex(session->root, 0))
{
return 1;
}
/* Set CWD */
if (ipftps_chdir(session, session->cwd) != 0)
{
IPCOM_LOG1(WARNING, "Invalid current directory: %s", session->cwd);
return 1;
}
}
/* Remove possible trailing slash */
len = ipcom_strlen(newpath);
if (len > 1 && ipcom_strchr(IPFTPS_DIRSEP, newpath[len - 1]) != IP_NULL)
{
newpath[len - 1] = '\0';
}
*path = newpath;
#ifdef IP_PORT_VXWORKS
{
char *fullPath = IP_NULL;
const char *pTail;
char *tmpPath = IP_NULL;
size_t pathLen = ipcom_strlen(*path);
size_t dirLen = 0;
if ((fullPath = ipcom_malloc(IP_PATH_MAX)) == NULL)
{
return 1;
}
if (root_path == IP_TRUE)
{
dirLen = ipcom_strlen(session->root);
if (pathLen + dirLen >= IP_PATH_MAX)
{
ipcom_errno = IP_ERRNO_ENAMETOOLONG;
ipftps_free(fullPath);
return 1;
}
/* Use the absolute path for vxworks */
if (pathCat(session->root, *path, fullPath) == ERROR)
{
ipftps_free(fullPath);
return 1;
}
}
else
{
dirLen = ipcom_strlen(session->cwd);
if (pathLen + dirLen >= IP_PATH_MAX)
{
ipcom_errno = IP_ERRNO_ENAMETOOLONG;
ipftps_free(fullPath);
return 1;
}
/* Use the absolute path for vxworks */
if (pathCat(session->cwd, *path, fullPath) == ERROR)
{
ipftps_free(fullPath);
return 1;
}
}
pathCondense(fullPath);
tmpPath = *path;
if ((tmpPath[strlen(tmpPath) - 1] == '/') && strcmp(fullPath, "/"))
{
ipcom_strcat(fullPath, "/");
}
/* Make sure that new path starts with a device name */
iosDevFind (fullPath, &pTail);
if (pTail != fullPath)
{
ipcom_strcpy(*path, fullPath);
ipftps_free(fullPath);
return 0;
}
if (tmpPath[strlen(tmpPath) - 1] == '.')
{
ipcom_strcat(fullPath, "/");
iosDevFind (fullPath, &pTail);
if (pTail != fullPath)
{
ipcom_strcpy(*path, fullPath);
ipftps_free(fullPath);
return 0;
}
}
ipftps_free(fullPath);
return 1; /* ENODEV */
}
#else
if(root_path == IP_TRUE)
{
if(ipftps_chdir(session, session->root) == 0)
{
session->cwdroot = 1;
}
else
{
IPCOM_LOG1(WARNING, "Invalid root dir: %s", session->root);
return 1;
}
}
return 0;
#endif
}
/*
*===========================================================================
* ipftps_dir_check
*===========================================================================
*
* Description:
* Handle potential cwd change.
*
* Parameters:
* session Session descriptor.
*
* Returns:
* 0 if success, -1 otherwise.
*/
IP_STATIC int
ipftps_dir_check(Ipftps_session *session)
{
#ifndef IP_PORT_VXWORKS
if (session->cwd != session->root)
{
ipftps_free(session->cwd);
}
if ((session->cwd = ipcom_malloc(IP_PATH_MAX)) == IP_NULL ||
ipcom_getcwd(session->cwd, IP_PATH_MAX) == IP_NULL)
{
IPCOM_LOG0(ERR, "Out of memory, switched to root");
/* Avoid malloc here */
if (session->cwd != session->root)
{
ipftps_free(session->cwd);
}
session->cwd = session->root;
return -1;
} else
#endif
if (ipftps_dircmp(session->root,session->cwd) != 0)
{
/*
** This is never supposed to happen, teardown
** session to prevent from security breaches.
*/
IPCOM_LOG0(ERR, "Directory error, terminating session");
session->authentications = 0;
ipcom_errno = IP_ERRNO_ENOTDIR;
return -1;
}
return 0;
}
/*
*===========================================================================
* ipftps_sysget_int
*===========================================================================
*
* Description:
* Get integer system variable.
*
* Parameters:
* name Variable name.
* defval Default value if not found.
* message Print message if not found.
*
* Returns:
* Variable value.
*/
IP_STATIC int
ipftps_sysget_int(const char *name, int defval, Ip_bool message)
{
Ipftps_session *session = IP_NULL;
char strval[12];
Ip_size_t strval_len = sizeof(strval);
(void)session;
if (ipcom_sysvar_get(name, strval, &strval_len) == IP_NULL)
{
if (message)
{
IPCOM_LOG2(WARNING, "Missing sysvar %s, using %d", name, defval);
}
return defval;
}
return ipcom_atoi(strval);
}
/*
*===========================================================================
* ipftps_sysget_str
*===========================================================================
*
* Description:
* Get string system variable.
*
* Parameters:
* name Variable name.
* defval Default value if not found.
* message Print message if not found.
*
* Returns:
* Variable value.
*/
IP_STATIC char *
ipftps_sysget_str(const char *name, char *buf, Ip_size_t *bufsize,
const char *defval, Ip_bool message)
{
Ip_size_t oldsize = (buf == IP_NULL ? 0 : *bufsize);
Ipftps_session *session = IP_NULL;
char *ret;
(void)session;
if ((ret = ipcom_sysvar_get(name, buf, bufsize)) == IP_NULL)
{
if (oldsize > 0 && *bufsize > oldsize)
{
if (message)
{
IPCOM_LOG2(WARNING, "Buffer overflow reading sysvar %s, using %s",
name, defval);
}
}
else if (message)
{
IPCOM_LOG2(WARNING, "Missing sysvar %s, using %s",
name, defval);
}
ret = (buf == IP_NULL ? ipcom_strdup(defval) :
ipcom_strcpy(buf, defval));
}
return ret;
}
/*
*===========================================================================
* ipftps_ls
*===========================================================================
*
* Description:
* List file (long format).
*
* Parameters:
* session Session descriptor.
* fd File descriptor.
* path1 1st part of path.
* path2 2nd part of path.
*
* Returns:
*/
IP_STATIC int
ipftps_ls(Ipftps_session *session, Ip_fd fd, char *path1, char *path2)
{
static const Ip_mode_t perm[] =
{
IP_S_IRUSR, IP_S_IWUSR, IP_S_IXUSR,
IP_S_IRGRP, IP_S_IWGRP, IP_S_IXGRP,
IP_S_IROTH, IP_S_IWOTH, IP_S_IXOTH
};
char mode[] = "-rwxrwxrwx";
char timestr[16];
#ifdef IPCOM_USE_TIME
Ip_time_t now;
struct Ip_tm tm;
#endif
struct Ip_stat st;
char *opath;
char *path;
Ip_size_t p1len = ipcom_strlen(path1);
int ret = 0;
Ip_size_t i;
if ((opath = path = ipcom_malloc(ipcom_strlen(path1) +
ipcom_strlen(path2) + 2)) == IP_NULL)
{
IPCOM_LOG0(ERR, "Out of memory");
ipftps_reply(session, "452 Out of memory"CL);
ret = 1;
goto leave2;
}
ipcom_strcpy(path, path1);
ipcom_strcat(path, (p1len != 0 && path[p1len - 1] != '/' ? "/" : ""));
ipcom_strcat(path, path2);
if (ipcom_stat(path, &st) != 0)
{
ipcom_memset(&st, 0, sizeof(st));
}
/* Set mode */
if (IP_S_ISDIR(st.st_mode))
mode[0] = 'd';
#ifdef IP_S_ISCHR
else if (IP_S_ISCHR(st.st_mode))
mode[0] = 'c';
#endif
#ifdef IP_S_ISBLK
else if (IP_S_ISBLK(st.st_mode))
mode[0] = 'b';
#endif
#ifdef IP_S_ISFIFO
else if (IP_S_ISFIFO(st.st_mode))
mode[0] = 'p';
#endif
#ifdef IP_S_ISLNK
else if (IP_S_ISLNK(st.st_mode))
mode[0] = 'l';
#endif
#ifdef IP_S_ISSOCK
else if (IP_S_ISSOCK(st.st_mode))
mode[0] = 's';
#endif
/* Set permissions */
for (i = 0; i < (sizeof(perm) / sizeof perm[0]); i++)
{
if ((st.st_mode & perm[i]) == 0)
{
mode[1 + i] = '-';
}
}
/* Create window for fine grain time */
#ifdef IPCOM_USE_TIME
(void)ipcom_time(&now);
(void)ipcom_localtime_r(&st.st_mtime, &tm);
if (st.st_mtime < (now - (6L * IPFTPS_MONTHS)) ||
st.st_mtime > (now + (1L * IPFTPS_HOURS)))
{
/* Low resolution */
i = ipcom_strftime(timestr, sizeof(timestr), "%b %d %Y", &tm);
}
else
{
/* High resolution */
i = ipcom_strftime(timestr, sizeof(timestr), "%b %d %H:%M", &tm);
}
/* Terminate timestr. */
if (i == 0)
timestr[0] = '\0';
else if (i == sizeof(timestr))
timestr[sizeof(timestr) - 1] = '\0';
#else
ipcom_strcpy(timestr, "-");
#endif
ipftps_reply_sock(session, fd,
"%s %3d %-6d %-6d %10lu %12.12s %s%s"CL,
mode, st.st_nlink, st.st_uid, st.st_gid,
(unsigned long)st.st_size, timestr,
(session->cwdroot && path1[0] == '\0' ? "/" : ""),
path2);
ipcom_free(opath);
leave2:
return ret;
}
/*
*===========================================================================
* ipftps_abor
*===========================================================================
*
* Description:
* ABOR command.
*
* Parameters:
* session Session descriptor.
* argc Number of arguments.
* argv Argument vector.
*
* Returns:
*/
IP_STATIC void
ipftps_abor(Ipftps_session *session, int argc, char *argv[])
{
(void)argc;
(void)argv;
if (session->dsock.fd == -1)
{
ipftps_reply(session, "226 No data connection"CL);
}
else
{
ipftps_dsock_close(session);
ipftps_reply(session, "226 Closing data connection"CL);
}
}
/*
*===========================================================================
* ipftps_acct
*===========================================================================
*
* Description:
* ACCT command.
*
* Parameters:
* session Session descriptor.
* argc Number of arguments.
* argv Argument vector.
*
* Returns:
*/
IP_STATIC void
ipftps_acct(Ipftps_session *session, int argc, char *argv[])
{
(void)argc;
(void)argv;
ipftps_reply(session, "202 Command not implemented"CL);
}
/*
*===========================================================================
* ipftps_appe
*===========================================================================
*
* Description:
* APPE command.
*
* Parameters:
* session Session descriptor.
* argc Number of arguments.
* argv Argument vector.
*
* Returns:
*/
IP_STATIC void
ipftps_appe(Ipftps_session *session, int argc, char *argv[])
{
argv[argc++] = "a";
ipftps_stor(session, argc, argv);
}
/*
*===========================================================================
* ipftps_cdup
*===========================================================================
*
* Description:
* CDUP command.
*
* Parameters:
* session Session descriptor.
* argc Number of arguments.
* argv Argument vector.
*
* Returns:
*/
IP_STATIC void
ipftps_cdup(Ipftps_session *session, int argc, char *argv[])
{
char *dotdotp;
char dotdot[IP_PATH_MAX];
(void)argc;
(void)argv;
ipcom_strcpy(dotdot,"..");
dotdotp = dotdot;
ipftps_cwd(session, 1, &dotdotp);
}
/*
*===========================================================================
* ipftps_cwd
*===========================================================================
*
* Description:
* CWD command.
*
* Parameters:
* session Session descriptor.
* argc Number of arguments.
* argv Argument vector.
*
* Returns:
*/
IP_STATIC void
ipftps_cwd(Ipftps_session *session, int argc, char *argv[])
{
(void)argc;
if (ipftps_root_check(session, &argv[0]) != 0)
{
IPCOM_LOG2(WARNING, "Access denied to %s from %s",
argv[0], session->cwd);
ipftps_reply(session, "550 Permission denied"CL);
}
else if (ipftps_chdir(session, argv[0]) != 0)
{
ipftps_perror(session, 550);
}
else if (ipftps_dir_check(session) != 0)
{
ipftps_perror(session, (ipcom_errno == IP_ERRNO_ENOMEM ? 452 : 550));
}
else
{
ipftps_reply(session, "250 CWD changed"CL);
}
}
/*
*===========================================================================
* ipftps_dele
*===========================================================================
*
* Description:
* DELE command.
*
* Parameters:
* session Session descriptor.
* argc Number of arguments.
* argv Argument vector.
*
* Returns:
*/
IP_STATIC void
ipftps_dele(Ipftps_session *session, int argc, char *argv[])
{
(void)argc;
if (session->readonly)
{
IPCOM_LOG0(WARNING, "File deletion denied");
ipftps_reply(session, "550 Permission denied"CL);
}
else if (ipftps_root_check(session, &argv[0]) != 0)
{
IPCOM_LOG2(WARNING, "Access denied to %s from %s",
argv[0], session->cwd);
ipftps_reply(session, "550 Permission denied"CL);
}
else if (ipcom_unlink(argv[0]) != 0)
{
ipftps_perror(session, 550);
}
else
{
ipftps_reply(session, "250 File deleted"CL);
}
}
/*
*===========================================================================
* ipftps_eprt
*===========================================================================
*
* Description:
* EPRT command.
*
* Parameters:
* session Session descriptor.
* argc Number of arguments.
* argv Argument vector.
*
* Returns:
*/
IP_STATIC void
ipftps_eprt(Ipftps_session *session, int argc, char *argv[])
{
union Ip_sockaddr_union addr;
Ip_u32 h[3];
int i;
(void)argc;
if (session->epsvonly)
{
ipftps_reply(session, "501 In extended passive mode"CL);
return;
}
session->passive = 0;
/* Parse first and last argument */
for (i = 0; i < 3; i += 2)
{
char *stop;
h[i] = (Ip_u32)ipcom_strtol(argv[i], &stop, 10);
if (*stop != '\0' || h[i] > 65535)
{
ipftps_reply(session, "501 Bad address family or port"CL);
return;
}
}
ipcom_memset(&addr, 0, sizeof(addr));
switch (h[0])
{
case 1:
/* IPv4 */
IPCOM_SA_LEN_SET(&addr.sin, sizeof(struct Ip_sockaddr_in));
addr.sin.sin_family = IP_AF_INET;
if (ipcom_inet_pton(IP_AF_INET, argv[1], &addr.sin.sin_addr) != 1)
{
ipftps_reply(session, "501 Bad IPv4 address"CL);
return;
}
addr.sin.sin_port = (Ip_u16)ip_htons(h[2]);
break;
#ifdef IPCOM_USE_INET6
case 2:
/* IPv6 */
ipcom_memset(&addr.sin6, 0, sizeof(addr.sin6));
IPCOM_SA_LEN_SET(&addr.sin6, sizeof(struct Ip_sockaddr_in6));
addr.sin6.sin6_family = IP_AF_INET6;
if (ipcom_inet_pton(IP_AF_INET6, argv[1], &addr.sin6.sin6_addr) != 1)
{
ipftps_reply(session, "501 Bad IPv6 address"CL);
return;
}
addr.sin6.sin6_port = (Ip_u16)ip_htons(h[2]);
break;
#endif
default:
ipftps_reply(session, "522 Bad address family, use " IPFTPS_AFSTR CL);
return;
}
if (session->proxy == 0 &&
IPFTPS_ADDRCMP(&addr, &session->csock.paddr) != 0)
{
IPCOM_LOG1(WARNING, "EPRT IP address %s denied", argv[1]);
ipftps_reply(session, "504 Invalid host"CL);
return;
}
if (h[2] <= session->pportbase)
{
IPCOM_LOG1(WARNING, "EPRT port number %u denied",
(unsigned int)h[2]);
ipftps_reply(session, "504 Invalid port"CL);
return;
}
ipcom_memcpy(&session->dsock.paddr, &addr, sizeof(session->dsock.paddr));
ipftps_reply(session, "200 Extended port OK"CL);
}
/*
*===========================================================================
* ipftps_epsv
*===========================================================================
*
* Description:
* EPSV command.
*
* Parameters:
* session Session descriptor.
* argc Number of arguments.
* argv Argument vector.
*
* Returns:
*/
IP_STATIC void
ipftps_epsv(Ipftps_session *session, int argc, char *argv[])
{
int af = (session->csock.paddr.sa.sa_family == IP_AF_INET ? 1 : 2);
if (argc == 1)
{
if (ipcom_strcasecmp(argv[0], "ALL") == 0)
{
ipftps_reply(session, "200 Locked in extended passive mode"CL);
session->epsvonly = 1;
return;
}
else
{
char *stop;
af = (int)ipcom_strtol(argv[0], &stop, 10);
if (*stop != '\0' || af < 1 || af > IPFTPS_AFMAX)
{
ipftps_reply(session, "522 Bad address family, use "
IPFTPS_AFSTR CL);
return;
}
if (session->proxy == 0 && af != session->csock.paddr.sa.sa_family)
{
ipftps_reply(session, "522 Bad address family, use (%d)" CL,
(session->csock.paddr.sa.sa_family == IP_AF_INET ?
1 : 2));
return;
}
}
}
session->dsock.paddr.sa.sa_family = (Ip_sa_family_t)(af == 1 ? IP_AF_INET : IP_AF_INET6);
if (ipftps_dsock_open(session, 1) != 0)
{
return;
}
ipftps_reply(session,
"229 Entering extended passive mode (|||%u|)"CL,
(unsigned int)ip_ntohs(IPFTPS_PORT(&session->dsock.laddr)));
}
/*
*===========================================================================
* ipftps_help
*===========================================================================
*
* Description:
* HELP command.
*
* Parameters:
* session Session descriptor.
* argc Number of arguments.
* argv Argument vector.
*
* Returns:
*/
IP_STATIC void
ipftps_help(Ipftps_session *session, int argc, char *argv[])
{
const Ipftps_cmd *cmd;
if (argc == 0)
{
ipftps_reply(session, "211- Command list:"CL);
}
/* Loop for help texts */
for (cmd = ipftps_cmdlist; cmd->name != IP_NULL; cmd++)
{
if (argc == 0)
{
/* Help on all commands */
ipftps_reply(session, " %4s - %s"CL, cmd->name, cmd->help);
}
else if (ipcom_strcasecmp(argv[0], cmd->name) == 0)
{
/* Help on specific command */
ipftps_reply(session, "214 %s - %s"CL, cmd->name, cmd->help);
return;
}
}
/* Terminate */
if (argc == 0)
{
ipftps_reply(session, "211 Use HELP <cmd> for help on cmd"CL);
}
else
{
ipftps_reply(session, "501 No help available"CL);
}
}
/*
*===========================================================================
* ipftps_list
*===========================================================================
*
* Description:
* LIST command.
*
* Parameters:
* session Session descriptor.
* argc Number of arguments.
* argv Argument vector.
*
* Returns:
*/
IP_STATIC void
ipftps_list(Ipftps_session *session, int argc, char *argv[])
{
struct Ip_stat st;
char *path = argv[0];
struct dirent *ent;
char dot[IP_PATH_MAX];
int ret = 0;
Ip_bool aflag = IP_FALSE;
ipcom_strcpy(dot,".");
if (argc == 0)
{
path = dot;
}
else if ((ipcom_strncmp(path, "-l", 2) == 0) ||
(ipcom_strncmp(path, "-al", 3) == 0))
{
if (ipcom_strncmp(path, "-al", 3) == 0)
aflag = IP_TRUE;
path = dot;
}
if (ipftps_root_check(session, &path) != 0)
{
IPCOM_LOG2(WARNING, "Access denied to %s from %s",
path, session->cwd);
ipftps_reply(session, "550 Permission denied"CL);
return;
}
if (ipcom_stat(path, &st) != 0)
{
ipftps_perror(session, 550);
return;
}
/* Open data socket */
if (ipftps_dsock_open(session, 0) != 0)
{
return;
}
/* Dir or file? */
if (IP_S_ISDIR(st.st_mode))
{
DIR *dir;
dir = opendir(path);
if (dir == IP_NULL)
{
ipftps_perror(session, 550);
ipftps_dsock_close(session);
return;
}
/* Loop for files */
while ((ent = readdir(dir)) != 0)
{
if ((aflag == IP_TRUE) || (ent->d_name[0] != '.'))
{
if ((ret = ipftps_ls(session, session->dsock.fd, path, ent->d_name)) != 0)
{
break;
}
}
}
if (closedir(dir) != 0)
{
IPCOM_LOG2(WARNING, "Directory close failed for %s: %s",
path, ipcom_strerror(ipcom_errno));
}
}
else
{
ret = ipftps_ls(session, session->dsock.fd, "", path);
}
ipftps_dsock_close(session);
if (ret == 0)
{
ipftps_reply(session, "226 Transfer complete"CL);
}
}
/*
*===========================================================================
* ipftps_mkd
*===========================================================================
*
* Description:
* MKD command.
*
* Parameters:
* session Session descriptor.
* argc Number of arguments.
* argv Argument vector.
*
* Returns:
*/
IP_STATIC void
ipftps_mkd(Ipftps_session *session, int argc, char *argv[])
{
char *path = argv[0];
#ifdef IP_PORT_VXWORKS
char *argv0 = IP_NULL;
#endif
(void)argc;
#ifdef IP_PORT_VXWORKS
if(argv[0])
{
if ((argv0 = ipcom_malloc(IP_PATH_MAX)) == IP_NULL)
{
IPCOM_LOG0(ERR, "Out of memory");
ipftps_reply(session, "452 Out of memory"CL);
return;
}
ipcom_strcpy(argv0, argv[0]);
}
#endif
if (session->readonly)
{
IPCOM_LOG0(WARNING, "Make dir denied");
ipftps_reply(session, "550 Permission denied"CL);
}
else if (ipftps_root_check(session, &path) != 0)
{
IPCOM_LOG2(WARNING, "Access denied to %s from %s",
argv[0], session->cwd);
ipftps_reply(session, "550 Permission denied"CL);
}
else if (ipcom_mkdir(path, 0777) != 0)
{
ipftps_perror(session, 550);
}
else
{
#ifdef IP_PORT_VXWORKS
ipftps_reply(session, "257 \"%s\" directory created"CL, argv0);
#else
ipftps_reply(session, "257 \"%s\" directory created"CL, argv[0]);
#endif
}
#ifdef IP_PORT_VXWORKS
ipftps_free(argv0);
#endif
}
/*
*===========================================================================
* ipftps_mode
*===========================================================================
*
* Description:
* MODE command.
*
* Parameters:
* session Session descriptor.
* argc Number of arguments.
* argv Argument vector.
*
* Returns:
*/
IP_STATIC void
ipftps_mode(Ipftps_session *session, int argc, char *argv[])
{
char *mode = argv[0];
(void)argc;
if (ipcom_toupper(mode[0]) != 'S' || mode[1] != '\0')
{
ipftps_reply(session, "504 Only S supported"CL);
}
else
{
ipftps_reply(session, "200 Stream mode selected"CL);
}
}
/*
*===========================================================================
* ipftps_nlst
*===========================================================================
*
* Description:
* NLST command.
*
* Parameters:
* session Session descriptor.
* argc Number of arguments.
* argv Argument vector.
*
* Returns:
*/
IP_STATIC void
ipftps_nlst(Ipftps_session *session, int argc, char *argv[])
{
struct Ip_stat st;
char *path = argv[0];
struct dirent *ent;
char dot[IP_PATH_MAX];
char *pat = IP_NULL;
char *path1 = IP_NULL;
char *nbuf = IP_NULL;
char *ptr = IP_NULL;
ipcom_strcpy(dot,".");
if (argc == 0)
{
path = dot;
}
else if((ipcom_strncmp(path, "-l", 2) == 0) ||
(ipcom_strncmp(path, "-al", 3) == 0))
{
ipftps_list(session, argc, argv);
return;
}
path1= ipcom_malloc(IP_PATH_MAX);
if (path1 == IP_NULL)
{
IPCOM_LOG0(ERR, "Out of memory");
ipftps_reply(session, "452 Out of memory"CL);
return;
}
nbuf= ipcom_malloc(IP_PATH_MAX);
if (nbuf == IP_NULL)
{
IPCOM_LOG0(ERR, "Out of memory");
ipftps_reply(session, "452 Out of memory"CL);
goto exit;
}
ipcom_strcpy(path1, path);
if (ipftps_root_check(session, &path) != 0)
{
IPCOM_LOG2(WARNING, "Access denied to %s from %s",
path, session->cwd);
ipftps_reply(session, "550 Permission denied"CL);
goto exit;
}
if (ipcom_stat(path, &st) != 0)
{
/* Stat failed. Check for a wild cards in the path */
if((pat = ipftps_wildcard_check(path, &st)) == IP_NULL)
{
ipftps_perror(session, 550);
goto exit;
}
if ((ptr = ipcom_strrchr(path1,'/')) == IP_NULL)
ptr = ipcom_strrchr(path1,'\\');
if (ptr != IP_NULL) *(++ptr) = '\0';
}
/* Open data socket */
if (ipftps_dsock_open(session, 0) != 0)
{
goto exit;
}
/* Dir or file? */
if (IP_S_ISDIR(st.st_mode))
{
DIR *dir;
dir = opendir(path);
if (dir == IP_NULL)
{
ipftps_perror(session, 550);
ipftps_dsock_close(session);
goto exit;
}
/* Loop for files */
ent = readdir(dir);
while (ent != 0)
{
if (ent->d_name[0] != '.')
{
if(pat == IP_NULL)
{
ipftps_reply_sock(session, session->dsock.fd,
"%s"CL, ent->d_name);
}
else
{
if (ipftps_pattern_check(pat, ent->d_name))
{
if (ptr == IP_NULL)
ipcom_snprintf(nbuf, IP_PATH_MAX,"%s", ent->d_name);
else
ipcom_snprintf(nbuf, IP_PATH_MAX,"%s%s",path1, ent->d_name);
ipftps_reply_sock(session, session->dsock.fd,
"%s"CL, nbuf);
}
}
}
ent = readdir(dir);
}
if (closedir(dir) != 0)
{
IPCOM_LOG2(WARNING, "Directory close failed for %s: %s",
path, ipcom_strerror(ipcom_errno));
}
}
else
{
ipftps_reply_sock(session, session->dsock.fd, "%s%s"CL,
(session->cwdroot ? "/" : ""), path);
}
ipftps_dsock_close(session);
ipftps_reply(session, "226 Transfer complete"CL);
exit:
ipcom_free(pat);
ipcom_free(path1);
ipcom_free(nbuf);
}
/*
*===========================================================================
* ipftps_noop
*===========================================================================
*
* Description:
* NOOP command.
*
* Parameters:
* session Session descriptor.
* argc Number of arguments.
* argv Argument vector.
*
* Returns:
*/
IP_STATIC void
ipftps_noop(Ipftps_session *session, int argc, char *argv[])
{
(void)argc;
(void)argv;
ipftps_reply(session, "200 OK"CL);
}
/*
*===========================================================================
* ipftps_pass
*===========================================================================
*
* Description:
* PASS command.
*
* Parameters:
* session Session descriptor.
* argc Number of arguments.
* argv Argument vector.
*
* Returns:
*/
IP_STATIC void
ipftps_pass(Ipftps_session *session, int argc, char *argv[])
{
int ret;
#if defined(IP_PORT_VXWORKS) && defined(LOGINEVENT_CHECK_AUTH_STAT)
int event_err;
int auth_result = 0;
#endif
(void)argc;
if (session->login != 0)
{
ipftps_reply(session, "503 Already logged in"CL);
return;
}
if (session->last == IP_NULL ||
ipcom_strcasecmp(session->last->name, "USER") != 0 ||
session->username == IP_NULL)
{
ipftps_reply(session, "503 Login with USER first"CL);
return;
}
ret = ipftps_authenticate(session, argv[0]);
#ifdef IP_PORT_VXWORKS
#ifdef LOGINEVENT_CHECK_AUTH_STAT
if (ret != 0)
auth_result = SEC_EVENT_AUTH_FAILED;
else
auth_result = SEC_EVENT_AUTH_SUCCESS;
if (_func_loginEvent != IP_NULL)
event_err = _func_loginEvent(SEC_EVENT_FTP_LOGIN, session->username, session->csock.fd, SEC_EVENT_AUTH_PASSWD, auth_result);
if (event_err != 0)
ret = -1;
#else
if (ret == 0)
{
if (_func_loginEvent != IP_NULL)
_func_loginEvent(SEC_EVENT_FTP_LOGIN, session->username, session->csock.fd, SEC_EVENT_AUTH_PASSWD);
}
#endif
#endif
if (ret != 0)
{
int secs;
if ((secs = ipftps_sysget_int("ipftps.authsleep", 5, 1)) != 0)
{
(void)ipcom_sleep(secs);
}
ipftps_reply(session, (--session->authentications <= 0 ?
"421 Service not available, closing control connection"CL :
"530 Authorization failed"CL));
return;
}
/* Change to selected directory */
if (ipftps_chdir(session, session->cwd) != 0 ||
ipftps_dir_check(session) != 0)
{
IPCOM_LOG1(ERR, "Invalid working directory: %s", session->cwd);
ipftps_reply(session, "421 Service not available, "
"closing control connection"CL);
session->authentications = 0;
return;
}
session->login = 1;
ipftps_reply(session, "230 Login OK"CL);
}
/*
*===========================================================================
* ipftps_pasv
*===========================================================================
*
* Description:
* PASV command.
*
* Parameters:
* session Session descriptor.
* argc Number of arguments.
* argv Argument vector.
*
* Returns:
*/
IP_STATIC void
ipftps_pasv(Ipftps_session *session, int argc, char *argv[])
{
int h[4],p[2];
Ip_u32 v4addr;
Ip_u16 v4port;
(void)argc;
(void)argv;
if (session->epsvonly)
{
ipftps_reply(session, "501 In extended passive mode"CL);
return;
}
IPCOM_SA_LEN_SET(&session->dsock.paddr.sin, sizeof(struct Ip_sockaddr_in));
session->dsock.paddr.sin.sin_family = IP_AF_INET;
if (ipftps_dsock_open(session, 1) != 0)
{
return;
}
v4addr = ip_ntohl(session->dsock.laddr.sin.sin_addr.s_addr);
h[0] = (v4addr >> 24) & 0xFF;
h[1] = (v4addr >> 16) & 0xFF;
h[2] = (v4addr >> 8) & 0xFF;
h[3] = v4addr & 0xFF;
v4port = ip_ntohs(session->dsock.laddr.sin.sin_port);
p[0] = (v4port >> 8) & 0xFF;
p[1] = v4port & 0xFF;
ipftps_reply(session,
"227 Entering passive mode (%d,%d,%d,%d,%d,%d)"CL,
h[0], h[1], h[2], h[3], p[0], p[1]);
}
/*
*===========================================================================
* ipftps_port
*===========================================================================
*
* Description:
* PORT command.
*
* Parameters:
* session Session descriptor.
* argc Number of arguments.
* argv Argument vector.
*
* Returns:
*/
IP_STATIC void
ipftps_port(Ipftps_session *session, int argc, char *argv[])
{
Ip_u32 h[6];
int i;
Ip_u32 addr;
Ip_u16 port;
(void)argc;
if (session->epsvonly)
{
ipftps_reply(session, "501 In extended passive mode"CL);
return;
}
session->passive = 0;
for (i = 0; i < 6; i++)
{
char *stop;
h[i] = (Ip_u32)ipcom_strtol(argv[i], &stop, 10);
if (*stop != '\0' || h[i] > 255)
{
ipftps_reply(session, "501 Bad IP address or port"CL);
return;
}
}
addr = (h[0] << 24) | (h[1] << 16) | (h[2] << 8) | h[3];
port = (Ip_u16) ((h[4] << 8) | h[5]);
if (session->proxy == 0 &&
(session->csock.paddr.sa.sa_family != IP_AF_INET ||
addr != ip_ntohl(session->csock.paddr.sin.sin_addr.s_addr)))
{
char buf[IPFTPS_IPV4_MAXLEN];
Ip_u32 u = ip_htonl(addr);
(void)ipcom_inet_ntop(IP_AF_INET, &u, buf, sizeof(buf));
IPCOM_LOG1(WARNING, "PORT IP address %s denied", buf);
ipftps_reply(session, "504 Invalid host"CL);
return;
}
if (port <= session->pportbase)
{
IPCOM_LOG1(WARNING, "PORT port number %lu denied", (Ip_u32)port);
ipftps_reply(session, "504 Invalid port"CL);
return;
}
IPCOM_SA_LEN_SET(&session->dsock.paddr.sin, sizeof(struct Ip_sockaddr_in));
session->dsock.paddr.sin.sin_family = IP_AF_INET;
session->dsock.paddr.sin.sin_addr.s_addr = (Ip_u32)ip_htonl(addr);
session->dsock.paddr.sin.sin_port = ip_htons(port);
ipftps_reply(session, "200 Port OK"CL);
}
/*
*===========================================================================
* ipftps_pwd
*===========================================================================
*
* Description:
* PWD command.
*
* Parameters:
* session Session descriptor.
* argc Number of arguments.
* argv Argument vector.
*
* Returns:
*/
IP_STATIC void
ipftps_pwd(Ipftps_session *session, int argc, char *argv[])
{
char *wd;
char *path;
char *cp;
(void)argc;
(void)argv;
if ((path = wd = ipcom_strdup(session->cwd)) == IP_NULL)
{
IPCOM_LOG0(ERR, "Out of memory");
ipftps_reply(session, "452 Out of memory"CL);
return;
}
/* Use forward slashes */
for (cp = path + ipcom_strcspn(path, IPFTPS_DIRSEP); *cp != '\0'; )
{
*cp++ = '/';
cp += ipcom_strcspn(cp, IPFTPS_DIRSEP);
}
/* Paranoid check if path OK */
if (ipftps_dircmp(session->root, path) != 0)
{
/*
** This is never supposed to happen, teardown
** session to prevent from security breaches.
*/
IPCOM_LOG0(ERR, "Directory error, terminating session");
ipftps_reply(session, "421 Service not available, "
"closing control connection"CL);
session->authentications = 0;
}
else
{
Ip_size_t rlen = ipcom_strlen(session->root);
Ip_size_t plen = ipcom_strlen(path);
/* Advance past root part of path */
path += IP_MIN(rlen, plen);
if (path > wd && *path != '/')
{
*--path = '/';
}
ipftps_reply(session, "257 \"%s\" is current directory"CL, path);
}
ipcom_free(wd);
}
/*
*===========================================================================
* ipftps_quit
*===========================================================================
*
* Description:
* QUIT command.
*
* Parameters:
* session Session descriptor.
* argc Number of arguments.
* argv Argument vector.
*
* Returns:
*/
IP_STATIC void
ipftps_quit(Ipftps_session *session, int argc, char *argv[])
{
(void)argc;
(void)argv;
#ifdef IP_PORT_VXWORKS
if ((_func_logoutEvent != IP_NULL) && session->login)
_func_logoutEvent(SEC_EVENT_FTP_LOGOUT, session->username);
#endif
session->login = 0;
ipftps_reply(session, "221 Bye"CL);
session->authentications = 0;
}
/*
*===========================================================================
* ipftps_retr
*===========================================================================
*
* Description:
* RETR command.
*
* Parameters:
* session Session descriptor.
* argc Number of arguments.
* argv Argument vector.
*
* Returns:
*/
IP_STATIC void
ipftps_retr(Ipftps_session *session, int argc, char *argv[])
{
char *msg = "226 Transfer complete"CL;
char *nbuf = IP_NULL;
char *buf;
struct Ip_stat st;
Ip_fd fd;
int perrno = 0;
int num, no;
Ip_s32 mode;
Ip_u32 chunks = 0;
#ifdef IPFTP_TLS
int ret;
#endif
(void)argc;
if (ipftps_root_check(session, &argv[0]) != 0)
{
IPCOM_LOG2(WARNING, "Access denied to %s from %s",
argv[0], session->cwd);
ipftps_reply(session, "550 Permission denied"CL);
goto leave5;
}
if ((buf = ipcom_malloc(ipftps.databuf_size)) == IP_NULL)
{
IPCOM_LOG0(ERR, "Out of memory");
ipftps_reply(session, "452 Out of memory"CL);
goto leave5;
}
if (session->binary == 0 &&
(nbuf = ipcom_malloc(2 * ipftps.databuf_size)) == IP_NULL)
{
IPCOM_LOG0(ERR, "Out of memory");
ipftps_reply(session, "452 Out of memory"CL);
goto leave4;
}
mode = IP_O_RDONLY
#ifdef IP_O_BINARY
| (session->binary ? IP_O_BINARY : 0)
#endif
;
if ((fd = ipcom_fileopen(argv[0], mode, 0)) < 0)
{
ipftps_perror(session, 550);
goto leave3;
}
if (ipcom_fstat(fd, &st) != 0)
{
ipftps_perror(session, 550);
goto leave2;
}
if (IP_S_ISREG(st.st_mode) == 0)
{
ipftps_reply(session, "550 No regular file"CL);
goto leave2;
}
if (ipftps_dsock_open(session, 0) != 0)
{
goto leave2;
}
session->trtotal = (Ip_u32)st.st_size;
session->trnow = 0;
for (;;)
{
static struct Ip_timeval timeval = {0, 0};
Ip_fd_set cmdset;
#ifdef IPFTPS_USE_WRITESELECT
Ip_fd_set dataset;
timeval.tv_sec = ipftps_sysget_int("ipftps.send_timeout", 30, 1);
timeval.tv_usec = 0;
#endif
if ((no = (int)ipcom_fileread(fd, buf, ipftps.databuf_size)) == 0)
{
goto leave1;
}
else if (no < 0)
{
perrno = 451;
goto leave1;
}
again:
#ifdef IPFTPS_USE_WRITESELECT
/* Wait until ready for write, or async command */
IP_FD_ZERO(&cmdset);
IP_FD_SET(session->csock.fd, &cmdset);
IP_FD_ZERO(&dataset);
IP_FD_SET(session->dsock.fd, &dataset);
num = ipcom_socketselect(IP_MAX(session->csock.fd, session->dsock.fd) + 1,
&cmdset, &dataset, IP_NULL, &timeval);
if (num == -1)
{
perrno = 451;
goto leave1;
}
else if (num > 0 && IP_FD_ISSET(session->csock.fd, &cmdset))
{
if (ipftps_async(session) != 0)
{
msg = "226 Abort OK"CL;
goto leave1;
}
goto again;
}
else if (num == 0 || !IP_FD_ISSET(session->dsock.fd, &dataset))
{
msg = "426 Transfer timeout"CL;
goto leave1;
}
#else
/* Check for async command */
IP_FD_ZERO(&cmdset);
IP_FD_SET(session->csock.fd, &cmdset);
num = ipcom_socketselect(session->csock.fd + 1, &cmdset, IP_NULL, IP_NULL, &timeval);
if (num == -1)
{
perrno = 451;
goto leave1;
}
else if (num > 0 && IP_FD_ISSET(session->csock.fd, &cmdset))
{
if (ipftps_async(session) != 0)
{
msg = "226 Abort OK"CL;
goto leave1;
}
goto again;
}
#endif
if (session->binary == 0)
{
if (ipftps_socketwrite_ascii(session,session->dsock.fd,
buf, nbuf, no) != 0)
{
perrno = 451;
goto leave1;
}
}
#ifdef IPFTP_TLS
else if ((ipftps_tls_enbale == IP_TRUE) &&
(ret = ipftps_tls_send(session,session->dsock.fd,buf,no))!= 2)
{
if(ret == 1)
{
perrno = 451;
goto leave1;
}
}
#endif
else if (ipcom_socketwrite(session->dsock.fd, buf, no) != no)
{
perrno = 451;
goto leave1;
}
session->trnow += no;
chunks++;
}
leave1:
IPCOM_LOG2(DEBUG2, "Sent %lu bytes in %lu chunks",
(unsigned long)session->trnow, (unsigned long)chunks);
(void)chunks;
/* Preserve ipcom_errno */
no = ipcom_errno;
ipftps_dsock_close(session);
ipcom_errno = no;
if (perrno == 0)
{
ipftps_reply(session, msg);
}
else
{
ipftps_perror(session, perrno);
}
leave2:
(void)ipcom_fileclose(fd);
leave3:
ipftps_free(nbuf);
leave4:
ipcom_free(buf);
leave5:
return;
}
/*
*===========================================================================
* ipftps_rmd
*===========================================================================
*
* Description:
* RMD command.
*
* Parameters:
* session Session descriptor.
* argc Number of arguments.
* argv Argument vector.
*
* Returns:
*/
IP_STATIC void
ipftps_rmd(Ipftps_session *session, int argc, char *argv[])
{
(void)argc;
if (session->readonly)
{
IPCOM_LOG0(WARNING, "Remove dir denied");
ipftps_reply(session, "550 Permission denied"CL);
}
else if (ipftps_root_check(session, &argv[0]) != 0)
{
IPCOM_LOG2(WARNING, "Access denied to %s from %s",
argv[0], session->cwd);
ipftps_reply(session, "550 Permission denied"CL);
}
else if (ipcom_rmdir(argv[0]) != 0)
{
ipftps_perror(session, 550);
}
else
{
ipftps_reply(session, "250 Directory removed"CL);
}
}
/*
*===========================================================================
* ipftps_rnfr
*===========================================================================
*
* Description:
* RNFR command.
*
* Parameters:
* session Session descriptor.
* argc Number of arguments.
* argv Argument vector.
*
* Returns:
*/
IP_STATIC void
ipftps_rnfr(Ipftps_session *session, int argc, char *argv[])
{
(void)argc;
ipftps_free(session->rnfr);
if (session->readonly)
{
IPCOM_LOG0(WARNING, "Rename file denied");
ipftps_reply(session, "550 Permission denied"CL);
}
else if (ipftps_root_check(session, &argv[0]) != 0)
{
IPCOM_LOG2(WARNING, "Access denied to %s from %s",
argv[0], session->cwd);
ipftps_reply(session, "550 Permission denied"CL);
}
else if (ipcom_access(argv[0], 0) != 0)
{
ipftps_perror(session, 550);
}
else if ((session->rnfr = ipcom_strdup(argv[0])) == IP_NULL)
{
IPCOM_LOG0(ERR, "Out of memory");
ipftps_reply(session, "452 Out of memory"CL);
}
else
{
ipftps_reply(session, "350 Continue with RNTO"CL);
}
}
/*
*===========================================================================
* ipftps_rnto
*===========================================================================
*
* Description:
* RNTO command.
*
* Parameters:
* session Session descriptor.
* argc Number of arguments.
* argv Argument vector.
*
* Returns:
*/
IP_STATIC void
ipftps_rnto(Ipftps_session *session, int argc, char *argv[])
{
(void)argc;
if (session->readonly)
{
IPCOM_LOG0(WARNING, "Rename file denied");
ipftps_reply(session, "550 Permission denied"CL);
}
else if (session->last == IP_NULL ||
ipcom_strcasecmp(session->last->name, "RNFR") != 0 ||
session->rnfr == IP_NULL)
{
ipftps_reply(session, "503 Missing RNFR"CL);
}
else if (ipftps_root_check(session, &argv[0]) != 0)
{
IPCOM_LOG2(WARNING, "Access denied to %s from %s",
argv[0], session->cwd);
ipftps_reply(session, "550 Permission denied"CL);
}
else if (ipcom_rename(session->rnfr, argv[0]) != 0)
{
ipftps_perror(session, 553);
}
else
{
ipftps_free(session->rnfr);
ipftps_reply(session, "250 File renamed"CL);
}
}
/*
*===========================================================================
* ipftps_stat
*===========================================================================
*
* Description:
* STAT command.
*
* Parameters:
* session Session descriptor.
* argc Number of arguments.
* argv Argument vector.
*
* Returns:
*/
IP_STATIC void
ipftps_stat(Ipftps_session *session, int argc, char *argv[])
{
if (argc == 0)
{
char buf[IPFTPS_IP_MAXLEN];
(void)ipftps_ntop(&session->csock.laddr, buf, sizeof(buf));
ipftps_reply(session, "211- Session status:"CL
" Server: %s port %d"CL, buf,
(unsigned)ip_ntohs(IPFTPS_PORT(&session->csock.laddr)));
(void)ipftps_ntop(&session->csock.paddr, buf, sizeof(buf));
ipftps_reply(session,
" Client: %s port %d"CL, buf,
(unsigned)ip_ntohs(IPFTPS_PORT(&session->csock.paddr)));
ipftps_reply(session,
" Type: %s"CL
" Mode: Stream"CL
" Structure: File"CL
" Readonly: %s"CL
" Proxy FTP: %s"CL
"211 End of status"CL,
(session->binary ? "Binary" : "Ascii"),
(session->readonly ? "Yes" : "No"),
(session->proxy ? "Yes" : "No"));
}
else
{
struct Ip_stat st;
char *path = argv[0];
struct dirent *ent;
if (ipftps_root_check(session, &path) != 0)
{
IPCOM_LOG2(WARNING, "Access denied to %s from %s",
path, session->cwd);
ipftps_reply(session, "550 Permission denied"CL);
return;
}
if (ipcom_stat(path, &st) != 0)
{
ipftps_perror(session, 550);
return;
}
/* Dir or file? */
if (IP_S_ISDIR(st.st_mode))
{
DIR *dir;
int ret = 0;
dir = opendir(path);
if (dir == IP_NULL)
{
ipftps_perror(session, 550);
return;
}
/* Loop for files */
ipftps_reply(session, "212- Directory status"CL);
while ((ent = readdir(dir)) != 0)
{
if (ent->d_name[0] != '.')
{
if ((ret = ipftps_ls(session, session->csock.fd, path, ent->d_name)) != 0)
{
break;
}
}
}
if (ret == 0)
{
ipftps_reply(session, "212 Transfer complete"CL);
}
if (closedir(dir) != 0)
{
IPCOM_LOG2(WARNING, "Directory close failed for %s: %s",
path, ipcom_strerror(ipcom_errno));
}
}
else
{
ipftps_reply(session, "213- File status"CL);
if (ipftps_ls(session, session->csock.fd, "", path) == 0)
{
ipftps_reply(session, "213 Transfer complete"CL);
}
}
}
}
/*
*===========================================================================
* ipftps_stor
*===========================================================================
*
* Description:
* STOR command.
*
* Parameters:
* session Session descriptor.
* argc Number of arguments.
* argv Argument vector.
*
* Returns:
*/
IP_STATIC void
ipftps_stor(Ipftps_session *session, int argc, char *argv[])
{
char *msg = "226 Transfer complete"CL;
char *nbuf = IP_NULL;
char *buf;
struct Ip_stat st;
Ip_fd fd;
int perrno = 0;
int num, no;
Ip_bool orphant = 0;
Ip_bool append = 0;
Ip_s32 mode;
Ip_u32 chunks = 0;
if (session->readonly)
{
IPCOM_LOG0(WARNING, "Store file denied");
ipftps_reply(session, "550 Permission denied"CL);
goto leave5;
}
if (ipftps_root_check(session, &argv[0]) != 0)
{
IPCOM_LOG2(WARNING, "Access denied to %s from %s",
argv[0], session->cwd);
ipftps_reply(session, "550 Permission denied"CL);
goto leave5;
}
if ((buf = ipcom_malloc(ipftps.databuf_size)) == IP_NULL)
{
IPCOM_LOG0(ERR, "Out of memory");
ipftps_reply(session, "452 Out of memory"CL);
goto leave5;
}
if (session->binary == 0 &&
(nbuf = ipcom_malloc(ipftps.databuf_size + 1)) == IP_NULL)
{
IPCOM_LOG0(ERR, "Out of memory");
ipftps_reply(session, "452 Out of memory"CL);
goto leave4;
}
/*
* Remove file before opening it to simulate O_TRUNC,
* which isn't supported by IPCOM.
*/
/* if append cmd, don't call ipcom_unlink() */
if(argc > 1 && ipcom_strcmp(argv[argc-1], "a") == 0)
append = 1;
else
(void)ipcom_unlink(argv[0]);
mode = IP_O_RDWR | IP_O_CREAT | (append ? IP_O_APPEND : 0)
#ifdef IP_O_BINARY
| (session->binary ? IP_O_BINARY : 0)
#endif
;
if ((fd = ipcom_fileopen(argv[0], mode,
IP_S_IRUSR | IP_S_IWUSR | IP_S_IRGRP | IP_S_IROTH)) < 0)
{
ipftps_perror(session, 550);
goto leave3;
}
if (ipcom_fstat(fd, &st) != 0)
{
ipftps_perror(session, 550);
goto leave2;
}
if (ipftps_dsock_open(session, 0) != 0)
{
goto leave2;
}
session->trtotal = 0;
session->trnow = 0;
for (;;)
{
struct Ip_timeval timeval;
Ip_fd_set set;
IP_FD_ZERO(&set);
IP_FD_SET(session->csock.fd, &set);
IP_FD_SET(session->dsock.fd, &set);
timeval.tv_sec = ipftps_sysget_int("ipftps.receive_timeout", 30, 1);
timeval.tv_usec = 0;
num = ipcom_socketselect(IP_MAX(session->csock.fd,
session->dsock.fd) + 1,
&set, IP_NULL, IP_NULL, &timeval);
if (num == -1)
{
perrno = 451;
goto leave1;
}
else if (num > 0 && IP_FD_ISSET(session->csock.fd, &set))
{
if (ipftps_async(session) != 0)
{
msg = "226 Abort OK"CL;
goto leave1;
}
continue;
}
else if (num == 0 || !IP_FD_ISSET(session->dsock.fd, &set))
{
msg = "426 Transfer timeout"CL;
goto leave1;
}
#ifdef IPFTP_TLS
if( (ipftps_tls_enbale == IP_TRUE) &&
(ipftps_tls_read(session,session->dsock.fd,buf,ipftps.databuf_size,&no) != 1))
{
if (no == 0)
{
goto leave1;
}
else if(no < 0)
{
perrno = 451;
goto leave1;
}
}
else
#endif
if ((no = (int)ipcom_socketread(session->dsock.fd, buf,
ipftps.databuf_size)) == 0)
{
goto leave1;
}
else if (no < 0)
{
perrno = 451;
goto leave1;
}
if (session->binary == 0)
{
if (ipftps_filewrite_ascii(fd, buf, nbuf, no, &orphant) != 0)
{
perrno = 451;
goto leave1;
}
}
else if (ipcom_filewrite(fd, buf, no) != no)
{
perrno = 451;
goto leave1;
}
session->trnow += no;
chunks++;
}
leave1:
/* Write orphant '\r' */
if (orphant && perrno == 0 && ipcom_filewrite(fd, "\r", 1) != 1)
{
perrno = 451;
}
IPCOM_LOG2(DEBUG2, "Received %lu bytes in %lu chunks",
(unsigned long)session->trnow, (unsigned long)chunks);
(void)chunks;
/* Preserve ipcom_errno */
no = ipcom_errno;
ipftps_dsock_close(session);
ipcom_errno = no;
if (perrno == 0)
{
ipftps_reply(session, msg);
}
else
{
ipftps_perror(session, perrno);
}
leave2:
(void)ipcom_fileclose(fd);
leave3:
ipftps_free(nbuf);
leave4:
ipcom_free(buf);
leave5:
return;
}
/*
*===========================================================================
* ipftps_stru
*===========================================================================
*
* Description:
* STRU command.
*
* Parameters:
* session Session descriptor.
* argc Number of arguments.
* argv Argument vector.
*
* Returns:
*/
IP_STATIC void
ipftps_stru(Ipftps_session *session, int argc, char *argv[])
{
char *stru = argv[0];
(void)argc;
if (ipcom_toupper(stru[0]) != 'F' || stru[1] != '\0')
{
ipftps_reply(session, "504 Only F supported"CL);
}
else
{
ipftps_reply(session, "200 File structure selected"CL);
}
}
/*
*===========================================================================
* ipftps_syst
*===========================================================================
*
* Description:
* SYST command.
*
* Parameters:
* session Session descriptor.
* argc Number of arguments.
* argv Argument vector.
*
* Returns:
*/
IP_STATIC void
ipftps_syst(Ipftps_session *session, int argc, char *argv[])
{
char ver[16];
char sys[16];
Ip_size_t versize = sizeof(ver);
Ip_size_t syssize = sizeof(sys);
(void)argc;
(void)argv;
ipftps_reply(session, "215 %s Type: L8 Version: IPFTPS %s"CL,
ipftps_sysget_str("ipftps.system", sys, &syssize, "UNIX", 1),
ipftps_sysget_str("ipftps.versionstr", ver, &versize, "-", 1));
}
/*
*===========================================================================
* ipftps_type
*===========================================================================
*
* Description:
* TYPE command.
*
* Parameters:
* session Session descriptor.
* argc Number of arguments.
* argv Argument vector.
*
* Returns:
*/
IP_STATIC void
ipftps_type(Ipftps_session *session, int argc, char *argv[])
{
char *space = " ";
/* Dummy space to facilitate display */
if (argc < 2)
{
argv[1] = space;
space = "";
}
switch (ipcom_toupper(argv[0][0]))
{
case 'A':
if (ipcom_strchr("NT ", ipcom_toupper(argv[1][0])) == IP_NULL)
{
goto leave;
}
session->binary = 0;
break;
case 'I':
if (argc > 1)
{
goto leave;
}
session->binary = 1;
break;
case 'L':
if (ipcom_toupper(argv[1][0]) != '8')
{
goto leave;
}
session->binary = 1;
break;
default:
goto leave;
}
ipftps_reply(session, "200 Type %c%s%c%sselected"CL,
argv[0][0], space, argv[1][0], space);
return;
leave:
ipftps_reply(session, "504 Only TYPE A [N|T], I and L 8 supported"CL);
}
/*
*===========================================================================
* ipftps_user
*===========================================================================
*
* Description:
* USER command.
*
* Parameters:
* session Session descriptor.
* argc Number of arguments.
* argv Argument vector.
*
* Returns:
*/
IP_STATIC void
ipftps_user(Ipftps_session *session, int argc, char *argv[])
{
(void)argc;
(void)argv;
if (session->login != 0)
{
ipftps_reply(session, "503 Cannot change user"CL);
return;
}
if (session->username != IP_NULL)
ipftps_free(session->username);
#ifdef IP_PORT_VXWORKS
if (systemSecurityIsEnabled == TRUE)
{
if (argv[0] == IP_NULL)
{
ipftps_reply(session, "332 Need account for login"CL);
session->authentications = 0;
return;
}
if ((session->username = ipcom_strdup(argv[0])) == IP_NULL)
{
IPCOM_LOG0(ERR, "Out of memory");
ipftps_reply(session, "421 Service not available, "
"closing control connection"CL);
session->authentications = 0;
return;
}
ipftps_reply(session, "331 Password required for user %s"CL, argv[0]);
}
else
#endif /* IP_PORT_VXWORKS */
#ifdef IPFTPS_USE_TEST
if (IP_TRUE) /* enabled password check in IPTESTENGINE */
{
if (argv[0] == IP_NULL || ((session->username = ipcom_strdup(argv[0])) == IP_NULL))
{
IPCOM_LOG0(ERR, "Out of memory");
ipftps_reply(session, "421 Service not available, "
"closing control connection"CL);
return;
}
ipftps_reply(session, "331 Password required for user %s"CL, argv[0]);
}
else
#endif
{
/* Change to selected directory */
if (ipftps_chdir(session, session->cwd) != 0 ||
ipftps_dir_check(session) != 0)
{
IPCOM_LOG1(ERR, "Invalid working directory: %s", session->cwd);
ipftps_reply(session, "421 Service not available, "
"closing control connection"CL);
session->authentications = 0;
return;
}
session->login = 1;
ipftps_reply(session, "230 Login OK"CL);
}
}
/*
*===========================================================================
* ipftps_size
*===========================================================================
*
* Description:
* SIZE command.
*
* Parameters:
* session Session descriptor.
* argc Number of arguments.
* argv Argument vector.
*
* Returns:
*/
IP_STATIC void
ipftps_size(Ipftps_session *session, int argc, char *argv[])
{
struct Ip_stat st;
Ip_fd fd;
Ip_s32 mode;
Ip_ssize_t no = 0, extra,end,perrno;
char *buf;
(void)argc;
if (ipftps_root_check(session, &argv[0]) != 0)
{
IPCOM_LOG2(WARNING, "Access denied to %s from %s",
argv[0], session->cwd);
ipftps_reply(session, "550 Could not get file size"CL);
return;
}
if ((buf = ipcom_malloc(ipftps.databuf_size)) == IP_NULL)
{
IPCOM_LOG0(ERR, "Out of memory");
ipftps_reply(session, "452 Out of memory"CL);
return;
}
mode = IP_O_RDONLY
#ifdef IP_O_BINARY
| (session->binary ? IP_O_BINARY : 0)
#endif
;
extra = 0;
perrno = 0;
if ((fd = ipcom_fileopen(argv[0], mode, 0)) < 0)
{
ipcom_free(buf);
ipftps_perror(session, 550);
return;
}
/* Get the size of file*/
if (ipcom_fstat(fd, &st) != 0)
{
ipftps_perror(session, 550);
(void)ipcom_fileclose(fd);
ipcom_free(buf);
return;
}
/* TYPE == ASCII */
if (session->binary == 0)
{
for(;;)
{
if ((no = ipcom_fileread(fd, buf, ipftps.databuf_size)) == 0)
{
goto response;
}
else if (no < 0)
{
perrno = 451;
goto response;
}
for(end = 0; end < no; end++)
{
if (buf[end] == '\n')
extra++;
}
}
}
response:
ipcom_errno = no;
if (perrno == 0)
ipftps_reply(session,"213 %d"CL,(st.st_size+extra));
else
ipftps_perror(session, perrno);
(void)ipcom_fileclose(fd);
ipcom_free(buf);
return;
}
#ifdef IPFTP_TLS
/*
*===========================================================================
* ipftps_auth
*===========================================================================
*
* Description:
* AUTH command.
*
* Parameters:
* session Session descriptor.
* argc Number of arguments.
* argv Argument vector.
*
* Returns:
*/
IP_STATIC void ipftps_auth(Ipftps_session *session, int argc, char *argv[])
{
(void)argc;
if(ipftps_tls_enbale == IP_FALSE)
{
ipftps_reply(session, "500 don't recognize the AUTH command"CL);
return;
}
if(ipcom_strcmp(argv[0],"TLS") == 0 || ipcom_strcmp(argv[0], "TLS-C") == 0)
{
ipftps_reply(session, "234 AUTH TLS OK"CL);
if (ipftps_create_new_tls_csession(session) != IPCOM_SUCCESS)
{
ipftps_reply(session, "431, TLS connection can't be created"CL);
ipftps_tls_close_session(session,IPFTPS_CTRL_FLAG);
ipftps_free_tls_session(session);
}
else
{
ipftps_tls_set_flag(session, IPFTPS_CTRL_FLAG, IP_TRUE);
}
}
else
{
ipftps_reply(session, "504 the parameter (%s) is unknown"CL, argv[0]);
}
return;
}
/*
*===========================================================================
* ipftps_prot
*===========================================================================
*
* Description:
* PROT command.
*
* Parameters:
* session Session descriptor.
* argc Number of arguments.
* argv Argument vector.
*
* Returns:
*/
IP_STATIC void ipftps_prot(Ipftps_session *session, int argc, char *argv[])
{
(void)argc;
if (ipftps_tls_get_ccc(session) == IP_TRUE)
{
ipftps_reply(session, "504 Control session is already cleared, don't accept PROT command"CL);
return;
}
switch (*argv[0])
{
case 'C':
{
ipftps_reply(session, "200 data is not protected"CL);
ipftps_tls_set_flag(session, IPFTPS_DATA_FLAG,IP_FALSE);
break;
}
case 'S':
case 'E':
{
ipftps_reply(session, "504 Only support parameter 'C' or 'P'"CL);
break;
}
case 'P':
ipftps_reply(session, "200 data is protected"CL);
ipftps_tls_set_flag(session, IPFTPS_DATA_FLAG,IP_TRUE);
break;
default :
ipftps_reply(session, "504 Only support parameter 'C' or 'P'"CL);
break;
}
return;
}
/*
*===========================================================================
* ipftps_pbsz
*===========================================================================
*
* Description:
* AUTH command.
*
* Parameters:
* session Session descriptor.
* argc Number of arguments.
* argv Argument vector.
*
* Returns:
*/
IP_STATIC void ipftps_pbsz(Ipftps_session *session, int argc, char *argv[])
{
(void)argc;
(void)argv;
if (ipftps_tls_get_ccc(session) == IP_TRUE)
{
ipftps_reply(session, "504 Control session is already cleared, don't accept PBSZ command"CL);
return;
}
if(ipcom_strcmp(argv[0],"0") == 0)
{
ipftps_reply(session,"200 PBSZ=0"CL);
}
else
{
ipftps_reply(session, "504 Only PBSZ=0 supported"CL);
}
return;
}
/*
*===========================================================================
* ipftps_ccc
*===========================================================================
*
* Description:
* CCC command.
*
* Parameters:
* session Session descriptor.
* argc Number of arguments.
* argv Argument vector.
*
* Returns:
*/
IP_STATIC void ipftps_ccc(Ipftps_session *session, int argc, char *argv[])
{
(void)argc;
(void)argv;
if(ipftps_tls_get_ccc(session) == IP_TRUE)
{
ipftps_reply(session, "504 control session is already cleaned, cleaning control session is invalid"CL);
return;
}
ipftps_reply(session, "200 clear control session"CL);
ipftps_tls_shutdown(session, IPFTPS_CTRL_FLAG);
ipftps_tls_set_flag(session, IPFTPS_CTRL_FLAG, IP_FALSE);
ipftps_tls_set_ccc(session,IP_TRUE);
return;
}
#endif
/*
*===========================================================================
* ipftps_xftp
*===========================================================================
*
* Description:
* XFTP command.
*
* WARNING--This function is designed to be used for test
* purposes and contains a number of commands that may be
* used to compromise security. It is of utmost importance
* that this function is disabled before deploying the FTP
* server. This is done by not defining IPFTPS_USE_TEST.
*
* Parameters:
* session Session descriptor.
* argc Number of arguments.
* argv Argument vector.
*
* Returns:
*/
#ifdef IPFTPS_USE_TEST
IP_STATIC void
ipftps_xftp(Ipftps_session *session, int argc, char *argv[])
{
char *path = argv[1];
IPCOM_LOG0(EMERG,
"**** SECURITY HAZARD - TEST FUNCTIONALITY ENABLED ****");
if (ipcom_strcmp(argv[0], "creat") == 0)
{
int mode = IP_O_RDWR | IP_O_CREAT
#ifdef IP_O_BINARY
| IP_O_BINARY
#endif
;
Ip_fd fd;
#ifdef IP_PORT_VXWORKS
char *fullPath = IP_NULL;
if(argv[1])
{
if ((fullPath = ipcom_malloc(IP_PATH_MAX)) == IP_NULL)
{
IPCOM_LOG0(ERR, "Out of memory");
ipftps_reply(session, "452 Out of memory"CL);
return;
}
ipcom_strcpy(fullPath, argv[1]);
/* Use the absolute path for vxworks */
if (pathCat(session->cwd, path, fullPath) == ERROR)
goto leave1;
pathCondense(fullPath);
path = fullPath;
}
#endif
if ((fd = ipcom_fileopen(path, mode,
IP_S_IRUSR | IP_S_IWUSR |
IP_S_IRGRP | IP_S_IROTH)) < 0)
{
ipftps_perror(session, 550);
goto leave1;
}
else
{
static const char data[] = "\r\n\n\n\r\r\n";
int datalen = strlen(data);
int len = ipcom_strtol(argv[2], 0, 10);
int i;
for (i = 0; i < len; i += datalen)
{
int writelen = IP_MIN(datalen, len - i);
if (ipcom_filewrite(fd, data, writelen) != writelen)
{
ipftps_perror(session, 451);
(void)ipcom_fileclose(fd);
leave1:
#ifdef IP_PORT_VXWORKS
ipftps_free(fullPath);
#endif
return;
}
}
(void)ipcom_fileclose(fd);
}
}
else if (ipcom_strcmp(argv[0], "connect") == 0)
{
Ipftps_sockcb cb;
int option = 1;
ipcom_memset(&cb, 0, sizeof(cb));
cb.fd = -1;
cb.laddr.sa.sa_family = IP_AF_INET;
cb.paddr.sa.sa_family = IP_AF_INET;
if (ipcom_inet_pton(IP_AF_INET, argv[1],
&cb.laddr.sin.sin_addr) != 1 ||
ipcom_inet_pton(IP_AF_INET, argv[2],
&cb.paddr.sin.sin_addr) != 1)
{
ipftps_reply(session, "501 Address error"CL);
return;
}
cb.paddr.sin.sin_port = (Ip_u16)ipcom_strtol(argv[3], IP_NULL, 10);
cb.paddr.sin.sin_port = ip_htons(cb.paddr.sin.sin_port);
if ((cb.fd = ipcom_socket(IP_AF_INET, IP_SOCK_STREAM, IPFTPS_PROTO)) < 0 ||
ipcom_setsockopt(cb.fd, IP_SOL_SOCKET, IP_SO_REUSEADDR,
&option, sizeof(option)) < 0 ||
ipcom_bind(cb.fd, &cb.laddr.sa,
IPFTPS_SOCKADDRLEN(&cb.laddr)) < 0 ||
ipcom_connect(cb.fd, &cb.paddr.sa,
IPFTPS_SOCKADDRLEN(&cb.paddr)) < 0)
{
ipftps_reply(session, "451 Socket error"CL);
}
else
{
ipftps_reply(session, "200 OK"CL);
}
if (cb.fd != -1)
{
ipcom_socketclose(cb.fd);
}
return;
}
else if (ipcom_strcmp(argv[0], "root") == 0)
{
#ifdef IP_PORT_VXWORKS
if (session->cwd != session->root)
{
ipftps_free(session->root);
}
if(argc == 2)
{
ipcom_strcpy(session->cwd, argv[1]);
}
else
{
ipcom_strcpy(session->cwd, "/");
}
session->root = ipcom_strdup(argc == 2 ? argv[1] : "/");
#else
if (session->cwd != session->root)
{
ipftps_free(session->cwd);
}
ipftps_free(session->root);
session->cwd = session->root = ipcom_strdup(argc == 2 ? argv[1] : "/");
#endif
}
#ifdef IPCOM_USE_TIME
else if (ipcom_strcmp(argv[0], "date") == 0)
{
char timestr[16];
Ip_time_t now;
struct Ip_tm tm;
(void)ipcom_time(&now);
(void)ipcom_localtime_r(&now, &tm);
(void)ipcom_strftime(timestr, sizeof(timestr), "%b %d %H:%M", &tm);
ipftps_reply(session, " %s"CL, timestr);
}
#endif
else if (ipcom_strcmp(argv[0], "readonly") == 0)
{
session->readonly = argv[1][0] - '0';
}
else if (ipcom_strcmp(argv[0], "proxy") == 0)
{
session->proxy = argv[1][0] - '0';
}
else if (ipcom_strcmp(argv[0], "lportbase") == 0)
{
session->lportbase = (Ip_u16)ipcom_strtol(argv[1], IP_NULL, 10);
}
else if (ipcom_strcmp(argv[0], "pportbase") == 0)
{
session->pportbase = (Ip_u16)ipcom_strtol(argv[1], IP_NULL, 10);
}
else
{
ipftps_reply(session, "501 Syntax error"CL);
}
ipftps_reply(session, "200 OK"CL);
}
#ifdef IPFTP_TLS
IP_STATIC void ipftps_create_cert_and_privateKey()
{
IP_STATIC char defaultCert[]={
0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x42, 0x45, 0x47, 0x49, 0x4E, 0x20, 0x52, 0x53, 0x41, 0x20, 0x50,
0x52, 0x49, 0x56, 0x41, 0x54, 0x45, 0x20, 0x4B, 0x45, 0x59, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x0D,
0x0A, 0x4D, 0x49, 0x49, 0x43, 0x58, 0x41, 0x49, 0x42, 0x41, 0x41, 0x4B, 0x42, 0x67, 0x51, 0x43,
0x59, 0x67, 0x6F, 0x42, 0x46, 0x76, 0x74, 0x5A, 0x2F, 0x76, 0x47, 0x4D, 0x4F, 0x50, 0x54, 0x50,
0x36, 0x70, 0x41, 0x75, 0x72, 0x47, 0x4D, 0x48, 0x4C, 0x76, 0x39, 0x64, 0x39, 0x4B, 0x6C, 0x6B,
0x67, 0x2F, 0x78, 0x44, 0x2B, 0x7A, 0x73, 0x4B, 0x31, 0x76, 0x52, 0x6A, 0x74, 0x35, 0x57, 0x2F,
0x61, 0x0D, 0x0A, 0x34, 0x2F, 0x36, 0x78, 0x48, 0x6F, 0x54, 0x2F, 0x69, 0x2B, 0x77, 0x78, 0x49,
0x46, 0x75, 0x4A, 0x72, 0x5A, 0x71, 0x55, 0x35, 0x49, 0x44, 0x6A, 0x54, 0x50, 0x77, 0x33, 0x43,
0x6D, 0x33, 0x6F, 0x76, 0x68, 0x49, 0x4A, 0x2B, 0x38, 0x6A, 0x73, 0x56, 0x6F, 0x6F, 0x46, 0x32,
0x66, 0x51, 0x50, 0x2B, 0x2B, 0x6E, 0x30, 0x30, 0x59, 0x58, 0x67, 0x58, 0x71, 0x57, 0x53, 0x2F,
0x51, 0x37, 0x2F, 0x0D, 0x0A, 0x6E, 0x44, 0x64, 0x4C, 0x6F, 0x78, 0x62, 0x4F, 0x39, 0x4E, 0x6F,
0x6D, 0x43, 0x4B, 0x43, 0x68, 0x5A, 0x61, 0x32, 0x63, 0x46, 0x6E, 0x7A, 0x57, 0x63, 0x42, 0x68,
0x54, 0x79, 0x67, 0x41, 0x2B, 0x6A, 0x31, 0x38, 0x78, 0x34, 0x4D, 0x50, 0x77, 0x36, 0x30, 0x41,
0x46, 0x33, 0x77, 0x4D, 0x59, 0x67, 0x78, 0x4E, 0x4E, 0x6E, 0x62, 0x4B, 0x37, 0x44, 0x77, 0x49,
0x44, 0x41, 0x51, 0x41, 0x42, 0x0D, 0x0A, 0x41, 0x6F, 0x47, 0x42, 0x41, 0x49, 0x30, 0x5A, 0x42,
0x38, 0x58, 0x2F, 0x52, 0x6F, 0x4A, 0x4E, 0x62, 0x37, 0x4F, 0x6E, 0x79, 0x69, 0x52, 0x55, 0x69,
0x33, 0x73, 0x54, 0x58, 0x35, 0x43, 0x36, 0x2F, 0x34, 0x6F, 0x4D, 0x6D, 0x51, 0x4E, 0x66, 0x47,
0x49, 0x45, 0x32, 0x46, 0x34, 0x78, 0x2B, 0x30, 0x38, 0x61, 0x64, 0x59, 0x2F, 0x77, 0x32, 0x76,
0x64, 0x64, 0x75, 0x62, 0x67, 0x76, 0x6A, 0x0D, 0x0A, 0x6A, 0x33, 0x54, 0x77, 0x41, 0x2B, 0x42,
0x2F, 0x33, 0x69, 0x6C, 0x73, 0x73, 0x78, 0x59, 0x59, 0x6A, 0x71, 0x76, 0x35, 0x6D, 0x54, 0x41,
0x67, 0x55, 0x5A, 0x79, 0x2F, 0x4E, 0x73, 0x38, 0x36, 0x30, 0x58, 0x73, 0x5A, 0x6B, 0x44, 0x4D,
0x44, 0x59, 0x4E, 0x50, 0x64, 0x4C, 0x6F, 0x58, 0x35, 0x66, 0x39, 0x67, 0x58, 0x65, 0x53, 0x6C,
0x4E, 0x68, 0x76, 0x63, 0x36, 0x6F, 0x72, 0x31, 0x63, 0x0D, 0x0A, 0x75, 0x54, 0x76, 0x6C, 0x50,
0x34, 0x5A, 0x4F, 0x6C, 0x79, 0x38, 0x52, 0x50, 0x79, 0x62, 0x53, 0x4E, 0x39, 0x7A, 0x6C, 0x4B,
0x43, 0x44, 0x38, 0x39, 0x39, 0x4D, 0x61, 0x30, 0x37, 0x63, 0x63, 0x30, 0x66, 0x62, 0x50, 0x52,
0x52, 0x57, 0x70, 0x32, 0x67, 0x2B, 0x74, 0x77, 0x4D, 0x65, 0x70, 0x41, 0x6B, 0x45, 0x41, 0x79,
0x76, 0x6C, 0x34, 0x73, 0x34, 0x6E, 0x43, 0x59, 0x63, 0x4A, 0x2F, 0x0D, 0x0A, 0x39, 0x41, 0x7A,
0x73, 0x6A, 0x43, 0x62, 0x67, 0x71, 0x76, 0x66, 0x41, 0x62, 0x52, 0x66, 0x52, 0x66, 0x67, 0x44,
0x58, 0x49, 0x6D, 0x6C, 0x4D, 0x6D, 0x4D, 0x69, 0x53, 0x64, 0x36, 0x33, 0x46, 0x45, 0x66, 0x72,
0x59, 0x74, 0x32, 0x4A, 0x4E, 0x61, 0x62, 0x44, 0x4D, 0x65, 0x54, 0x76, 0x71, 0x6B, 0x4D, 0x7A,
0x55, 0x34, 0x55, 0x6E, 0x69, 0x67, 0x38, 0x31, 0x44, 0x4A, 0x42, 0x75, 0x71, 0x0D, 0x0A, 0x63,
0x63, 0x4C, 0x4E, 0x4E, 0x73, 0x70, 0x2B, 0x55, 0x77, 0x4A, 0x42, 0x41, 0x4D, 0x42, 0x61, 0x44,
0x4B, 0x6F, 0x34, 0x32, 0x6C, 0x39, 0x4B, 0x54, 0x6C, 0x6C, 0x54, 0x59, 0x73, 0x62, 0x41, 0x6B,
0x43, 0x44, 0x42, 0x44, 0x43, 0x30, 0x57, 0x4B, 0x62, 0x79, 0x63, 0x37, 0x44, 0x35, 0x6D, 0x4A,
0x5A, 0x73, 0x6F, 0x52, 0x72, 0x4E, 0x4F, 0x65, 0x57, 0x4B, 0x65, 0x41, 0x53, 0x4B, 0x58, 0x0D,
0x0A, 0x58, 0x4B, 0x37, 0x47, 0x6A, 0x41, 0x62, 0x39, 0x53, 0x74, 0x6C, 0x52, 0x42, 0x6F, 0x35,
0x41, 0x75, 0x35, 0x57, 0x37, 0x47, 0x71, 0x56, 0x35, 0x46, 0x4C, 0x43, 0x56, 0x49, 0x6C, 0x69,
0x31, 0x34, 0x4E, 0x55, 0x43, 0x51, 0x41, 0x49, 0x6A, 0x45, 0x6B, 0x52, 0x42, 0x70, 0x51, 0x78,
0x47, 0x63, 0x66, 0x5A, 0x74, 0x31, 0x47, 0x65, 0x39, 0x57, 0x51, 0x77, 0x7A, 0x77, 0x35, 0x44,
0x69, 0x0D, 0x0A, 0x65, 0x56, 0x41, 0x73, 0x54, 0x68, 0x65, 0x4D, 0x71, 0x45, 0x50, 0x4C, 0x69,
0x4D, 0x38, 0x39, 0x77, 0x78, 0x39, 0x6E, 0x56, 0x72, 0x54, 0x48, 0x6B, 0x69, 0x30, 0x55, 0x73,
0x58, 0x4A, 0x74, 0x55, 0x52, 0x44, 0x70, 0x4E, 0x79, 0x79, 0x51, 0x44, 0x4A, 0x52, 0x36, 0x71,
0x73, 0x52, 0x4D, 0x6A, 0x6B, 0x54, 0x59, 0x57, 0x6A, 0x54, 0x44, 0x65, 0x51, 0x55, 0x43, 0x51,
0x44, 0x7A, 0x4B, 0x0D, 0x0A, 0x2B, 0x52, 0x2B, 0x2F, 0x6B, 0x6A, 0x7A, 0x31, 0x74, 0x69, 0x65,
0x44, 0x4E, 0x44, 0x2F, 0x4F, 0x30, 0x6E, 0x36, 0x58, 0x70, 0x4F, 0x71, 0x48, 0x43, 0x36, 0x2F,
0x69, 0x42, 0x4D, 0x52, 0x2F, 0x38, 0x6A, 0x6A, 0x45, 0x6C, 0x50, 0x76, 0x4D, 0x76, 0x49, 0x36,
0x50, 0x6B, 0x35, 0x70, 0x45, 0x4C, 0x6E, 0x58, 0x4B, 0x71, 0x4B, 0x7A, 0x34, 0x31, 0x76, 0x51,
0x79, 0x4B, 0x4A, 0x6C, 0x44, 0x0D, 0x0A, 0x47, 0x6B, 0x5A, 0x72, 0x65, 0x54, 0x4E, 0x39, 0x50,
0x69, 0x33, 0x46, 0x4A, 0x4C, 0x4C, 0x57, 0x34, 0x50, 0x55, 0x43, 0x51, 0x47, 0x36, 0x44, 0x67,
0x53, 0x65, 0x56, 0x71, 0x75, 0x37, 0x5A, 0x6D, 0x75, 0x55, 0x53, 0x35, 0x77, 0x5A, 0x50, 0x69,
0x33, 0x69, 0x63, 0x61, 0x66, 0x33, 0x5A, 0x57, 0x31, 0x31, 0x36, 0x43, 0x5A, 0x4C, 0x35, 0x77,
0x6F, 0x58, 0x68, 0x2B, 0x46, 0x47, 0x4A, 0x0D, 0x0A, 0x54, 0x77, 0x32, 0x59, 0x39, 0x76, 0x55,
0x36, 0x67, 0x50, 0x4C, 0x63, 0x56, 0x67, 0x51, 0x39, 0x6E, 0x33, 0x4E, 0x34, 0x63, 0x2F, 0x62,
0x65, 0x46, 0x51, 0x70, 0x4C, 0x48, 0x30, 0x2B, 0x55, 0x33, 0x39, 0x4D, 0x48, 0x31, 0x2B, 0x4C,
0x41, 0x6D, 0x42, 0x30, 0x3D, 0x0D, 0x0A, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x45, 0x4E, 0x44, 0x20,
0x52, 0x53, 0x41, 0x20, 0x50, 0x52, 0x49, 0x56, 0x41, 0x54, 0x45, 0x20, 0x4B, 0x45, 0x59, 0x2D,
0x2D, 0x2D, 0x2D, 0x2D, 0x0D, 0x0A, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x42, 0x45, 0x47, 0x49, 0x4E,
0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2D, 0x2D, 0x2D, 0x2D,
0x2D, 0x0D, 0x0A, 0x4D, 0x49, 0x49, 0x44, 0x54, 0x44, 0x43, 0x43, 0x41, 0x72, 0x57, 0x67, 0x41,
0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x4A, 0x41, 0x4D, 0x67, 0x68, 0x75, 0x72, 0x6B, 0x54, 0x6E,
0x6D, 0x6D, 0x48, 0x4D, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44,
0x51, 0x45, 0x42, 0x42, 0x51, 0x55, 0x41, 0x4D, 0x48, 0x67, 0x78, 0x43, 0x7A, 0x41, 0x4A, 0x42,
0x67, 0x4E, 0x56, 0x0D, 0x0A, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6B, 0x4E, 0x4F, 0x4D, 0x51, 0x73,
0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x49, 0x45, 0x77, 0x4A, 0x43, 0x53, 0x6A, 0x45,
0x4C, 0x4D, 0x41, 0x6B, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x78, 0x4D, 0x43, 0x51, 0x6B, 0x6F,
0x78, 0x45, 0x6A, 0x41, 0x51, 0x42, 0x67, 0x4E, 0x56, 0x42, 0x41, 0x6F, 0x54, 0x43, 0x58, 0x64,
0x70, 0x62, 0x6D, 0x52, 0x79, 0x0D, 0x0A, 0x61, 0x58, 0x5A, 0x6C, 0x63, 0x6A, 0x45, 0x4D, 0x4D,
0x41, 0x6F, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x78, 0x4D, 0x44, 0x51, 0x30, 0x52, 0x44, 0x4D,
0x51, 0x38, 0x77, 0x44, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x77, 0x5A, 0x49, 0x62,
0x33, 0x64, 0x68, 0x63, 0x6D, 0x51, 0x78, 0x48, 0x44, 0x41, 0x61, 0x42, 0x67, 0x6B, 0x71, 0x68,
0x6B, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x0D, 0x0A, 0x43, 0x51, 0x45, 0x57, 0x44, 0x58, 0x68,
0x6F, 0x4E, 0x44, 0x49, 0x34, 0x51, 0x44, 0x45, 0x32, 0x4D, 0x79, 0x35, 0x6A, 0x62, 0x32, 0x30,
0x77, 0x48, 0x68, 0x63, 0x4E, 0x4D, 0x54, 0x49, 0x77, 0x4D, 0x7A, 0x45, 0x30, 0x4D, 0x44, 0x55,
0x77, 0x4D, 0x7A, 0x41, 0x35, 0x57, 0x68, 0x63, 0x4E, 0x4D, 0x54, 0x49, 0x77, 0x4E, 0x44, 0x45,
0x7A, 0x4D, 0x44, 0x55, 0x77, 0x4D, 0x7A, 0x41, 0x35, 0x0D, 0x0A, 0x57, 0x6A, 0x42, 0x34, 0x4D,
0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4A, 0x44, 0x54,
0x6A, 0x45, 0x4C, 0x4D, 0x41, 0x6B, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x42, 0x4D, 0x43, 0x51,
0x6B, 0x6F, 0x78, 0x43, 0x7A, 0x41, 0x4A, 0x42, 0x67, 0x4E, 0x56, 0x42, 0x41, 0x63, 0x54, 0x41,
0x6B, 0x4A, 0x4B, 0x4D, 0x52, 0x49, 0x77, 0x45, 0x41, 0x59, 0x44, 0x0D, 0x0A, 0x56, 0x51, 0x51,
0x4B, 0x45, 0x77, 0x6C, 0x33, 0x61, 0x57, 0x35, 0x6B, 0x63, 0x6D, 0x6C, 0x32, 0x5A, 0x58, 0x49,
0x78, 0x44, 0x44, 0x41, 0x4B, 0x42, 0x67, 0x4E, 0x56, 0x42, 0x41, 0x73, 0x54, 0x41, 0x30, 0x4E,
0x45, 0x51, 0x7A, 0x45, 0x50, 0x4D, 0x41, 0x30, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x4D,
0x47, 0x53, 0x47, 0x39, 0x33, 0x59, 0x58, 0x4A, 0x6B, 0x4D, 0x52, 0x77, 0x77, 0x0D, 0x0A, 0x47,
0x67, 0x59, 0x4A, 0x4B, 0x6F, 0x5A, 0x49, 0x68, 0x76, 0x63, 0x4E, 0x41, 0x51, 0x6B, 0x42, 0x46,
0x67, 0x31, 0x34, 0x61, 0x44, 0x51, 0x79, 0x4F, 0x45, 0x41, 0x78, 0x4E, 0x6A, 0x4D, 0x75, 0x59,
0x32, 0x39, 0x74, 0x4D, 0x49, 0x47, 0x66, 0x4D, 0x41, 0x30, 0x47, 0x43, 0x53, 0x71, 0x47, 0x53,
0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x41, 0x51, 0x55, 0x41, 0x41, 0x34, 0x47, 0x4E, 0x0D,
0x0A, 0x41, 0x44, 0x43, 0x42, 0x69, 0x51, 0x4B, 0x42, 0x67, 0x51, 0x43, 0x59, 0x67, 0x6F, 0x42,
0x46, 0x76, 0x74, 0x5A, 0x2F, 0x76, 0x47, 0x4D, 0x4F, 0x50, 0x54, 0x50, 0x36, 0x70, 0x41, 0x75,
0x72, 0x47, 0x4D, 0x48, 0x4C, 0x76, 0x39, 0x64, 0x39, 0x4B, 0x6C, 0x6B, 0x67, 0x2F, 0x78, 0x44,
0x2B, 0x7A, 0x73, 0x4B, 0x31, 0x76, 0x52, 0x6A, 0x74, 0x35, 0x57, 0x2F, 0x61, 0x34, 0x2F, 0x36,
0x78, 0x0D, 0x0A, 0x48, 0x6F, 0x54, 0x2F, 0x69, 0x2B, 0x77, 0x78, 0x49, 0x46, 0x75, 0x4A, 0x72,
0x5A, 0x71, 0x55, 0x35, 0x49, 0x44, 0x6A, 0x54, 0x50, 0x77, 0x33, 0x43, 0x6D, 0x33, 0x6F, 0x76,
0x68, 0x49, 0x4A, 0x2B, 0x38, 0x6A, 0x73, 0x56, 0x6F, 0x6F, 0x46, 0x32, 0x66, 0x51, 0x50, 0x2B,
0x2B, 0x6E, 0x30, 0x30, 0x59, 0x58, 0x67, 0x58, 0x71, 0x57, 0x53, 0x2F, 0x51, 0x37, 0x2F, 0x6E,
0x44, 0x64, 0x4C, 0x0D, 0x0A, 0x6F, 0x78, 0x62, 0x4F, 0x39, 0x4E, 0x6F, 0x6D, 0x43, 0x4B, 0x43,
0x68, 0x5A, 0x61, 0x32, 0x63, 0x46, 0x6E, 0x7A, 0x57, 0x63, 0x42, 0x68, 0x54, 0x79, 0x67, 0x41,
0x2B, 0x6A, 0x31, 0x38, 0x78, 0x34, 0x4D, 0x50, 0x77, 0x36, 0x30, 0x41, 0x46, 0x33, 0x77, 0x4D,
0x59, 0x67, 0x78, 0x4E, 0x4E, 0x6E, 0x62, 0x4B, 0x37, 0x44, 0x77, 0x49, 0x44, 0x41, 0x51, 0x41,
0x42, 0x6F, 0x34, 0x48, 0x64, 0x0D, 0x0A, 0x4D, 0x49, 0x48, 0x61, 0x4D, 0x42, 0x30, 0x47, 0x41,
0x31, 0x55, 0x64, 0x44, 0x67, 0x51, 0x57, 0x42, 0x42, 0x54, 0x53, 0x6E, 0x7A, 0x4C, 0x6B, 0x51,
0x41, 0x33, 0x6B, 0x6C, 0x66, 0x4D, 0x78, 0x33, 0x57, 0x69, 0x31, 0x4A, 0x52, 0x56, 0x53, 0x37,
0x70, 0x35, 0x2F, 0x33, 0x6A, 0x43, 0x42, 0x71, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x6A, 0x42,
0x49, 0x47, 0x69, 0x4D, 0x49, 0x47, 0x66, 0x0D, 0x0A, 0x67, 0x42, 0x54, 0x53, 0x6E, 0x7A, 0x4C,
0x6B, 0x51, 0x41, 0x33, 0x6B, 0x6C, 0x66, 0x4D, 0x78, 0x33, 0x57, 0x69, 0x31, 0x4A, 0x52, 0x56,
0x53, 0x37, 0x70, 0x35, 0x2F, 0x33, 0x71, 0x46, 0x38, 0x70, 0x48, 0x6F, 0x77, 0x65, 0x44, 0x45,
0x4C, 0x4D, 0x41, 0x6B, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4D, 0x43, 0x51, 0x30, 0x34,
0x78, 0x43, 0x7A, 0x41, 0x4A, 0x42, 0x67, 0x4E, 0x56, 0x0D, 0x0A, 0x42, 0x41, 0x67, 0x54, 0x41,
0x6B, 0x4A, 0x4B, 0x4D, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x48, 0x45,
0x77, 0x4A, 0x43, 0x53, 0x6A, 0x45, 0x53, 0x4D, 0x42, 0x41, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43,
0x68, 0x4D, 0x4A, 0x64, 0x32, 0x6C, 0x75, 0x5A, 0x48, 0x4A, 0x70, 0x64, 0x6D, 0x56, 0x79, 0x4D,
0x51, 0x77, 0x77, 0x43, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4C, 0x0D, 0x0A, 0x45, 0x77, 0x4E,
0x44, 0x52, 0x45, 0x4D, 0x78, 0x44, 0x7A, 0x41, 0x4E, 0x42, 0x67, 0x4E, 0x56, 0x42, 0x41, 0x4D,
0x54, 0x42, 0x6B, 0x68, 0x76, 0x64, 0x32, 0x46, 0x79, 0x5A, 0x44, 0x45, 0x63, 0x4D, 0x42, 0x6F,
0x47, 0x43, 0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x4A, 0x41, 0x52, 0x59,
0x4E, 0x65, 0x47, 0x67, 0x30, 0x4D, 0x6A, 0x68, 0x41, 0x4D, 0x54, 0x59, 0x7A, 0x0D, 0x0A, 0x4C,
0x6D, 0x4E, 0x76, 0x62, 0x59, 0x49, 0x4A, 0x41, 0x4D, 0x67, 0x68, 0x75, 0x72, 0x6B, 0x54, 0x6E,
0x6D, 0x6D, 0x48, 0x4D, 0x41, 0x77, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x51, 0x46, 0x4D,
0x41, 0x4D, 0x42, 0x41, 0x66, 0x38, 0x77, 0x44, 0x51, 0x59, 0x4A, 0x4B, 0x6F, 0x5A, 0x49, 0x68,
0x76, 0x63, 0x4E, 0x41, 0x51, 0x45, 0x46, 0x42, 0x51, 0x41, 0x44, 0x67, 0x59, 0x45, 0x41, 0x0D,
0x0A, 0x4D, 0x44, 0x34, 0x41, 0x6C, 0x62, 0x4A, 0x42, 0x48, 0x6C, 0x47, 0x76, 0x70, 0x6D, 0x4B,
0x51, 0x52, 0x6F, 0x4B, 0x55, 0x4B, 0x59, 0x6F, 0x74, 0x79, 0x2B, 0x67, 0x41, 0x4C, 0x39, 0x44,
0x76, 0x6D, 0x50, 0x6F, 0x61, 0x68, 0x75, 0x6B, 0x46, 0x59, 0x6E, 0x35, 0x78, 0x33, 0x47, 0x39,
0x53, 0x58, 0x72, 0x51, 0x32, 0x57, 0x4F, 0x33, 0x4D, 0x69, 0x51, 0x65, 0x56, 0x4A, 0x65, 0x4F,
0x73, 0x0D, 0x0A, 0x4B, 0x36, 0x49, 0x6B, 0x6F, 0x35, 0x4A, 0x49, 0x69, 0x50, 0x70, 0x6F, 0x55,
0x4F, 0x30, 0x62, 0x71, 0x36, 0x6D, 0x30, 0x77, 0x64, 0x79, 0x67, 0x2F, 0x78, 0x5A, 0x41, 0x77,
0x45, 0x2F, 0x77, 0x78, 0x6B, 0x44, 0x38, 0x4B, 0x62, 0x43, 0x57, 0x32, 0x54, 0x38, 0x31, 0x37,
0x63, 0x42, 0x47, 0x58, 0x77, 0x58, 0x6B, 0x63, 0x42, 0x51, 0x65, 0x38, 0x70, 0x71, 0x64, 0x49,
0x68, 0x2F, 0x33, 0x0D, 0x0A, 0x37, 0x4B, 0x35, 0x6D, 0x75, 0x78, 0x70, 0x41, 0x31, 0x70, 0x6E,
0x41, 0x73, 0x73, 0x57, 0x46, 0x39, 0x78, 0x47, 0x46, 0x63, 0x50, 0x5A, 0x75, 0x6F, 0x68, 0x37,
0x39, 0x56, 0x78, 0x61, 0x4D, 0x44, 0x42, 0x62, 0x59, 0x33, 0x72, 0x46, 0x42, 0x4A, 0x7A, 0x73,
0x3D, 0x0D, 0x0A, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x45, 0x4E, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54,
0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D};
int mode = IP_O_RDWR | IP_O_CREAT
#ifdef IP_O_BINARY
| IP_O_BINARY
#endif
;
Ip_fd fd;
fd = ipcom_fileopen("ftp_tls.cert", mode,
IP_S_IRUSR | IP_S_IWUSR |
IP_S_IRGRP | IP_S_IROTH);
if(fd < 0)
{
return;
}
ipcom_filewrite(fd, defaultCert, sizeof(defaultCert));
ipcom_fileclose(fd);
return;
}
#endif
#endif
/*
*===========================================================================
* ipftps_ntop
*===========================================================================
*
* Description:
* Print IP address using ntop.
*
* Parameters:
* addr IP address.
* dest Result buffer.
* len Size of result buffer.
*
* Returns:
* Pointer to buffer if success, 0 otherwise.
*/
IP_STATIC const char *
ipftps_ntop(union Ip_sockaddr_union *addr, char *dest, int len)
{
switch (addr->sa.sa_family)
{
#ifdef IPCOM_USE_INET
case IP_AF_INET:
return ipcom_inet_ntop(addr->sa.sa_family,
&addr->sin.sin_addr, dest, len);
#endif
#ifdef IPCOM_USE_INET6
case IP_AF_INET6:
return ipcom_inet_ntop(addr->sa.sa_family,
&addr->sin6.sin6_addr, dest, len);
#endif
default:
ipcom_strcpy(dest, "?");
break;
}
return (const char *)dest;
}
/*
*===========================================================================
* ipftps_perror
*===========================================================================
*
* Description:
* Send errno based error message to control socket.
*
* Parameters:
* session Session descriptor.
* no FTP error number.
*
* Returns:
* Nothing.
*/
IP_STATIC void
ipftps_perror(Ipftps_session *session, int no)
{
ipftps_reply(session, "%d %s"CL, no, ipcom_strerror(ipcom_errno));
}
/*
*===========================================================================
* ipftps_dsock_open
*===========================================================================
*
* Description:
* Open data socket.
*
* Parameters:
* session Session descriptor.
* passive_open True if opening a passive socket.
*
* Returns:
* 0 if success, 1 otherwise.
*/
IP_STATIC int
ipftps_dsock_open(Ipftps_session *session, int passive_open)
{
Ipftps_sockcb *dsock = &session->dsock;
Ip_fd fd;
int attempts;
int num, eno = 0;
int passive_accept = (passive_open == 0 && session->passive != 0);
char buf[IPFTPS_IP_MAXLEN];
#ifdef IP_SO_LINGER
struct Ip_linger ling;
#endif
/* No active connections allowed when EPSV ALL is selected */
if (session->epsvonly && passive_open == 0 && session->passive == 0)
{
ipftps_reply(session, "503 Missing EPSV after EPSV ALL"CL);
goto leave2;
}
/* Handle passive mode */
if (passive_accept)
{
struct Ip_timeval timeval;
Ip_socklen_t len = sizeof(dsock->paddr);
Ip_fd_set set;
IP_FD_ZERO(&set);
IP_FD_SET(session->dsock.fd, &set);
timeval.tv_sec = ipftps_sysget_int("ipftps.receive_timeout", 30, 1);
timeval.tv_usec = 0;
num = ipcom_socketselect(session->dsock.fd + 1, &set,
IP_NULL, IP_NULL, &timeval);
if (num == -1)
{
eno = ipcom_errno;
IPCOM_LOG1(ERR, "Cannot select on data socket: %s",
ipcom_strerror(eno));
goto leave1;
}
else if (num == 0 || !IP_FD_ISSET(session->dsock.fd, &set))
{
IPCOM_LOG0(WARNING, "No connect from peer in passive mode");
eno = 0;
goto leave1;
}
fd = ipcom_accept(dsock->fd, &dsock->paddr.sa, &len);
if (fd < 0)
{
eno = ipcom_errno;
IPCOM_LOG2(ERR, "ipcom_accept() failed : %s [%d]",
ipcom_strerror(eno), eno);
goto leave1;
}
/* Close original socket and replace with new */
if (ipcom_socketclose(dsock->fd) != 0)
{
IPCOM_LOG1(ERR, "Cannot close socket: %s",
ipcom_strerror(ipcom_errno));
}
dsock->fd = fd;
if (session->proxy == 0 &&
IPFTPS_ADDRCMP(&dsock->paddr, &session->csock.paddr) != 0)
{
(void)ipftps_ntop(&dsock->paddr, buf, sizeof(buf));
IPCOM_LOG1(WARNING, "Peer IP address %s denied", buf);
ipftps_reply(session, "425 Invalid host"CL);
eno = 0;
goto leave1;
}
ipftps_reply(session, "125 Using existing data connection"CL);
}
else
{
int option;
int port;
if (dsock->fd != -1)
{
if (ipcom_socketclose(dsock->fd) != 0)
{
IPCOM_LOG1(ERR, "Cannot close socket: %s",
ipcom_strerror(ipcom_errno));
}
session->dsock.fd = -1;
session->passive = 0;
}
if ((dsock->fd = ipcom_socket(dsock->paddr.sa.sa_family,
IP_SOCK_STREAM, IPFTPS_PROTO)) < 0)
{
eno = ipcom_errno;
IPCOM_LOG1(ERR, "Cannot allocate data socket: %s",
ipcom_strerror(eno));
goto leave2;
}
option = 1;
if (ipcom_setsockopt(dsock->fd, IP_SOL_SOCKET, IP_SO_REUSEADDR,
&option, sizeof(option)) < 0)
{
IPCOM_LOG1(WARNING, "Cannot reuse socket address: %s",
ipcom_strerror(ipcom_errno));
}
#ifdef IP_SO_LINGER
ling.l_onoff = 1;
ling.l_linger = ipftps_sysget_int("ipftps.dsock_linger", 10, IP_NULL);
if (ipcom_setsockopt(dsock->fd, IP_SOL_SOCKET, IP_SO_LINGER, &ling, sizeof(ling)) < 0)
{
IPCOM_LOG1(WARNING, "ipcom_setsockopt(IP_SO_LINGER) failed : %s",
ipcom_strerror(ipcom_errno));
}
#endif /* IP_SO_LINGER */
attempts = IPFTPS_BIND_ATTEMPTS;
/* Loop for bind attempts */
for (;;)
{
if (passive_open == 0)
{
/* According to RFC959 an active FTP session should use a adjacent port to
* the configured ctrl port (i.e. control connection port -1).
*/
port = ipftps_sysget_int("ipftps.port_number", 21, 1) - 1;
}
else
{
/* Select random port above lportbase */
port = (int)ipcom_random();
port = (int)(((unsigned long)port %
(65535U - session->lportbase)) +
session->lportbase + 1);
ip_assert(port > session->lportbase);
ip_assert(port <= 65535);
}
IPFTPS_PORT(&dsock->laddr) = (Ip_u16)ip_htons(port);
if (ipcom_bind(dsock->fd, &dsock->laddr.sa,
(Ip_socklen_t)IPFTPS_SOCKADDRLEN(&dsock->laddr)) < 0)
{
/* Reiterate if using random port numbers */
if (passive_open != 0 && --attempts > 0)
{
continue;
}
eno = ipcom_errno;
IPCOM_LOG3(ERR, "Cannot bind data socket %s:%d: %s",
ipftps_ntop(&dsock->laddr, buf, sizeof(buf)), (int)port,
ipcom_strerror(eno));
goto leave1;
}
break;
}
#ifdef IPIPTOS_THROUGHPUT
/* Setup for max throughput service */
option = IPIPTOS_THROUGHPUT;
if (ipcom_setsockopt(dsock->fd, IP_IPPROTO_IP, IPIP_TOS,
&option, sizeof(option)) < 0)
{
IPCOM_LOG1(WARNING,
"Cannot setup for max throughput service: %s",
ipcom_strerror(ipcom_errno));
}
#endif
/* Active or passive open */
if (passive_open)
{
if (ipcom_listen(dsock->fd, 1) != 0)
{
eno = ipcom_errno;
IPCOM_LOG1(ERR, "Cannot listen on data socket: %s",
ipcom_strerror(eno));
goto leave1;
}
session->passive = 1;
}
else
{
#ifdef IPFTPS_USE_IIS_150
/*
* The IIS FTP server sends the 150 message
* before opening the data connection.
*/
ipftps_reply(session, "150 Opening data connection"CL);
#endif
#ifdef IPCOM_USE_INET6
if (dsock->paddr.sa.sa_family == IP_AF_INET6)
{
struct Ip_sockaddr_in6 laddr;
Ip_socklen_t laddr_len = sizeof(laddr);
/* Get the scope from the local address */
if (ipcom_getsockname(dsock->fd, (struct Ip_sockaddr *) &laddr, &laddr_len) < 0)
{
eno = ipcom_errno;
IPCOM_LOG1(ERR, "Cannot get local address of socket: %s",
ipcom_strerror(eno));
goto leave1;
}
/* Use the same scope as the local address */
dsock->paddr.sin6.sin6_scope_id = laddr.sin6_scope_id;
}
#endif /* IPCOM_USE_INET6 */
if (ipcom_connect(dsock->fd, &dsock->paddr.sa,
(Ip_socklen_t)IPFTPS_SOCKADDRLEN(&dsock->paddr)) < 0)
{
eno = ipcom_errno;
IPCOM_LOG1(ERR, "Cannot connect to data socket: %s",
ipcom_strerror(eno));
goto leave1;
}
#ifndef IPFTPS_USE_IIS_150
ipftps_reply(session, "150 Opening data connection"CL);
#endif
}
}
#ifdef IPFTP_TLS
if((passive_open == 0)
&&(ipftps_tls_enbale == IP_TRUE)
&&(ipftps_create_new_tls_dsession(session,&eno) != IPCOM_SUCCESS))
{
ipftps_dsock_close(session);
ipftps_reply(session, "425 TLS data session can't be created. err = %d"CL, eno);
return 1;
}
#endif
return 0;
leave1:
ipftps_dsock_close(session);
leave2:
if (eno != 0)
{
ipftps_reply(session, "425 %s"CL, ipcom_strerror(eno));
}
return 1;
}
/*
*===========================================================================
* ipftps_dsock_close
*===========================================================================
*
* Description:
* Close data socket.
*
* Parameters:
* session Session descriptor.
*
* Returns:
* Nothing.
*/
IP_STATIC void
ipftps_dsock_close(Ipftps_session *session)
{
#ifdef IPFTP_TLS
if(ipftps_tls_enbale == IP_TRUE)
{
ipftps_tls_close_session(session,IPFTPS_DATA_FLAG);
}
#endif
if (session->dsock.fd != -1 && ipcom_socketclose(session->dsock.fd) != 0)
{
IPCOM_LOG1(ERR, "Cannot close socket: %s",
ipcom_strerror(ipcom_errno));
}
/* Reset peer address to default */
session->dsock.fd = -1;
session->passive = 0;
}
/*
*===========================================================================
* ipftps_write
*===========================================================================
*
* Description:
* Write to socket, terminate session if control socket down.
*
* Parameters:
* session Session descriptor.
* fd Socket descriptor.
* buf Buffer.
* len Buffer length.
*
* Returns:
* 0 if success, 1 otherwise.
*/
IP_STATIC int
ipftps_write(Ipftps_session *session, Ip_fd fd, void *buf, int len)
{
#ifdef IPFTP_TLS
int ret;
#endif
#ifdef IPFTP_TLS
if((ipftps_tls_enbale == IP_TRUE)&&
(ret = ipftps_tls_send(session,fd,buf,len)) != 2)
{
if(ret == 1)
{
IPCOM_LOG0(WARNING,"TLS write error");
goto leave;
}
}
else
#endif
if (ipcom_socketwrite(fd, buf, len) != len)
{
IPCOM_LOG1(WARNING, "Socket write error: %s",
ipcom_strerror(ipcom_errno));
goto leave;
}
return 0;
leave:
/* Terminate session if control socket closed */
if (fd == session->csock.fd)
{
session->authentications = 0;
}
return 1;
}
/*
*===========================================================================
* ipftps_reply_sock
*===========================================================================
*
* Description:
* Reply to peer.
*
* Parameters:
* session Session descriptor.
* fd Socket descriptor.
* fmt Format string.
* ... Additional parms.
*
* Returns:
* Nothing.
*/
IP_STATIC void
ipftps_reply_sock(Ipftps_session *session, Ip_fd fd, const char *fmt, ...)
{
char buf[512];
va_list argptr;
int len;
va_start(argptr, fmt);
len = ipcom_vsnprintf(buf, sizeof(buf), fmt, argptr);
va_end(argptr);
if (len < 0)
{
IPCOM_LOG0(ERR, "Error in ipcom_vsnprintf(), out of memory?");
ipcom_strcpy(buf, "452 Error in ipcom_vsnprintf(), out of memory?");
len = (int)ipcom_strlen(buf);
}
else if (len > (int)sizeof(buf))
{
IPCOM_LOG0(WARNING, "Reply buffer overflow");
buf[sizeof(buf) - 2] = '\r';
buf[sizeof(buf) - 1] = '\n';
len = sizeof(buf);
}
(void)ipftps_write(session, fd, buf, len);
}
/*
*===========================================================================
* ipftps_reply
*===========================================================================
*
* Description:
* Reply to the peer PI.
*
* Parameters:
* session Session descriptor.
* fmt Format string.
* ... Additional parms.
*
* Returns:
* Nothing.
*/
IP_STATIC void
ipftps_reply(Ipftps_session *session, const char *fmt, ...)
{
char buf[512];
va_list argptr;
int len;
va_start(argptr, fmt);
len = ipcom_vsnprintf(buf, sizeof(buf), fmt, argptr);
va_end(argptr);
if (len < 0)
{
IPCOM_LOG0(ERR, "Error in ipcom_vsnprintf(), out of memory?");
ipcom_strcpy(buf, "452 Error in ipcom_vsnprintf(), out of memory?");
len = (int)ipcom_strlen(buf);
}
else if (len > (int)sizeof(buf))
{
IPCOM_LOG0(WARNING, "Reply buffer overflow");
buf[sizeof(buf) - 2] = '\r';
buf[sizeof(buf) - 1] = '\n';
len = sizeof(buf);
}
(void)ipftps_write(session, session->csock.fd, buf, len);
}
/*
*===========================================================================
* ipftps_telnet
*===========================================================================
*
* Description:
* Handle telnet stuff.
*
* Parameters:
* session Session descriptor.
*
* Returns:
* 0 if success, 1 otherwise.
*/
IP_STATIC int
ipftps_telnet(Ipftps_session *session)
{
Ip_u8 *cp = (Ip_u8 *)(session->cmdbuf);
int i = 0;
/* Loop through entire command buffer */
while (i < session->cmdbuflen)
{
int left = session->cmdbuflen - i;
do
{
int skip = 0;
int reply = 0;
int j;
/* Check for telnet */
if (cp[0] == IPFTPS_DM)
{
/*
** This is a special case which will occur when
** inline handling of OOB data is missing. It
** seems a reasonable compromise to ignore all
** DMs in input even if not preceded by IAC.
*/
skip = 1;
}
else if (cp[0] == IPFTPS_IAC && left >= 2)
{
switch (cp[1])
{
case IPFTPS_WILL:
if (left >= 3)
{
skip = 3;
reply = 1;
cp[1] = IPFTPS_DONT;
}
break;
case IPFTPS_DO:
if (left >= 3)
{
skip = 3;
reply = 1;
cp[1] = IPFTPS_WONT;
}
break;
case IPFTPS_WONT:
case IPFTPS_DONT:
if (left >= 3)
{
skip = 3;
}
break;
default:
skip = 2;
break;
}
/* Reply if negotiation detected */
if (reply)
{
(void)ipftps_write(session, session->csock.fd, cp, skip);
}
}
/* Remove telnet stuff from command buffer */
if (skip > 0)
{
for (j = 0; j < (left - skip); j++)
{
cp[j] = cp[j + skip];
}
session->cmdbuflen -= skip;
/* Continue without advancing indices */
break;
}
i++;
cp++;
}
while (0);
}
return 0;
}
/*
*===========================================================================
* ipftps_get_command
*===========================================================================
*
* Description:
* Get a complete command from the PI socket.
*
* Parameters:
* session Session descriptor.
*
* Returns:
* 0 if success, 1 otherwise.
*/
IP_STATIC int
ipftps_get_command(Ipftps_session *session)
{
int len;
int num, i;
int width;
/* Put possible last command first in buffer */
for (i = 0; i < (session->cmdbuflen - session->cmdlen); i++)
{
session->cmdbuf[i] = session->cmdbuf[session->cmdlen + i];
}
session->cmdbuflen -= session->cmdlen;
session->cmdlen = 0;
/* Loop until command available */
for (;;)
{
struct Ip_timeval timeval;
Ip_fd_set set;
timeval.tv_sec = ipftps_sysget_int("ipftps.session_timeout", 300, 1);
timeval.tv_usec = 0;
/* If session->login is 1, this session must be a FTP session. */
if (session->login != 1)
/* Handle telnet stuff */
(void)ipftps_telnet(session);
/* Check if there already is a pending command */
for (i = 0; i < session->cmdbuflen; i++)
{
if (session->cmdbuf[i] == '\r')
{
if (i < (session->cmdbuflen - 1) &&
session->cmdbuf[i + 1] == '\n')
{
session->cmdbuf[i] = '\0';
session->cmdlen = i + 2;
return 0;
}
}
}
/* Truncate if buffer is full but no command received */
if (session->cmdbuflen >= IPFTPS_CMDBUFSIZE)
{
session->cmdbuf[session->cmdbuflen - 1] = '\0';
session->cmdlen = session->cmdbuflen;
return 0;
}
IP_FD_ZERO(&set);
IP_FD_SET(session->csock.fd, &set);
IP_FD_SET(ipftps.pipe_fd[0], &set);
width = IP_MAX(ipftps.pipe_fd[0], session->csock.fd);
num = ipcom_socketselect(width + 1, &set,
IP_NULL, IP_NULL, &timeval);
if (num == -1)
{
IPCOM_LOG1(WARNING, "Cannot select on control socket: %s",
ipcom_strerror(ipcom_errno));
break;
}
else if (num > 0 && IP_FD_ISSET(ipftps.pipe_fd[0], &set))
{
ipftps_reply(session, "421 Timeout, closing control connection"CL);
break;
}
else if (num == 0 || !IP_FD_ISSET(session->csock.fd, &set))
{
IPCOM_LOG0(WARNING, "Session timeout");
ipftps_reply(session, "421 Timeout, closing control connection"CL);
break;
}
#ifdef IPFTP_TLS
if((ipftps_tls_enbale == IP_TRUE)&&
(ipftps_tls_read(session,
session->csock.fd,
session->cmdbuf + session->cmdbuflen,
IPFTPS_CMDBUFSIZE - session->cmdbuflen,
&len) != 1))
{
if (len == 0)
{
IPCOM_LOG0(INFO, "Connection closed by remote host");
break;
}
else if(len < 0)
{
IPCOM_LOG0(WARNING, "Cannot read from TLS control socket");
break;
}
}
else
#endif
/* Get more data */
if ((len = (int)ipcom_socketread(session->csock.fd,
session->cmdbuf + session->cmdbuflen,
IPFTPS_CMDBUFSIZE - session->cmdbuflen)) == 0)
{
IPCOM_LOG0(INFO, "Connection closed by remote host");
break;
}
else if (len < 0)
{
IPCOM_LOG1(WARNING, "Cannot read from control socket: %s",
ipcom_strerror(ipcom_errno));
break;
}
session->cmdbuflen += len;
}
return 1;
}
/*
*===========================================================================
* ipftps_parse_command
*===========================================================================
*
* Description:
* Parse a command from the PI socket.
*
* Parameters:
* session Session descriptor.
*
* Returns:
*/
IP_STATIC int
ipftps_parse_command(Ipftps_session *session)
{
char *argv[IPFTPS_MAX_ARGS];
const Ipftps_cmd *cmd;
char *stop;
char *cp = session->cmdbuf;
int i;
#ifdef IP_PORT_VXWORKS
char *tmpPtr = IP_NULL;
char *tmpPtr1 = IP_NULL;
#endif
ipcom_memset(argv, 0, IPFTPS_MAX_ARGS * sizeof(char *));
/* Ignore initial whitespace */
cp += ipcom_strspn(cp, IPFTPS_DELIMITERS);
if (*cp == '\0')
{
return 0;
}
/* Parse arguments */
/* Get the command */
for (i = 0; *cp != '\0' && i < 1; i++)
{
argv[i] = cp;
cp += ipcom_strcspn(cp, IPFTPS_DELIMITERS);
stop = cp;
if ((ipcom_strncasecmp(argv[0], "PASS", 4) == 0)||
(ipcom_strncasecmp(argv[0], "USER", 4) == 0))
{
/*
* The password will start after PASS cmd plus one blank space char.
* And it could be any character except <CR> and <LF>
*/
if (*cp == ' ')
cp++;
}
else
cp += ipcom_strspn(cp, IPFTPS_DELIMITERS);
*stop = '\0';
}
/* Scan through command list */
for (cmd = ipftps_cmdlist; cmd->name != IP_NULL; cmd++)
{
if (ipcom_strcasecmp(cmd->name, argv[0]) == 0)
{
if(cmd->argtype == 0)
{
char delimiters[16];
if ((ipcom_strncasecmp(argv[0], "PASS", 4) == 0) ||
(ipcom_strncasecmp(argv[0], "USER", 4) == 0))
ipcom_strcpy(delimiters, IPFTPS_PASS_DELIMITERS);
else
ipcom_strcpy(delimiters, IPFTPS_DELIMITERS);
for (i = i; *cp != '\0' && i < IPFTPS_MAX_ARGS; i++)
{
argv[i] = cp;
cp += ipcom_strcspn(cp, delimiters);
stop = cp;
cp += ipcom_strspn(cp, delimiters);
*stop = '\0';
}
}
else
{ /* Command argument type is string */
if (*cp != '\0')
{
argv[i] = cp;
i++;
}
}
i--;
/* Check if logged in */
if (cmd->login != 0 && session->login == 0)
{
IPCOM_LOG1(WARNING, "Attempted %s without login",
cmd->name);
ipftps_reply(session, "530 Login required"CL);
return 0;
}
/* Check argument no */
if (i < cmd->min || i > cmd->max)
{
ipftps_reply(session, "501 Invalid number of arguments"CL,
argv[0]);
return 0;
}
session->cwdroot = 0;
#ifdef IP_PORT_VXWORKS
if ((argv[1] != IP_NULL) && (i != 0))
{
tmpPtr = argv[1];
tmpPtr1 = ipcom_malloc(IP_PATH_MAX);
if(tmpPtr1 != IP_NULL)
{
argv[1] = tmpPtr1;
ipcom_strncpy(argv[1], tmpPtr, IP_PATH_MAX-1);
tmpPtr1[IP_PATH_MAX-1] = '\0';
}
}
#endif
/* Do command */
cmd->func(session, i, argv + 1);
#ifdef IP_PORT_VXWORKS
if (tmpPtr1 != IP_NULL)
{
/* Reset password buffer */
ipcom_memset(tmpPtr1, 0, IP_PATH_MAX);
ipcom_free(tmpPtr1);
argv[1] = tmpPtr;
}
#endif
/* Reset password buffer */
if(ipcom_strcasecmp(cmd->name, "PASS") == 0)
{
ipcom_memset(argv[1], 0, ipcom_strlen(argv[1]));
}
session->last = cmd;
return (session->authentications == 0 ? 1 : 0);
}
}
ipftps_reply(session, "500 Invalid command: \"%s\""CL, argv[0]);
return 0;
}
/*
*===========================================================================
* ipftps_async
*===========================================================================
*
* Description:
* Handle asynchronous commands during file transfer.
*
* Parameters:
* session Session descriptor.
*
* Returns:
* 1 if an ABOR command is found, 0 otherwise.
*/
IP_STATIC int
ipftps_async(Ipftps_session *session)
{
int closed = 0;
int aborted = 0;
int asynclen;
int len;
int i;
/* Put possible last command first in buffer */
for (i = 0; i < session->cmdlen; i++)
{
session->cmdbuf[i] = session->cmdbuf[session->cmdlen + i];
}
session->cmdbuflen -= session->cmdlen;
session->cmdlen = 0;
/* Get more data */
#ifdef IPFTP_TLS
if((ipftps_tls_enbale == IP_TRUE)&&
(ipftps_tls_read(session,
session->csock.fd,
session->cmdbuf + session->cmdbuflen,
IPFTPS_CMDBUFSIZE - session->cmdbuflen,
&len) != 1))
{
if (len > 0)
{
session->cmdbuflen += len;
}
else
{
IPCOM_LOG0(WARNING, "Cannot read from TLS control socket");
closed = 1;
}
}
else
#endif
{
if ((len = (int)ipcom_socketread(session->csock.fd,
session->cmdbuf + session->cmdbuflen,
IPFTPS_CMDBUFSIZE - session->cmdbuflen)) > 0)
{
session->cmdbuflen += len;
}
else
{
IPCOM_LOG1(WARNING, "Cannot read from control socket: %s",
ipcom_strerror(ipcom_errno));
closed = 1;
}
}
/* Handle telnet */
(void)ipftps_telnet(session);
/* Loop for multiple async commands */
do
{
char *asyncpos;
asynclen = 0;
#define IPFTPS_ABORLEN 6
#define IPFTPS_STATLEN 6
/* Do a minimum parse */
session->cmdbuf[session->cmdbuflen] = '\0';
if ((asyncpos = ipcom_strstr(session->cmdbuf, "ABOR"CL)) != IP_NULL)
{
asynclen = IPFTPS_ABORLEN;
aborted = 1;
}
else if ((asyncpos = ipcom_strstr(session->cmdbuf, "STAT"CL)) != IP_NULL)
{
asynclen = IPFTPS_STATLEN;
if (session->trtotal == 0)
{
ipftps_reply(session, "213 Received %ld bytes"CL,
(long)session->trnow);
}
else
{
ipftps_reply(session, "213 Sent %ld of %ld bytes"CL,
(long)session->trnow, (long)session->trtotal);
}
}
/*
** An async command that is handled above must be removed
** from the command buffer so it doesn't occur in the normal
** command stream later on.
*/
if (asyncpos != IP_NULL)
{
for (i = (int)(asyncpos - session->cmdbuf); i < (session->cmdbuflen - asynclen); i++)
{
session->cmdbuf[i] = session->cmdbuf[asynclen + i];
}
}
session->cmdbuflen -= asynclen;
}
while (aborted == 0 && asynclen > 0);
if (aborted)
{
ipftps_reply(session, "426 Transfer aborted"CL);
}
else if (closed)
{
ipftps_reply(session, "426 Control connection closed, transfer aborted"CL);
}
return aborted || closed;
}
/*
*===========================================================================
* ipftps_chdir
*===========================================================================
*
* Description:
* Change to the requested directory.
*
* Parameters:
* session Session descriptor.
* path Path to change directory to
*
* Returns:
* Nothing.
*/
IP_STATIC int
ipftps_chdir(Ipftps_session *session, char *path)
{
#ifdef IP_PORT_VXWORKS
DIR *dir;
char *cwd = IP_NULL;
const char *pTail;
/*
* VxWorks filesystem does not check that the destination dir is valid--
* this must be done by the clients.
*/
if ((dir = opendir(path)) == NULL)
return -1;
(void)closedir(dir);
/*
* Store the full path on a session by session basis for vxworks.
*
* Since vxWorks is not a multi-user OS, changing directory via
* ipcom_chdir will change the cwd for every client connected
* to the server in the same RTP. To work around this limitation, we
* store the full cwd for each session and use absolute paths when
* issuing various commands (ie. mkdir, dele, etc).
*
* We make use of the existing pathCat and pathCondense
* routines to properly deal with path navigation elements
* ie '.' , '..' , '/../..', etc
*/
if ((cwd = ipcom_malloc(IP_PATH_MAX)) == NULL)
{
return -1;
}
if (ipcom_strcmp(session->cwd, path) != 0)
{
if (pathCat(session->cwd, path, cwd) == ERROR)
{
ipftps_free(cwd);
return -1;
}
pathCondense(cwd);
}
else
{
ipcom_strcpy(cwd, session->cwd);
pathCondense(cwd);
}
if ((path[strlen(path) - 1] == '/') && strcmp(cwd, "/"))
{
ipcom_strcat(cwd, "/");
}
/* Make sure that new path starts with a device name */
iosDevFind (cwd, &pTail);
if (pTail != cwd)
{
ipcom_strcpy(session->cwd, cwd);
ipftps_free(cwd);
return 0;
}
if (path[strlen(path) - 1] == '.')
{
ipcom_strcat(cwd, "/");
iosDevFind (cwd, &pTail);
if (pTail != cwd)
{
ipcom_strcpy(session->cwd, cwd);
ipftps_free(cwd);
return 0;
}
}
ipftps_free(cwd);
return -1;
#else
IPCOM_UNUSED_ARG(session);
if (ipcom_chdir(path) != 0)
{
return -1;
}
return 0;
#endif
}
/*
*===========================================================================
* ipftps_allo
*===========================================================================
*
* Description:
* ALLO command.
*
* Parameters:
* session Session descriptor.
* argc Number of arguments.
* argv Argument vector.
*
* Returns:
*/
IP_STATIC void
ipftps_allo(Ipftps_session *session, int argc, char *argv[])
{
(void)argc;
(void)argv;
ipftps_reply(session, "202 Command not implemented"CL);
}
/*
*===========================================================================
* ipftps_terminate_sessions
*===========================================================================
* Description: Terminate all active FTP sessions
* Parameters:
* Returns:
*
*/
IP_STATIC void
ipftps_terminate_sessions(void)
{
(void)ipcom_socketclose(ipftps.pipe_fd[1]);
(void)ipcom_millisleep(10);
for (;;)
{
ipcom_mutex_lock(ipftps.lock);
if (0 == ipftps.session_number)
{
ipcom_mutex_unlock(ipftps.lock);
break;
}
ipcom_mutex_unlock(ipftps.lock);
(void)ipcom_millisleep(10);
}
(void)ipcom_socketclose(ipftps.pipe_fd[0]);
ipftps.pipe_fd[0] = IP_INVALID_SOCKET;
ipftps.pipe_fd[1] = IP_INVALID_SOCKET;
return;
}
/*
****************************************************************************
* 10 PUBLIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipftps_get_activesession
*===========================================================================
* Description: Get the current active session number of ftp server.
* Parameters:
* Returns:
*/
IP_PUBLIC int
ipftps_get_activesession(void)
{
return ipftps.session_number;
}
/*
*===========================================================================
* ipftps_session
*===========================================================================
*
* Description:
* FTP session handler subprocess.
*
* Parameters:
*
* Returns:
*/
IPCOM_PROCESS(ipftps_session)
{
char buf[IPFTPS_IP_MAXLEN];
Ipftps_session *session = IP_NULL;
char ver[16];
Ip_size_t versize = sizeof(ver);
Ipcom_ipc ipc;
int retries = 5;
int retry_time = 1;
Ip_size_t cwdsize = IP_PATH_MAX;
#ifdef IP_PORT_VXWORKS
char *rmtBanner, *banner;
int length;
char *bannerP1, *bannerP2;
#endif
ipcom_proc_init();
/* Get session info from main */
if (ipcom_ipc_open(&ipc, "ipftps", -1) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "Failed to open IPC channel to 'ftps'");
goto leave;
}
/* Try getting memory a couple of times to avoid locking the main process */
while (--retries > 0 &&
(session = ipcom_ipc_malloc(1)) == IP_NULL)
{
IPCOM_LOG0(ERR, "Failed to allocate IPC buffer, retry");
(void)ipcom_sleep(retry_time);
retry_time *= 2;
}
if (session == IP_NULL)
{
goto leave;
}
if (ipcom_ipc_send(&ipc, session) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "Failed to send IPC buffer");
ipcom_ipc_free(session);
session = IP_NULL;
goto leave;
}
session = IP_NULL;
if (ipcom_ipc_receive(IP_NULL, &session, -1) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "Failed to receive IPC buffer");
goto leave;
}
#ifdef IP_PORT_OSE5
session->csock.fd = efs_receive_fd(0);
if (session->csock.fd == -1)
{
IPCOM_LOG0(ERR, "efs_receive_fd() failed");
goto leave;
}
#endif
if (ipcom_ipc_close(&ipc) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "Failed to close IPC channel");
goto leave;
}
(void)ipftps_ntop(&session->csock.paddr, buf, sizeof(buf));
IPCOM_LOG1(INFO, "Session handler start for %s", buf);
/* Use control socket as default template for data socket */
ipcom_memcpy(&session->dsock, &session->csock, sizeof(session->dsock));
session->dsock.fd = -1;
/* Set session defaults */
session->readonly = ipftps_sysget_int("ipftps.readonly", 0, 1);
session->proxy = ipftps_sysget_int("ipftps.proxy", 0, 1);
session->pportbase = (Ip_u16)ipftps_sysget_int("ipftps.pportbase", 1023, 1);
session->lportbase = (Ip_u16)ipftps_sysget_int("ipftps.lportbase", 49151, 1);
session->authentications = ipftps_sysget_int("ipftps.authentications", 3, 1);
session->root = ipftps_sysget_str("ipftps.root", IP_NULL, IP_NULL, "/", 1);
session->cwd = ipcom_malloc(cwdsize);
if (session->cwd == IP_NULL)
goto leave;
/* coverity[leaked_storage] */
(void)ipftps_sysget_str("ipftps.dir", session->cwd, &cwdsize,IPCOM_FILE_ROOT, 1);
#ifdef IPFTP_TLS
#ifdef IPFTPS_USE_TEST
ipftps_create_cert_and_privateKey();
#endif
ipcom_mutex_lock(ipftps.lock);
if(ipftps_init_tls(session) == IPCOM_ERR_FAILED)
{
ipcom_mutex_unlock(ipftps.lock);
session->tlsopt = IP_NULL;
goto leave;
}
ipcom_mutex_unlock(ipftps.lock);
if (ipftps_tls_enbale == IP_TRUE)
{
if (ipftps_init_tls_session(session) == IPCOM_ERR_FAILED)
goto leave;
}
#endif
#ifdef IP_SO_OOBINLINE
{
int option = 1;
/* Inline handling of OOB data */
if (ipcom_setsockopt(session->csock.fd, IP_SOL_SOCKET,
IP_SO_OOBINLINE, &option, sizeof(option)) < 0)
{
IPCOM_LOG1(WARNING, "Cannot setup inline OOB data: %s",
ipcom_strerror(ipcom_errno));
}
}
#endif
#ifdef IPIPTOS_LOWDELAY
{
int option = IPIPTOS_LOWDELAY;
/* Setup for low delay service */
if (ipcom_setsockopt(session->csock.fd, IP_IPPROTO_IP,
IPIP_TOS, &option, sizeof(option)) < 0)
{
IPCOM_LOG1(WARNING, "Cannot setup for low delay service: %s",
ipcom_strerror(ipcom_errno));
}
}
#endif
#ifdef IP_PORT_VXWORKS
if(_func_loginBanner != IP_NULL)
{
if(_func_loginBanner(&rmtBanner, &length) > 0)
{
banner = ipcom_strdup(rmtBanner);
if (IP_NULL == banner)
{
IPCOM_LOG0(ERR, "Failed to strdup");
goto leave;
}
bannerP1 = &banner[0];
while((bannerP2 = strchr(bannerP1,'\n')) != IP_NULL)
{
*bannerP2 = '\0';
if(bannerP1 == &banner[0])
ipftps_reply(session, "220- %s"CL, bannerP1);
else
ipftps_reply(session, "%s"CL, bannerP1);
bannerP1 = bannerP2 + 1;
}
if(bannerP1 == &banner[0])
ipftps_reply(session, "220- %s"CL, bannerP1);
else
ipftps_reply(session, "%s"CL, bannerP1);
if (banner != IP_NULL)
ipcom_free(banner);
}
}
#endif
ipftps_reply(session, "220 Wind River FTP server %s ready."CL,
ipftps_sysget_str("ipftps.versionstr", ver, &versize, "-", 1));
/* Command loop */
while (ipftps_get_command(session) == 0 &&
ipftps_parse_command(session) == 0)
{
}
leave:
IPCOM_LOG0(INFO, "Session handler stop");
/* Cleanup */
if (session != IP_NULL)
{
/* Close data socket */
ipftps_dsock_close(session);
#ifdef IPFTP_TLS
if(ipftps_tls_enbale == IP_TRUE)
{
ipftps_tls_close_session(session,IPFTPS_CTRL_FLAG);
ipftps_free_tls_session(session);
}
#endif
/* Close control socket */
if (session->csock.fd != IP_INVALID_SOCKET &&
ipcom_socketclose(session->csock.fd) != 0)
{
IPCOM_LOG1(ERR, "Cannot close socket: %s",
ipcom_strerror(ipcom_errno));
}
/* Free session descriptor */
if (session->cwd != session->root)
{
ipftps_free(session->cwd);
}
ipftps_free(session->root);
if(session->username != IP_NULL)
ipftps_free(session->username);
ipftps_free(session->rnfr);
ipcom_mutex_lock(ipftps.lock);
/* Decrement number of sessions. */
if (--ipftps.session_number < 0)
ipftps.session_number = 0;
ipcom_mutex_unlock(ipftps.lock);
ipcom_ipc_free(session);
}
if (ipcom_ipc_isopen(&ipc))
{
(void)ipcom_ipc_close(&ipc);
}
ipcom_proc_exit();
}
/*
*===========================================================================
* ipftps_main
*===========================================================================
*
* Description:
* FTP main process.
*
* Parameters:
*
* Returns:
*/
IPCOM_PROCESS(ipftps_main)
{
Ipftps_session *session = IP_NULL;
Ip_fd ipd_fd = IP_INVALID_SOCKET;
char bind_str[IPFTPS_IP_MAXLEN];
Ip_size_t bind_size;
int ipd_init = 0;
int option;
Ip_u16 port_number;
Ip_pid_t pid;
Ipcom_proc_attr attr;
#ifdef IPFTP_TLS
char *sysvar;
#endif
IPCOM_LOG0(INFO, "Starting server daemon");
/* Init data */
ipcom_proc_init();
ipcom_memset(&ipftps, 0, sizeof(ipftps));
ipftps.pipe_fd[0] = IP_INVALID_SOCKET;
ipftps.pipe_fd[1] = IP_INVALID_SOCKET;
#ifdef IPCOM_USE_INET
ipftps.sock4.fd = IP_INVALID_SOCKET;
#endif
#ifdef IPCOM_USE_INET6
ipftps.sock6.fd = IP_INVALID_SOCKET;
#endif
/* create mutex to lock ipftps.session_number */
if (ipcom_mutex_create(&ipftps.lock) != IPCOM_SUCCESS)
{
IPCOM_LOG1(ERR, "Cannot create ipftps lock: %s",
ipcom_strerror(ipcom_errno));
goto leave;
}
ipftps.databuf_size = ipftps_sysget_int("ipftps.databuf_size", 4096, 1);
if (ipcom_ipc_install() != IPCOM_SUCCESS)
{
IPCOM_LOG1(ERR, "Cannot install IPC service: %s",
ipcom_strerror(ipcom_errno));
goto leave;
}
if (ipcom_ipd_init("ipftps", IPCOM_SUCCESS, &ipd_fd) != IPCOM_SUCCESS)
{
IPCOM_LOG1(ERR, "Cannot initialize ipd: %s",
ipcom_strerror(ipcom_errno));
goto leave;
}
ipd_init = 1;
ipcom_proc_attr_init(&attr);
attr.stacksize = IPCOM_PROC_STACK_LARGE;
attr.priority = IPFTPS_SESSION_PROC_PRIO;
#ifdef IPFTP_TLS
sysvar = ipcom_sysvar_get("ipftps.tls.enable", IP_NULL, IP_NULL);
if (sysvar == IP_NULL)
goto leave;
if(ipcom_atoi(sysvar) == 1)
attr.flags |= IPCOM_PROC_FLAG_FP;
if (sysvar != IP_NULL)
ipcom_free(sysvar);
#endif
reconfigure:
port_number = (Ip_u16)ipftps_sysget_int("ipftps.port_number", 21, 1);
if (ipftps_socketpair(IP_AF_UNSPEC) != 0)
goto leave;
#ifdef IPCOM_USE_INET
/* Get IPv4 socket */
ipftps.sock4.fd = ipcom_socket(IP_AF_INET, IP_SOCK_STREAM, IPFTPS_PROTO);
if (ipftps.sock4.fd == IP_INVALID_SOCKET)
{
IPCOM_LOG1(ERR, "Cannot allocate IPv4 server socket: %s",
ipcom_strerror(ipcom_errno));
goto done4;
}
option = 1;
if (ipcom_setsockopt(ipftps.sock4.fd, IP_SOL_SOCKET, IP_SO_REUSEADDR,
&option, sizeof(option)) < 0)
{
IPCOM_LOG1(WARNING, "Cannot reuse IPv4 server socket address: %s",
ipcom_strerror(ipcom_errno));
}
/* Set IPv4 defaults */
IPCOM_SA_LEN_SET(&ipftps.sock4.laddr.sin, sizeof(struct Ip_sockaddr_in));
ipftps.sock4.laddr.sin.sin_family = IP_AF_INET;
ipftps.sock4.laddr.sin.sin_addr.s_addr = ip_htonl(IP_INADDR_ANY);
ipftps.sock4.laddr.sin.sin_port = ip_htons(port_number);
/* Get local IPv4 bind address */
bind_size = sizeof(bind_str);
if (ipcom_sysvar_get("ipftps.local_ip4", bind_str, &bind_size) != IP_NULL)
{
if (ipcom_inet_pton(IP_AF_INET, bind_str,
&ipftps.sock4.laddr.sin.sin_addr) != 1)
{
IPCOM_LOG2(ERR, "Cannot convert IPv4 local address %s: %s",
bind_str, ipcom_strerror(ipcom_errno));
goto fail4;
}
}
/* Bind to FTP port */
if (ipcom_bind(ipftps.sock4.fd, &ipftps.sock4.laddr.sa,
sizeof(ipftps.sock4.laddr.sin)) < 0)
{
IPCOM_LOG1(ERR, "Cannot bind IPv4 server socket: %s",
ipcom_strerror(ipcom_errno));
goto fail4;
}
/* Enter listen state. */
if (ipcom_listen(ipftps.sock4.fd, ipcom_sysvar_get_as_int("ipftps.socket_backlog", 0)) != 0)
{
IPCOM_LOG1(ERR, "Cannot listen on IPv4 server socket: %s",
ipcom_strerror(ipcom_errno));
fail4:
(void)ipcom_socketclose(ipftps.sock4.fd);
ipftps.sock4.fd = IP_INVALID_SOCKET;
}
done4:
#endif /* IPCOM_USE_INET */
#ifdef IPCOM_USE_INET6
/* Get IPv6 socket */
ipftps.sock6.fd = ipcom_socket(IP_AF_INET6, IP_SOCK_STREAM, IPFTPS_PROTO);
if (ipftps.sock6.fd == IP_INVALID_SOCKET)
{
IPCOM_LOG1(ERR, "Cannot allocate IPv6 server socket: %s",
ipcom_strerror(ipcom_errno));
goto done6;
}
option = 1;
if (ipcom_setsockopt(ipftps.sock6.fd, IP_SOL_SOCKET, IP_SO_REUSEADDR,
&option, sizeof(option)) < 0)
{
IPCOM_LOG1(WARNING, "Cannot reuse IPv6 server socket address: %s",
ipcom_strerror(ipcom_errno));
}
/* Set IPv6 defaults */
ipcom_memset(&ipftps.sock6.laddr.sin6, 0, sizeof(ipftps.sock6.laddr.sin6));
IPCOM_SA_LEN_SET(&ipftps.sock6.laddr.sin6, sizeof(struct Ip_sockaddr_in6));
ipftps.sock6.laddr.sin6.sin6_family = IP_AF_INET6;
/* ipftps.sock6.laddr.sin6.sin6_addr already set to 'any' with memset() */
ipftps.sock6.laddr.sin6.sin6_port = ip_htons(port_number);
/* Get local IPv6 bind address */
bind_size = sizeof(bind_str);
if (ipcom_sysvar_get("ipftps.local_ip6", bind_str, &bind_size) != IP_NULL)
{
if (ipcom_inet_pton(IP_AF_INET, bind_str,
&ipftps.sock6.laddr.sin6.sin6_addr) != 1)
{
IPCOM_LOG2(ERR, "Cannot convert IPv6 local address %s: %s",
bind_str, ipcom_strerror(ipcom_errno));
goto fail6;
}
}
/* Bind to FTP port */
if (ipcom_bind(ipftps.sock6.fd, &ipftps.sock6.laddr.sa,
sizeof(ipftps.sock6.laddr.sin6)) < 0)
{
IPCOM_LOG1(ERR, "Cannot bind IPv6 server socket: %s",
ipcom_strerror(ipcom_errno));
goto fail6;
}
/* Enter listen state. */
if (ipcom_listen(ipftps.sock6.fd, ipcom_sysvar_get_as_int("ipftps.socket_backlog", 0)) != 0)
{
IPCOM_LOG1(ERR, "Cannot listen on IPv6 server socket: %s",
ipcom_strerror(ipcom_errno));
fail6:
(void)ipcom_socketclose(ipftps.sock6.fd);
ipftps.sock6.fd = IP_INVALID_SOCKET;
}
done6:
#endif /* IPCOM_USE_INET6 */
for (;;)
{
char buf[IPFTPS_IP_MAXLEN];
Ipftps_sockcb *sock;
Ip_fd fd;
Ip_fd_set set;
Ip_socklen_t len;
int num;
int width;
session = IP_NULL;
IP_FD_ZERO(&set);
IP_FD_SET(ipd_fd, &set);
width = (int)ipd_fd;
#ifdef IPCOM_USE_INET
if (ipftps.sock4.fd != IP_INVALID_SOCKET)
{
IP_FD_SET(ipftps.sock4.fd, &set);
width = IP_MAX(width, ipftps.sock4.fd);
}
#endif
#ifdef IPCOM_USE_INET6
if (ipftps.sock6.fd != IP_INVALID_SOCKET)
{
IP_FD_SET(ipftps.sock6.fd, &set);
width = IP_MAX(width, ipftps.sock6.fd);
}
#endif
num = ipcom_socketselect(width + 1, &set, IP_NULL, IP_NULL, IP_NULL);
if (num < 0)
{
IPCOM_LOG1(ERR, "Cannot select on server sockets: %s",
ipcom_strerror(ipcom_errno));
goto leave;
}
else if (num == 0)
{
/* Ill-behaved stack */
continue;
}
else if (IP_FD_ISSET(ipd_fd, &set))
{
int event;
/* IPD message */
event = ipcom_ipd_input(ipd_fd);
switch(event)
{
case IPCOM_IPD_EVENT_RECONFIGURE:
IPCOM_LOG0(INFO, "Reconfiguring due to IPD request");
#ifdef IPFTP_TLS
ipftps_free_tls();
#endif
#ifdef IPCOM_USE_INET
if (ipftps.sock4.fd != IP_INVALID_SOCKET)
ipcom_socketclose(ipftps.sock4.fd);
#endif
#ifdef IPCOM_USE_INET6
if (ipftps.sock6.fd != IP_INVALID_SOCKET)
ipcom_socketclose(ipftps.sock6.fd);
#endif
ipftps_terminate_sessions();
goto reconfigure;
case IPCOM_IPD_EVENT_KILL:
IPCOM_LOG0(INFO, "Aborting due to IPD request");
ipftps_terminate_sessions();
goto leave;
default:
/* Ignore, back to main loop */
continue;
}
}
#ifdef IPCOM_USE_INET
else if (ipftps.sock4.fd != IP_INVALID_SOCKET
&& IP_FD_ISSET(ipftps.sock4.fd, &set))
{
sock = &ipftps.sock4;
}
#endif
#ifdef IPCOM_USE_INET6
else if (ipftps.sock6.fd != IP_INVALID_SOCKET
&& IP_FD_ISSET(ipftps.sock6.fd, &set))
{
sock = &ipftps.sock6;
}
#endif
else
{
IPCOM_LOG1(ERR, "Cannot select on server sockets: %s",
ipcom_strerror(ipcom_errno));
goto leave;
}
/* Wait for connections */
len = sizeof(sock->paddr);
fd = ipcom_accept(sock->fd, &sock->paddr.sa, &len);
if (fd < 0)
{
IPCOM_LOG2(ERR, "ipcom_accept() failed : %s [%d]",
ipcom_strerror(ipcom_errno), ipcom_errno);
continue;
}
(void)ipftps_ntop(&sock->paddr, buf, sizeof(buf));
IPCOM_LOG2(INFO, "%s connection from %s",
(sock->paddr.sa.sa_family == IP_AF_INET ? "IPv4" : "IPv6"),
buf);
/* Get the number of sessions */
ipcom_mutex_lock(ipftps.lock);
num = ipftps.session_number;
ipcom_mutex_unlock(ipftps.lock);
#define IPFTPS_REPLY(x,y) \
do \
{ \
char *_msg = y; \
(void)ipcom_socketwrite(x, _msg, ipcom_strlen(_msg)); \
} \
while (0)
if (num >= ipftps_sysget_int("ipftps.max_sessions", 8, 1))
{
IPCOM_LOG0(WARNING, "Session limit is reached");
IPFTPS_REPLY(fd, "421 Session limit is reached"CL);
}
else if ((session = ipcom_ipc_malloc(sizeof(*session))) == IP_NULL)
{
IPCOM_LOG0(ERR, "Out of memory");
IPFTPS_REPLY(fd, "421 Out of memory"CL);
}
else
{
len = sizeof(sock->laddr);
if (ipcom_getsockname(fd, &sock->laddr.sa, &len) != 0)
{
IPCOM_LOG0(ERR, "Cannot get server IP address");
IPFTPS_REPLY(fd, "421 Missing server IP address"CL);
}
else
{
void *ignore = IP_NULL;
Ipcom_ipc ipc;
ipcom_memset(&ipc, 0, sizeof(ipc));
ipcom_memset(session, 0, sizeof(*session));
ipcom_memcpy(&session->csock, sock, sizeof(session->csock));
session->csock.fd = fd;
/* Increment number of sessions. */
ipcom_mutex_lock(ipftps.lock);
ipftps.session_number++;
ipcom_sprintf(session->name, "ipftps_%lu", ipftps.session_number);
ipcom_mutex_unlock(ipftps.lock);
/* Spawn session handler */
if (ipcom_proc_acreate(session->name, ipftps_session,
&attr, &pid) != IPCOM_SUCCESS)
{
IPCOM_LOG1(ERR, "Cannot spawn session handler: %s",
ipcom_strerror(ipcom_errno));
IPFTPS_REPLY(fd, "421 No session handler available"CL);
/* Decrement number of sessions. */
ipcom_mutex_lock(ipftps.lock);
ipftps.session_number--;
ipcom_mutex_unlock(ipftps.lock);
}
else if (ipcom_ipc_receive(&ipc, &ignore, -1) != IPCOM_SUCCESS)
{
IPCOM_LOG1(ERR, "Cannot receive from session handler: %s",
ipcom_strerror(ipcom_errno));
IPFTPS_REPLY(fd, "421 Session handler setup failure"CL);
/* Decrement number of sessions. */
ipcom_mutex_lock(ipftps.lock);
ipftps.session_number--;
ipcom_mutex_unlock(ipftps.lock);
}
else
{
ipcom_ipc_free(ignore);
if (ipcom_ipc_send(&ipc, session) != IPCOM_SUCCESS)
{
IPCOM_LOG1(ERR, "Cannot send to session handler: %s",
ipcom_strerror(ipcom_errno));
IPFTPS_REPLY(fd, "421 Session handler setup failure"CL);
/* Decrement number of sessions. */
ipcom_mutex_lock(ipftps.lock);
ipftps.session_number--;
ipcom_mutex_unlock(ipftps.lock);
ipcom_ipc_free(session);
session = IP_NULL;
}
#ifdef IP_PORT_OSE5
/* OSE5 has process specific sockets -> donate child fd */
else if ((Ip_err)efs_donate_fd(fd, pid) != 0)
{
IPCOM_LOG0(ERR, "Cannot donate socket descriptor");
IPFTPS_REPLY(fd, "421 Session handler setup failure"CL);
}
#endif /* IP_PORT_OSE5 */
else
{
/* Ok, skip cleanup */
(void)ipcom_ipc_close(&ipc);
continue;
}
}
if (ipcom_ipc_isopen(&ipc))
{
(void)ipcom_ipc_close(&ipc);
}
}
if(session)
ipcom_ipc_free(session);
}
(void)ipcom_socketclose(fd);
}
leave:
#ifdef IPFTP_TLS
ipftps_free_tls();
#endif
#ifdef IPCOM_USE_INET
if (ipftps.sock4.fd != IP_INVALID_SOCKET)
ipcom_socketclose(ipftps.sock4.fd);
#endif
#ifdef IPCOM_USE_INET6
if (ipftps.sock6.fd != IP_INVALID_SOCKET)
ipcom_socketclose(ipftps.sock6.fd);
#endif
if (ipftps.pipe_fd[0] != IP_INVALID_SOCKET)
(void)ipcom_socketclose(ipftps.pipe_fd[0]);
if (ipftps.pipe_fd[1] != IP_INVALID_SOCKET)
(void)ipcom_socketclose(ipftps.pipe_fd[1]);
/* Have to call ipd init if not done yet */
if (ipd_init == 0 &&
ipcom_ipd_init("ipftps", IPCOM_ERR_FAILED, &ipd_fd) == IPCOM_SUCCESS)
{
ipd_init = 1;
}
if (ipd_init != 0)
{
(void)ipcom_ipd_exit("ipftps", ipd_fd);
}
(void)ipcom_ipc_uninstall();
ipcom_proc_exit();
}
/*
*===========================================================================
* ipftps_create
*===========================================================================
* Description: Create FTP daemon.
* Parameters:
* Returns:
*
*/
IP_PUBLIC Ip_err
ipftps_create(void)
{
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipftps_start
*===========================================================================
* Description: Start FTP daemon.
* Parameters:
* Returns:
*/
IP_PUBLIC Ip_err
ipftps_start(void)
{
/* Spawn new daemon process */
Ipcom_proc_attr attr;
ipcom_proc_attr_init(&attr);
attr.priority = IPFTPS_MAIN_PROC_PRIO;
if (ipcom_proc_acreate("ipftps", ipftps_main, &attr, IP_NULL))
{
return IPCOM_ERR_FAILED;
}
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipftps_wildcard_check
*===========================================================================
*
* Description:
* Check wild cards in path.
*
* Parameters:
* path File path.
* st Stat struct.
*
* Returns: Pointer to pattern buffer if wild cards are found.
* IP_NULL otherwise. Allocated buffer should be
* removed by calling function.
*/
IP_STATIC char*
ipftps_wildcard_check(char *path, struct Ip_stat *st)
{
char* pat = IP_NULL;
char* pattern = path;
char rootdir = '\0';
if (path == IP_NULL) goto exit;
pattern = ipcom_strrchr(path, '/');
if(pattern == IP_NULL) ipcom_strrchr(path, '\\');
if (pattern != IP_NULL)
{
/* Check for wild cards */
if ((ipcom_strchr(pattern, '*') != 0) || (ipcom_strchr(pattern, '?') != 0))
{
if(path == pattern)
{
/* Could be a root dir */
rootdir = *pattern;
}
*(pattern++) = '\0';
pat = ipcom_malloc(ipcom_strlen(pattern) + 1);
if (pat == IP_NULL) goto exit;
ipcom_strcpy(pat, pattern);
if(rootdir != '\0')
{
path[0] = rootdir;
path[1] = '\0';
}
/* Validate the dir path.*/
if (ipcom_stat(path, st) != 0)
{
ipcom_free(pat);
pat = IP_NULL;
}
}
}
else
{
/* We might have file or dir. Check for wild cards */
if ((ipcom_strchr(path, '*') != 0) || (ipcom_strchr(path, '?') != 0))
{
pat = ipcom_malloc(ipcom_strlen(path) + 1);
if (pat == IP_NULL) goto exit;
ipcom_strcpy(pat, path);
/* Set the path to current dir */
ipcom_strcpy(path, ".");
/* Validate the dir path */
if (ipcom_stat(path, st) != 0)
{
ipcom_free(pat);
pat = IP_NULL;
}
}
}
exit:
return pat;
}
/*
*===========================================================================
* ipftps_pattern_check
*===========================================================================
*
* Description:
* Compare file name pattern with actual file name.
*
* Parameters:
* pattern File name pattern with wild cards.
* name File name.
*
* Returns: 1 if pattern and file match. 0 otherwise.
*/
IP_STATIC int ipftps_pattern_check (char * pattern, char * name)
{
char * pat, *next, *pre = IP_NULL;
const char anyone = '?' ;
const char anymany = '*' ;
const char *anymanystr = "*";
pat = pattern;
if ((ipcom_strcmp(pat, anymanystr) == 0) && (name[0] != '.'))
return 1;
for (next = name ; * next != '\0' ; pre = next ++)
{
if (*pat == anyone)
{
pat ++ ;
}
else if (*pat == anymany)
{
if ((next[0] == '.') && pre == IP_NULL)
return 0 ;
if (ipcom_toupper((int)pat[1]) == ipcom_toupper((int)next[1]))
pat ++ ;
else if (ipcom_toupper((int)pat[1]) == ipcom_toupper((int)next[0]))
pat += 2 ;
else
continue ;
}
else if (ipcom_toupper((int)*pat) != ipcom_toupper((int)*next))
{
return 0 ;
}
else
{
pat ++ ;
}
}
if ((*pat == '\0') || (pat[0] == anymany && pat[1] == '\0'))
return 1;
else
return 0;
}
/*
*===========================================================================
* ipftps_version
*===========================================================================
* Description::
* Parameters::
* Returns:
*
*/
IP_PUBLIC const char *
ipftps_version(void)
{
return "@(#) IPFTPS $Name: VXWORKS_ITER40_RCPL8_2024030303 $ - INTERPEAK_COPYRIGHT_STRING";
}
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/