static const char rcsid[] = "$Id: pam.c,v 1.6 2004/04/30 17:00:58 will Exp $"; /* The code should compile with either ANSI C or K&R compilers. */ /* * Copyright (c) 1993 by California Institute of Technology. * Written by William Deich. Not derived from licensed software. * You may distribute under the terms of either the GNU General Public * License or the Artistic License, as specified in the README file. */ #include "super.h" #include "version.h" #ifndef HAVE_PAM_START int get_pam(cmd, caller, user) char *cmd; char *caller; /* the person who invoked super */ char *user; /* the person whose authentication is required */ { Error(0, 1, "Error in super.tab file -- this copy of super was compiled on a host without support for authtype=pam\n"); } #else #ifndef HAVE_PAM_STRERROR /* pam_strerror converts a PAM status code to a string, and a returns * a ptr to a static string. This is the Linux pam_strerror() code, * except that I've #ifdef'd everything so that it compiles on systems * that don't have all of the PAM_xxx values. (Note that this only * works if #define is used; an enum would break this.) */ char * pam_strerror(pam_handle_t *pamh, int status) { switch (errnum) { #ifdef PAM_SUCCESS case PAM_SUCCESS: return "Success"; #endif #ifdef PAM_ABORT case PAM_ABORT: return "Critical error - immediate abort"; #endif #ifdef PAM_OPEN_ERR case PAM_OPEN_ERR: return "dlopen() failure"; #endif #ifdef PAM_SYMBOL_ERR case PAM_SYMBOL_ERR: return "Symbol not found"; #endif #ifdef PAM_SERVICE_ERR case PAM_SERVICE_ERR: return "Error in service module"; #endif #ifdef PAM_SYSTEM_ERR case PAM_SYSTEM_ERR: return "System error"; #endif #ifdef PAM_BUF_ERR case PAM_BUF_ERR: return "Memory buffer error"; #endif #ifdef PAM_PERM_DENIED case PAM_PERM_DENIED: return "Permission denied"; #endif #ifdef PAM_AUTH_ERR case PAM_AUTH_ERR: return "Authentication failure"; #endif #ifdef PAM_CRED_INSUFFICIENT case PAM_CRED_INSUFFICIENT: return "Insufficient credentials to access authentication data"; #endif #ifdef PAM_AUTHINFO_UNAVAIL case PAM_AUTHINFO_UNAVAIL: return "Authentication service cannot retrieve authentication info."; #endif #ifdef PAM_USER_UNKNOWN case PAM_USER_UNKNOWN: return "User not known to the underlying authentication module"; #endif #ifdef PAM_MAXTRIES case PAM_MAXTRIES: return "Have exhasted maximum number of retries for service."; #endif #ifdef PAM_NEW_AUTHTOK_REQD case PAM_NEW_AUTHTOK_REQD: return "Authentication token is no longer valid; new one required."; #endif #ifdef PAM_ACCT_EXPIRED case PAM_ACCT_EXPIRED: return "User account has expired"; #endif #ifdef PAM_SESSION_ERR case PAM_SESSION_ERR: return "Cannot make/remove an entry for the specified session"; #endif #ifdef PAM_CRED_UNAVAIL case PAM_CRED_UNAVAIL: return "Authentication service cannot retrieve user credentials"; #endif #ifdef PAM_CRED_EXPIRED case PAM_CRED_EXPIRED: return "User credentials expired"; #endif #ifdef PAM_CRED_ERR case PAM_CRED_ERR: return "Failure setting user credentials"; #endif #ifdef PAM_NO_MODULE_DATA case PAM_NO_MODULE_DATA: return "No module specific data is present"; #endif #ifdef PAM_BAD_ITEM case PAM_BAD_ITEM: return "Bad item passed to pam_*_item()"; #endif #ifdef PAM_CONV_ERR case PAM_CONV_ERR: return "Conversation error"; #endif #ifdef PAM_AUTHTOK_ERR case PAM_AUTHTOK_ERR: return "Authentication token manipulation error"; #endif #ifdef PAM_AUTHTOK_LOCK_BUSY case PAM_AUTHTOK_LOCK_BUSY: return "Authentication token lock busy"; #endif #ifdef PAM_AUTHTOK_DISABLE_AGING case PAM_AUTHTOK_DISABLE_AGING: return "Authentication token aging disabled"; #endif #ifdef PAM_TRY_AGAIN case PAM_TRY_AGAIN: return "Failed preliminary check by password service"; #endif #ifdef PAM_IGNORE case PAM_IGNORE: return "Please ignore underlying account module"; #endif #ifdef PAM_MODULE_UNKNOWN case PAM_MODULE_UNKNOWN: return "Module is unknown"; #endif #ifdef PAM_AUTHTOK_EXPIRED case PAM_AUTHTOK_EXPIRED: return "Authentication token expired"; #endif #ifdef PAM_CONV_AGAIN case PAM_CONV_AGAIN: return "Conversation is waiting for event"; #endif #ifdef PAM_INCOMPLETE case PAM_INCOMPLETE: return "Application needs to call libpam again"; #endif } return "Unknown PAM error (need to upgrade libpam?)"; } #endif /* !HAVE_PAM_STRERROR */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Get authentication via PAM */ /* Return 1 on success, -1 on error. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int get_pam(cmd, caller, user) char *cmd; char *caller; /* the person who invoked super */ char *user; /* the person whose authentication is required */ { int misc_conv(int num_msg, const struct pam_message **msgm, struct pam_response **response, void *appdata_ptr); static struct pam_conv conv = { misc_conv, NULL }; pam_handle_t *pamh = NULL; int ntry, pamstatus; char msg[500]; FILE *prompt_fp = NULL; char *prompt_dev="/dev/tty"; if (pam_start(ONETRUENAME, user, &conv, &pamh) != PAM_SUCCESS) { return Error(0, 0, "Internal error: can't start PAM authentication!\n"); } if (!(prompt_fp = fopen(prompt_dev, "r+"))) { return Error(0, 0, "Can't open %s for authentication message!\n", prompt_dev); } /* Note that the actual number of tries is the lesser of our MAXTRY * and the PAM module's maximum... */ for (ntry=0, pamstatus = PAM_AUTH_ERR; ntry < MAXTRY && pamstatus == PAM_AUTH_ERR; ntry++) { if (ntry == 0) { if (localinfo.authinfo.prompt && localinfo.authinfo.prompt[0]) { stringcopy(msg, do_variables(localinfo.authinfo.prompt), sizeof(msg)); } else if (strcmp(caller, user) == 0) { (void) sprintf(msg, "Authentication is required for super command `%.400s'...", cmd); } else { (void) sprintf(msg, "Authentication for user %s is required for super command `%.400s'...", user, cmd); } fprintf(prompt_fp, "%s\n", msg); } else { fprintf(prompt_fp, "Authentication failed; try again...\n"); } pamstatus = pam_authenticate(pamh, PAM_DISALLOW_NULL_AUTHTOK); } fclose(prompt_fp); if (pamstatus != PAM_SUCCESS) { pam_end(pamh, pamstatus); return Error(0, 0, "Authentication failed: %s\n", pam_strerror(pamh, pamstatus)); } if ((pamstatus=pam_acct_mgmt(pamh, 0)) != PAM_SUCCESS) { pam_end(pamh, pamstatus); return Error(0, 0, "Authentication succeeded, \ but PAM doesn't grant access:\n\t%s\n", pam_strerror(pamh, pamstatus)); } if (pam_end(pamh, pamstatus) != PAM_SUCCESS) { return Error(0, 0, "Internal error: failed to release authenticator\n"); } return 1; } #endif /* HAVE_PAM_START */