解決策 1:
今後の参考のために:この問題の調査とデバッグに何時間も費やした後、私は最終的に根本原因を発見しました。
Synology が使用する OpenSSH バージョンは、高度にカスタマイズされたバージョンであり、しない 元のコードのように動作します。多くのハックとアドホックなカスタマイズがあります。たとえば、ログインを受け入れる前に追加のチェックを行って、Web インターフェイス内で SSH サービスが有効になっているかどうかを確認したり、rsync コマンドから特殊文字 (;、|、') を削除したり、または.. . 待ってください... 通常のユーザーが /bin/sh または /bin/ash 以外のシェルを使用しないようにする .はい、バイナリ内にハードコードされています。
これは、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;
}
なぜ私がそのような奇妙な行動を経験していたのか不思議ではありません. root 以外のユーザーには、シェル /bin/sh および /bin/ash のみが受け入れられます または 管理者 .これは uid に関係なく (joeuser の作成もテストしました) uid=0 で、うまくいきませんでした。その理由は明らかです。
原因を特定したら、修正は簡単でした。IsAllowShell() の呼び出しを削除するだけです。 . openssh とそのすべての依存関係をクロスコンパイルするための適切な構成を取得するのにしばらく時間がかかりましたが、最終的にはうまくいきました。
誰かが同じことをすることに興味がある場合 (または、Synology の他のカーネル モジュールまたはバイナリをクロスコンパイルしようとする場合)、これが私のバージョンの Makefile です。 . OpenSSH-5.8p1 ソースでテストされており、Marvell Kirkwood mv6281/mv6282 CPU (DS212+ など) を実行しているモデルでうまく動作します。 Ubuntu 12.10 x64 を実行するホストを使用しました。
結論:悪い習慣、ひどいコード、そうでないことの良い例 する。 OEM が特別なカスタマイズを開発する必要がある場合があることは理解していますが、深く掘り下げる前によく考える必要があります。これにより、コードが保守不能になるだけでなく、今後あらゆる種類の予期しない問題が発生します。ありがたいことに、GPL はそれらを正直かつオープンに保つために存在します。
解決策 2:
この問題を回避するために、ipkg 経由で bash をインストールしましたが、/opt が常に使用可能 (正しくマウントされている) かどうか確信が持てないため、単純に .profile に以下を追加しました
[ -x /opt/bin/bash ] && exec /opt/bin/bash
一方、/etc/passwd にはシェルとして /bin/ash が含まれています。