我试图将bash作为embedded式设备(Synology DS212 + NAS)上运行的ARM Linux的默认shell安装。 但是有些事情是错的,我不知道它是什么。
症状:
1)Root有/ bin / bash作为默认shell,可以通过SSH正常login:
$ grep root /etc/passwd root:x:0:0:root:/root:/bin/bash $ ssh root@NAS root@NAS's password: Last login: Sun Dec 16 14:06:56 2012 from desktop #
2)joeuser将/ bin / bash作为默认shell,并在尝试通过SSHlogin时收到“Permission denied”
$ grep joeuser /etc/passwd joeuser:x:1029:100:Joe User:/home/joeuser:/bin/bash $ ssh joeuser@localhost joeuser@NAS's password: Last login: Sun Dec 16 14:07:22 2012 from desktop Permission denied, please try again. Connection to localhost closed.
3)将joeuser的shell更改回/ bin / sh:
$ grep joeuser /etc/passwd joeuser:x:1029:100:Joe User:/home/joeuser:/bin/sh $ ssh joeuser@localhost Last login: Sun Dec 16 15:50:52 2012 from localhost $
为了让事情更奇怪,我可以使用串口控制台(!)使用/bin/bash
以joeuser身份login。 还有一个su - joeuser
作为根工作正常,所以bash二进制本身工作正常。
在一个绝望的行为中,我把/ etc / passwd中的joeuser的uid改为0,但是也没有工作,所以它似乎没有什么权限相关的。
似乎bash正在做一些额外的检查,sshd不喜欢,并阻止非root用户的连接。 也许某种理智的检查 – 或terminal仿真 – 触发SIGCHLD,但只有通过ssh调用时。
我已经通过sshd_config上的每一个单独的项目,也把SSHDdebugging模式,但没有发现任何奇怪的东西。 这是我的/etc/ssh/sshd_config
:
LogLevel DEBUG LoginGraceTime 2m PermitRootLogin yes RSAAuthentication yes PubkeyAuthentication yes AuthorizedKeysFile %h/.ssh/authorized_keys ChallengeResponseAuthentication no UsePAM yes AllowTcpForwarding no ChrootDirectory none Subsystem sftp internal-sftp -f DAEMON -u 000
以下是/usr/syno/sbin/sshd -d
,显示了joeuser尝试login的失败尝试,以/ bin / bash作为shell:
debug1: Config token is loglevel debug1: Config token is logingracetime debug1: Config token is permitrootlogin debug1: Config token is rsaauthentication debug1: Config token is pubkeyauthentication debug1: Config token is authorizedkeysfile debug1: Config token is challengeresponseauthentication debug1: Config token is usepam debug1: Config token is allowtcpforwarding debug1: Config token is chrootdirectory debug1: Config token is subsystem debug1: HPN Buffer Size: 87380 debug1: sshd version OpenSSH_5.8p1-hpn13v11 debug1: read PEM private key done: type RSA debug1: private host key: #0 type 1 RSA debug1: read PEM private key done: type DSA debug1: private host key: #1 type 2 DSA debug1: read PEM private key done: type ECDSA debug1: private host key: #2 type 3 ECDSA debug1: rexec_argv[0]='/usr/syno/sbin/sshd' debug1: rexec_argv[1]='-d' Set /proc/self/oom_adj from 0 to -17 debug1: Bind to port 22 on ::. debug1: Server TCP RWIN socket size: 87380 debug1: HPN Buffer Size: 87380 Server listening on :: port 22. debug1: Bind to port 22 on 0.0.0.0. debug1: Server TCP RWIN socket size: 87380 debug1: HPN Buffer Size: 87380 Server listening on 0.0.0.0 port 22. debug1: Server will not fork when running in debugging mode. debug1: rexec start in 6 out 6 newsock 6 pipe -1 sock 9 debug1: inetd sockets after dupping: 4, 4 Connection from 127.0.0.1 port 52212 debug1: HPN Disabled: 0, HPN Buffer Size: 87380 debug1: Client protocol version 2.0; client software version OpenSSH_5.8p1-hpn13v11 SSH: Server;Ltype: Version;Remote: 127.0.0.1-52212;Protocol: 2.0;Client: OpenSSH_5.8p1-hpn13v11 debug1: match: OpenSSH_5.8p1-hpn13v11 pat OpenSSH* debug1: Enabling compatibility mode for protocol 2.0 debug1: Local version string SSH-2.0-OpenSSH_5.8p1-hpn13v11 debug1: permanently_set_uid: 1024/100 debug1: MYFLAG IS 1 debug1: list_hostkey_types: ssh-rsa,ssh-dss,ecdsa-sha2-nistp256 debug1: SSH2_MSG_KEXINIT sent debug1: SSH2_MSG_KEXINIT received debug1: AUTH STATE IS 0 debug1: REQUESTED ENC.NAME is 'aes128-ctr' debug1: kex: client->server aes128-ctr hmac-md5 none SSH: Server;Ltype: Kex;Remote: 127.0.0.1-52212;Enc: aes128-ctr;MAC: hmac-md5;Comp: none debug1: REQUESTED ENC.NAME is 'aes128-ctr' debug1: kex: server->client aes128-ctr hmac-md5 none debug1: expecting SSH2_MSG_KEX_ECDH_INIT debug1: SSH2_MSG_NEWKEYS sent debug1: expecting SSH2_MSG_NEWKEYS debug1: SSH2_MSG_NEWKEYS received debug1: KEX done debug1: userauth-request for user joeuser service ssh-connection method none SSH: Server;Ltype: Authname;Remote: 127.0.0.1-52212;Name: joeuser debug1: attempt 0 failures 0 debug1: Config token is loglevel debug1: Config token is logingracetime debug1: Config token is permitrootlogin debug1: Config token is rsaauthentication debug1: Config token is pubkeyauthentication debug1: Config token is authorizedkeysfile debug1: Config token is challengeresponseauthentication debug1: Config token is usepam debug1: Config token is allowtcpforwarding debug1: Config token is chrootdirectory debug1: Config token is subsystem debug1: PAM: initializing for "joeuser" debug1: PAM: setting PAM_RHOST to "localhost" debug1: PAM: setting PAM_TTY to "ssh" debug1: userauth-request for user joeuser service ssh-connection method password debug1: attempt 1 failures 0 debug1: do_pam_account: called Accepted password for joeuser from 127.0.0.1 port 52212 ssh2 debug1: monitor_child_preauth: joeuser has been authenticated by privileged process debug1: PAM: establishing credentials User child is on pid 9129 debug1: Entering interactive session for SSH2. debug1: server_init_dispatch_20 debug1: server_input_channel_open: ctype session rchan 0 win 65536 max 16384 debug1: input_session_request debug1: channel 0: new [server-session] debug1: session_new: session 0 debug1: session_open: channel 0 debug1: session_open: session 0: link with channel 0 debug1: server_input_channel_open: confirm session debug1: server_input_global_request: rtype [email protected] want_reply 0 debug1: server_input_channel_req: channel 0 request pty-req reply 1 debug1: session_by_channel: session 0 channel 0 debug1: session_input_channel_req: session 0 req pty-req debug1: Allocating pty. debug1: session_new: session 0 debug1: session_pty_req: session 0 alloc /dev/pts/1 debug1: server_input_channel_req: channel 0 request shell reply 1 debug1: session_by_channel: session 0 channel 0 debug1: session_input_channel_req: session 0 req shell debug1: Setting controlling tty using TIOCSCTTY. debug1: Received SIGCHLD. debug1: session_by_pid: pid 9130 debug1: session_exit_message: session 0 channel 0 pid 9130 debug1: session_exit_message: release channel 0 debug1: session_by_tty: session 0 tty /dev/pts/1 debug1: session_pty_cleanup: session 0 release /dev/pts/1 Received disconnect from 127.0.0.1: 11: disconnected by user debug1: do_cleanup debug1: do_cleanup debug1: PAM: cleanup debug1: PAM: closing session debug1: PAM: deleting credentials
这里有sshd -dd和ssh -vv的完整输出 。
击:
# bash --version GNU bash, version 3.2.49(1)-release (arm-none-linux-gnueabi) Copyright (C) 2007 Free Software Foundation, Inc.
bash二进制文件是从源代码中交叉编译的。 我也试过从Optware发行版中使用预编译的二进制文件,但是完全一样的问题。 我使用objdump -x
检查了缺失的共享库,但它们都在那里。
任何想法可能导致这个“ 权限被拒绝,请再试一次。 ”? 我几乎在bash源代码中进行调查,但是试图避免几个小时追逐可能很愚蠢的事情。
编辑:添加更多关于bash和系统的信息
$ ls -la /bin/bash -rwxr-xr-x 1 root root 724676 Dec 15 23:57 /bin/bash $ file /bin/bash /bin/bash: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.14, stripped $ uname -a Linux NAS 2.6.32.12 #2661 Mon Nov 12 23:10:15 CST 2012 armv5tel GNU/Linux synology_88f6282_212+ $ grep bash /etc/shells /bin/bash /bin/bash2
以供将来参考:经过这么多小时的研究和debugging这个问题,我终于find了根源。
Synology使用的OpenSSH版本是高度自定义的版本,不像原始代码。 它有很多黑客和临时定制 – 例如,在接受login之前进行额外的检查,以查看Web界面中是否启用了SSH服务,或者从rsync命令中剥离了特殊字符(;,|,')。等待它… 避免常规用户使用不同于/ bin / sh或/ bin / ash的shell 。 是的,硬编码在二进制。
以下是由Synology在其源代码(DSM4.1 – 分支2636) ,文件session.c
分发的OpenSSH 5.8p1代码:
void do_child(Session *s, const char *command) { ... #ifdef MY_ABC_HERE char szValue[8]; int RunSSH = 0; SSH_CMD SSHCmd = REQ_UNKNOWN; if (1 == GetKeyValue("/etc/synoinfo.conf", "runssh", szValue, sizeof(szValue))) { if (strcasecmp(szValue, "yes") == 0) { RunSSH = 1; } } if (IsSFTPReq(command)){ SSHCmd = REQ_SFTP; } else if (IsRsyncReq(command)){ SSHCmd = REQ_RSYNC; } else if (IsTimebkpRequest(command)){ SSHCmd = REQ_TIMEBKP; } else if (RunSSH && IsAllowShell(pw)){ SSHCmd = REQ_SHELL; } else { goto Err; } if (REQ_RSYNC == SSHCmd) { pw = SYNOChgValForRsync(pw); } if (!SSHCanLogin(SSHCmd, pw)) { goto Err; } goto Pass; Err: fprintf(stderr, "Permission denied, please try again.\n"); exit(1); Pass: #endif /* MY_ABC_HERE */ ... }
你可以想象, IsAllowShell(pw)
是罪魁祸首:
static int IsAllowShell(const struct passwd *pw) { struct passwd *pUnPrivilege = NULL; char *szUserName = NULL; if (!pw || !pw->pw_name) { return 0; } szUserName = pw->pw_name; if(!strcmp(szUserName, "root") || !strcmp(szUserName, "admin")){ return 1; } if (NULL != (pUnPrivilege = getpwnam(szUserName))){ if (!strcmp(pUnPrivilege->pw_shell, "/bin/sh") || !strcmp(pUnPrivilege->pw_shell, "/bin/ash")) { return 1; } } return 0; }
难怪我为什么遇到这样一个奇怪的行为。 只有shell / bin / sh和/ bin / ash会被接受不同于root或admin的用户。 而且这个不pipe用户身份(我testing过也使得joeuser uid = 0,而且没有工作,现在很明显为什么)。
一旦确定了原因,修复很容易:只要删除对IsAllowShell()的调用即可。 我花了一段时间才得到正确的configuration来交叉编译openssh及其所有的依赖关系,但最终运行良好。
如果有人想做同样的事情(或者为Synology交叉编译其他内核模块或二进制文件), 这里是我的Makefile版本 。 它使用OpenSSH-5.8p1来源进行testing,并且与运行Marvell Kirkwood mv6281 / mv6282 CPU(如DS212 +)的型号配合良好。 我使用了一台运行Ubuntu 12.10 x64的主机。
底线:糟糕的做法,可怕的代码,以及不该做的一个很好的例子。 我知道有时候OEM需要开发特殊的定制,但是在深入挖掘之前,他们应该三思而后行。 这不仅会导致他们无法维护的代码,而且还会造成各种不可预见的问题。 幸好GPL的存在让他们保持诚实,并且开放。
为了避免这个问题,并且由于我通过ipkg安装了bash,并且我不能确定/ opt将始终可用(正确安装),所以我简单地将以下内容放在我的.profile
[ -x /opt/bin/bash ] && exec /opt/bin/bash
而/ etc / passwd包含/ bin / ash作为shell。
让我们来看看。 它被隔离到一个单一的shell,再加上你看着sshddebugging输出,所以它不是世界上可写的〜joeuser / .ssh权限问题。 这是大多数人获得的。
你有没有尝试创build一个额外的普通用户(即不是joeuser),以确保它遇到同样的问题? 这将它隔离到用户的configuration与系统范围的configuration。
如果这是一个全系统的问题,接下来我要看看共享的configuration文件,例如/ etc / profile,这些文件都是由每个人提供的。 如果用户名是root,那么可能有一个条件块不会触发。 (不是有效的userid,因为你已经testing过了)
如果还没有,请检查dmesg是否存在分段故障报告,以防万一发生exception情况。
请尝试/ etc / ssh / sshd_config
searchAllowUsers
如果在那里尝试添加joeuser那里,只是用户名
也可能被封锁在帕姆…我不记得是哪个文件…
他们的openssh的修改版本寻找/bin/sh
shell?
简单的解决scheme
ln -fs / bin / bash / bin / sh
尝试重新安装Bash,看看是否有帮助。
如果有人因为犯了同样的错误而绊倒了我,
是: $ sudo usermod -s /bin/bash your_username
no: $ sudo usermod -s bash your_username
第二次将导致在ssh'ing时被拒绝的权限。