Liebe Systemtüftler,
ein befreundeter Admin hat mir folgende Frage gestellt:
Auf einer Reihe von Netzwerkelementen und Servern verwendet er die Remote-Authentifizierung gegenüber einem TACACS+-Server. Auf einigen dieser proprietären Geräte fragt die Authentifizierung nur dann eine lokale Authentifizierungsdatenbank ab, wenn die Remote-Methode „Authentifizierungsserver nicht verfügbar“ (nicht erreichbar, Zeitüberschreitung) zurückgibt. Wenn der Remote-AuthentifizierungsserverIstverfügbar ist und eine negative Antwort zurückgibt, nimmt die betreffende Box dies für bare Münze und versucht nicht, sich bei einer lokalen Benutzerdatenbank zu authentifizieren.
Nun... auf einer Linux-basierten Box möchte er dasselbe Verhalten erreichen. Und das scheint ihm nicht zu gelingen. Das Linux-Betriebssystem versucht zunächst die Remote-Authentifizierung, aber bei einer eindeutig negativen Antwort (der Server antwortet „Authentifizierung fehlgeschlagen, das sind keine gültigen Anmeldeinformationen“) fährt es fort und versucht es auch nur mit der lokalen Datenbank.
Ich habe inzwischen verstanden, dass die Remote-TACACS+-Authentifizierung von einem netten PAM-Modul namens pam_tacplus arrangiert wird. Wenn ich allgemein über PAM lese, dämmert mir, dass pam_tacplus nicht schuld ist. Das beobachtete Verhalten ist vielmehr einfach die Art und Weise, wie PAM als Ganzes funktioniert. Wenn dies der Fall ist, müsste eine direkte Lösung wahrscheinlich das Hinzufügen einer konfigurierbaren globalen Option zur PAM-Codebasis und möglicherweise spezifischer Schlüsselwörter/Syntax für die PAM-Konfigurationsdatei beinhalten, um das Verhalten in die gewünschte Richtung zu ändern.
Weitere Anmerkungen zu diesem Thema sind willkommen :-)
Antwort1
... basierend auf weiterer Lektüre möchte ich eine Antwort vorschlagen. Ergänzungen oder Korrekturen sind selbstverständlich herzlich willkommen.
Zunächst einmal habe ich festgestellt, dass dies uralt istEinführung in PAM. Von seinem scharfen Witz hat es über die Jahre wohl nichts eingebüßt.
Wenn ich einen Blick unter die Haube werfe, sind die Rückgabewerte des Auth-Modulsdokumentiert in der offiziellen Linux-PAM-Dokumentation.
In der Liste sehe ich einen vielversprechenden Retval namens PAM_AUTHINFO_UNAVAIL.
Eigentlich definiert inlibpam/include/security/_pam_types.h.
#define PAM_SUCCESS 0
#define PAM_AUTHINFO_UNAVAIL 9
#define _PAM_RETURN_VALUES 32
Es scheint eine widersprüchliche Definition von PAM_AUTHINFO_UNAVAIL zu geben inlibpam/include/security/_pam_compat.h
# define PAM_AUTHINFO_UNAVAIL 12
-- kann wahrscheinlich ignoriert werden.
Die Quelldateilibpam/pam_dispatch.c enthält eine Schlüsselfunktion namens _pam_dispatch_aux()das tatsächlich den Stapel der registrierten Authentifizierungsmodule durchläuft und auf ihre Rückgabewerte reagiert. Und es stellt sich heraus, dass es nicht viel direkt auf der Grundlage des „retval“ tut, das möglicherweise enthält PAM_AUTHINFO_UNAVAIL
. Es reagiert direkt auf einige bestimmte „Inside Special Use“-Werte von retval
, hat aber keine spezielle Behandlung für PAM_AUTHINFO_UNAVAIL
. retval
ist kein Rückgabewert von _pam_dispatch_aux()
sich selbst: Vielmehr retval
ist es nur eine lokale Variable, die innerhalb der for(;;)-Schleife deklariert wird, die den Stapel der registrierten Authentifizierungsmodule durchläuft, wobei der Block-Local retval
den Rückgabewert des bestimmten Moduls sammelt. Die Stackwalking-Schleife trifft tatsächlich wichtige Entscheidungen auf der Grundlage anderer Variablen: Eine davon wird abgeleitet und genannt action
, und die andere ist ein Strukturelement namens impression
„returned“ (zurückgegeben) von den Modulen per Referenz. Vielleicht wird es also doch vom eigenen Code des Moduls beeinflusst?
Tatsächlich stellt sich heraus, dass action
es aus einer "Nachschlagetabelle von Aktionen" stammt,
indexiert vondas retval
- ahaa!
action = h->actions[cached_retval];
Ist die Tabelle der Aktionen durch das Modul definiert? Aber wie, wenn die _PAM_ACTION_* Makros ein #defined inlibpam/pam_private.h?
Es stellt sich heraus, dass die Tabelle actions[]auf generische Weise initialisiertdurch eine _pam_parse_conf_file()
in aufgerufene Funktion libpam/pam_handlers.c
, diedirekter Stringvergleich(Übereinstimmung) auf Schlüsselwörter wie
required
, requisite
, optional
, sufficient
.
Und die gesamte Tabelle hat derzeit 32 Positionen (siehe die oben zitierte Makrodefinition), dieGroßhandel initialisiertzu _PAM_ACTION_UNDEF, bevor der Konfigurationseintrag für das jeweilige Modul analysiert wird. Einzelne „Stärke-Schlüsselwörter“ ordnen dann einzelne retval
s bestimmten gewünschten Aktionen zu.
Es liegt also auf der Hand, sich beispielsweise hiervon inspirieren zu lassen:
} else if (!strcasecmp("required", tok)) {
D(("*PAM_F_REQUIRED*"));
actions[PAM_SUCCESS] = _PAM_ACTION_OK;
actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK;
actions[PAM_IGNORE] = _PAM_ACTION_IGNORE;
_pam_set_default_control(actions, _PAM_ACTION_BAD);
} else if (!strcasecmp("sufficient", tok)) {
D(("*PAM_F_SUFFICIENT*"));
actions[PAM_SUCCESS] = _PAM_ACTION_DONE;
actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_DONE;
_pam_set_default_control(actions, _PAM_ACTION_IGNORE);
}
und füge etwas hinzu wie
} else if (!strcasecmp("reqd_if_avail", tok)) {
D(("*PAM_F_REQD_IF_AVAIL*"));
actions[PAM_SUCCESS] = _PAM_ACTION_OK;
actions[PAM_AUTHINFO_UNAVAIL] = _PAM_ACTION_IGNORE; // !!!!!!!!!!
actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK; // ?
actions[PAM_IGNORE] = _PAM_ACTION_IGNORE;
_pam_set_default_control(actions, _PAM_ACTION_BAD); // !!!
}
Und anscheinend pam_tacplushilft uns auf diesem Weg.
Es wäre sicherlich schön, wenn derselbe Effekt mit der vorhandenen PAM-Konfigurationsdateisyntax erzielt werden könnte, ohne den Quellcode hacken zu müssen.