Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue #23: Update mod_vroot to tweak various commands when dealing wi… #25

Merged
merged 1 commit into from
Aug 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ mod_vroot.h
*.lo
*.log
*Tests*.log
*.a
*.o
*~
245 changes: 215 additions & 30 deletions mod_vroot.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* ProFTPD: mod_vroot -- a module implementing a virtual chroot capability
* via the FSIO API
* Copyright (c) 2002-2019 TJ Saunders
* Copyright (c) 2002-2021 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
Expand Down Expand Up @@ -41,6 +41,7 @@ unsigned int vroot_opts = 0;
module vroot_module;

static int vroot_engine = FALSE;
static const char *trace_channel = "vroot";

#if PROFTPD_VERSION_NUMBER >= 0x0001030407
static int vroot_use_mkdtemp = FALSE;
Expand Down Expand Up @@ -242,19 +243,20 @@ MODRET set_vrootserverroot(cmd_rec *cmd) {
/* Command handlers
*/

MODRET vroot_log_retr(cmd_rec *cmd) {
const char *key, *path;

if (vroot_engine == FALSE ||
session.chroot_path == NULL) {
return PR_DECLINED(cmd);
}

key = "mod_xfer.retr-path";
static const char *vroot_cmd_fixup_path(cmd_rec *cmd, const char *key,
int use_best_path) {
const char *path;
char *real_path = NULL;

path = pr_table_get(cmd->notes, key, NULL);
if (path != NULL) {
char *real_path;
if (use_best_path == TRUE) {
/* Only needed for mod_sftp sessions, to do what mod_xfer does for FTP
* commands, but in a way that does not require mod_sftp changes.
* Probably too clever.
*/
path = dir_best_path(cmd->pool, path);
}

if (*path == '/') {
const char *base_path;
Expand All @@ -267,43 +269,209 @@ MODRET vroot_log_retr(cmd_rec *cmd) {
real_path = vroot_realpath(cmd->pool, path, VROOT_REALPATH_FL_ABS_PATH);
}

pr_trace_msg(trace_channel, 17,
"fixed up '%s' path in command %s; was '%s', now '%s'", key,
(char *) cmd->argv[0], path, real_path);
pr_table_set(cmd->notes, key, real_path, 0);
}

return real_path;
}

MODRET vroot_pre_scp_retr(cmd_rec *cmd) {
const char *key, *proto, *real_path;

if (vroot_engine == FALSE ||
session.chroot_path == NULL) {
return PR_DECLINED(cmd);
}

/* As a PRE_CMD handler, we only run for SCP sessions. */
proto = pr_session_get_protocol(0);
if (strcmp(proto, "scp") != 0) {
return PR_DECLINED(cmd);
}

/* Unlike SFTP sessions, mod_sftp does NOT set these cmd->notes for SCP
* sessions before doing the PRE_CMD dispatching. So we do it ourselves,
* pre-emptively, before using our other machinery.
*/
key = "mod_xfer.retr-path";
(void) pr_table_add(cmd->notes, key, pstrdup(cmd->pool, cmd->arg), 0);

real_path = vroot_cmd_fixup_path(cmd, key, TRUE);
if (real_path != NULL) {
/* In addition, for SCP sessions, we modify cmd->arg as well, for
* mod_sftp's benefit.
*/
cmd->arg = (char *) real_path;
}

return PR_DECLINED(cmd);
}

MODRET vroot_log_stor(cmd_rec *cmd) {
const char *key, *path;
MODRET vroot_pre_sftp_retr(cmd_rec *cmd) {
const char *key, *proto, *real_path;

if (vroot_engine == FALSE ||
session.chroot_path == NULL) {
return PR_DECLINED(cmd);
}

key = "mod_xfer.store-path";
/* As a PRE_CMD handler, we only run for SFTP sessions. */
proto = pr_session_get_protocol(0);
if (strcmp(proto, "sftp") != 0) {
return PR_DECLINED(cmd);
}

key = "mod_xfer.retr-path";
real_path = vroot_cmd_fixup_path(cmd, key, TRUE);
if (real_path != NULL) {
/* In addition, for SFTP sessions, we modify cmd->arg as well, for
* mod_sftp's benefit.
*/
cmd->arg = (char *) real_path;
}

return PR_DECLINED(cmd);
}

MODRET vroot_post_sftp_retr(cmd_rec *cmd) {
const char *key, *path, *proto;

if (vroot_engine == FALSE ||
session.chroot_path == NULL) {
return PR_DECLINED(cmd);
}

/* As a POST_CMD handler, we only run for SFTP sessions. */
proto = pr_session_get_protocol(0);
if (strcmp(proto, "sftp") != 0) {
return PR_DECLINED(cmd);
}

key = "mod_xfer.retr-path";
path = pr_table_get(cmd->notes, key, NULL);
if (path != NULL) {
char *real_path;
/* In addition, for SFTP sessions, we modify session.xfer.path as well,
* for mod_xfer's benefit in TransferLog entries.
*/
session.xfer.path = pstrdup(session.xfer.p, path);
}

if (*path == '/') {
const char *base_path;
return PR_DECLINED(cmd);
}

base_path = vroot_path_get_base(cmd->tmp_pool, NULL);
real_path = pdircat(cmd->pool, base_path, path, NULL);
vroot_path_clean(real_path);
MODRET vroot_log_retr(cmd_rec *cmd) {
const char *key;

} else {
real_path = vroot_realpath(cmd->pool, path, VROOT_REALPATH_FL_ABS_PATH);
}
if (vroot_engine == FALSE ||
session.chroot_path == NULL) {
return PR_DECLINED(cmd);
}

pr_table_set(cmd->notes, key, real_path, 0);
key = "mod_xfer.retr-path";
(void) vroot_cmd_fixup_path(cmd, key, FALSE);
return PR_DECLINED(cmd);
}

MODRET vroot_pre_scp_stor(cmd_rec *cmd) {
const char *key, *proto, *real_path;

if (vroot_engine == FALSE ||
session.chroot_path == NULL) {
return PR_DECLINED(cmd);
}

/* As a PRE_CMD handler, we only run for SCP sessions. */
proto = pr_session_get_protocol(0);
if (strcmp(proto, "scp") != 0) {
return PR_DECLINED(cmd);
}

/* Unlike SFTP sessions, mod_sftp does NOT set these cmd->notes for SCP
* sessions before doing the PRE_CMD dispatching. So we do it ourselves,
* pre-emptively, before using our other machinery.
*/
key = "mod_xfer.store-path";
(void) pr_table_add(cmd->notes, key, pstrdup(cmd->pool, cmd->arg), 0);

real_path = vroot_cmd_fixup_path(cmd, key, TRUE);
if (real_path != NULL) {
/* In addition, for SCP sessions, we modify cmd->arg as well, for
* mod_sftp's benefit.
*/
cmd->arg = (char *) real_path;
}

return PR_DECLINED(cmd);
}

MODRET vroot_pre_sftp_stor(cmd_rec *cmd) {
const char *key, *proto, *real_path;

if (vroot_engine == FALSE ||
session.chroot_path == NULL) {
return PR_DECLINED(cmd);
}

/* As a PRE_CMD handler, we only run for SFTP sessions. */
proto = pr_session_get_protocol(0);
if (strcmp(proto, "sftp") != 0) {
return PR_DECLINED(cmd);
}

key = "mod_xfer.store-path";
real_path = vroot_cmd_fixup_path(cmd, key, TRUE);
if (real_path != NULL) {
/* In addition, for SFTP sessions, we modify cmd->arg as well, for
* mod_sftp's benefit.
*/
cmd->arg = (char *) real_path;
}

return PR_DECLINED(cmd);
}

MODRET vroot_post_sftp_stor(cmd_rec *cmd) {
const char *key, *path, *proto;

if (vroot_engine == FALSE ||
session.chroot_path == NULL) {
return PR_DECLINED(cmd);
}

/* As a POST_CMD handler, we only run for SFTP sessions. */
proto = pr_session_get_protocol(0);
if (strcmp(proto, "sftp") != 0) {
return PR_DECLINED(cmd);
}

key = "mod_xfer.store-path";
path = pr_table_get(cmd->notes, key, NULL);
if (path != NULL) {
/* In addition, for SFTP sessions, we modify session.xfer.path as well,
* for mod_xfer's benefit in TransferLog entries.
*/
session.xfer.path = pstrdup(session.xfer.p, path);
}

return PR_DECLINED(cmd);
}

MODRET vroot_log_stor(cmd_rec *cmd) {
const char *key;

if (vroot_engine == FALSE ||
session.chroot_path == NULL) {
return PR_DECLINED(cmd);
}

key = "mod_xfer.store-path";
(void) vroot_cmd_fixup_path(cmd, key, FALSE);
return PR_DECLINED(cmd);
}

MODRET vroot_pre_mkd(cmd_rec *cmd) {
if (vroot_engine == FALSE ||
session.chroot_path == NULL) {
Expand Down Expand Up @@ -527,12 +695,13 @@ static cmdtable vroot_cmdtab[] = {
/* These command handlers are for manipulating cmd->notes, to get
* paths properly logged.
*
* Ideally these would be LOG_CMD/LOG_CMD_ERR phase handlers. HOWEVER,
* we need to transform things before the cmd is dispatched to mod_log,
* and mod_log uses a C_ANY handler for logging. And when dispatching,
* C_ANY handlers are run before named handlers. This means that using
* LOG_CMD/LOG_CMD_ERR handlers would be run AFTER mod_log's handler,
* even though we appear BEFORE mod_log in the module load order.
* Ideally these POST_CMD handlers would be LOG_CMD/LOG_CMD_ERR phase
* handlers. HOWEVER, we need to transform things before the cmd is
* dispatched to mod_log, and mod_log uses a C_ANY handler for logging.
* And when dispatching, C_ANY handlers are run before named handlers.
* This means that using * LOG_CMD/LOG_CMD_ERR handlers would be run AFTER
* mod_log's handler, even though we appear BEFORE mod_log in the module
* load order.
*
* Thus to do the transformation, we actually use CMD/POST_CMD_ERR phase
* handlers here. The reason to use CMD, rather than POST_CMD, is the
Expand All @@ -549,6 +718,22 @@ static cmdtable vroot_cmdtab[] = {
{ CMD, C_STOR, G_NONE, vroot_log_stor, FALSE, FALSE, CL_WRITE },
{ POST_CMD_ERR, C_STOR, G_NONE, vroot_log_stor, FALSE, FALSE },

/* To make this more complicated, we DO actually want these handlers to
* run as PRE_CMD handlers, but only for mod_sftp sessions. Why? The
* mod_sftp module does not use the normal CMD handlers; it handles
* dispatching on its own. And we do still want mod_vroot to fix up
* the paths properly for SFTP/SCP sessions, too.
*/
{ PRE_CMD, C_APPE, G_NONE, vroot_pre_sftp_stor, FALSE, FALSE, CL_WRITE },
{ POST_CMD, C_APPE, G_NONE, vroot_post_sftp_stor, FALSE, FALSE },
{ PRE_CMD, C_RETR, G_NONE, vroot_pre_sftp_retr, FALSE, FALSE, CL_READ },
{ POST_CMD, C_RETR, G_NONE, vroot_post_sftp_retr, FALSE, FALSE },
{ PRE_CMD, C_STOR, G_NONE, vroot_pre_sftp_stor, FALSE, FALSE, CL_WRITE },
{ POST_CMD, C_STOR, G_NONE, vroot_post_sftp_stor, FALSE, FALSE },

{ PRE_CMD, C_RETR, G_NONE, vroot_pre_scp_retr, FALSE, FALSE, CL_READ },
{ PRE_CMD, C_STOR, G_NONE, vroot_pre_scp_stor, FALSE, FALSE, CL_WRITE },

{ 0, NULL }
};

Expand Down
2 changes: 1 addition & 1 deletion mod_vroot.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

#include "conf.h"

#define MOD_VROOT_VERSION "mod_vroot/0.9.8"
#define MOD_VROOT_VERSION "mod_vroot/0.9.9"

/* Make sure the version of proftpd is as necessary. */
#if PROFTPD_VERSION_NUMBER < 0x0001030602
Expand Down
3 changes: 1 addition & 2 deletions t/lib/ProFTPD/Tests/Modules/mod_vroot.pm
Original file line number Diff line number Diff line change
Expand Up @@ -10313,15 +10313,14 @@ sub vroot_log_extlog_stor {
auth_group_write($auth_group_file, $group, $gid, $user);

my $test_file = File::Spec->rel2abs("$tmpdir/test.txt");

my $ext_log = File::Spec->rel2abs("$tmpdir/custom.log");

my $config = {
PidFile => $pid_file,
ScoreboardFile => $scoreboard_file,
SystemLog => $log_file,
TraceLog => $log_file,
Trace => 'fsio:10',
Trace => 'fsio:10 jot:20 vroot:20',

AuthUserFile => $auth_user_file,
AuthGroupFile => $auth_group_file,
Expand Down
Loading