这是上一个问题的更难版本chroot 目录组件的所有权或模式不正确。
在另一个问题中,我们了解到,如果用户主目录具有正常权限,openssh 会拒绝将用户 chroot 到其自己的主目录。相反,您必须将 root 设置为用户主目录的所有者。这可以防止用户上传到其自己的主目录。
我正在使用一个我将简称为的程序stupid_legacy_application
,SLA
它希望通过 sftp 上传将其输出发送给我。它坚持要上传到(在客户端看来是)根目录。上传失败并在服务器日志中留下这些消息:
Jun 17 18:05:53 sftphost sftp-server[29031]: open "/SLA\\SLA_Data_ 2018617_18551.zip" flags WRITE,CREATE,TRUNCATE mode 0666
Jun 17 18:05:53 sftphost sftp-server[29031]: sent status Permission denied
请注意路径中斜杠和反斜杠的混合。我猜它是用来与某个 Windows sftp 服务器通信的,并且/SLA
应该是一个目录。
如果我不 chroot 用户,它会尝试上传到真正的根目录并失败。如果我 chroot 用户并且不将目录 chown 设置为 root,sshd 不会允许登录。如果我 chroot 用户并将目录 chown 设置为 root,它会再次失败。如果我通过组或世界位为用户添加写权限,sshd 不会允许登录。
我甚至尝试用 ACL 来欺骗它,以为 sshd 不会注意到传统权限之外的任何内容,但这只是在欺骗自己(请参阅这个问题为什么它不起作用)。
重新编译 sshd 并破解目录权限检查似乎是解决此问题的唯一方法。还有其他方法吗?它不需要干净,因为我只需要它工作一次,并且服务器是一次性虚拟机。
答案1
我找到了几个解决这个问题的办法,大部分办法都是因为我愿意在上传完这个文件后就扔掉服务器,所以才有用的。但有一个办法我觉得还算合理。
最丑陋的解决方案:
坏主意 #1 - 忘记 chroot 和chmod 777 /
。Openssh 仅在您 chroot 时检查合理的权限。
坏主意 #2 - 允许客户端写入真实根目录(如坏主意 #1 中一样)可以通过组权限或用户 ACL 更巧妙地完成。
坏主意 #3 - 正如我在问题中所写,可以从 sshd 中破解权限检查。只需bad ownership or modes for chroot
在源中搜索错误消息,将附近的更改022
为002
,它就不会再注意到 chroot 上松散的组权限和 ACL。
好主意(?)——那个反斜杠是问题的根源。如果客户端只是上传/SLA/SLA_Data_blah_blah.zip
所有内容就没问题了。因此,让我们通过包装系统调用,在它到达文件系统的位置修复反斜杠open
:
/* wrapopen.c */
#define _GNU_SOURCE
#include <string.h>
#include <sys/types.h>
#include <dlfcn.h>
static int (*libc_open)(const char *, int, mode_t);
/* Behave like normal open() but translate backslashes to slashes. */
int open(const char *fn, int flags, mode_t mode)
{
char fn_fixed[strlen(fn)+1], *p;
strcpy(fn_fixed, fn);
for(p=fn_fixed;*p;++p)
if(*p == '\\')
*p = '/';
if(!libc_open)
libc_open = dlsym(RTLD_NEXT, "open");
return libc_open(fn_fixed, flags, mode);
}
用法:
$ gcc -fPIC -shared wrapopen.c -o wrapopen.so -ldl
$ /etc/init.d/ssh stop
$ LD_PRELOAD=$PWD/wrapopen.so /usr/sbin/sshd
现在,当 sshd 尝试创建时,SLA\SLA_Data_blah_blah
它实际上会创建SLA/SLA_Data_blah_blah
。用户可以被 chroot,chroot 由 root 模式 755 拥有,SLA
chroot 下的目录由用户拥有,并且上传有效。