2011-05-06 11 views
8

Tengo una aplicación heredada que recibe una solicitud de nombre de usuario/contraseña de forma asincrónica a través del cable. Como ya tengo el nombre de usuario y la contraseña almacenados como variables, ¿cuál sería la mejor manera de autenticarse con PAM en Linux (Debian 6)?Autenticación PAM para una aplicación heredada

He intentado escribir mi propia función de conversación, pero no estoy seguro de la mejor manera de introducir la contraseña. He considerado almacenarlo en appdata y hacer referencia a eso desde la estructura pam_conv, pero casi no hay documentación sobre cómo hacerlo.

¿Existe una manera más simple de autenticar usuarios sin la sobrecarga de una función de conversación? Tampoco puedo usar pam_set_data correctamente, y no estoy seguro de que sea apropiado.

Esto es lo que estoy haciendo:

user = guiMessage->username; 
pass = guiMessage->password; 

pam_handle_t* pamh = NULL; 
int   pam_ret; 
struct pam_conv conv = { 
    my_conv, 
    NULL 
}; 

pam_start("nxs_login", user, &conv, &pamh); 
pam_ret = pam_authenticate(pamh, 0); 

if (pam_ret == PAM_SUCCESS) 
    permissions = 0xff; 

pam_end(pamh, pam_ret); 

Y iniciales intentos de la función de conversación dio lugar a (la contraseña se modificable para la prueba):

int 
my_conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *data) 
{ 
    struct pam_response *aresp; 

    if (num_msg <= 0 || num_msg > PAM_MAX_NUM_MSG) 
    return (PAM_CONV_ERR); 
    if ((aresp = (pam_response*)calloc(num_msg, sizeof *aresp)) == NULL) 
    return (PAM_BUF_ERR); 
    aresp[0].resp_retcode = 0; 
    aresp[0].resp = strdup("mypassword"); 

    *resp = aresp; 
    return (PAM_SUCCESS); 
} 

Cualquier ayuda sería muy apreciada. ¡Gracias!

Respuesta

12

Esto es lo que terminé haciendo. Vea el comentario marcado con tres asteriscos.

#include <stdlib.h> 
#include <iostream> 
#include <fstream> 
#include <security/pam_appl.h> 
#include <unistd.h> 

// To build this: 
// g++ test.cpp -lpam -o test 

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; 
} 
+0

Gracias! Y aquí estaba tratando de encontrar formas de comunicarme con la función de conversación en lugar de solo pasar por alto y trabajar con la respuesta fuera de ella. –

+0

Esto no funciona para 'raíz' (solo 'raíz', todos los demás usuarios son autómatas). ¿Es eso un error? – alexandernst

+0

No lo sé. No intenté con root. Probablemente esté haciendo algo mal si necesita usar la contraseña de root regularmente. – Fantius

1

La forma de información estándar (por ejemplo, una contraseña) se pasa para PAM es mediante el uso de variables establecidas en el mango con pam pam_set_item (véase la página del manual de pam_set_item).

Puede configurar cualquier cosa que su aplicación necesite usar más adelante en pam_stack. Si usted quiere poner la contraseña en el pam_stack usted debería ser capaz de hacer eso inmediatamente después de llamar pam_start() estableciendo la variable PAM_AUTHTOK en la pila similar a la pseudo código a continuación:

pam_handle_t* handle = NULL; 
pam_start("common-auth", username, NULL, &handle); 
pam_set_item(handle, PAM_AUTHTOK, password); 

Esto hará que la contraseña disponible en la pila a cualquier módulo que se preocupe por usarlo, pero generalmente tiene que decirle al módulo que lo use estableciendo las opciones estándar use_first_pass, o try_first_pass en pam_configuration para el servicio (en este caso /etc/pam.d/ common-auth).

El módulo pam_unix estándar es compatible con try_first_pass, por lo que no estaría de más añadir eso a la configuración de su pam en su sistema (al final de la línea para pam_unix).

Después de hacer esto, cualquier llamada al pam_authenticate() que se invoca desde el servicio de autenticación común debe simplemente recoger la contraseña e ir con ella.

Una pequeña nota acerca de la diferencia entre use_first_pass y try_first_pass: Ambos le dicen al módulo (en este caso pam_unix) que pruebe la contraseña en pam_stack, pero difieren en el comportamiento cuando no hay contraseña/AUTHTOK disponible. En el caso perdido, use_first_pass falla, y try_first_pass permite que el módulo solicite una contraseña.

+0

http://pubs.opengroup.org/onlinepubs/8329799/chap4.htm#tagcjh_05_02_01_01 menciona que 'PAM_AUTHTOK' está" _solo disponible para los módulos PAM y no para las aplicaciones_ ". Entonces no deberías poder hacer lo que describes. ¿Has comprobado si funciona? Tal vez lo hace, pero no es portátil? –

+0

Luego, nuevamente, la documentación 'pam_set_item' (http://pubs.opengroup.org/onlinepubs/8329799/pam_set_item.htm#tagmref_pam_set_item) no parece repetir esa condición mientras ofrece' PAM_AUTHOK'. –

0

La solución de Fantius funcionó para mí, incluso como root.

Al principio opté por la solución de John, ya que era más limpia y utilizaba variables PAM sin la función de conversación (realmente, aquí no la necesita), pero no funcionó, y no funcionará. Como Adam Badura aludió en ambas publicaciones, PAM tiene algunas verificaciones internas para evitar el establecimiento directo de PAM_AUTHTOK.

La solución de John dará como resultado un comportamiento similar al mencionado here, donde se permitirá el inicio de sesión de cualquier contraseña (incluso si declara, pero no define, la variable pam_conv).

También recomendaría a los usuarios que conozcan la ubicación del malloc, ya que es probable que difiera en su aplicación (recuerde que el código anterior es más una prueba/plantilla que cualquier otra cosa).

+0

Esto no proporciona una respuesta a la pregunta. Una vez que tenga suficiente [reputación] (https://stackoverflow.com/help/whats-reputation) podrá [comentar cualquier publicación] (https://stackoverflow.com/help/privileges/comment); en su lugar, [brinde respuestas que no requieran aclaración del autor de la pregunta] (https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can- i-do-instead). - [De la crítica] (/ review/low-quality-posts/18803902) – Umair

+0

Por favor, no agregue "gracias" como respuesta. En su lugar, vote las respuestas que encuentre útiles. - [De la crítica] (/ revisión/mensajes de baja calidad/18803902) – Graham

+0

gracias por recordarme por qué soy un casual en este tipo de sitios;) mis disculpas! – gagan

Cuestiones relacionadas