Lösung 1:
Als zukünftige Referenz:Nach viel zu vielen Stunden der Recherche und Fehlerbehebung dieses Problems habe ich endlich die Grundursache entdeckt.
Die von Synology verwendete OpenSSH-Version ist eine stark angepasste Version, die nicht verhalten sich wie der Originalcode. Es hat viele Hacks und Ad-hoc-Anpassungen - z. B. zusätzliche Überprüfung vor dem Akzeptieren einer Anmeldung, um zu sehen, ob der SSH-Dienst innerhalb der Weboberfläche aktiviert ist, oder das Entfernen von Sonderzeichen (;, |, ') aus rsync-Befehlen oder ... Warten Sie darauf ... vermeiden Sie normale Benutzer, eine andere Shell als /bin/sh oder /bin/ash zu verwenden . Ja, fest codiert in der Binärdatei.
Hier ist das Stück Code von OpenSSH 5.8p1, wie es von Synology in ihrem Quellcode (DSM4.1 - Zweig 2636), Datei session.c
verteilt wird :
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 */
...
}
Wie Sie sich vorstellen können, ist die IsAllowShell(pw)
war der Übeltäter:
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;
}
Kein Wunder, warum ich so ein seltsames Verhalten erlebte. Nur die Shells /bin/sh und /bin/ash würden für andere Benutzer als root akzeptiert oder admin . Und das unabhängig von der UID (ich hatte auch getestet, wie man joeuser macht uid=0, und es hat nicht funktioniert. Jetzt ist es offensichtlich warum).
Sobald die Ursache identifiziert war, war die Lösung einfach:Entfernen Sie einfach den Aufruf von IsAllowShell() . Es hat eine Weile gedauert, bis ich die richtige Konfiguration zum Querkompilieren von openssh und all seinen Abhängigkeiten gefunden hatte, aber am Ende hat es gut funktioniert.
Falls jemand daran interessiert ist, dasselbe zu tun (oder versucht, andere Kernel-Module oder Binärdateien für Synology zu kompilieren), hier ist meine Version von Makefile . Es wurde mit OpenSSH-5.8p1-Quelle getestet und funktioniert gut mit Modellen mit Marvell Kirkwood mv6281/mv6282-CPU (wie DS212+). Ich habe einen Host verwendet, auf dem Ubuntu 12.10 x64 ausgeführt wird.
Fazit:schlechte Praxis, schrecklicher Code und ein großartiges Beispiel dafür, was nicht ist machen. Ich verstehe, dass OEMs manchmal spezielle Anpassungen entwickeln müssen, aber sie sollten es sich zweimal überlegen, bevor sie zu tief graben. Dies führt nicht nur zu nicht wartbarem Code für sie, sondern auch zu allen möglichen unvorhergesehenen Problemen im Laufe der Zeit. Zum Glück gibt es GPL, um sie ehrlich zu halten - und offen.
Lösung 2:
Um das Problem zu umgehen, und da ich bash über ipkg installiert habe und ich nicht sicher sein kann, dass /opt immer verfügbar (korrekt gemountet) ist, füge ich einfach Folgendes in mein .profile
ein[ -x /opt/bin/bash ] && exec /opt/bin/bash
während /etc/passwd /bin/ash als Shell enthält.