/* * * (c) 2000,2001 Chema Peribáñez * chema@softlibre.net * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* * Este programa sirve para ilustrar la forma de autentificar un usuario * utilizando PAM y lo compara con hacer lo mismo utilizando un sistema * tradicional vía shadow passwords. Para que funcione, necesita privilegios * de superusuario. * * La función autentificar_PAM usa PAM mientras que autentificar_shadow * lee del ficheor /etc/shadow. Ambas funciones reciben como primer * parámetro el usuario, como segundo la contraseña y retornan 0 para indicar * que no se ha autentificado y 1 para que sí. * * Ventajas de autentificar_PAM: * -Funciona sea shadow password o no, se utilice DES, MD5 o cualquier * otro algoritmo. Por contra autentificar_shadow requiere que haya shadow * password. En sistemas en que la función crypt no corresponda con la * función hash para encriptar la clave, no funcionará. Hay sistemas que * permiten tanto DES como MD5; distinguen el segundo por el "salt", que tiene * la forma $1$<8 bytes>$ * * -Permite olvidarse de controles como si la contraseña ha caducado, si puede * conectarse o no a esa hora o desde esa máquina... Todo eso lo hacen módulos * PAM que el administrador (y no el programador) elige y configura. Se hace * mediante módulos "account" y se pueden hacer módulos que decidan si * autorizar el acceso de un usuario autentificado bajo cualquier criterio. * * -Permite utilizar otros sistemas de autentificación distintas al fichero * /etc/shadow, por ejemplo una autentificación vía red, con LDAP, o utilizando * una base de datos. Incluso puede autentificarse ante un servidor NT. Para * ello están los módulos auth. * * -Permite utilizar módulos de sesión que ejecuten código arbitrario al * autentificarse con éxito el usuario. */ /* Para compilar: * * gcc autentifica.c -lcrypt -lpam */ #include #include #include #include #include int funcionConversacion (int num, const struct pam_message **entradas, struct pam_response **salidas, void *passPAM) { struct pam_response *respuestas; respuestas = (struct pam_response *) calloc (num, sizeof (struct pam_response)); for (--num; num >= 0; --num) switch (entradas[num]->msg_style) { case PAM_PROMPT_ECHO_OFF: respuestas[num].resp = strdup ((char *) passPAM); respuestas[num].resp_retcode = PAM_SUCCESS; break; case PAM_TEXT_INFO: case PAM_ERROR_MSG: respuestas[num].resp = NULL; respuestas[num].resp_retcode = PAM_SUCCESS; break; default: free (respuestas); return PAM_CONV_ERR; } *salidas = respuestas; return PAM_SUCCESS; } int autentificar_PAM (char *usuario, char *password) { /* Retorna 1 si se autenficó correctamente, cero en caso contrario */ int autentificado; struct pam_conv sFuncionConversacion; pam_handle_t *manejadorPAM; sFuncionConversacion.conv = funcionConversacion; sFuncionConversacion.appdata_ptr = (void *) password; autentificado = (pam_start ("login", usuario, &sFuncionConversacion, &manejadorPAM) == PAM_SUCCESS && pam_authenticate (manejadorPAM, 0) == PAM_SUCCESS && pam_acct_mgmt (manejadorPAM, 0) == PAM_SUCCESS) ? 1 : 0; pam_end (manejadorPAM, autentificado ? PAM_SUCCESS : 0); return autentificado; } int autentificar_shadow (char *usuario, char *password) { /* Retorna 1 si se autentificó correctamente, cero en caso contrario */ struct spwd *linea_shadow; char salt[13]; /* salt de md5 es $1$8bytes$ y siempre hay que dejar sitio para el \0 final. */ linea_shadow = getspnam (usuario); if (linea_shadow == NULL) return 0; if (linea_shadow->sp_pwdp[0] == '$') strncpy (salt, linea_shadow->sp_pwdp, 12); else strncpy (salt, linea_shadow->sp_pwdp, 2); printf("%s\n",crypt(password,salt)); if (strcmp (linea_shadow->sp_pwdp, crypt (password, salt))) return 0; else { /* Pendiente: comprobar si ha expirado la cuenta, que viene dada en días desde el 1 de Enero de 1970; basta tener en cuenta que time() devuelve el número de segundos desde la misma fecha, y que un día tiene 86400 x segundos */ return 1; } } int main(int argc,char **argv[]) { printf("Usuario: %s resultado: %d\n","jomar",autentificar_shadow("usuario","clave")); printf("Usuario: %s resultado: %d\n","jomar",autentificar_PAM("usuario","clave")); }