Die Art und Weise, wie Standardinformationen (z. B. ein Passwort) für PAM übergeben werden, ist die Verwendung von Variablen, die im pam-Handle mit pam_set_item gesetzt werden (siehe Manpage für pam_set_item).
Sie können alles, was Ihre Anwendung später verwenden muss, in pam_stack einstellen. Wenn Sie das Passwort in den pam_stack legen möchten, sollten Sie dies unmittelbar nach dem Aufruf von pam_start() tun können, indem Sie die Variable PAM_AUTHTOK in den Stapel setzen, ähnlich wie im folgenden Pseudocode:
pam_handle_t* handle = NULL;
pam_start("common-auth", username, NULL, &handle);
pam_set_item( handle, PAM_AUTHTOK, password);
Dadurch wird das Passwort auf dem Stapel jedem Modul zur Verfügung gestellt, das es verwenden möchte, aber Sie müssen das Modul im Allgemeinen anweisen, es zu verwenden, indem Sie die Standardoptionen use_first_pass oder try_first_pass in der pam_configuration für den Dienst (in diesem Fall /etc /pam.d/common-auth).
Das Standardmodul pam_unix unterstützt try_first_pass, also würde es nicht schaden, das in Ihre pam-Konfiguration auf Ihrem System aufzunehmen (am Ende der Zeile für pam_unix).
Nachdem Sie dies getan haben, rufen Sie pam_authenticate() auf die vom Common-Auth-Dienst aufgerufen werden, sollten einfach das Passwort abholen und damit fortfahren.
Eine kleine Anmerkung zum Unterschied zwischen use_first_pass und try_first_pass:Beide weisen das Modul (in diesem Fall pam_unix) an, das Passwort auf dem pam_stack auszuprobieren, aber sie unterscheiden sich im Verhalten, wenn kein Passwort/AUTHTOK verfügbar ist. Im fehlenden Fall schlägt use_first_pass fehl und try_first_pass erlaubt dem Modul, nach einem Passwort zu fragen.
Das habe ich letztendlich getan. Siehe den mit drei Sternchen markierten Kommentar.
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <security/pam_appl.h>
#include <unistd.h>
// To build this:
// g++ test.cpp -lpam -o test
// if pam header files missing try:
// sudo apt install libpam0g-dev
struct pam_response *reply;
//function used to get user input
int function_conversation(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr)
{
*resp = reply;
return PAM_SUCCESS;
}
int main(int argc, char** argv)
{
if(argc != 2) {
fprintf(stderr, "Usage: check_user <username>\n");
exit(1);
}
const char *username;
username = argv[1];
const struct pam_conv local_conversation = { function_conversation, NULL };
pam_handle_t *local_auth_handle = NULL; // this gets set by pam_start
int retval;
// local_auth_handle gets set based on the service
retval = pam_start("common-auth", username, &local_conversation, &local_auth_handle);
if (retval != PAM_SUCCESS)
{
std::cout << "pam_start returned " << retval << std::endl;
exit(retval);
}
reply = (struct pam_response *)malloc(sizeof(struct pam_response));
// *** Get the password by any method, or maybe it was passed into this function.
reply[0].resp = getpass("Password: ");
reply[0].resp_retcode = 0;
retval = pam_authenticate(local_auth_handle, 0);
if (retval != PAM_SUCCESS)
{
if (retval == PAM_AUTH_ERR)
{
std::cout << "Authentication failure." << std::endl;
}
else
{
std::cout << "pam_authenticate returned " << retval << std::endl;
}
exit(retval);
}
std::cout << "Authenticated." << std::endl;
retval = pam_end(local_auth_handle, retval);
if (retval != PAM_SUCCESS)
{
std::cout << "pam_end returned " << retval << std::endl;
exit(retval);
}
return retval;
}