mod_case/ 0000755 0001750 0001750 00000000000 11560344252 010446 5 ustar tj tj mod_case/mod_case.html 0000644 0001750 0001750 00000012023 11553331744 013110 0 ustar tj tj
ProFTPD module mod_case
ProFTPD module mod_case
The mod_case
module is designed to help ProFTPD be
case-insensitive, for those sites that may need it (e.g. those
that are migrating from a Windows environment or have mounted Windows
filesystems).
mod_case
works by performing two checks on the filename used in
FTP commands. First, mod_case
will scan the directory to see
if there is already a file whose name exactly matches the given filename. If
not, mod_case
will scan the directory again, this time looking
for case-insensitive matches.
This module is contained in the mod_case.c
file for
ProFTPD 1.3.x, and is not compiled by default. Installation instructions
are discussed here.
The most current version of mod_case
can be found at:
http://www.castaglia.org/proftpd/
Author
Please contact TJ Saunders <tj at castaglia.org> with any
questions, concerns, or suggestions regarding this module.
Directives
Syntax: CaseEngine on|off
Default: off
Context: server config, <VirtualHost>
, <Global>
Module: mod_case
Compatibility: 1.2.9 and later
The CaseEngine
directive enables or disables the module's
runtime case-matching engine. If it is set to off this module does no
case-insensitive checking. Use this directive to disable the module instead of
commenting out all mod_case
directives.
Syntax: CaseIgnore on|off|cmd-list
Default: off
Context: server config, <VirtualHost>
, <Global>
, <Anonymous>
, <Directory>
Module: mod_case
Compatibility: 1.2.9 and later
The CaseIgnore
directive is used to enable case-insensitive
matching, possibly on a per-FTP command basis. If it is set to off,
no case-insensitive matching is performed. If set to on, then
case-insensitive matcing is performed for all FTP commands that
mod_case
handles (see below). Otherwise, one can configure
a cmd-list, which is a comma-separated list of FTP commands for
which mod_case
is to do case-insensitive matching.
mod_case
handles the following FTP commands: APPE, CWD, DELE,
LIST, MDTM, MKD, MLSD, MLST, NLST, RETR, RMD, RNFR, RNTO, SIZE, STOR, XCWD,
XMKD, and XRMD.
Examples:
# Enable case-insensitivity for all FTP commands handled by mod_case
CaseIgnore on
# Enable case-insensitivity only for downloads
CaseIgnore RETR
# Enable case-insensitivity for uploads and downloads
CaseIgnore APPE,RETR,STOR
Syntax: CaseLog path|"none"
Default: None
Context: server config, <VirtualHost>
, <Global>
Module: mod_case
Compatibility: 1.2.9 and later
The CaseLog
directive is used to a specify a log file for
mod_case
reporting and debugging, and can be done a per-server
basis. The path parameter must be the full path to the file to use for
logging. Note that this path must not be to a world-writeable
directory and, unless AllowLogSymlinks
is explicitly set to
on (generally a bad idea), the path must not be a symbolic
link.
If path is "none", no logging will be done at all; this
setting can be used to override a CaseLog
setting inherited from
a <Global>
context.
To install mod_case
, copy the mod_case.c
file into
proftpd-dir/contrib/
after unpacking the latest proftpd-1.2 source code. Then follow the usual
steps for using third-party modules in proftpd:
./configure --with-modules=mod_case
make
make install
Author: $Author: tj $
Last Updated: $Date: 2011/04/19 16:09:58 $
© Copyright 2004-2011 TJ Saunders
All Rights Reserved
mod_case/mod_case.c 0000644 0001750 0001750 00000043474 11560345132 012376 0 ustar tj tj /*
* ProFTPD: mod_case -- provides case-insensivity
*
* Copyright (c) 2004-2011 TJ Saunders
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*
* This is mod_case, contrib software for proftpd 1.2 and above.
* For more information contact TJ Saunders .
*
* $Id: mod_case.c,v 1.9 2011/05/04 21:50:41 tj Exp tj $
*/
#include "conf.h"
#include "privs.h"
#define MOD_CASE_VERSION "mod_case/0.7"
/* Make sure the version of proftpd is as necessary. */
#if PROFTPD_VERSION_NUMBER < 0x0001030402
# error "ProFTPD 1.3.4rc2 or later required"
#endif
static int case_engine = FALSE;
static int case_logfd = -1;
/* Support routines
*/
static int case_expr_eval_cmds(cmd_rec *cmd, array_header *list) {
int cmd_id, found;
register unsigned int i;
for (i = 0; i < list->nelts; i++) {
char *c = ((char **) list->elts)[i];
found = 0;
if (*c == '!') {
found = !found;
c++;
}
cmd_id = pr_cmd_get_id(c);
if (cmd_id > 0) {
if (pr_cmd_cmp(cmd, cmd_id) == 0) {
found = !found;
}
} else {
/* Fallback to doing a full strcmp(3). */
if (strcmp(cmd->argv[0], c) == 0) {
found = !found;
}
}
if (found) {
return 1;
}
}
return 0;
}
static char *case_get_opts_path(cmd_rec *cmd, int *path_index) {
char *ptr;
char *path;
size_t pathlen;
if (cmd->arg == NULL) {
return NULL;
}
ptr = path = cmd->arg;
pathlen = strlen(path);
if (pathlen == 0) {
return NULL;
}
while (isspace((int) *ptr)) {
pr_signals_handle();
ptr++;
}
if (*ptr == '-') {
/* Options are found; skip past the leading whitespace. */
path = ptr;
}
while (path &&
*path == '-') {
/* Advance to the next whitespace */
while (*path != '\0' &&
!isspace((int) *path)) {
path++;
}
ptr = path;
while (*ptr &&
isspace((int) *ptr)) {
pr_signals_handle();
ptr++;
}
if (*ptr == '-') {
/* Options are found; skip past the leading whitespace. */
path = ptr;
} else if (*(path + 1) == ' ') {
/* If the next character is a blank space, advance just one
* character.
*/
path++;
break;
} else {
path = ptr;
break;
}
}
pathlen = strlen(path);
if (pathlen == 0) {
return NULL;
}
*path_index = (ptr - cmd->arg);
return path;
}
static void case_replace_link_paths(cmd_rec *cmd, const char *proto,
const char *src_path, const char *dst_path) {
/* Minor nit: if src_path/dst_path is "//", then reduce it to just "/". */
if (strcmp(src_path, "//") == 0) {
src_path = pstrdup(cmd->tmp_pool, "/");
}
if (strcmp(dst_path, "//") == 0) {
dst_path = pstrdup(cmd->tmp_pool, "/");
}
if (strncmp(proto, "sftp", 5) == 0) {
/* We should only be handling SFTP SYMLINk and LINK requests here */
cmd->arg = pstrcat(cmd->pool, src_path, "\t", dst_path, NULL);
if (cmd->argv[1] != cmd->arg) {
cmd->argv[1] = cmd->arg;
}
}
return;
}
static void case_replace_path(cmd_rec *cmd, const char *proto, const char *dir,
const char *file, int path_index) {
/* Minor nit: if dir is "//", then reduce it to just "/". */
if (strcmp(dir, "//") == 0) {
dir = pstrdup(cmd->tmp_pool, "/");
}
if (strncmp(proto, "ftp", 4) == 0) {
/* Special handling of LIST/NLST/STAT commands, which can take options */
if (pr_cmd_cmp(cmd, PR_CMD_LIST_ID) == 0 ||
pr_cmd_cmp(cmd, PR_CMD_NLST_ID) == 0 ||
pr_cmd_cmp(cmd, PR_CMD_STAT_ID) == 0) {
if (path_index > 0) {
char *arg;
arg = pstrdup(cmd->tmp_pool, cmd->arg);
arg[path_index] = '\0';
arg = pstrcat(cmd->pool, arg, dir, file, NULL);
cmd->arg = arg;
} else {
cmd->arg = pstrcat(cmd->pool, dir, file, NULL);
}
} else {
cmd->argv[1] = pstrcat(cmd->pool, dir, file, NULL);
/* In the case of many commands, we also need to overwrite cmd->arg. */
if (pr_cmd_cmp(cmd, PR_CMD_APPE_ID) == 0 ||
pr_cmd_cmp(cmd, PR_CMD_CWD_ID) == 0 ||
pr_cmd_cmp(cmd, PR_CMD_DELE_ID) == 0 ||
pr_cmd_cmp(cmd, PR_CMD_MKD_ID) == 0 ||
pr_cmd_cmp(cmd, PR_CMD_MDTM_ID) == 0 ||
pr_cmd_cmp(cmd, PR_CMD_MLSD_ID) == 0 ||
pr_cmd_cmp(cmd, PR_CMD_MLST_ID) == 0 ||
pr_cmd_cmp(cmd, PR_CMD_RETR_ID) == 0 ||
pr_cmd_cmp(cmd, PR_CMD_RMD_ID) == 0 ||
pr_cmd_cmp(cmd, PR_CMD_RNFR_ID) == 0 ||
pr_cmd_cmp(cmd, PR_CMD_RNTO_ID) == 0 ||
pr_cmd_cmp(cmd, PR_CMD_SIZE_ID) == 0 ||
pr_cmd_cmp(cmd, PR_CMD_STOR_ID) == 0 ||
pr_cmd_cmp(cmd, PR_CMD_XCWD_ID) == 0 ||
pr_cmd_cmp(cmd, PR_CMD_XMKD_ID) == 0 ||
pr_cmd_cmp(cmd, PR_CMD_XRMD_ID) == 0) {
cmd->arg = pstrcat(cmd->pool, dir, file, NULL);
}
}
return;
}
if (strncmp(proto, "sftp", 5) == 0) {
/* Main SFTP commands */
if (pr_cmd_cmp(cmd, PR_CMD_RETR_ID) == 0 ||
pr_cmd_cmp(cmd, PR_CMD_STOR_ID) == 0 ||
pr_cmd_cmp(cmd, PR_CMD_MKD_ID) == 0 ||
pr_cmd_cmp(cmd, PR_CMD_RMD_ID) == 0 ||
pr_cmd_cmp(cmd, PR_CMD_DELE_ID) == 0 ||
pr_cmd_strcmp(cmd, "LSTAT") == 0 ||
pr_cmd_strcmp(cmd, "OPENDIR") == 0 ||
pr_cmd_strcmp(cmd, "READLINK") == 0 ||
pr_cmd_strcmp(cmd, "REALPATH") == 0 ||
pr_cmd_strcmp(cmd, "SETSTAT") == 0 ||
pr_cmd_strcmp(cmd, "STAT") == 0) {
cmd->arg = pstrcat(cmd->pool, dir, file, NULL);
}
return;
}
}
static int case_have_file(pool *p, const char *dir, const char *file,
size_t file_len, char **matched_file) {
DIR *dirh;
struct dirent *dent;
char *file_match;
/* Open the directory. */
dirh = pr_fsio_opendir(dir);
if (dirh == NULL) {
(void) pr_log_writefile(case_logfd, MOD_CASE_VERSION,
"error opening directory '%s': %s", dir, strerror(errno));
return -1;
}
/* Escape any existing fnmatch(3) characters in the file name. */
file_match = pstrdup(p, file);
if (strchr(file_match, '?') != NULL) {
file_match = sreplace(p, file_match, "?", "\\?", NULL);
}
if (strchr(file_match, '*') != NULL) {
file_match = sreplace(p, file_match, "*", "\\*", NULL);
}
if (strchr(file_match, '[') != NULL) {
file_match = sreplace(p, file_match, "[", "\\[", NULL);
}
/* For each file in the directory, check it against the given name, both
* as an exact match and as a possible match.
*/
dent = pr_fsio_readdir(dirh);
while (dent) {
pr_signals_handle();
if (strncmp(dent->d_name, file, file_len + 1) == 0) {
(void) pr_log_writefile(case_logfd, MOD_CASE_VERSION,
"found exact match");
pr_fsio_closedir(dirh);
*matched_file = NULL;
return TRUE;
}
if (pr_fnmatch(file_match, dent->d_name, PR_FNM_CASEFOLD) == 0) {
(void) pr_log_writefile(case_logfd, MOD_CASE_VERSION,
"found case-insensitive match '%s' for '%s'", dent->d_name, file_match);
pr_fsio_closedir(dirh);
*matched_file = pstrdup(p, dent->d_name);
return TRUE;
}
dent = pr_fsio_readdir(dirh);
}
/* Close the directory. */
pr_fsio_closedir(dirh);
return FALSE;
}
/* Command handlers
*/
MODRET case_pre_cmd(cmd_rec *cmd) {
config_rec *c;
char *path = NULL, *dir = NULL, *file = NULL, *file_match = NULL, *tmp;
const char *proto = NULL;
size_t file_len;
int path_index = -1, res;
if (!case_engine) {
return PR_DECLINED(cmd);
}
c = find_config(CURRENT_CONF, CONF_PARAM, "CaseIgnore", FALSE);
if (c == NULL) {
return PR_DECLINED(cmd);
}
if (*((unsigned int *) c->argv[0]) != TRUE) {
return PR_DECLINED(cmd);
}
if (c->argv[1] &&
case_expr_eval_cmds(cmd, *((array_header **) c->argv[1])) == 0) {
return PR_DECLINED(cmd);
}
proto = pr_session_get_protocol(0);
if (strncmp(proto, "sftp", 5) == 0) {
path = pstrdup(cmd->tmp_pool, cmd->arg);
} else {
/* Special handling of LIST/NLST/STAT, given that they may have options
* in the command.
*/
if (pr_cmd_cmp(cmd, PR_CMD_LIST_ID) == 0 ||
pr_cmd_cmp(cmd, PR_CMD_NLST_ID) == 0 ||
pr_cmd_cmp(cmd, PR_CMD_STAT_ID) == 0) {
path = case_get_opts_path(cmd, &path_index);
/* LIST, NLST, and STAT can send no path arguments. If that's the
* case, we're done.
*/
if (path == NULL) {
return PR_DECLINED(cmd);
}
} else {
path = pstrdup(cmd->tmp_pool, cmd->argv[1]);
}
}
/* Separate the path into directory and file components. */
tmp = strrchr(path, '/');
if (tmp == NULL) {
dir = ".";
file = path;
} else {
if (tmp != path) {
*tmp++ = '\0';
dir = path;
file = tmp;
} else {
/* Handle the case where the path is "/path". */
dir = "/";
file = tmp + 1;
}
}
file_len = strlen(file);
res = case_have_file(cmd->tmp_pool, dir, file, file_len, &file_match);
if (res < 0) {
return PR_DECLINED(cmd);
}
if (res == FALSE) {
/* No match found. */
return PR_DECLINED(cmd);
}
/* We found a match for the given file. */
if (file_match == NULL) {
/* Exact match found; nothing more to do. */
return PR_DECLINED(cmd);
}
/* Overwrite the client-given path. */
case_replace_path(cmd, proto,
tmp ? pstrcat(cmd->pool, dir, "/", NULL) : "", file_match, path_index);
return PR_DECLINED(cmd);
}
/* The SYMLINK/LINK SFTP requests are different enough to warrant their
* own command handler.
*/
MODRET case_pre_link(cmd_rec *cmd) {
config_rec *c;
char *arg = NULL, *src_path, *src_dir = NULL, *src_file = NULL,
*dst_path, *dst_dir = NULL, *dst_file = NULL, *file_match = NULL,
*src_ptr, *dst_ptr, *ptr;
const char *proto = NULL;
size_t file_len;
int modified_arg = FALSE, res;
if (!case_engine) {
return PR_DECLINED(cmd);
}
c = find_config(CURRENT_CONF, CONF_PARAM, "CaseIgnore", FALSE);
if (c == NULL) {
return PR_DECLINED(cmd);
}
if (*((unsigned int *) c->argv[0]) != TRUE) {
return PR_DECLINED(cmd);
}
if (c->argv[1] &&
case_expr_eval_cmds(cmd, *((array_header **) c->argv[1])) == 0) {
return PR_DECLINED(cmd);
}
proto = pr_session_get_protocol(0);
/* We know the protocol here will always be "sftp", right? And that we
* are only handling SFTP SYMLINK and LINK requests here.
*/
arg = pstrdup(cmd->tmp_pool, cmd->arg);
ptr = strchr(arg, '\t');
if (ptr == NULL) {
/* Malformed SFTP SYMLINK/LINK cmd_rec. */
(void) pr_log_writefile(case_logfd, MOD_CASE_VERSION,
"malformed SFTP %s request, ignoring", cmd->argv[0]);
return PR_DECLINED(cmd);
}
*ptr = '\0';
src_path = arg;
dst_path = ptr + 1;
/* Separate the path into directory and file components. */
src_ptr = strrchr(src_path, '/');
if (src_ptr == NULL) {
src_dir = ".";
src_file = src_path;
} else {
if (src_ptr != src_path) {
*src_ptr = '\0';
src_dir = src_path;
src_file = src_ptr + 1;
} else {
/* Handle the case where the path is "/path". */
src_dir = "/";
src_file = src_ptr + 1;
}
}
dst_ptr = strrchr(dst_path, '/');
if (dst_ptr == NULL) {
dst_dir = ".";
dst_file = dst_path;
} else {
if (dst_ptr != dst_path) {
*dst_ptr = '\0';
dst_dir = dst_path;
dst_file = dst_ptr + 1;
} else {
/* Handle the case where the path is "/path". */
dst_dir = "/";
dst_file = dst_ptr + 1;
}
}
file_len = strlen(src_file);
res = case_have_file(cmd->tmp_pool, src_dir, src_file, file_len, &file_match);
if (res < 0) {
return PR_DECLINED(cmd);
}
if (res == TRUE &&
file_match != NULL) {
/* Replace the source path */
src_path = pdircat(cmd->tmp_pool, src_dir, file_match, NULL);
modified_arg = TRUE;
} else {
/* No match (or exact match) found; restore the original src_path. */
if (src_ptr != NULL) {
*src_ptr = '/';
}
}
file_len = strlen(dst_file);
file_match = NULL;
res = case_have_file(cmd->tmp_pool, dst_dir, dst_file, file_len, &file_match);
if (res < 0) {
return PR_DECLINED(cmd);
}
if (res == TRUE &&
file_match != NULL) {
/* Replace the destination path */
dst_path = pdircat(cmd->tmp_pool, dst_dir, file_match, NULL);
modified_arg = TRUE;
} else {
/* No match (or exact match) found; restore the original src_path. */
if (dst_ptr != NULL) {
*dst_ptr = '/';
}
}
/* Overwrite the client-given paths. */
if (modified_arg) {
case_replace_link_paths(cmd, proto, src_path, dst_path);
}
return PR_DECLINED(cmd);
}
/* Configuration handlers
*/
/* usage: CaseEngine on|off */
MODRET set_caseengine(cmd_rec *cmd) {
int bool;
config_rec *c;
CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
CHECK_ARGS(cmd, 1);
bool = get_boolean(cmd, 1);
if (bool == -1)
CONF_ERROR(cmd, "expected Boolean parameter");
c = add_config_param(cmd->argv[0], 1, NULL);
c->argv[0] = pcalloc(c->pool, sizeof(unsigned int));
*((unsigned int *) c->argv[0]) = bool;
return PR_HANDLED(cmd);
}
/* usage: CaseIgnore on|off|cmd-list */
MODRET set_caseignore(cmd_rec *cmd) {
int bool, argc;
char **argv;
config_rec *c;
CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL|CONF_ANON|CONF_DIR);
CHECK_ARGS(cmd, 1);
bool = get_boolean(cmd, 1);
c = add_config_param(cmd->argv[0], 2, NULL, NULL);
c->flags |= CF_MERGEDOWN_MULTI;
c->argv[0] = pcalloc(c->pool, sizeof(unsigned int));
*((unsigned int *) c->argv[0]) = 1;
if (bool != -1) {
*((unsigned int *) c->argv[0]) = bool;
return PR_HANDLED(cmd);
}
/* Parse the parameter as a command list. */
argc = cmd->argc-1;
argv = cmd->argv;
c->argv[1] = pcalloc(c->pool, sizeof(array_header *));
*((array_header **) c->argv[1]) = pr_expr_create(c->pool, &argc, argv);
return PR_HANDLED(cmd);
}
/* usage: CaseLog path|"none" */
MODRET set_caselog(cmd_rec *cmd) {
CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
CHECK_ARGS(cmd, 1);
if (pr_fs_valid_path(cmd->argv[1]) < 0)
CONF_ERROR(cmd, "must be an absolute path");
add_config_param_str(cmd->argv[0], 1, cmd->argv[1]);
return PR_HANDLED(cmd);
}
/* Initialization functions
*/
static int case_sess_init(void) {
config_rec *c;
c = find_config(main_server->conf, CONF_PARAM, "CaseEngine", FALSE);
if (c != NULL &&
*((unsigned int *) c->argv[0]) == TRUE) {
case_engine = TRUE;
}
if (!case_engine) {
return 0;
}
c = find_config(main_server->conf, CONF_PARAM, "CaseLog", FALSE);
if (c == NULL)
return 0;
if (strncasecmp((char *) c->argv[0], "none", 5) != 0) {
int res;
pr_signals_block();
PRIVS_ROOT
res = pr_log_openfile((char *) c->argv[0], &case_logfd, 0660);
PRIVS_RELINQUISH
pr_signals_unblock();
if (res < 0) {
pr_log_pri(PR_LOG_NOTICE, MOD_CASE_VERSION
": error opening CaseLog '%s': %s", (char *) c->argv[0],
strerror(errno));
}
}
return 0;
}
/* Module API tables
*/
static conftable case_conftab[] = {
{ "CaseEngine", set_caseengine, NULL },
{ "CaseIgnore", set_caseignore, NULL },
{ "CaseLog", set_caselog, NULL },
{ NULL }
};
static cmdtable case_cmdtab[] = {
{ PRE_CMD, C_APPE, G_NONE, case_pre_cmd, TRUE, FALSE },
{ PRE_CMD, C_CWD, G_NONE, case_pre_cmd, TRUE, FALSE },
{ PRE_CMD, C_DELE, G_NONE, case_pre_cmd, TRUE, FALSE },
{ PRE_CMD, C_LIST, G_NONE, case_pre_cmd, TRUE, FALSE },
{ PRE_CMD, C_MDTM, G_NONE, case_pre_cmd, TRUE, FALSE },
{ PRE_CMD, C_MKD, G_NONE, case_pre_cmd, TRUE, FALSE },
{ PRE_CMD, C_MLSD, G_NONE, case_pre_cmd, TRUE, FALSE },
{ PRE_CMD, C_MLST, G_NONE, case_pre_cmd, TRUE, FALSE },
{ PRE_CMD, C_NLST, G_NONE, case_pre_cmd, TRUE, FALSE },
{ PRE_CMD, C_RETR, G_NONE, case_pre_cmd, TRUE, FALSE },
{ PRE_CMD, C_RMD, G_NONE, case_pre_cmd, TRUE, FALSE },
{ PRE_CMD, C_RNFR, G_NONE, case_pre_cmd, TRUE, FALSE },
{ PRE_CMD, C_RNTO, G_NONE, case_pre_cmd, TRUE, FALSE },
{ PRE_CMD, C_SIZE, G_NONE, case_pre_cmd, TRUE, FALSE },
{ PRE_CMD, C_STAT, G_NONE, case_pre_cmd, TRUE, FALSE },
{ PRE_CMD, C_STOR, G_NONE, case_pre_cmd, TRUE, FALSE },
{ PRE_CMD, C_XCWD, G_NONE, case_pre_cmd, TRUE, FALSE },
{ PRE_CMD, C_XMKD, G_NONE, case_pre_cmd, TRUE, FALSE },
{ PRE_CMD, C_XRMD, G_NONE, case_pre_cmd, TRUE, FALSE },
/* The following is for mod_copy's SITE CPFR and SITE CPTO commands. */
/* XXX Need to handle SITE CHMOD, SITE CHGRP as well */
/* The following are SFTP requests */
{ PRE_CMD, "LINK", G_NONE, case_pre_link, TRUE, FALSE },
{ PRE_CMD, "LSTAT", G_NONE, case_pre_cmd, TRUE, FALSE },
{ PRE_CMD, "OPENDIR", G_NONE, case_pre_cmd, TRUE, FALSE },
{ PRE_CMD, "READLINK", G_NONE, case_pre_cmd, TRUE, FALSE },
{ PRE_CMD, "REALPATH", G_NONE, case_pre_cmd, TRUE, FALSE },
{ PRE_CMD, "SETSTAT", G_NONE, case_pre_cmd, TRUE, FALSE },
{ PRE_CMD, "STAT", G_NONE, case_pre_cmd, TRUE, FALSE },
{ PRE_CMD, "SYMLINK", G_NONE, case_pre_link, TRUE, FALSE },
{ 0, NULL }
};
module case_module = {
NULL, NULL,
/* Module API version 2.0 */
0x20,
/* Module name */
"case",
/* Module configuration handler table */
case_conftab,
/* Module command handler table */
case_cmdtab,
/* Module authentication handler table */
NULL,
/* Module initialization function */
NULL,
/* Session initialization function */
case_sess_init,
/* Module version */
MOD_CASE_VERSION
};
mod_case/t/ 0000755 0001750 0001750 00000000000 11547155521 010715 5 ustar tj tj mod_case/t/lib/ 0000755 0001750 0001750 00000000000 11547155514 011465 5 ustar tj tj mod_case/t/lib/ProFTPD/ 0000755 0001750 0001750 00000000000 11547155514 012703 5 ustar tj tj mod_case/t/lib/ProFTPD/Tests/ 0000755 0001750 0001750 00000000000 11547155514 014005 5 ustar tj tj mod_case/t/lib/ProFTPD/Tests/Modules/ 0000755 0001750 0001750 00000000000 11555364201 015407 5 ustar tj tj mod_case/t/lib/ProFTPD/Tests/Modules/mod_case/ 0000755 0001750 0001750 00000000000 11560344722 017163 5 ustar tj tj mod_case/t/lib/ProFTPD/Tests/Modules/mod_case/sftp.pm 0000644 0001750 0001750 00000162315 11560343630 020502 0 ustar tj tj package ProFTPD::Tests::Modules::mod_case::sftp;
use lib qw(t/lib);
use base qw(ProFTPD::TestSuite::Child);
use strict;
use File::Copy;
use File::Path qw(mkpath);
use File::Spec;
use IO::Handle;
use POSIX qw(:fcntl_h);
use ProFTPD::TestSuite::FTP;
use ProFTPD::TestSuite::Utils qw(:auth :config :running :test :testsuite);
$| = 1;
my $order = 0;
my $TESTS = {
caseignore_sftp_realpath => {
order => ++$order,
test_class => [qw(forking mod_sftp sftp)],
},
caseignore_sftp_lstat => {
order => ++$order,
test_class => [qw(forking mod_sftp sftp)],
},
caseignore_sftp_setstat => {
order => ++$order,
test_class => [qw(forking mod_sftp sftp)],
},
caseignore_sftp_opendir => {
order => ++$order,
test_class => [qw(forking mod_sftp sftp)],
},
caseignore_sftp_stat => {
order => ++$order,
test_class => [qw(forking mod_sftp sftp)],
},
caseignore_sftp_readlink => {
order => ++$order,
test_class => [qw(forking mod_sftp sftp)],
},
caseignore_sftp_symlink_src => {
order => ++$order,
test_class => [qw(forking mod_sftp sftp)],
},
caseignore_sftp_symlink_dst => {
order => ++$order,
test_class => [qw(forking mod_sftp sftp)],
},
caseignore_sftp_download => {
order => ++$order,
test_class => [qw(forking mod_sftp sftp)],
},
caseignore_sftp_upload => {
order => ++$order,
test_class => [qw(forking mod_sftp sftp)],
},
caseignore_sftp_mkdir => {
order => ++$order,
test_class => [qw(forking mod_sftp sftp)],
},
caseignore_sftp_rmdir => {
order => ++$order,
test_class => [qw(forking mod_sftp sftp)],
},
caseignore_sftp_remove => {
order => ++$order,
test_class => [qw(forking mod_sftp sftp)],
},
};
sub new {
return shift()->SUPER::new(@_);
}
sub list_tests {
return testsuite_get_runnable_tests($TESTS);
}
sub set_up {
my $self = shift;
$self->SUPER::set_up(@_);
# Make sure that mod_sftp does not complain about permissions on the hostkey
# files.
my $rsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_rsa_key");
my $dsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_dsa_key");
unless (chmod(0400, $rsa_host_key, $dsa_host_key)) {
die("Can't set perms on $rsa_host_key, $dsa_host_key: $!");
}
}
sub caseignore_sftp_realpath {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $config_file = "$tmpdir/case.conf";
my $pid_file = File::Spec->rel2abs("$tmpdir/case.pid");
my $scoreboard_file = File::Spec->rel2abs("$tmpdir/case.scoreboard");
my $log_file = File::Spec->rel2abs('tests.log');
my $auth_user_file = File::Spec->rel2abs("$tmpdir/case.passwd");
my $auth_group_file = File::Spec->rel2abs("$tmpdir/case.group");
my $user = 'proftpd';
my $passwd = 'test';
my $group = 'ftpd';
my $home_dir = File::Spec->rel2abs($tmpdir);
my $uid = 500;
my $gid = 500;
# Make sure that, if we're running as root, that the home directory has
# permissions/privs set for the account we create
if ($< == 0) {
unless (chmod(0755, $home_dir)) {
die("Can't set perms on $home_dir to 0755: $!");
}
unless (chown($uid, $gid, $home_dir)) {
die("Can't set owner of $home_dir to $uid/$gid: $!");
}
}
auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
'/bin/bash');
auth_group_write($auth_group_file, $group, $gid, $user);
my $rsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_rsa_key");
my $dsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_dsa_key");
my $sub_dir = File::Spec->rel2abs("$home_dir/test.d");
mkpath($sub_dir);
my $config = {
PidFile => $pid_file,
ScoreboardFile => $scoreboard_file,
SystemLog => $log_file,
AuthUserFile => $auth_user_file,
AuthGroupFile => $auth_group_file,
AllowOverwrite => 'on',
AllowStoreRestart => 'on',
IfModules => {
'mod_case.c' => {
CaseEngine => 'on',
CaseIgnore => 'on',
CaseLog => $log_file,
},
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_sftp.c' => [
"SFTPEngine on",
"SFTPLog $log_file",
"SFTPHostKey $rsa_host_key",
"SFTPHostKey $dsa_host_key",
],
},
};
my ($port, $config_user, $config_group) = config_write($config_file, $config);
# Open pipes, for use between the parent and child processes. Specifically,
# the child will indicate when it's done with its test by writing a message
# to the parent.
my ($rfh, $wfh);
unless (pipe($rfh, $wfh)) {
die("Can't open pipe: $!");
}
require Net::SSH2;
my $ex;
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
my $ssh2 = Net::SSH2->new();
sleep(1);
unless ($ssh2->connect('127.0.0.1', $port)) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't connect to SSH2 server: [$err_name] ($err_code) $err_str");
}
unless ($ssh2->auth_password($user, $passwd)) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't login to SSH2 server: [$err_name] ($err_code) $err_str");
}
my $sftp = $ssh2->sftp();
unless ($sftp) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't use SFTP on SSH2 server: [$err_name] ($err_code) $err_str");
}
my $cwd = $sftp->realpath('TeSt.D');
unless ($cwd) {
my ($err_code, $err_name) = $sftp->error();
die("Can't get real path for 'TeSt.D': [$err_name] ($err_code)");
}
my $expected;
$expected = $sub_dir;
$self->assert($expected eq $cwd,
test_msg("Expected '$expected', got '$cwd'"));
$sftp = undef;
$ssh2->disconnect();
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($config_file, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($pid_file);
$self->assert_child_ok($pid);
if ($ex) {
die($ex);
}
unlink($log_file);
}
sub caseignore_sftp_lstat {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $config_file = "$tmpdir/case.conf";
my $pid_file = File::Spec->rel2abs("$tmpdir/case.pid");
my $scoreboard_file = File::Spec->rel2abs("$tmpdir/case.scoreboard");
my $log_file = File::Spec->rel2abs('tests.log');
my $auth_user_file = File::Spec->rel2abs("$tmpdir/case.passwd");
my $auth_group_file = File::Spec->rel2abs("$tmpdir/case.group");
my $user = 'proftpd';
my $passwd = 'test';
my $group = 'ftpd';
my $home_dir = File::Spec->rel2abs($tmpdir);
my $uid = 500;
my $gid = 500;
# Make sure that, if we're running as root, that the home directory has
# permissions/privs set for the account we create
if ($< == 0) {
unless (chmod(0755, $home_dir)) {
die("Can't set perms on $home_dir to 0755: $!");
}
unless (chown($uid, $gid, $home_dir)) {
die("Can't set owner of $home_dir to $uid/$gid: $!");
}
}
auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
'/bin/bash');
auth_group_write($auth_group_file, $group, $gid, $user);
my $rsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_rsa_key");
my $dsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_dsa_key");
my $test_file = File::Spec->rel2abs("$tmpdir/test.txt");
if (open(my $fh, "> $test_file")) {
print $fh "ABCD" x 1024;
unless (close($fh)) {
die("Can't write $test_file: $!");
}
} else {
die("Can't open $test_file: $!");
}
my $test_size = (stat($test_file))[7];
my $test_symlink = File::Spec->rel2abs("$tmpdir/test.lnk");
unless (symlink($test_file, $test_symlink)) {
die("Can't symlink $test_symlink to $test_file: $!");
}
my $test_symlink_size = (lstat($test_symlink))[7];
my $config = {
PidFile => $pid_file,
ScoreboardFile => $scoreboard_file,
SystemLog => $log_file,
AuthUserFile => $auth_user_file,
AuthGroupFile => $auth_group_file,
AllowOverwrite => 'on',
AllowStoreRestart => 'on',
IfModules => {
'mod_case.c' => {
CaseEngine => 'on',
CaseIgnore => 'on',
CaseLog => $log_file,
},
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_sftp.c' => [
"SFTPEngine on",
"SFTPLog $log_file",
"SFTPHostKey $rsa_host_key",
"SFTPHostKey $dsa_host_key",
],
},
};
my ($port, $config_user, $config_group) = config_write($config_file, $config);
# Open pipes, for use between the parent and child processes. Specifically,
# the child will indicate when it's done with its test by writing a message
# to the parent.
my ($rfh, $wfh);
unless (pipe($rfh, $wfh)) {
die("Can't open pipe: $!");
}
require Net::SSH2;
my $ex;
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
my $ssh2 = Net::SSH2->new();
sleep(1);
unless ($ssh2->connect('127.0.0.1', $port)) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't connect to SSH2 server: [$err_name] ($err_code) $err_str");
}
unless ($ssh2->auth_password($user, $passwd)) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't login to SSH2 server: [$err_name] ($err_code) $err_str");
}
my $sftp = $ssh2->sftp();
unless ($sftp) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't use SFTP on SSH2 server: [$err_name] ($err_code) $err_str");
}
my $attrs = $sftp->stat('TeSt.LnK', 0);
unless ($attrs) {
my ($err_code, $err_name) = $sftp->error();
die("FXP_LSTAT TeSt.LnK failed: [$err_name] ($err_code)");
}
my $expected;
$expected = $test_symlink_size;
my $file_size = $attrs->{size};
$self->assert($expected == $file_size,
test_msg("Expected '$expected', got '$file_size'"));
$expected = $<;
my $file_uid = $attrs->{uid};
$self->assert($expected == $file_uid,
test_msg("Expected '$expected', got '$file_uid'"));
$expected = $(;
my $file_gid = $attrs->{gid};
$self->assert($expected == $file_gid,
test_msg("Expected '$expected', got '$file_gid'"));
$sftp = undef;
$ssh2->disconnect();
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($config_file, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($pid_file);
$self->assert_child_ok($pid);
if ($ex) {
die($ex);
}
unlink($log_file);
}
sub caseignore_sftp_setstat {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $config_file = "$tmpdir/case.conf";
my $pid_file = File::Spec->rel2abs("$tmpdir/case.pid");
my $scoreboard_file = File::Spec->rel2abs("$tmpdir/case.scoreboard");
my $log_file = File::Spec->rel2abs('tests.log');
my $auth_user_file = File::Spec->rel2abs("$tmpdir/case.passwd");
my $auth_group_file = File::Spec->rel2abs("$tmpdir/case.group");
my $user = 'proftpd';
my $passwd = 'test';
my $group = 'ftpd';
my $home_dir = File::Spec->rel2abs($tmpdir);
my $uid = 500;
my $gid = 500;
# Make sure that, if we're running as root, that the home directory has
# permissions/privs set for the account we create
if ($< == 0) {
unless (chmod(0755, $home_dir)) {
die("Can't set perms on $home_dir to 0755: $!");
}
unless (chown($uid, $gid, $home_dir)) {
die("Can't set owner of $home_dir to $uid/$gid: $!");
}
}
auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
'/bin/bash');
auth_group_write($auth_group_file, $group, $gid, $user);
my $rsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_rsa_key");
my $dsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_dsa_key");
my $test_file = File::Spec->rel2abs("$tmpdir/test.txt");
if (open(my $fh, "> $test_file")) {
print $fh "ABCD" x 1024;
unless (close($fh)) {
die("Can't write $test_file: $!");
}
} else {
die("Can't open $test_file: $!");
}
my $config = {
PidFile => $pid_file,
ScoreboardFile => $scoreboard_file,
SystemLog => $log_file,
AuthUserFile => $auth_user_file,
AuthGroupFile => $auth_group_file,
AllowOverwrite => 'on',
AllowStoreRestart => 'on',
IfModules => {
'mod_case.c' => {
CaseEngine => 'on',
CaseIgnore => 'on',
CaseLog => $log_file,
},
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_sftp.c' => [
"SFTPEngine on",
"SFTPLog $log_file",
"SFTPHostKey $rsa_host_key",
"SFTPHostKey $dsa_host_key",
],
},
};
my ($port, $config_user, $config_group) = config_write($config_file, $config);
# Open pipes, for use between the parent and child processes. Specifically,
# the child will indicate when it's done with its test by writing a message
# to the parent.
my ($rfh, $wfh);
unless (pipe($rfh, $wfh)) {
die("Can't open pipe: $!");
}
require Net::SSH2;
my $ex;
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
my $ssh2 = Net::SSH2->new();
sleep(1);
unless ($ssh2->connect('127.0.0.1', $port)) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't connect to SSH2 server: [$err_name] ($err_code) $err_str");
}
unless ($ssh2->auth_password($user, $passwd)) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't login to SSH2 server: [$err_name] ($err_code) $err_str");
}
my $sftp = $ssh2->sftp();
unless ($sftp) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't use SFTP on SSH2 server: [$err_name] ($err_code) $err_str");
}
my $res = $sftp->setstat('TeSt.TxT',
atime => 0,
mtime => 0,
);
unless ($res) {
my ($err_code, $err_name) = $sftp->error();
die("Can't setstat TeSt.TxT: [$err_name] ($err_code)");
}
my $attrs = $sftp->stat('test.txt');
unless ($attrs) {
my ($err_code, $err_name) = $sftp->error();
die("Can't stat test.txt: [$err_name] ($err_code)");
}
$sftp = undef;
$ssh2->disconnect();
my $expected;
$expected = 0;
my $file_atime = $attrs->{atime};
$self->assert($expected == $file_atime,
test_msg("Expected '$expected', got '$file_atime'"));
my $file_mtime = $attrs->{mtime};
$self->assert($expected == $file_mtime,
test_msg("Expected '$expected', got '$file_mtime'"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($config_file, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($pid_file);
$self->assert_child_ok($pid);
if ($ex) {
die($ex);
}
unlink($log_file);
}
sub caseignore_sftp_opendir {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $config_file = "$tmpdir/case.conf";
my $pid_file = File::Spec->rel2abs("$tmpdir/case.pid");
my $scoreboard_file = File::Spec->rel2abs("$tmpdir/case.scoreboard");
my $log_file = File::Spec->rel2abs('tests.log');
my $auth_user_file = File::Spec->rel2abs("$tmpdir/case.passwd");
my $auth_group_file = File::Spec->rel2abs("$tmpdir/case.group");
my $user = 'proftpd';
my $passwd = 'test';
my $group = 'ftpd';
my $home_dir = File::Spec->rel2abs($tmpdir);
my $uid = 500;
my $gid = 500;
# Make sure that, if we're running as root, that the home directory has
# permissions/privs set for the account we create
if ($< == 0) {
unless (chmod(0755, $home_dir)) {
die("Can't set perms on $home_dir to 0755: $!");
}
unless (chown($uid, $gid, $home_dir)) {
die("Can't set owner of $home_dir to $uid/$gid: $!");
}
}
auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
'/bin/bash');
auth_group_write($auth_group_file, $group, $gid, $user);
my $rsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_rsa_key");
my $dsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_dsa_key");
my $sub_dir = File::Spec->rel2abs("$home_dir/test.d");
mkpath($sub_dir);
my $config = {
PidFile => $pid_file,
ScoreboardFile => $scoreboard_file,
SystemLog => $log_file,
AuthUserFile => $auth_user_file,
AuthGroupFile => $auth_group_file,
AllowOverwrite => 'on',
AllowStoreRestart => 'on',
IfModules => {
'mod_case.c' => {
CaseEngine => 'on',
CaseIgnore => 'on',
CaseLog => $log_file,
},
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_sftp.c' => [
"SFTPEngine on",
"SFTPLog $log_file",
"SFTPHostKey $rsa_host_key",
"SFTPHostKey $dsa_host_key",
],
},
};
my ($port, $config_user, $config_group) = config_write($config_file, $config);
# Open pipes, for use between the parent and child processes. Specifically,
# the child will indicate when it's done with its test by writing a message
# to the parent.
my ($rfh, $wfh);
unless (pipe($rfh, $wfh)) {
die("Can't open pipe: $!");
}
require Net::SSH2;
my $ex;
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
my $ssh2 = Net::SSH2->new();
sleep(1);
unless ($ssh2->connect('127.0.0.1', $port)) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't connect to SSH2 server: [$err_name] ($err_code) $err_str");
}
unless ($ssh2->auth_password($user, $passwd)) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't login to SSH2 server: [$err_name] ($err_code) $err_str");
}
my $sftp = $ssh2->sftp();
unless ($sftp) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't use SFTP on SSH2 server: [$err_name] ($err_code) $err_str");
}
my $dir = $sftp->opendir('TeSt.D');
unless ($dir) {
my ($err_code, $err_name) = $sftp->error();
die("Can't open directory 'TeSt.D': [$err_name] ($err_code)");
}
my $res = {};
my $file = $dir->read();
while ($file) {
$res->{$file->{name}} = $file;
$file = $dir->read();
}
my $expected = {
'.' => 1,
'..' => 1,
};
# To issue the FXP_CLOSE, we have to explicitly destroy the dirhandle
$dir = undef;
$sftp = undef;
$ssh2->disconnect();
my $ok = 1;
my $mismatch;
my $seen = [];
foreach my $name (keys(%$res)) {
push(@$seen, $name);
unless (defined($expected->{$name})) {
$mismatch = $name;
$ok = 0;
last;
}
}
unless ($ok) {
die("Unexpected name '$mismatch' appeared in READDIR data")
}
# Now remove from $expected all of the paths we saw; if there are
# any entries remaining in $expected, something went wrong.
foreach my $name (@$seen) {
delete($expected->{$name});
}
my $remaining = scalar(keys(%$expected));
$self->assert(0 == $remaining,
test_msg("Expected 0, got $remaining"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($config_file, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($pid_file);
$self->assert_child_ok($pid);
if ($ex) {
die($ex);
}
unlink($log_file);
}
sub caseignore_sftp_stat {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $config_file = "$tmpdir/case.conf";
my $pid_file = File::Spec->rel2abs("$tmpdir/case.pid");
my $scoreboard_file = File::Spec->rel2abs("$tmpdir/case.scoreboard");
my $log_file = File::Spec->rel2abs('tests.log');
my $auth_user_file = File::Spec->rel2abs("$tmpdir/case.passwd");
my $auth_group_file = File::Spec->rel2abs("$tmpdir/case.group");
my $user = 'proftpd';
my $passwd = 'test';
my $group = 'ftpd';
my $home_dir = File::Spec->rel2abs($tmpdir);
my $uid = 500;
my $gid = 500;
# Make sure that, if we're running as root, that the home directory has
# permissions/privs set for the account we create
if ($< == 0) {
unless (chmod(0755, $home_dir)) {
die("Can't set perms on $home_dir to 0755: $!");
}
unless (chown($uid, $gid, $home_dir)) {
die("Can't set owner of $home_dir to $uid/$gid: $!");
}
}
auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
'/bin/bash');
auth_group_write($auth_group_file, $group, $gid, $user);
my $rsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_rsa_key");
my $dsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_dsa_key");
my $test_file = File::Spec->rel2abs("$tmpdir/test.txt");
if (open(my $fh, "> $test_file")) {
print $fh "ABCD" x 1024;
unless (close($fh)) {
die("Can't write $test_file: $!");
}
} else {
die("Can't open $test_file: $!");
}
my $test_size = (stat($test_file))[7];
my $config = {
PidFile => $pid_file,
ScoreboardFile => $scoreboard_file,
SystemLog => $log_file,
AuthUserFile => $auth_user_file,
AuthGroupFile => $auth_group_file,
AllowOverwrite => 'on',
AllowStoreRestart => 'on',
IfModules => {
'mod_case.c' => {
CaseEngine => 'on',
CaseIgnore => 'on',
CaseLog => $log_file,
},
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_sftp.c' => [
"SFTPEngine on",
"SFTPLog $log_file",
"SFTPHostKey $rsa_host_key",
"SFTPHostKey $dsa_host_key",
],
},
};
my ($port, $config_user, $config_group) = config_write($config_file, $config);
# Open pipes, for use between the parent and child processes. Specifically,
# the child will indicate when it's done with its test by writing a message
# to the parent.
my ($rfh, $wfh);
unless (pipe($rfh, $wfh)) {
die("Can't open pipe: $!");
}
require Net::SSH2;
my $ex;
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
my $ssh2 = Net::SSH2->new();
sleep(1);
unless ($ssh2->connect('127.0.0.1', $port)) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't connect to SSH2 server: [$err_name] ($err_code) $err_str");
}
unless ($ssh2->auth_password($user, $passwd)) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't login to SSH2 server: [$err_name] ($err_code) $err_str");
}
my $sftp = $ssh2->sftp();
unless ($sftp) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't use SFTP on SSH2 server: [$err_name] ($err_code) $err_str");
}
my $attrs = $sftp->stat('TeSt.TxT', 1);
unless ($attrs) {
my ($err_code, $err_name) = $sftp->error();
die("Can't stat TeSt.TxT: [$err_name] ($err_code)");
}
my $expected;
$expected = $test_size;
my $file_size = $attrs->{size};
$self->assert($expected == $file_size,
test_msg("Expected '$expected', got '$file_size'"));
$expected = $<;
my $file_uid = $attrs->{uid};
$self->assert($expected == $file_uid,
test_msg("Expected '$expected', got '$file_uid'"));
$expected = $(;
my $file_gid = $attrs->{gid};
$self->assert($expected == $file_gid,
test_msg("Expected '$expected', got '$file_gid'"));
$sftp = undef;
$ssh2->disconnect();
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($config_file, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($pid_file);
$self->assert_child_ok($pid);
if ($ex) {
die($ex);
}
unlink($log_file);
}
sub caseignore_sftp_readlink {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $config_file = "$tmpdir/case.conf";
my $pid_file = File::Spec->rel2abs("$tmpdir/case.pid");
my $scoreboard_file = File::Spec->rel2abs("$tmpdir/case.scoreboard");
my $log_file = File::Spec->rel2abs('tests.log');
my $auth_user_file = File::Spec->rel2abs("$tmpdir/case.passwd");
my $auth_group_file = File::Spec->rel2abs("$tmpdir/case.group");
my $user = 'proftpd';
my $passwd = 'test';
my $group = 'ftpd';
my $home_dir = File::Spec->rel2abs($tmpdir);
my $uid = 500;
my $gid = 500;
# Make sure that, if we're running as root, that the home directory has
# permissions/privs set for the account we create
if ($< == 0) {
unless (chmod(0755, $home_dir)) {
die("Can't set perms on $home_dir to 0755: $!");
}
unless (chown($uid, $gid, $home_dir)) {
die("Can't set owner of $home_dir to $uid/$gid: $!");
}
}
auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
'/bin/bash');
auth_group_write($auth_group_file, $group, $gid, $user);
my $rsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_rsa_key");
my $dsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_dsa_key");
my $test_file = File::Spec->rel2abs("$tmpdir/test.txt");
if (open(my $fh, "> $test_file")) {
print $fh "ABCD" x 1024;
unless (close($fh)) {
die("Can't write $test_file: $!");
}
} else {
die("Can't open $test_file: $!");
}
my $test_symlink = File::Spec->rel2abs("$tmpdir/test.lnk");
unless (symlink($test_file, $test_symlink)) {
die("Can't symlink $test_symlink to $test_file: $!");
}
my $config = {
PidFile => $pid_file,
ScoreboardFile => $scoreboard_file,
SystemLog => $log_file,
AuthUserFile => $auth_user_file,
AuthGroupFile => $auth_group_file,
AllowOverwrite => 'on',
AllowStoreRestart => 'on',
IfModules => {
'mod_case.c' => {
CaseEngine => 'on',
CaseIgnore => 'on',
CaseLog => $log_file,
},
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_sftp.c' => [
"SFTPEngine on",
"SFTPLog $log_file",
"SFTPHostKey $rsa_host_key",
"SFTPHostKey $dsa_host_key",
],
},
};
my ($port, $config_user, $config_group) = config_write($config_file, $config);
# Open pipes, for use between the parent and child processes. Specifically,
# the child will indicate when it's done with its test by writing a message
# to the parent.
my ($rfh, $wfh);
unless (pipe($rfh, $wfh)) {
die("Can't open pipe: $!");
}
require Net::SSH2;
my $ex;
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
my $ssh2 = Net::SSH2->new();
sleep(1);
unless ($ssh2->connect('127.0.0.1', $port)) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't connect to SSH2 server: [$err_name] ($err_code) $err_str");
}
unless ($ssh2->auth_password($user, $passwd)) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't login to SSH2 server: [$err_name] ($err_code) $err_str");
}
my $sftp = $ssh2->sftp();
unless ($sftp) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't use SFTP on SSH2 server: [$err_name] ($err_code) $err_str");
}
my $path = $sftp->readlink('TeSt.LnK');
unless ($path) {
my ($err_code, $err_name) = $sftp->error();
die("Can't readlink TeSt.LnK: [$err_name] ($err_code)");
}
$sftp = undef;
$ssh2->disconnect();
$self->assert($test_file eq $path,
test_msg("Expected '$test_file', got '$path'"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($config_file, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($pid_file);
$self->assert_child_ok($pid);
if ($ex) {
die($ex);
}
unlink($log_file);
}
sub caseignore_sftp_symlink_src {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $config_file = "$tmpdir/case.conf";
my $pid_file = File::Spec->rel2abs("$tmpdir/case.pid");
my $scoreboard_file = File::Spec->rel2abs("$tmpdir/case.scoreboard");
my $log_file = File::Spec->rel2abs('tests.log');
my $auth_user_file = File::Spec->rel2abs("$tmpdir/case.passwd");
my $auth_group_file = File::Spec->rel2abs("$tmpdir/case.group");
my $user = 'proftpd';
my $passwd = 'test';
my $group = 'ftpd';
my $home_dir = File::Spec->rel2abs($tmpdir);
my $uid = 500;
my $gid = 500;
# Make sure that, if we're running as root, that the home directory has
# permissions/privs set for the account we create
if ($< == 0) {
unless (chmod(0755, $home_dir)) {
die("Can't set perms on $home_dir to 0755: $!");
}
unless (chown($uid, $gid, $home_dir)) {
die("Can't set owner of $home_dir to $uid/$gid: $!");
}
}
auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
'/bin/bash');
auth_group_write($auth_group_file, $group, $gid, $user);
my $rsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_rsa_key");
my $dsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_dsa_key");
my $test_file = File::Spec->rel2abs("$tmpdir/test.txt");
if (open(my $fh, "> $test_file")) {
print $fh "ABCD" x 1024;
unless (close($fh)) {
die("Can't write $test_file: $!");
}
} else {
die("Can't open $test_file: $!");
}
my $test_symlink = File::Spec->rel2abs("$tmpdir/test.lnk");
# Not sure why, but Net::SSH2::SFTP seems to need a little more time
# for this test case.
my $timeout_idle = 15;
my $config = {
PidFile => $pid_file,
ScoreboardFile => $scoreboard_file,
SystemLog => $log_file,
TraceLog => $log_file,
AuthUserFile => $auth_user_file,
AuthGroupFile => $auth_group_file,
AllowOverwrite => 'on',
AllowStoreRestart => 'on',
TimeoutIdle => 5,
IfModules => {
'mod_case.c' => {
CaseEngine => 'on',
CaseIgnore => 'on',
CaseLog => $log_file,
},
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_sftp.c' => [
"SFTPEngine on",
"SFTPLog $log_file",
"SFTPHostKey $rsa_host_key",
"SFTPHostKey $dsa_host_key",
],
},
};
my ($port, $config_user, $config_group) = config_write($config_file, $config);
# Open pipes, for use between the parent and child processes. Specifically,
# the child will indicate when it's done with its test by writing a message
# to the parent.
my ($rfh, $wfh);
unless (pipe($rfh, $wfh)) {
die("Can't open pipe: $!");
}
require Net::SSH2;
my $ex;
# Ignore SIGPIPE
local $SIG{PIPE} = sub { };
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
my $ssh2 = Net::SSH2->new();
sleep(1);
unless ($ssh2->connect('127.0.0.1', $port)) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't connect to SSH2 server: [$err_name] ($err_code) $err_str");
}
unless ($ssh2->auth_password($user, $passwd)) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't login to SSH2 server: [$err_name] ($err_code) $err_str");
}
my $sftp = $ssh2->sftp();
unless ($sftp) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't use SFTP on SSH2 server: [$err_name] ($err_code) $err_str");
}
my $res = $sftp->symlink('TeSt.TxT', 'test.lnk');
unless (defined($res)) {
my ($err_code, $err_name) = $sftp->error();
die("Can't symlink test.lnk to TeSt.TxT: [$err_name] ($err_code)");
}
$sftp = undef;
$ssh2->disconnect();
$self->assert(-l $test_symlink,
test_msg("Symlink $test_symlink does not exist as expected"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($config_file, $rfh, $timeout_idle + 1) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($pid_file);
$self->assert_child_ok($pid);
if ($ex) {
die($ex);
}
unlink($log_file);
}
sub caseignore_sftp_symlink_dst {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $config_file = "$tmpdir/case.conf";
my $pid_file = File::Spec->rel2abs("$tmpdir/case.pid");
my $scoreboard_file = File::Spec->rel2abs("$tmpdir/case.scoreboard");
my $log_file = File::Spec->rel2abs('tests.log');
my $auth_user_file = File::Spec->rel2abs("$tmpdir/case.passwd");
my $auth_group_file = File::Spec->rel2abs("$tmpdir/case.group");
my $user = 'proftpd';
my $passwd = 'test';
my $group = 'ftpd';
my $home_dir = File::Spec->rel2abs($tmpdir);
my $uid = 500;
my $gid = 500;
# Make sure that, if we're running as root, that the home directory has
# permissions/privs set for the account we create
if ($< == 0) {
unless (chmod(0755, $home_dir)) {
die("Can't set perms on $home_dir to 0755: $!");
}
unless (chown($uid, $gid, $home_dir)) {
die("Can't set owner of $home_dir to $uid/$gid: $!");
}
}
auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
'/bin/bash');
auth_group_write($auth_group_file, $group, $gid, $user);
my $rsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_rsa_key");
my $dsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_dsa_key");
my $test_file = File::Spec->rel2abs("$tmpdir/test.txt");
if (open(my $fh, "> $test_file")) {
print $fh "ABCD" x 1024;
unless (close($fh)) {
die("Can't write $test_file: $!");
}
} else {
die("Can't open $test_file: $!");
}
my $test_symlink = File::Spec->rel2abs("$tmpdir/test.lnk");
if (open(my $fh, "> $test_symlink")) {
close($fh);
} else {
die("Can't open $test_symlink: $!");
}
# Not sure why, but Net::SSH2::SFTP seems to need a little more time
# for this test case.
my $timeout_idle = 15;
my $config = {
PidFile => $pid_file,
ScoreboardFile => $scoreboard_file,
SystemLog => $log_file,
TraceLog => $log_file,
AuthUserFile => $auth_user_file,
AuthGroupFile => $auth_group_file,
AllowOverwrite => 'on',
AllowStoreRestart => 'on',
TimeoutIdle => 5,
IfModules => {
'mod_case.c' => {
CaseEngine => 'on',
CaseIgnore => 'on',
CaseLog => $log_file,
},
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_sftp.c' => [
"SFTPEngine on",
"SFTPLog $log_file",
"SFTPHostKey $rsa_host_key",
"SFTPHostKey $dsa_host_key",
],
},
};
my ($port, $config_user, $config_group) = config_write($config_file, $config);
# Open pipes, for use between the parent and child processes. Specifically,
# the child will indicate when it's done with its test by writing a message
# to the parent.
my ($rfh, $wfh);
unless (pipe($rfh, $wfh)) {
die("Can't open pipe: $!");
}
require Net::SSH2;
my $ex;
# Ignore SIGPIPE
local $SIG{PIPE} = sub { };
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
my $ssh2 = Net::SSH2->new();
sleep(1);
unless ($ssh2->connect('127.0.0.1', $port)) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't connect to SSH2 server: [$err_name] ($err_code) $err_str");
}
unless ($ssh2->auth_password($user, $passwd)) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't login to SSH2 server: [$err_name] ($err_code) $err_str");
}
my $sftp = $ssh2->sftp();
unless ($sftp) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't use SFTP on SSH2 server: [$err_name] ($err_code) $err_str");
}
my $res = $sftp->symlink('test.txt', 'TeSt.LnK');
if ($res) {
die("Symlink of TeSt.LnK to test.txt succeeded unexpectedly");
}
$sftp = undef;
$ssh2->disconnect();
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($config_file, $rfh, $timeout_idle + 1) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($pid_file);
$self->assert_child_ok($pid);
if ($ex) {
die($ex);
}
unlink($log_file);
}
sub caseignore_sftp_download {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $config_file = "$tmpdir/case.conf";
my $pid_file = File::Spec->rel2abs("$tmpdir/case.pid");
my $scoreboard_file = File::Spec->rel2abs("$tmpdir/case.scoreboard");
my $log_file = File::Spec->rel2abs('tests.log');
my $auth_user_file = File::Spec->rel2abs("$tmpdir/case.passwd");
my $auth_group_file = File::Spec->rel2abs("$tmpdir/case.group");
my $user = 'proftpd';
my $passwd = 'test';
my $group = 'ftpd';
my $home_dir = File::Spec->rel2abs($tmpdir);
my $uid = 500;
my $gid = 500;
# Make sure that, if we're running as root, that the home directory has
# permissions/privs set for the account we create
if ($< == 0) {
unless (chmod(0755, $home_dir)) {
die("Can't set perms on $home_dir to 0755: $!");
}
unless (chown($uid, $gid, $home_dir)) {
die("Can't set owner of $home_dir to $uid/$gid: $!");
}
}
auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
'/bin/bash');
auth_group_write($auth_group_file, $group, $gid, $user);
my $rsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_rsa_key");
my $dsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_dsa_key");
my $test_file = File::Spec->rel2abs("$home_dir/test.txt");
if (open(my $fh, "> $test_file")) {
print $fh "Hello, World!\n";
unless (close($fh)) {
die("Can't write $test_file: $!");
}
} else {
die("Can't open $test_file: $!");
}
my $test_sz = -s $test_file;
my $config = {
PidFile => $pid_file,
ScoreboardFile => $scoreboard_file,
SystemLog => $log_file,
AuthUserFile => $auth_user_file,
AuthGroupFile => $auth_group_file,
AllowOverwrite => 'on',
AllowStoreRestart => 'on',
IfModules => {
'mod_case.c' => {
CaseEngine => 'on',
CaseIgnore => 'on',
CaseLog => $log_file,
},
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_sftp.c' => [
"SFTPEngine on",
"SFTPLog $log_file",
"SFTPHostKey $rsa_host_key",
"SFTPHostKey $dsa_host_key",
],
},
};
my ($port, $config_user, $config_group) = config_write($config_file, $config);
# Open pipes, for use between the parent and child processes. Specifically,
# the child will indicate when it's done with its test by writing a message
# to the parent.
my ($rfh, $wfh);
unless (pipe($rfh, $wfh)) {
die("Can't open pipe: $!");
}
require Net::SSH2;
my $ex;
# Ignore SIGPIPE
local $SIG{PIPE} = sub { };
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
my $ssh2 = Net::SSH2->new();
sleep(1);
unless ($ssh2->connect('127.0.0.1', $port)) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't connect to SSH2 server: [$err_name] ($err_code) $err_str");
}
unless ($ssh2->auth_password($user, $passwd)) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't login to SSH2 server: [$err_name] ($err_code) $err_str");
}
my $sftp = $ssh2->sftp();
unless ($sftp) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't use SFTP on SSH2 server: [$err_name] ($err_code) $err_str");
}
my $fh = $sftp->open('TeSt.TxT', O_RDONLY);
unless ($fh) {
my ($err_code, $err_name) = $sftp->error();
die("Can't open TeSt.TxT: [$err_name] ($err_code)");
}
my $buf;
my $size = 0;
my $res = $fh->read($buf, 8192);
while ($res) {
$size += $res;
$res = $fh->read($buf, 8192);
}
# To issue the FXP_CLOSE, we have to explicitly destroy the filehandle
$fh = undef;
$sftp = undef;
$ssh2->disconnect();
$self->assert($test_sz == $size,
test_msg("Expected $test_sz, got $size"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($config_file, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($pid_file);
$self->assert_child_ok($pid);
if ($ex) {
die($ex);
}
unlink($log_file);
}
sub caseignore_sftp_upload {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $config_file = "$tmpdir/case.conf";
my $pid_file = File::Spec->rel2abs("$tmpdir/case.pid");
my $scoreboard_file = File::Spec->rel2abs("$tmpdir/case.scoreboard");
my $log_file = File::Spec->rel2abs('tests.log');
my $auth_user_file = File::Spec->rel2abs("$tmpdir/case.passwd");
my $auth_group_file = File::Spec->rel2abs("$tmpdir/case.group");
my $user = 'proftpd';
my $passwd = 'test';
my $group = 'ftpd';
my $home_dir = File::Spec->rel2abs($tmpdir);
my $uid = 500;
my $gid = 500;
# Make sure that, if we're running as root, that the home directory has
# permissions/privs set for the account we create
if ($< == 0) {
unless (chmod(0755, $home_dir)) {
die("Can't set perms on $home_dir to 0755: $!");
}
unless (chown($uid, $gid, $home_dir)) {
die("Can't set owner of $home_dir to $uid/$gid: $!");
}
}
auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
'/bin/bash');
auth_group_write($auth_group_file, $group, $gid, $user);
my $rsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_rsa_key");
my $dsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_dsa_key");
my $test_file = File::Spec->rel2abs("$home_dir/test.txt");
if (open(my $fh, "> $test_file")) {
close($fh);
} else {
die("Can't open $test_file: $!");
}
my $test_sz = 32;
my $config = {
PidFile => $pid_file,
ScoreboardFile => $scoreboard_file,
SystemLog => $log_file,
AuthUserFile => $auth_user_file,
AuthGroupFile => $auth_group_file,
AllowOverwrite => 'on',
AllowStoreRestart => 'on',
IfModules => {
'mod_case.c' => {
CaseEngine => 'on',
CaseIgnore => 'on',
CaseLog => $log_file,
},
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_sftp.c' => [
"SFTPEngine on",
"SFTPLog $log_file",
"SFTPHostKey $rsa_host_key",
"SFTPHostKey $dsa_host_key",
],
},
};
my ($port, $config_user, $config_group) = config_write($config_file, $config);
# Open pipes, for use between the parent and child processes. Specifically,
# the child will indicate when it's done with its test by writing a message
# to the parent.
my ($rfh, $wfh);
unless (pipe($rfh, $wfh)) {
die("Can't open pipe: $!");
}
require Net::SSH2;
my $ex;
# Ignore SIGPIPE
local $SIG{PIPE} = sub { };
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
my $ssh2 = Net::SSH2->new();
sleep(1);
unless ($ssh2->connect('127.0.0.1', $port)) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't connect to SSH2 server: [$err_name] ($err_code) $err_str");
}
unless ($ssh2->auth_password($user, $passwd)) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't login to SSH2 server: [$err_name] ($err_code) $err_str");
}
my $sftp = $ssh2->sftp();
unless ($sftp) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't use SFTP on SSH2 server: [$err_name] ($err_code) $err_str");
}
my $fh = $sftp->open('TeSt.TxT', O_WRONLY|O_CREAT, 0644);
unless ($fh) {
my ($err_code, $err_name) = $sftp->error();
die("Can't open TeSt.TxT: [$err_name] ($err_code)");
}
print $fh "ABCD" x 8;
# To issue the FXP_CLOSE, we have to explicitly destroy the filehandle
$fh = undef;
$sftp = undef;
$ssh2->disconnect();
my $size = -s $test_file;
$self->assert($size == $test_sz,
test_msg("Expected $test_sz, got $size"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($config_file, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($pid_file);
$self->assert_child_ok($pid);
if ($ex) {
die($ex);
}
unlink($log_file);
}
sub caseignore_sftp_mkdir {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $config_file = "$tmpdir/case.conf";
my $pid_file = File::Spec->rel2abs("$tmpdir/case.pid");
my $scoreboard_file = File::Spec->rel2abs("$tmpdir/case.scoreboard");
my $log_file = File::Spec->rel2abs('tests.log');
my $auth_user_file = File::Spec->rel2abs("$tmpdir/case.passwd");
my $auth_group_file = File::Spec->rel2abs("$tmpdir/case.group");
my $user = 'proftpd';
my $passwd = 'test';
my $group = 'ftpd';
my $home_dir = File::Spec->rel2abs($tmpdir);
my $uid = 500;
my $gid = 500;
# Make sure that, if we're running as root, that the home directory has
# permissions/privs set for the account we create
if ($< == 0) {
unless (chmod(0755, $home_dir)) {
die("Can't set perms on $home_dir to 0755: $!");
}
unless (chown($uid, $gid, $home_dir)) {
die("Can't set owner of $home_dir to $uid/$gid: $!");
}
}
auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
'/bin/bash');
auth_group_write($auth_group_file, $group, $gid, $user);
my $rsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_rsa_key");
my $dsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_dsa_key");
my $test_dir = File::Spec->rel2abs("$home_dir/test.d");
mkpath($test_dir);
my $bad_dir = File::Spec->rel2abs("$home_dir/TeSt.D");
my $config = {
PidFile => $pid_file,
ScoreboardFile => $scoreboard_file,
SystemLog => $log_file,
AuthUserFile => $auth_user_file,
AuthGroupFile => $auth_group_file,
AllowOverwrite => 'on',
AllowStoreRestart => 'on',
IfModules => {
'mod_case.c' => {
CaseEngine => 'on',
CaseIgnore => 'on',
CaseLog => $log_file,
},
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_sftp.c' => [
"SFTPEngine on",
"SFTPLog $log_file",
"SFTPHostKey $rsa_host_key",
"SFTPHostKey $dsa_host_key",
],
},
};
my ($port, $config_user, $config_group) = config_write($config_file, $config);
# Open pipes, for use between the parent and child processes. Specifically,
# the child will indicate when it's done with its test by writing a message
# to the parent.
my ($rfh, $wfh);
unless (pipe($rfh, $wfh)) {
die("Can't open pipe: $!");
}
require Net::SSH2;
my $ex;
# Ignore SIGPIPE
local $SIG{PIPE} = sub { };
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
my $ssh2 = Net::SSH2->new();
sleep(1);
unless ($ssh2->connect('127.0.0.1', $port)) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't connect to SSH2 server: [$err_name] ($err_code) $err_str");
}
unless ($ssh2->auth_password($user, $passwd)) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't login to SSH2 server: [$err_name] ($err_code) $err_str");
}
my $sftp = $ssh2->sftp();
unless ($sftp) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't use SFTP on SSH2 server: [$err_name] ($err_code) $err_str");
}
my $res = $sftp->mkdir('TeSt.D');
if ($res) {
die("MKDIR TeSt.D succeeded unexpectedly");
}
my ($err_code, $err_name) = $sftp->error();
$sftp = undef;
$ssh2->disconnect();
my $expected = 'SSH_FX_FAILURE';
$self->assert($expected eq $err_name,
test_msg("Expected '$expected', got '$err_name'"));
$self->assert(!-d $bad_dir,
test_msg("Directory $bad_dir exists unexpectedly"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($config_file, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($pid_file);
$self->assert_child_ok($pid);
if ($ex) {
die($ex);
}
unlink($log_file);
}
sub caseignore_sftp_rmdir {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $config_file = "$tmpdir/case.conf";
my $pid_file = File::Spec->rel2abs("$tmpdir/case.pid");
my $scoreboard_file = File::Spec->rel2abs("$tmpdir/case.scoreboard");
my $log_file = File::Spec->rel2abs('tests.log');
my $auth_user_file = File::Spec->rel2abs("$tmpdir/case.passwd");
my $auth_group_file = File::Spec->rel2abs("$tmpdir/case.group");
my $user = 'proftpd';
my $passwd = 'test';
my $group = 'ftpd';
my $home_dir = File::Spec->rel2abs($tmpdir);
my $uid = 500;
my $gid = 500;
# Make sure that, if we're running as root, that the home directory has
# permissions/privs set for the account we create
if ($< == 0) {
unless (chmod(0755, $home_dir)) {
die("Can't set perms on $home_dir to 0755: $!");
}
unless (chown($uid, $gid, $home_dir)) {
die("Can't set owner of $home_dir to $uid/$gid: $!");
}
}
auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
'/bin/bash');
auth_group_write($auth_group_file, $group, $gid, $user);
my $rsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_rsa_key");
my $dsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_dsa_key");
my $test_dir = File::Spec->rel2abs("$home_dir/test.d");
mkpath($test_dir);
my $config = {
PidFile => $pid_file,
ScoreboardFile => $scoreboard_file,
SystemLog => $log_file,
AuthUserFile => $auth_user_file,
AuthGroupFile => $auth_group_file,
AllowOverwrite => 'on',
AllowStoreRestart => 'on',
IfModules => {
'mod_case.c' => {
CaseEngine => 'on',
CaseIgnore => 'on',
CaseLog => $log_file,
},
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_sftp.c' => [
"SFTPEngine on",
"SFTPLog $log_file",
"SFTPHostKey $rsa_host_key",
"SFTPHostKey $dsa_host_key",
],
},
};
my ($port, $config_user, $config_group) = config_write($config_file, $config);
# Open pipes, for use between the parent and child processes. Specifically,
# the child will indicate when it's done with its test by writing a message
# to the parent.
my ($rfh, $wfh);
unless (pipe($rfh, $wfh)) {
die("Can't open pipe: $!");
}
require Net::SSH2;
my $ex;
# Ignore SIGPIPE
local $SIG{PIPE} = sub { };
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
my $ssh2 = Net::SSH2->new();
sleep(1);
unless ($ssh2->connect('127.0.0.1', $port)) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't connect to SSH2 server: [$err_name] ($err_code) $err_str");
}
unless ($ssh2->auth_password($user, $passwd)) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't login to SSH2 server: [$err_name] ($err_code) $err_str");
}
my $sftp = $ssh2->sftp();
unless ($sftp) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't use SFTP on SSH2 server: [$err_name] ($err_code) $err_str");
}
my $res = $sftp->rmdir('TeSt.D');
unless ($res) {
my ($err_code, $err_name) = $sftp->error();
die("Can't rmdir TeSt.D: [$err_name] ($err_code)");
}
$sftp = undef;
$ssh2->disconnect();
$self->assert(!-d $test_dir,
test_msg("Directory $test_dir exists unexpectedly"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($config_file, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($pid_file);
$self->assert_child_ok($pid);
if ($ex) {
die($ex);
}
unlink($log_file);
}
sub caseignore_sftp_remove {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $config_file = "$tmpdir/case.conf";
my $pid_file = File::Spec->rel2abs("$tmpdir/case.pid");
my $scoreboard_file = File::Spec->rel2abs("$tmpdir/case.scoreboard");
my $log_file = File::Spec->rel2abs('tests.log');
my $auth_user_file = File::Spec->rel2abs("$tmpdir/case.passwd");
my $auth_group_file = File::Spec->rel2abs("$tmpdir/case.group");
my $user = 'proftpd';
my $passwd = 'test';
my $group = 'ftpd';
my $home_dir = File::Spec->rel2abs($tmpdir);
my $uid = 500;
my $gid = 500;
# Make sure that, if we're running as root, that the home directory has
# permissions/privs set for the account we create
if ($< == 0) {
unless (chmod(0755, $home_dir)) {
die("Can't set perms on $home_dir to 0755: $!");
}
unless (chown($uid, $gid, $home_dir)) {
die("Can't set owner of $home_dir to $uid/$gid: $!");
}
}
auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
'/bin/bash');
auth_group_write($auth_group_file, $group, $gid, $user);
my $rsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_rsa_key");
my $dsa_host_key = File::Spec->rel2abs("$ENV{PROFTPD_TEST_DIR}/t/etc/modules/mod_sftp/ssh_host_dsa_key");
my $test_file = File::Spec->rel2abs("$home_dir/test.txt");
if (open(my $fh, "> $test_file")) {
print $fh "Hello, World!\n";
unless (close($fh)) {
die("Can't write $test_file: $!");
}
} else {
die("Can't open $test_file: $!");
}
my $config = {
PidFile => $pid_file,
ScoreboardFile => $scoreboard_file,
SystemLog => $log_file,
AuthUserFile => $auth_user_file,
AuthGroupFile => $auth_group_file,
AllowOverwrite => 'on',
AllowStoreRestart => 'on',
IfModules => {
'mod_case.c' => {
CaseEngine => 'on',
CaseIgnore => 'on',
CaseLog => $log_file,
},
'mod_delay.c' => {
DelayEngine => 'off',
},
'mod_sftp.c' => [
"SFTPEngine on",
"SFTPLog $log_file",
"SFTPHostKey $rsa_host_key",
"SFTPHostKey $dsa_host_key",
],
},
};
my ($port, $config_user, $config_group) = config_write($config_file, $config);
# Open pipes, for use between the parent and child processes. Specifically,
# the child will indicate when it's done with its test by writing a message
# to the parent.
my ($rfh, $wfh);
unless (pipe($rfh, $wfh)) {
die("Can't open pipe: $!");
}
require Net::SSH2;
my $ex;
# Ignore SIGPIPE
local $SIG{PIPE} = sub { };
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
my $ssh2 = Net::SSH2->new();
sleep(1);
unless ($ssh2->connect('127.0.0.1', $port)) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't connect to SSH2 server: [$err_name] ($err_code) $err_str");
}
unless ($ssh2->auth_password($user, $passwd)) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't login to SSH2 server: [$err_name] ($err_code) $err_str");
}
my $sftp = $ssh2->sftp();
unless ($sftp) {
my ($err_code, $err_name, $err_str) = $ssh2->error();
die("Can't use SFTP on SSH2 server: [$err_name] ($err_code) $err_str");
}
my $res = $sftp->unlink('TeSt.TxT');
unless ($res) {
my ($err_code, $err_name) = $sftp->error();
die("Can't remove TeSt.TxT: [$err_name] ($err_code)");
}
$sftp = undef;
$ssh2->disconnect();
$self->assert(!-f $test_file,
test_msg("File $test_file exists unexpectedly"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($config_file, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($pid_file);
$self->assert_child_ok($pid);
if ($ex) {
die($ex);
}
unlink($log_file);
}
1;
mod_case/t/lib/ProFTPD/Tests/Modules/mod_case.pm 0000644 0001750 0001750 00000204244 11555364201 017525 0 ustar tj tj package ProFTPD::Tests::Modules::mod_case;
use lib qw(t/lib);
use base qw(ProFTPD::TestSuite::Child);
use strict;
use File::Path qw(mkpath);
use File::Spec;
use IO::Handle;
use ProFTPD::TestSuite::FTP;
use ProFTPD::TestSuite::Utils qw(:auth :config :running :test :testsuite);
$| = 1;
my $order = 0;
my $TESTS = {
caseignore_appe => {
order => ++$order,
test_class => [qw(forking)],
},
caseignore_cwd => {
order => ++$order,
test_class => [qw(forking)],
},
caseignore_xcwd => {
order => ++$order,
test_class => [qw(forking)],
},
caseignore_dele => {
order => ++$order,
test_class => [qw(forking)],
},
caseignore_mdtm => {
order => ++$order,
test_class => [qw(forking)],
},
caseignore_mkd => {
order => ++$order,
test_class => [qw(forking)],
},
caseignore_xmkd => {
order => ++$order,
test_class => [qw(forking)],
},
caseignore_mlsd => {
order => ++$order,
test_class => [qw(forking)],
},
caseignore_mlst => {
order => ++$order,
test_class => [qw(forking)],
},
caseignore_retr => {
order => ++$order,
test_class => [qw(forking)],
},
caseignore_rmd => {
order => ++$order,
test_class => [qw(forking)],
},
caseignore_xrmd => {
order => ++$order,
test_class => [qw(forking)],
},
caseignore_rnfr => {
order => ++$order,
test_class => [qw(forking)],
},
caseignore_rnto => {
order => ++$order,
test_class => [qw(forking)],
},
caseignore_size => {
order => ++$order,
test_class => [qw(forking)],
},
caseignore_stat => {
order => ++$order,
test_class => [qw(forking)],
},
caseignore_stor => {
order => ++$order,
test_class => [qw(forking)],
},
caseignore_list => {
order => ++$order,
test_class => [qw(forking)],
},
caseignore_nlst => {
order => ++$order,
test_class => [qw(forking)],
},
caseignore_list_extlog_var_r => {
order => ++$order,
test_class => [qw(forking rootprivs)],
},
};
sub new {
return shift()->SUPER::new(@_);
}
sub list_tests {
return testsuite_get_runnable_tests($TESTS);
}
sub caseignore_appe {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $config_file = "$tmpdir/case.conf";
my $pid_file = File::Spec->rel2abs("$tmpdir/case.pid");
my $scoreboard_file = File::Spec->rel2abs("$tmpdir/case.scoreboard");
my $log_file = File::Spec->rel2abs('tests.log');
my $auth_user_file = File::Spec->rel2abs("$tmpdir/case.passwd");
my $auth_group_file = File::Spec->rel2abs("$tmpdir/case.group");
my $user = 'proftpd';
my $passwd = 'test';
my $group = 'ftpd';
my $home_dir = File::Spec->rel2abs($tmpdir);
my $uid = 500;
my $gid = 500;
# Make sure that, if we're running as root, that the home directory has
# permissions/privs set for the account we create
if ($< == 0) {
unless (chmod(0755, $home_dir)) {
die("Can't set perms on $home_dir to 0755: $!");
}
unless (chown($uid, $gid, $home_dir)) {
die("Can't set owner of $home_dir to $uid/$gid: $!");
}
}
auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
'/bin/bash');
auth_group_write($auth_group_file, $group, $gid, $user);
my $test_file = File::Spec->rel2abs("$home_dir/test.txt");
if (open(my $fh, "> $test_file")) {
print $fh "Hello, World!\n";
unless (close($fh)) {
die("Can't write $test_file: $!");
}
} else {
die("Can't open $test_file: $!");
}
my $config = {
PidFile => $pid_file,
ScoreboardFile => $scoreboard_file,
SystemLog => $log_file,
AuthUserFile => $auth_user_file,
AuthGroupFile => $auth_group_file,
AllowOverwrite => 'on',
AllowStoreRestart => 'on',
IfModules => {
'mod_case.c' => {
CaseEngine => 'on',
CaseIgnore => 'on',
CaseLog => $log_file,
},
'mod_delay.c' => {
DelayEngine => 'off',
},
},
};
my ($port, $config_user, $config_group) = config_write($config_file, $config);
# Open pipes, for use between the parent and child processes. Specifically,
# the child will indicate when it's done with its test by writing a message
# to the parent.
my ($rfh, $wfh);
unless (pipe($rfh, $wfh)) {
die("Can't open pipe: $!");
}
my $ex;
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($user, $passwd);
my $conn = $client->appe_raw("TeSt.TxT");
unless ($conn) {
die("APPE TeSt.TxT failed: " . $client->response_code() . " " .
$client->response_msg());
}
my $buf = "Hello again!\n";
$conn->write($buf, length($buf), 25);
eval { $conn->close() };
my $resp_code = $client->response_code();
my $resp_msg = $client->response_msg();
my $expected;
$expected = 226;
$self->assert($expected == $resp_code,
test_msg("Expected $expected, got $resp_code"));
$expected = 'Transfer complete';
$self->assert($expected eq $resp_msg,
test_msg("Expected '$expected', got '$resp_msg'"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($config_file, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($pid_file);
$self->assert_child_ok($pid);
if ($ex) {
die($ex);
}
unlink($log_file);
}
sub caseignore_cwd {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $config_file = "$tmpdir/case.conf";
my $pid_file = File::Spec->rel2abs("$tmpdir/case.pid");
my $scoreboard_file = File::Spec->rel2abs("$tmpdir/case.scoreboard");
my $log_file = File::Spec->rel2abs('tests.log');
my $auth_user_file = File::Spec->rel2abs("$tmpdir/case.passwd");
my $auth_group_file = File::Spec->rel2abs("$tmpdir/case.group");
my $user = 'proftpd';
my $passwd = 'test';
my $group = 'ftpd';
my $home_dir = File::Spec->rel2abs($tmpdir);
my $uid = 500;
my $gid = 500;
my $sub_dir = File::Spec->rel2abs("$tmpdir/subdir");
mkpath($sub_dir);
# Make sure that, if we're running as root, that the home directory has
# permissions/privs set for the account we create
if ($< == 0) {
unless (chmod(0755, $home_dir, $sub_dir)) {
die("Can't set perms on $home_dir to 0755: $!");
}
unless (chown($uid, $gid, $home_dir, $sub_dir)) {
die("Can't set owner of $home_dir to $uid/$gid: $!");
}
}
auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
'/bin/bash');
auth_group_write($auth_group_file, $group, $gid, $user);
my $config = {
PidFile => $pid_file,
ScoreboardFile => $scoreboard_file,
SystemLog => $log_file,
AuthUserFile => $auth_user_file,
AuthGroupFile => $auth_group_file,
IfModules => {
'mod_case.c' => {
CaseEngine => 'on',
CaseIgnore => 'on',
CaseLog => $log_file,
},
'mod_delay.c' => {
DelayEngine => 'off',
},
},
};
my ($port, $config_user, $config_group) = config_write($config_file, $config);
# Open pipes, for use between the parent and child processes. Specifically,
# the child will indicate when it's done with its test by writing a message
# to the parent.
my ($rfh, $wfh);
unless (pipe($rfh, $wfh)) {
die("Can't open pipe: $!");
}
my $ex;
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($user, $passwd);
my ($resp_code, $resp_msg) = $client->cwd('SuBdIr');
my $expected;
$expected = 250;
$self->assert($expected == $resp_code,
test_msg("Expected $expected, got $resp_code"));
$expected = 'CWD command successful';
$self->assert($expected eq $resp_msg,
test_msg("Expected '$expected', got '$resp_msg'"));
($resp_code, $resp_msg) = $client->pwd();
$expected = 257;
$self->assert($expected == $resp_code,
test_msg("Expected $expected, got $resp_code"));
$expected = "\"$sub_dir\" is the current directory";
$self->assert($expected eq $resp_msg,
test_msg("Expected '$expected', got '$resp_msg'"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($config_file, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($pid_file);
$self->assert_child_ok($pid);
if ($ex) {
die($ex);
}
unlink($log_file);
}
sub caseignore_xcwd {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $config_file = "$tmpdir/case.conf";
my $pid_file = File::Spec->rel2abs("$tmpdir/case.pid");
my $scoreboard_file = File::Spec->rel2abs("$tmpdir/case.scoreboard");
my $log_file = File::Spec->rel2abs('tests.log');
my $auth_user_file = File::Spec->rel2abs("$tmpdir/case.passwd");
my $auth_group_file = File::Spec->rel2abs("$tmpdir/case.group");
my $user = 'proftpd';
my $passwd = 'test';
my $group = 'ftpd';
my $home_dir = File::Spec->rel2abs($tmpdir);
my $uid = 500;
my $gid = 500;
my $sub_dir = File::Spec->rel2abs("$tmpdir/subdir");
mkpath($sub_dir);
# Make sure that, if we're running as root, that the home directory has
# permissions/privs set for the account we create
if ($< == 0) {
unless (chmod(0755, $home_dir, $sub_dir)) {
die("Can't set perms on $home_dir to 0755: $!");
}
unless (chown($uid, $gid, $home_dir, $sub_dir)) {
die("Can't set owner of $home_dir to $uid/$gid: $!");
}
}
auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
'/bin/bash');
auth_group_write($auth_group_file, $group, $gid, $user);
my $config = {
PidFile => $pid_file,
ScoreboardFile => $scoreboard_file,
SystemLog => $log_file,
AuthUserFile => $auth_user_file,
AuthGroupFile => $auth_group_file,
IfModules => {
'mod_case.c' => {
CaseEngine => 'on',
CaseIgnore => 'on',
CaseLog => $log_file,
},
'mod_delay.c' => {
DelayEngine => 'off',
},
},
};
my ($port, $config_user, $config_group) = config_write($config_file, $config);
# Open pipes, for use between the parent and child processes. Specifically,
# the child will indicate when it's done with its test by writing a message
# to the parent.
my ($rfh, $wfh);
unless (pipe($rfh, $wfh)) {
die("Can't open pipe: $!");
}
my $ex;
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($user, $passwd);
my ($resp_code, $resp_msg) = $client->xcwd('SuBdIr');
my $expected;
$expected = 250;
$self->assert($expected == $resp_code,
test_msg("Expected $expected, got $resp_code"));
$expected = 'XCWD command successful';
$self->assert($expected eq $resp_msg,
test_msg("Expected '$expected', got '$resp_msg'"));
($resp_code, $resp_msg) = $client->pwd();
$expected = 257;
$self->assert($expected == $resp_code,
test_msg("Expected $expected, got $resp_code"));
$expected = "\"$sub_dir\" is the current directory";
$self->assert($expected eq $resp_msg,
test_msg("Expected '$expected', got '$resp_msg'"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($config_file, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($pid_file);
$self->assert_child_ok($pid);
if ($ex) {
die($ex);
}
unlink($log_file);
}
sub caseignore_dele {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $config_file = "$tmpdir/case.conf";
my $pid_file = File::Spec->rel2abs("$tmpdir/case.pid");
my $scoreboard_file = File::Spec->rel2abs("$tmpdir/case.scoreboard");
my $log_file = File::Spec->rel2abs('tests.log');
my $auth_user_file = File::Spec->rel2abs("$tmpdir/case.passwd");
my $auth_group_file = File::Spec->rel2abs("$tmpdir/case.group");
my $user = 'proftpd';
my $passwd = 'test';
my $group = 'ftpd';
my $home_dir = File::Spec->rel2abs($tmpdir);
my $uid = 500;
my $gid = 500;
# Make sure that, if we're running as root, that the home directory has
# permissions/privs set for the account we create
if ($< == 0) {
unless (chmod(0755, $home_dir)) {
die("Can't set perms on $home_dir to 0755: $!");
}
unless (chown($uid, $gid, $home_dir)) {
die("Can't set owner of $home_dir to $uid/$gid: $!");
}
}
auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
'/bin/bash');
auth_group_write($auth_group_file, $group, $gid, $user);
my $test_file = File::Spec->rel2abs("$home_dir/test.txt");
if (open(my $fh, "> $test_file")) {
print $fh "Hello, World!\n";
unless (close($fh)) {
die("Can't write $test_file: $!");
}
} else {
die("Can't open $test_file: $!");
}
my $config = {
PidFile => $pid_file,
ScoreboardFile => $scoreboard_file,
SystemLog => $log_file,
AuthUserFile => $auth_user_file,
AuthGroupFile => $auth_group_file,
IfModules => {
'mod_case.c' => {
CaseEngine => 'on',
CaseIgnore => 'on',
CaseLog => $log_file,
},
'mod_delay.c' => {
DelayEngine => 'off',
},
},
};
my ($port, $config_user, $config_group) = config_write($config_file, $config);
# Open pipes, for use between the parent and child processes. Specifically,
# the child will indicate when it's done with its test by writing a message
# to the parent.
my ($rfh, $wfh);
unless (pipe($rfh, $wfh)) {
die("Can't open pipe: $!");
}
my $ex;
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($user, $passwd);
my ($resp_code, $resp_msg) = $client->dele('TeSt.TxT');
my $expected;
$expected = 250;
$self->assert($expected == $resp_code,
test_msg("Expected $expected, got $resp_code"));
$expected = 'DELE command successful';
$self->assert($expected eq $resp_msg,
test_msg("Expected '$expected', got '$resp_msg'"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($config_file, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($pid_file);
$self->assert_child_ok($pid);
if ($ex) {
die($ex);
}
unlink($log_file);
}
sub caseignore_mdtm {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $config_file = "$tmpdir/case.conf";
my $pid_file = File::Spec->rel2abs("$tmpdir/case.pid");
my $scoreboard_file = File::Spec->rel2abs("$tmpdir/case.scoreboard");
my $log_file = File::Spec->rel2abs('tests.log');
my $auth_user_file = File::Spec->rel2abs("$tmpdir/case.passwd");
my $auth_group_file = File::Spec->rel2abs("$tmpdir/case.group");
my $user = 'proftpd';
my $passwd = 'test';
my $group = 'ftpd';
my $home_dir = File::Spec->rel2abs($tmpdir);
my $uid = 500;
my $gid = 500;
# Make sure that, if we're running as root, that the home directory has
# permissions/privs set for the account we create
if ($< == 0) {
unless (chmod(0755, $home_dir)) {
die("Can't set perms on $home_dir to 0755: $!");
}
unless (chown($uid, $gid, $home_dir)) {
die("Can't set owner of $home_dir to $uid/$gid: $!");
}
}
auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
'/bin/bash');
auth_group_write($auth_group_file, $group, $gid, $user);
my $test_file = File::Spec->rel2abs("$home_dir/test.txt");
if (open(my $fh, "> $test_file")) {
print $fh "Hello, World!\n";
unless (close($fh)) {
die("Can't write $test_file: $!");
}
} else {
die("Can't open $test_file: $!");
}
my $config = {
PidFile => $pid_file,
ScoreboardFile => $scoreboard_file,
SystemLog => $log_file,
AuthUserFile => $auth_user_file,
AuthGroupFile => $auth_group_file,
IfModules => {
'mod_case.c' => {
CaseEngine => 'on',
CaseIgnore => 'on',
CaseLog => $log_file,
},
'mod_delay.c' => {
DelayEngine => 'off',
},
},
};
my ($port, $config_user, $config_group) = config_write($config_file, $config);
# Open pipes, for use between the parent and child processes. Specifically,
# the child will indicate when it's done with its test by writing a message
# to the parent.
my ($rfh, $wfh);
unless (pipe($rfh, $wfh)) {
die("Can't open pipe: $!");
}
my $ex;
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($user, $passwd);
my ($resp_code, $resp_msg) = $client->mdtm('TeSt.TxT');
my $expected;
$expected = 213;
$self->assert($expected == $resp_code,
test_msg("Expected $expected, got $resp_code"));
$expected = '\d+';
$self->assert(qr/$expected/, $resp_msg,
test_msg("Expected '$expected', got '$resp_msg'"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($config_file, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($pid_file);
$self->assert_child_ok($pid);
if ($ex) {
die($ex);
}
unlink($log_file);
}
sub caseignore_mkd {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $config_file = "$tmpdir/case.conf";
my $pid_file = File::Spec->rel2abs("$tmpdir/case.pid");
my $scoreboard_file = File::Spec->rel2abs("$tmpdir/case.scoreboard");
my $log_file = File::Spec->rel2abs('tests.log');
my $auth_user_file = File::Spec->rel2abs("$tmpdir/case.passwd");
my $auth_group_file = File::Spec->rel2abs("$tmpdir/case.group");
my $user = 'proftpd';
my $passwd = 'test';
my $group = 'ftpd';
my $home_dir = File::Spec->rel2abs($tmpdir);
my $uid = 500;
my $gid = 500;
# Make sure that, if we're running as root, that the home directory has
# permissions/privs set for the account we create
if ($< == 0) {
unless (chmod(0755, $home_dir)) {
die("Can't set perms on $home_dir to 0755: $!");
}
unless (chown($uid, $gid, $home_dir)) {
die("Can't set owner of $home_dir to $uid/$gid: $!");
}
}
auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
'/bin/bash');
auth_group_write($auth_group_file, $group, $gid, $user);
my $test_dir = File::Spec->rel2abs("$home_dir/test.d");
mkpath($test_dir);
my $config = {
PidFile => $pid_file,
ScoreboardFile => $scoreboard_file,
SystemLog => $log_file,
AuthUserFile => $auth_user_file,
AuthGroupFile => $auth_group_file,
IfModules => {
'mod_case.c' => {
CaseEngine => 'on',
CaseIgnore => 'on',
CaseLog => $log_file,
},
'mod_delay.c' => {
DelayEngine => 'off',
},
},
};
my ($port, $config_user, $config_group) = config_write($config_file, $config);
# Open pipes, for use between the parent and child processes. Specifically,
# the child will indicate when it's done with its test by writing a message
# to the parent.
my ($rfh, $wfh);
unless (pipe($rfh, $wfh)) {
die("Can't open pipe: $!");
}
my $ex;
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($user, $passwd);
eval { $client->mkd('TeSt.D') };
unless ($@) {
die("MKD TeSt.D succeeded unexpectedly");
}
my $resp_code = $client->response_code();
my $resp_msg = $client->response_msg();
my $expected;
$expected = 550;
$self->assert($expected == $resp_code,
test_msg("Expected $expected, got $resp_code"));
$expected = 'test.d: File exists';
$self->assert($expected eq $resp_msg,
test_msg("Expected '$expected', got '$resp_msg'"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($config_file, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($pid_file);
$self->assert_child_ok($pid);
if ($ex) {
die($ex);
}
unlink($log_file);
}
sub caseignore_xmkd {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $config_file = "$tmpdir/case.conf";
my $pid_file = File::Spec->rel2abs("$tmpdir/case.pid");
my $scoreboard_file = File::Spec->rel2abs("$tmpdir/case.scoreboard");
my $log_file = File::Spec->rel2abs('tests.log');
my $auth_user_file = File::Spec->rel2abs("$tmpdir/case.passwd");
my $auth_group_file = File::Spec->rel2abs("$tmpdir/case.group");
my $user = 'proftpd';
my $passwd = 'test';
my $group = 'ftpd';
my $home_dir = File::Spec->rel2abs($tmpdir);
my $uid = 500;
my $gid = 500;
# Make sure that, if we're running as root, that the home directory has
# permissions/privs set for the account we create
if ($< == 0) {
unless (chmod(0755, $home_dir)) {
die("Can't set perms on $home_dir to 0755: $!");
}
unless (chown($uid, $gid, $home_dir)) {
die("Can't set owner of $home_dir to $uid/$gid: $!");
}
}
auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
'/bin/bash');
auth_group_write($auth_group_file, $group, $gid, $user);
my $test_dir = File::Spec->rel2abs("$home_dir/test.d");
mkpath($test_dir);
my $config = {
PidFile => $pid_file,
ScoreboardFile => $scoreboard_file,
SystemLog => $log_file,
AuthUserFile => $auth_user_file,
AuthGroupFile => $auth_group_file,
IfModules => {
'mod_case.c' => {
CaseEngine => 'on',
CaseIgnore => 'on',
CaseLog => $log_file,
},
'mod_delay.c' => {
DelayEngine => 'off',
},
},
};
my ($port, $config_user, $config_group) = config_write($config_file, $config);
# Open pipes, for use between the parent and child processes. Specifically,
# the child will indicate when it's done with its test by writing a message
# to the parent.
my ($rfh, $wfh);
unless (pipe($rfh, $wfh)) {
die("Can't open pipe: $!");
}
my $ex;
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($user, $passwd);
eval { $client->xmkd('TeSt.D') };
unless ($@) {
die("XMKD TeSt.D succeeded unexpectedly");
}
my $resp_code = $client->response_code();
my $resp_msg = $client->response_msg();
my $expected;
$expected = 550;
$self->assert($expected == $resp_code,
test_msg("Expected $expected, got $resp_code"));
$expected = 'test.d: File exists';
$self->assert($expected eq $resp_msg,
test_msg("Expected '$expected', got '$resp_msg'"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($config_file, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($pid_file);
$self->assert_child_ok($pid);
if ($ex) {
die($ex);
}
unlink($log_file);
}
sub caseignore_mlsd {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $config_file = "$tmpdir/case.conf";
my $pid_file = File::Spec->rel2abs("$tmpdir/case.pid");
my $scoreboard_file = File::Spec->rel2abs("$tmpdir/case.scoreboard");
my $log_file = File::Spec->rel2abs('tests.log');
my $auth_user_file = File::Spec->rel2abs("$tmpdir/case.passwd");
my $auth_group_file = File::Spec->rel2abs("$tmpdir/case.group");
my $user = 'proftpd';
my $passwd = 'test';
my $group = 'ftpd';
my $home_dir = File::Spec->rel2abs($tmpdir);
my $uid = 500;
my $gid = 500;
# Make sure that, if we're running as root, that the home directory has
# permissions/privs set for the account we create
if ($< == 0) {
unless (chmod(0755, $home_dir)) {
die("Can't set perms on $home_dir to 0755: $!");
}
unless (chown($uid, $gid, $home_dir)) {
die("Can't set owner of $home_dir to $uid/$gid: $!");
}
}
auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
'/bin/bash');
auth_group_write($auth_group_file, $group, $gid, $user);
my $test_dir = File::Spec->rel2abs("$home_dir/test.d");
mkpath($test_dir);
my $config = {
PidFile => $pid_file,
ScoreboardFile => $scoreboard_file,
SystemLog => $log_file,
AuthUserFile => $auth_user_file,
AuthGroupFile => $auth_group_file,
IfModules => {
'mod_case.c' => {
CaseEngine => 'on',
CaseIgnore => 'on',
CaseLog => $log_file,
},
'mod_delay.c' => {
DelayEngine => 'off',
},
},
};
my ($port, $config_user, $config_group) = config_write($config_file, $config);
# Open pipes, for use between the parent and child processes. Specifically,
# the child will indicate when it's done with its test by writing a message
# to the parent.
my ($rfh, $wfh);
unless (pipe($rfh, $wfh)) {
die("Can't open pipe: $!");
}
my $ex;
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($user, $passwd);
my ($resp_code, $resp_msg) = $client->mlsd('TeSt.D');
my $expected;
$expected = 226;
$self->assert($expected == $resp_code,
test_msg("Expected $expected, got $resp_code"));
$expected = 'Transfer complete';
$self->assert($expected eq $resp_msg,
test_msg("Expected '$expected', got '$resp_msg'"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($config_file, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($pid_file);
$self->assert_child_ok($pid);
if ($ex) {
die($ex);
}
unlink($log_file);
}
sub caseignore_mlst {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $config_file = "$tmpdir/case.conf";
my $pid_file = File::Spec->rel2abs("$tmpdir/case.pid");
my $scoreboard_file = File::Spec->rel2abs("$tmpdir/case.scoreboard");
my $log_file = File::Spec->rel2abs('tests.log');
my $auth_user_file = File::Spec->rel2abs("$tmpdir/case.passwd");
my $auth_group_file = File::Spec->rel2abs("$tmpdir/case.group");
my $user = 'proftpd';
my $passwd = 'test';
my $group = 'ftpd';
my $home_dir = File::Spec->rel2abs($tmpdir);
my $uid = 500;
my $gid = 500;
# Make sure that, if we're running as root, that the home directory has
# permissions/privs set for the account we create
if ($< == 0) {
unless (chmod(0755, $home_dir)) {
die("Can't set perms on $home_dir to 0755: $!");
}
unless (chown($uid, $gid, $home_dir)) {
die("Can't set owner of $home_dir to $uid/$gid: $!");
}
}
auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
'/bin/bash');
auth_group_write($auth_group_file, $group, $gid, $user);
my $test_file = File::Spec->rel2abs("$home_dir/test.txt");
if (open(my $fh, "> $test_file")) {
print $fh "Hello, World!\n";
unless (close($fh)) {
die("Can't write $test_file: $!");
}
} else {
die("Can't open $test_file: $!");
}
my $config = {
PidFile => $pid_file,
ScoreboardFile => $scoreboard_file,
SystemLog => $log_file,
AuthUserFile => $auth_user_file,
AuthGroupFile => $auth_group_file,
AllowOverwrite => 'on',
AllowStoreRestart => 'on',
IfModules => {
'mod_case.c' => {
CaseEngine => 'on',
CaseIgnore => 'on',
CaseLog => $log_file,
},
'mod_delay.c' => {
DelayEngine => 'off',
},
},
};
my ($port, $config_user, $config_group) = config_write($config_file, $config);
# Open pipes, for use between the parent and child processes. Specifically,
# the child will indicate when it's done with its test by writing a message
# to the parent.
my ($rfh, $wfh);
unless (pipe($rfh, $wfh)) {
die("Can't open pipe: $!");
}
my $ex;
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($user, $passwd);
my ($resp_code, $resp_msg) = $client->mlst("TeSt.TxT");
my $expected;
$expected = 250;
$self->assert($expected == $resp_code,
test_msg("Expected $expected, got $resp_code"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($config_file, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($pid_file);
$self->assert_child_ok($pid);
if ($ex) {
die($ex);
}
unlink($log_file);
}
sub caseignore_retr {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $config_file = "$tmpdir/case.conf";
my $pid_file = File::Spec->rel2abs("$tmpdir/case.pid");
my $scoreboard_file = File::Spec->rel2abs("$tmpdir/case.scoreboard");
my $log_file = File::Spec->rel2abs('tests.log');
my $auth_user_file = File::Spec->rel2abs("$tmpdir/case.passwd");
my $auth_group_file = File::Spec->rel2abs("$tmpdir/case.group");
my $user = 'proftpd';
my $passwd = 'test';
my $group = 'ftpd';
my $home_dir = File::Spec->rel2abs($tmpdir);
my $uid = 500;
my $gid = 500;
# Make sure that, if we're running as root, that the home directory has
# permissions/privs set for the account we create
if ($< == 0) {
unless (chmod(0755, $home_dir)) {
die("Can't set perms on $home_dir to 0755: $!");
}
unless (chown($uid, $gid, $home_dir)) {
die("Can't set owner of $home_dir to $uid/$gid: $!");
}
}
auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
'/bin/bash');
auth_group_write($auth_group_file, $group, $gid, $user);
my $test_file = File::Spec->rel2abs("$home_dir/test.txt");
if (open(my $fh, "> $test_file")) {
print $fh "Hello, World!\n";
unless (close($fh)) {
die("Can't write $test_file: $!");
}
} else {
die("Can't open $test_file: $!");
}
my $config = {
PidFile => $pid_file,
ScoreboardFile => $scoreboard_file,
SystemLog => $log_file,
AuthUserFile => $auth_user_file,
AuthGroupFile => $auth_group_file,
AllowOverwrite => 'on',
AllowStoreRestart => 'on',
IfModules => {
'mod_case.c' => {
CaseEngine => 'on',
CaseIgnore => 'on',
CaseLog => $log_file,
},
'mod_delay.c' => {
DelayEngine => 'off',
},
},
};
my ($port, $config_user, $config_group) = config_write($config_file, $config);
# Open pipes, for use between the parent and child processes. Specifically,
# the child will indicate when it's done with its test by writing a message
# to the parent.
my ($rfh, $wfh);
unless (pipe($rfh, $wfh)) {
die("Can't open pipe: $!");
}
my $ex;
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($user, $passwd);
my $conn = $client->retr_raw("TeSt.TxT");
unless ($conn) {
die("RETR TeSt.TxT failed: " . $client->response_code() . " " .
$client->response_msg());
}
my $buf;
$conn->read($buf, 25);
eval { $conn->close() };
my $resp_code = $client->response_code();
my $resp_msg = $client->response_msg();
my $expected;
$expected = 226;
$self->assert($expected == $resp_code,
test_msg("Expected $expected, got $resp_code"));
$expected = 'Transfer complete';
$self->assert($expected eq $resp_msg,
test_msg("Expected '$expected', got '$resp_msg'"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($config_file, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($pid_file);
$self->assert_child_ok($pid);
if ($ex) {
die($ex);
}
unlink($log_file);
}
sub caseignore_rmd {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $config_file = "$tmpdir/case.conf";
my $pid_file = File::Spec->rel2abs("$tmpdir/case.pid");
my $scoreboard_file = File::Spec->rel2abs("$tmpdir/case.scoreboard");
my $log_file = File::Spec->rel2abs('tests.log');
my $auth_user_file = File::Spec->rel2abs("$tmpdir/case.passwd");
my $auth_group_file = File::Spec->rel2abs("$tmpdir/case.group");
my $user = 'proftpd';
my $passwd = 'test';
my $group = 'ftpd';
my $home_dir = File::Spec->rel2abs($tmpdir);
my $uid = 500;
my $gid = 500;
# Make sure that, if we're running as root, that the home directory has
# permissions/privs set for the account we create
if ($< == 0) {
unless (chmod(0755, $home_dir)) {
die("Can't set perms on $home_dir to 0755: $!");
}
unless (chown($uid, $gid, $home_dir)) {
die("Can't set owner of $home_dir to $uid/$gid: $!");
}
}
auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
'/bin/bash');
auth_group_write($auth_group_file, $group, $gid, $user);
my $test_dir = File::Spec->rel2abs("$home_dir/test.d");
mkpath($test_dir);
my $config = {
PidFile => $pid_file,
ScoreboardFile => $scoreboard_file,
SystemLog => $log_file,
AuthUserFile => $auth_user_file,
AuthGroupFile => $auth_group_file,
IfModules => {
'mod_case.c' => {
CaseEngine => 'on',
CaseIgnore => 'on',
CaseLog => $log_file,
},
'mod_delay.c' => {
DelayEngine => 'off',
},
},
};
my ($port, $config_user, $config_group) = config_write($config_file, $config);
# Open pipes, for use between the parent and child processes. Specifically,
# the child will indicate when it's done with its test by writing a message
# to the parent.
my ($rfh, $wfh);
unless (pipe($rfh, $wfh)) {
die("Can't open pipe: $!");
}
my $ex;
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($user, $passwd);
my ($resp_code, $resp_msg) = $client->rmd('TeSt.D');
my $expected;
$expected = 250;
$self->assert($expected == $resp_code,
test_msg("Expected $expected, got $resp_code"));
$expected = 'RMD command successful';
$self->assert($expected eq $resp_msg,
test_msg("Expected '$expected', got '$resp_msg'"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($config_file, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($pid_file);
$self->assert_child_ok($pid);
if ($ex) {
die($ex);
}
unlink($log_file);
}
sub caseignore_xrmd {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $config_file = "$tmpdir/case.conf";
my $pid_file = File::Spec->rel2abs("$tmpdir/case.pid");
my $scoreboard_file = File::Spec->rel2abs("$tmpdir/case.scoreboard");
my $log_file = File::Spec->rel2abs('tests.log');
my $auth_user_file = File::Spec->rel2abs("$tmpdir/case.passwd");
my $auth_group_file = File::Spec->rel2abs("$tmpdir/case.group");
my $user = 'proftpd';
my $passwd = 'test';
my $group = 'ftpd';
my $home_dir = File::Spec->rel2abs($tmpdir);
my $uid = 500;
my $gid = 500;
# Make sure that, if we're running as root, that the home directory has
# permissions/privs set for the account we create
if ($< == 0) {
unless (chmod(0755, $home_dir)) {
die("Can't set perms on $home_dir to 0755: $!");
}
unless (chown($uid, $gid, $home_dir)) {
die("Can't set owner of $home_dir to $uid/$gid: $!");
}
}
auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
'/bin/bash');
auth_group_write($auth_group_file, $group, $gid, $user);
my $test_dir = File::Spec->rel2abs("$home_dir/test.d");
mkpath($test_dir);
my $config = {
PidFile => $pid_file,
ScoreboardFile => $scoreboard_file,
SystemLog => $log_file,
AuthUserFile => $auth_user_file,
AuthGroupFile => $auth_group_file,
IfModules => {
'mod_case.c' => {
CaseEngine => 'on',
CaseIgnore => 'on',
CaseLog => $log_file,
},
'mod_delay.c' => {
DelayEngine => 'off',
},
},
};
my ($port, $config_user, $config_group) = config_write($config_file, $config);
# Open pipes, for use between the parent and child processes. Specifically,
# the child will indicate when it's done with its test by writing a message
# to the parent.
my ($rfh, $wfh);
unless (pipe($rfh, $wfh)) {
die("Can't open pipe: $!");
}
my $ex;
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($user, $passwd);
my ($resp_code, $resp_msg) = $client->xrmd('TeSt.D');
my $expected;
$expected = 250;
$self->assert($expected == $resp_code,
test_msg("Expected $expected, got $resp_code"));
$expected = 'XRMD command successful';
$self->assert($expected eq $resp_msg,
test_msg("Expected '$expected', got '$resp_msg'"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($config_file, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($pid_file);
$self->assert_child_ok($pid);
if ($ex) {
die($ex);
}
unlink($log_file);
}
sub caseignore_rnfr {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $config_file = "$tmpdir/case.conf";
my $pid_file = File::Spec->rel2abs("$tmpdir/case.pid");
my $scoreboard_file = File::Spec->rel2abs("$tmpdir/case.scoreboard");
my $log_file = File::Spec->rel2abs('tests.log');
my $auth_user_file = File::Spec->rel2abs("$tmpdir/case.passwd");
my $auth_group_file = File::Spec->rel2abs("$tmpdir/case.group");
my $user = 'proftpd';
my $passwd = 'test';
my $group = 'ftpd';
my $home_dir = File::Spec->rel2abs($tmpdir);
my $uid = 500;
my $gid = 500;
# Make sure that, if we're running as root, that the home directory has
# permissions/privs set for the account we create
if ($< == 0) {
unless (chmod(0755, $home_dir)) {
die("Can't set perms on $home_dir to 0755: $!");
}
unless (chown($uid, $gid, $home_dir)) {
die("Can't set owner of $home_dir to $uid/$gid: $!");
}
}
auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
'/bin/bash');
auth_group_write($auth_group_file, $group, $gid, $user);
my $test_file = File::Spec->rel2abs("$home_dir/test.txt");
if (open(my $fh, "> $test_file")) {
print $fh "Hello, World!\n";
unless (close($fh)) {
die("Can't write $test_file: $!");
}
} else {
die("Can't open $test_file: $!");
}
my $config = {
PidFile => $pid_file,
ScoreboardFile => $scoreboard_file,
SystemLog => $log_file,
AuthUserFile => $auth_user_file,
AuthGroupFile => $auth_group_file,
AllowOverwrite => 'on',
AllowStoreRestart => 'on',
IfModules => {
'mod_case.c' => {
CaseEngine => 'on',
CaseIgnore => 'on',
CaseLog => $log_file,
},
'mod_delay.c' => {
DelayEngine => 'off',
},
},
};
my ($port, $config_user, $config_group) = config_write($config_file, $config);
# Open pipes, for use between the parent and child processes. Specifically,
# the child will indicate when it's done with its test by writing a message
# to the parent.
my ($rfh, $wfh);
unless (pipe($rfh, $wfh)) {
die("Can't open pipe: $!");
}
my $ex;
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($user, $passwd);
my ($resp_code, $resp_msg) = $client->rnfr('TeSt.TxT');
my $expected;
$expected = 350;
$self->assert($expected == $resp_code,
test_msg("Expected $expected, got $resp_code"));
$expected = 'File or directory exists, ready for destination name';
$self->assert($expected eq $resp_msg,
test_msg("Expected '$expected', got '$resp_msg'"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($config_file, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($pid_file);
$self->assert_child_ok($pid);
if ($ex) {
die($ex);
}
unlink($log_file);
}
sub caseignore_rnto {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $config_file = "$tmpdir/case.conf";
my $pid_file = File::Spec->rel2abs("$tmpdir/case.pid");
my $scoreboard_file = File::Spec->rel2abs("$tmpdir/case.scoreboard");
my $log_file = File::Spec->rel2abs('tests.log');
my $auth_user_file = File::Spec->rel2abs("$tmpdir/case.passwd");
my $auth_group_file = File::Spec->rel2abs("$tmpdir/case.group");
my $user = 'proftpd';
my $passwd = 'test';
my $group = 'ftpd';
my $home_dir = File::Spec->rel2abs($tmpdir);
my $uid = 500;
my $gid = 500;
# Make sure that, if we're running as root, that the home directory has
# permissions/privs set for the account we create
if ($< == 0) {
unless (chmod(0755, $home_dir)) {
die("Can't set perms on $home_dir to 0755: $!");
}
unless (chown($uid, $gid, $home_dir)) {
die("Can't set owner of $home_dir to $uid/$gid: $!");
}
}
auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
'/bin/bash');
auth_group_write($auth_group_file, $group, $gid, $user);
my $src_file = File::Spec->rel2abs("$home_dir/test.txt");
if (open(my $fh, "> $src_file")) {
print $fh "Hello, World!\n";
unless (close($fh)) {
die("Can't write $src_file: $!");
}
} else {
die("Can't open $src_file: $!");
}
my $dst_file = File::Spec->rel2abs("$home_dir/dst.txt");
if (open(my $fh, "> $dst_file")) {
print $fh "I'm here.\n";
unless (close($fh)) {
die("Can't write $dst_file: $!");
}
} else {
die("Can't open $dst_file: $!");
}
my $config = {
PidFile => $pid_file,
ScoreboardFile => $scoreboard_file,
SystemLog => $log_file,
AuthUserFile => $auth_user_file,
AuthGroupFile => $auth_group_file,
AllowOverwrite => 'off',
IfModules => {
'mod_case.c' => {
CaseEngine => 'on',
CaseIgnore => 'on',
CaseLog => $log_file,
},
'mod_delay.c' => {
DelayEngine => 'off',
},
},
};
my ($port, $config_user, $config_group) = config_write($config_file, $config);
# Open pipes, for use between the parent and child processes. Specifically,
# the child will indicate when it's done with its test by writing a message
# to the parent.
my ($rfh, $wfh);
unless (pipe($rfh, $wfh)) {
die("Can't open pipe: $!");
}
my $ex;
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($user, $passwd);
my ($resp_code, $resp_msg) = $client->rnfr('TeSt.TxT');
my $expected;
$expected = 350;
$self->assert($expected == $resp_code,
test_msg("Expected $expected, got $resp_code"));
$expected = 'File or directory exists, ready for destination name';
$self->assert($expected eq $resp_msg,
test_msg("Expected '$expected', got '$resp_msg'"));
eval { $client->rnto('DsT.tXt') };
unless ($@) {
die("RNTO DsT.tXt succeeded unexpectedly");
}
$resp_code = $client->response_code();
$resp_msg = $client->response_msg();
$expected = 550;
$self->assert($expected == $resp_code,
test_msg("Expected $expected, got $resp_code"));
$expected = 'dst.txt: Rename permission denied';
$self->assert($expected eq $resp_msg,
test_msg("Expected '$expected', got '$resp_msg'"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($config_file, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($pid_file);
$self->assert_child_ok($pid);
if ($ex) {
die($ex);
}
unlink($log_file);
}
sub caseignore_size {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $config_file = "$tmpdir/case.conf";
my $pid_file = File::Spec->rel2abs("$tmpdir/case.pid");
my $scoreboard_file = File::Spec->rel2abs("$tmpdir/case.scoreboard");
my $log_file = File::Spec->rel2abs('tests.log');
my $auth_user_file = File::Spec->rel2abs("$tmpdir/case.passwd");
my $auth_group_file = File::Spec->rel2abs("$tmpdir/case.group");
my $user = 'proftpd';
my $passwd = 'test';
my $group = 'ftpd';
my $home_dir = File::Spec->rel2abs($tmpdir);
my $uid = 500;
my $gid = 500;
# Make sure that, if we're running as root, that the home directory has
# permissions/privs set for the account we create
if ($< == 0) {
unless (chmod(0755, $home_dir)) {
die("Can't set perms on $home_dir to 0755: $!");
}
unless (chown($uid, $gid, $home_dir)) {
die("Can't set owner of $home_dir to $uid/$gid: $!");
}
}
auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
'/bin/bash');
auth_group_write($auth_group_file, $group, $gid, $user);
my $test_file = File::Spec->rel2abs("$home_dir/test.txt");
if (open(my $fh, "> $test_file")) {
print $fh "Hello, World!\n";
unless (close($fh)) {
die("Can't write $test_file: $!");
}
} else {
die("Can't open $test_file: $!");
}
my $config = {
PidFile => $pid_file,
ScoreboardFile => $scoreboard_file,
SystemLog => $log_file,
AuthUserFile => $auth_user_file,
AuthGroupFile => $auth_group_file,
AllowOverwrite => 'on',
AllowStoreRestart => 'on',
IfModules => {
'mod_case.c' => {
CaseEngine => 'on',
CaseIgnore => 'on',
CaseLog => $log_file,
},
'mod_delay.c' => {
DelayEngine => 'off',
},
},
};
my ($port, $config_user, $config_group) = config_write($config_file, $config);
# Open pipes, for use between the parent and child processes. Specifically,
# the child will indicate when it's done with its test by writing a message
# to the parent.
my ($rfh, $wfh);
unless (pipe($rfh, $wfh)) {
die("Can't open pipe: $!");
}
my $ex;
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($user, $passwd);
$client->type('binary');
my ($resp_code, $resp_msg) = $client->size("TeSt.TxT");
my $expected;
$expected = 213;
$self->assert($expected == $resp_code,
test_msg("Expected $expected, got $resp_code"));
$expected = '14';
$self->assert($expected eq $resp_msg,
test_msg("Expected '$expected', got '$resp_msg'"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($config_file, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($pid_file);
$self->assert_child_ok($pid);
if ($ex) {
die($ex);
}
unlink($log_file);
}
sub caseignore_stat {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $config_file = "$tmpdir/case.conf";
my $pid_file = File::Spec->rel2abs("$tmpdir/case.pid");
my $scoreboard_file = File::Spec->rel2abs("$tmpdir/case.scoreboard");
my $log_file = File::Spec->rel2abs('tests.log');
my $auth_user_file = File::Spec->rel2abs("$tmpdir/case.passwd");
my $auth_group_file = File::Spec->rel2abs("$tmpdir/case.group");
my $user = 'proftpd';
my $passwd = 'test';
my $group = 'ftpd';
my $home_dir = File::Spec->rel2abs($tmpdir);
my $uid = 500;
my $gid = 500;
# Make sure that, if we're running as root, that the home directory has
# permissions/privs set for the account we create
if ($< == 0) {
unless (chmod(0755, $home_dir)) {
die("Can't set perms on $home_dir to 0755: $!");
}
unless (chown($uid, $gid, $home_dir)) {
die("Can't set owner of $home_dir to $uid/$gid: $!");
}
}
auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
'/bin/bash');
auth_group_write($auth_group_file, $group, $gid, $user);
my $test_file = File::Spec->rel2abs("$home_dir/test.txt");
if (open(my $fh, "> $test_file")) {
print $fh "Hello, World!\n";
unless (close($fh)) {
die("Can't write $test_file: $!");
}
} else {
die("Can't open $test_file: $!");
}
my $config = {
PidFile => $pid_file,
ScoreboardFile => $scoreboard_file,
SystemLog => $log_file,
AuthUserFile => $auth_user_file,
AuthGroupFile => $auth_group_file,
AllowOverwrite => 'on',
AllowStoreRestart => 'on',
IfModules => {
'mod_case.c' => {
CaseEngine => 'on',
CaseIgnore => 'on',
CaseLog => $log_file,
},
'mod_delay.c' => {
DelayEngine => 'off',
},
},
};
my ($port, $config_user, $config_group) = config_write($config_file, $config);
# Open pipes, for use between the parent and child processes. Specifically,
# the child will indicate when it's done with its test by writing a message
# to the parent.
my ($rfh, $wfh);
unless (pipe($rfh, $wfh)) {
die("Can't open pipe: $!");
}
my $ex;
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($user, $passwd);
my ($resp_code, $resp_msg) = $client->stat("TeSt.TxT");
my $expected;
$expected = 211;
$self->assert($expected == $resp_code,
test_msg("Expected $expected, got $resp_code"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($config_file, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($pid_file);
$self->assert_child_ok($pid);
if ($ex) {
die($ex);
}
unlink($log_file);
}
sub caseignore_stor {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $config_file = "$tmpdir/case.conf";
my $pid_file = File::Spec->rel2abs("$tmpdir/case.pid");
my $scoreboard_file = File::Spec->rel2abs("$tmpdir/case.scoreboard");
my $log_file = File::Spec->rel2abs('tests.log');
my $auth_user_file = File::Spec->rel2abs("$tmpdir/case.passwd");
my $auth_group_file = File::Spec->rel2abs("$tmpdir/case.group");
my $user = 'proftpd';
my $passwd = 'test';
my $group = 'ftpd';
my $home_dir = File::Spec->rel2abs($tmpdir);
my $uid = 500;
my $gid = 500;
# Make sure that, if we're running as root, that the home directory has
# permissions/privs set for the account we create
if ($< == 0) {
unless (chmod(0755, $home_dir)) {
die("Can't set perms on $home_dir to 0755: $!");
}
unless (chown($uid, $gid, $home_dir)) {
die("Can't set owner of $home_dir to $uid/$gid: $!");
}
}
auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
'/bin/bash');
auth_group_write($auth_group_file, $group, $gid, $user);
my $test_file = File::Spec->rel2abs("$home_dir/test.txt");
if (open(my $fh, "> $test_file")) {
print $fh "Hello, World!\n";
unless (close($fh)) {
die("Can't write $test_file: $!");
}
} else {
die("Can't open $test_file: $!");
}
my $config = {
PidFile => $pid_file,
ScoreboardFile => $scoreboard_file,
SystemLog => $log_file,
AuthUserFile => $auth_user_file,
AuthGroupFile => $auth_group_file,
AllowOverwrite => 'on',
AllowStoreRestart => 'on',
IfModules => {
'mod_case.c' => {
CaseEngine => 'on',
CaseIgnore => 'on',
CaseLog => $log_file,
},
'mod_delay.c' => {
DelayEngine => 'off',
},
},
};
my ($port, $config_user, $config_group) = config_write($config_file, $config);
# Open pipes, for use between the parent and child processes. Specifically,
# the child will indicate when it's done with its test by writing a message
# to the parent.
my ($rfh, $wfh);
unless (pipe($rfh, $wfh)) {
die("Can't open pipe: $!");
}
my $ex;
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($user, $passwd);
my $conn = $client->stor_raw("TeSt.TxT");
unless ($conn) {
die("STOR TeSt.TxT failed: " . $client->response_code() . " " .
$client->response_msg());
}
my $buf = "Hello again!\n";
$conn->write($buf, length($buf), 25);
eval { $conn->close() };
my $resp_code = $client->response_code();
my $resp_msg = $client->response_msg();
my $expected;
$expected = 226;
$self->assert($expected == $resp_code,
test_msg("Expected $expected, got $resp_code"));
$expected = 'Transfer complete';
$self->assert($expected eq $resp_msg,
test_msg("Expected '$expected', got '$resp_msg'"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($config_file, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($pid_file);
$self->assert_child_ok($pid);
if ($ex) {
die($ex);
}
unlink($log_file);
}
sub caseignore_list {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $config_file = "$tmpdir/case.conf";
my $pid_file = File::Spec->rel2abs("$tmpdir/case.pid");
my $scoreboard_file = File::Spec->rel2abs("$tmpdir/case.scoreboard");
my $log_file = File::Spec->rel2abs('tests.log');
my $auth_user_file = File::Spec->rel2abs("$tmpdir/case.passwd");
my $auth_group_file = File::Spec->rel2abs("$tmpdir/case.group");
my $user = 'proftpd';
my $passwd = 'test';
my $group = 'ftpd';
my $home_dir = File::Spec->rel2abs($tmpdir);
my $uid = 500;
my $gid = 500;
my $sub_dir = File::Spec->rel2abs("$tmpdir/subdir");
mkpath($sub_dir);
# Make sure that, if we're running as root, that the home directory has
# permissions/privs set for the account we create
if ($< == 0) {
unless (chmod(0755, $home_dir, $sub_dir)) {
die("Can't set perms on $home_dir to 0755: $!");
}
unless (chown($uid, $gid, $home_dir, $sub_dir)) {
die("Can't set owner of $home_dir to $uid/$gid: $!");
}
}
auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
'/bin/bash');
auth_group_write($auth_group_file, $group, $gid, $user);
my $config = {
PidFile => $pid_file,
ScoreboardFile => $scoreboard_file,
SystemLog => $log_file,
AuthUserFile => $auth_user_file,
AuthGroupFile => $auth_group_file,
IfModules => {
'mod_case.c' => {
CaseEngine => 'on',
CaseIgnore => 'on',
CaseLog => $log_file,
},
'mod_delay.c' => {
DelayEngine => 'off',
},
},
};
my ($port, $config_user, $config_group) = config_write($config_file, $config);
# Open pipes, for use between the parent and child processes. Specifically,
# the child will indicate when it's done with its test by writing a message
# to the parent.
my ($rfh, $wfh);
unless (pipe($rfh, $wfh)) {
die("Can't open pipe: $!");
}
my $ex;
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($user, $passwd);
my $conn = $client->list_raw('-a -l SuBdIr');
unless ($conn) {
die("Failed to LIST: " . $client->response_code() . " " .
$client->response_msg());
}
my $buf;
$conn->read($buf, 8192, 25);
eval { $conn->close() };
my $resp_code = $client->response_code();
my $resp_msg = $client->response_msg();
my $expected;
$expected = 226;
$self->assert($expected == $resp_code,
test_msg("Expected $expected, got $resp_code"));
$expected = 'Transfer complete';
$self->assert($expected eq $resp_msg,
test_msg("Expected '$expected', got '$resp_msg'"));
# We have to be careful of the fact that readdir returns directory
# entries in an unordered fashion.
my $res = {};
my $lines = [split(/\n/, $buf)];
foreach my $line (@$lines) {
if ($line =~ /^\S+\s+\d+\s+\S+\s+\S+\s+.*?\s+(\S+)$/) {
$res->{$1} = 1;
}
}
my $expected = {
'.' => 1,
'..' => 1,
};
my $ok = 1;
my $mismatch;
foreach my $name (keys(%$res)) {
unless (defined($expected->{$name})) {
$mismatch = $name;
$ok = 0;
last;
}
}
$self->assert($ok,
test_msg("Unexpected name '$mismatch' appeared in LIST data"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($config_file, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($pid_file);
$self->assert_child_ok($pid);
if ($ex) {
die($ex);
}
unlink($log_file);
}
sub caseignore_nlst {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $config_file = "$tmpdir/case.conf";
my $pid_file = File::Spec->rel2abs("$tmpdir/case.pid");
my $scoreboard_file = File::Spec->rel2abs("$tmpdir/case.scoreboard");
my $log_file = File::Spec->rel2abs('tests.log');
my $auth_user_file = File::Spec->rel2abs("$tmpdir/case.passwd");
my $auth_group_file = File::Spec->rel2abs("$tmpdir/case.group");
my $user = 'proftpd';
my $passwd = 'test';
my $group = 'ftpd';
my $home_dir = File::Spec->rel2abs($tmpdir);
my $uid = 500;
my $gid = 500;
my $sub_dir = File::Spec->rel2abs("$tmpdir/subdir");
mkpath($sub_dir);
# Make sure that, if we're running as root, that the home directory has
# permissions/privs set for the account we create
if ($< == 0) {
unless (chmod(0755, $home_dir, $sub_dir)) {
die("Can't set perms on $home_dir to 0755: $!");
}
unless (chown($uid, $gid, $home_dir, $sub_dir)) {
die("Can't set owner of $home_dir to $uid/$gid: $!");
}
}
auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
'/bin/bash');
auth_group_write($auth_group_file, $group, $gid, $user);
my $config = {
PidFile => $pid_file,
ScoreboardFile => $scoreboard_file,
SystemLog => $log_file,
AuthUserFile => $auth_user_file,
AuthGroupFile => $auth_group_file,
IfModules => {
'mod_case.c' => {
CaseEngine => 'on',
CaseIgnore => 'on',
CaseLog => $log_file,
},
'mod_delay.c' => {
DelayEngine => 'off',
},
},
};
my ($port, $config_user, $config_group) = config_write($config_file, $config);
# Open pipes, for use between the parent and child processes. Specifically,
# the child will indicate when it's done with its test by writing a message
# to the parent.
my ($rfh, $wfh);
unless (pipe($rfh, $wfh)) {
die("Can't open pipe: $!");
}
my $ex;
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($user, $passwd);
my $conn = $client->nlst_raw('-a -l SuBdIr');
unless ($conn) {
die("Failed to NLST: " . $client->response_code() . " " .
$client->response_msg());
}
my $buf;
$conn->read($buf, 8192, 25);
eval { $conn->close() };
my $resp_code = $client->response_code();
my $resp_msg = $client->response_msg();
my $expected;
$expected = 226;
$self->assert($expected == $resp_code,
test_msg("Expected $expected, got $resp_code"));
$expected = 'Transfer complete';
$self->assert($expected eq $resp_msg,
test_msg("Expected '$expected', got '$resp_msg'"));
# We have to be careful of the fact that readdir returns directory
# entries in an unordered fashion.
my $res = {};
my $lines = [split(/\n/, $buf)];
foreach my $line (@$lines) {
$res->{$line} = 1;
}
my $expected = {
'subdir/.' => 1,
'subdir/..' => 1,
};
my $ok = 1;
my $mismatch;
foreach my $name (keys(%$res)) {
unless (defined($expected->{$name})) {
$mismatch = $name;
$ok = 0;
last;
}
}
$self->assert($ok,
test_msg("Unexpected name '$mismatch' appeared in LIST data"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($config_file, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($pid_file);
$self->assert_child_ok($pid);
if ($ex) {
die($ex);
}
unlink($log_file);
}
sub caseignore_list_extlog_var_r {
my $self = shift;
my $tmpdir = $self->{tmpdir};
my $config_file = "$tmpdir/case.conf";
my $pid_file = File::Spec->rel2abs("$tmpdir/case.pid");
my $scoreboard_file = File::Spec->rel2abs("$tmpdir/case.scoreboard");
my $log_file = File::Spec->rel2abs('tests.log');
my $auth_user_file = File::Spec->rel2abs("$tmpdir/case.passwd");
my $auth_group_file = File::Spec->rel2abs("$tmpdir/case.group");
my $user = 'proftpd';
my $passwd = 'test';
my $group = 'ftpd';
my $home_dir = File::Spec->rel2abs($tmpdir);
my $uid = 500;
my $gid = 500;
my $sub_dir = File::Spec->rel2abs("$tmpdir/subdir");
mkpath($sub_dir);
# Make sure that, if we're running as root, that the home directory has
# permissions/privs set for the account we create
if ($< == 0) {
unless (chmod(0755, $home_dir, $sub_dir)) {
die("Can't set perms on $home_dir to 0755: $!");
}
unless (chown($uid, $gid, $home_dir, $sub_dir)) {
die("Can't set owner of $home_dir to $uid/$gid: $!");
}
}
auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
'/bin/bash');
auth_group_write($auth_group_file, $group, $gid, $user);
my $ext_log = File::Spec->rel2abs("$tmpdir/custom.log");
my $config = {
PidFile => $pid_file,
ScoreboardFile => $scoreboard_file,
SystemLog => $log_file,
AuthUserFile => $auth_user_file,
AuthGroupFile => $auth_group_file,
DefaultRoot => '~',
LogFormat => 'custom "%r"',
ExtendedLog => "$ext_log DIRS custom",
IfModules => {
'mod_case.c' => {
CaseEngine => 'on',
CaseIgnore => 'on',
CaseLog => $log_file,
},
'mod_delay.c' => {
DelayEngine => 'off',
},
},
};
my ($port, $config_user, $config_group) = config_write($config_file, $config);
# Open pipes, for use between the parent and child processes. Specifically,
# the child will indicate when it's done with its test by writing a message
# to the parent.
my ($rfh, $wfh);
unless (pipe($rfh, $wfh)) {
die("Can't open pipe: $!");
}
my $ex;
# Fork child
$self->handle_sigchld();
defined(my $pid = fork()) or die("Can't fork: $!");
if ($pid) {
eval {
my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
$client->login($user, $passwd);
my $conn = $client->list_raw('/SuBdIr');
unless ($conn) {
die("Failed to LIST: " . $client->response_code() . " " .
$client->response_msg());
}
my $buf;
$conn->read($buf, 8192, 25);
eval { $conn->close() };
my $resp_code = $client->response_code();
my $resp_msg = $client->response_msg();
my $expected;
$expected = 226;
$self->assert($expected == $resp_code,
test_msg("Expected $expected, got $resp_code"));
$expected = 'Transfer complete';
$self->assert($expected eq $resp_msg,
test_msg("Expected '$expected', got '$resp_msg'"));
# We have to be careful of the fact that readdir returns directory
# entries in an unordered fashion.
my $res = {};
my $lines = [split(/\n/, $buf)];
foreach my $line (@$lines) {
if ($line =~ /^\S+\s+\d+\s+\S+\s+\S+\s+.*?\s+(\S+)$/) {
$res->{$1} = 1;
}
}
my $expected = {
'.' => 1,
'..' => 1,
};
my $ok = 1;
my $mismatch;
foreach my $name (keys(%$res)) {
unless (defined($expected->{$name})) {
$mismatch = $name;
$ok = 0;
last;
}
}
$self->assert($ok,
test_msg("Unexpected name '$mismatch' appeared in LIST data"));
};
if ($@) {
$ex = $@;
}
$wfh->print("done\n");
$wfh->flush();
} else {
eval { server_wait($config_file, $rfh) };
if ($@) {
warn($@);
exit 1;
}
exit 0;
}
# Stop server
server_stop($pid_file);
$self->assert_child_ok($pid);
if ($ex) {
die($ex);
}
# Now, read in the ExtendedLog, and see whether the %r variable was
# properly written out.
if (open(my $fh, "< $ext_log")) {
my $line = <$fh>;
chomp($line);
close($fh);
my $expected = 'LIST /subdir';
$self->assert($expected eq $line,
test_msg("Expected '$expected', got '$line'"));
} else {
die("Can't read $ext_log: $!");
}
unlink($log_file);
}
1;
mod_case/t/modules/ 0000755 0001750 0001750 00000000000 11555364206 012366 5 ustar tj tj mod_case/t/modules/mod_case/ 0000755 0001750 0001750 00000000000 11560341276 014136 5 ustar tj tj mod_case/t/modules/mod_case/sftp.t 0000644 0001750 0001750 00000000272 11547155647 015312 0 ustar tj tj #!/usr/bin/env perl
use lib qw(t/lib);
use strict;
use Test::Unit::HarnessUnit;
$| = 1;
my $r = Test::Unit::HarnessUnit->new();
$r->start("ProFTPD::Tests::Modules::mod_case::sftp");
mod_case/t/modules/mod_case.t 0000644 0001750 0001750 00000000264 11555364206 014327 0 ustar tj tj #!/usr/bin/env perl
use lib qw(t/lib);
use strict;
use Test::Unit::HarnessUnit;
$| = 1;
my $r = Test::Unit::HarnessUnit->new();
$r->start("ProFTPD::Tests::Modules::mod_case");