Il modo in cui le informazioni standard (come una password) vengono passate per PAM è usando le variabili impostate nell'handle pam con pam_set_item (vedi la pagina man per pam_set_item).
Puoi impostare tutto ciò che la tua applicazione dovrà utilizzare in seguito in pam_stack. Se vuoi inserire la password in pam_stack dovresti essere in grado di farlo subito dopo aver chiamato pam_start() impostando la variabile PAM_AUTHTOK nello stack in modo simile allo pseudo codice qui sotto:
pam_handle_t* handle = NULL;
pam_start("common-auth", username, NULL, &handle);
pam_set_item( handle, PAM_AUTHTOK, password);
Ciò renderà la password disponibile sullo stack a qualsiasi modulo che si preoccupi di usarla, ma in genere devi dire al modulo di usarla impostando le opzioni standard use_first_pass o try_first_pass nella pam_configuration per il servizio (in questo caso /etc /pam.d/common-auth).
Il modulo pam_unix standard supporta try_first_pass, quindi non sarebbe male aggiungerlo alla configurazione di pam sul tuo sistema (alla fine della riga per pam_unix).
Dopo aver fatto ciò qualsiasi chiamata a pam_authenticate() che vengono invocati dal servizio common-auth dovrebbero semplicemente prendere la password e seguirla.
Una piccola nota sulla differenza tra use_first_pass e try_first_pass:entrambi dicono al modulo (in questo caso pam_unix) di provare la password su pam_stack, ma differiscono nel comportamento quando la loro password/AUTHTOK non è disponibile. Nel caso mancante, use_first_pass fallisce e try_first_pass consente al modulo di richiedere una password.
Questo è quello che ho finito per fare. Vedi il commento contrassegnato da tre asterischi.
#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;
}