diff options
Diffstat (limited to 'source4')
-rw-r--r-- | source4/lib/pam_errors.c | 2 | ||||
-rw-r--r-- | source4/web_server/calls.c | 71 | ||||
-rw-r--r-- | source4/web_server/config.m4 | 12 | ||||
-rw-r--r-- | source4/web_server/config.mk | 5 | ||||
-rw-r--r-- | source4/web_server/pam.c | 341 |
5 files changed, 427 insertions, 4 deletions
diff --git a/source4/lib/pam_errors.c b/source4/lib/pam_errors.c index 925441fb1d..a00464e624 100644 --- a/source4/lib/pam_errors.c +++ b/source4/lib/pam_errors.c @@ -20,7 +20,7 @@ #include "includes.h" -#ifdef WITH_PAM +#ifdef WITH_HAVE_SECURITY_PAM_APPL_H #include <security/pam_appl.h> #if defined(PAM_AUTHTOK_RECOVERY_ERR) && !defined(PAM_AUTHTOK_RECOVER_ERR) diff --git a/source4/web_server/calls.c b/source4/web_server/calls.c index fc23a113fe..ab20c38193 100644 --- a/source4/web_server/calls.c +++ b/source4/web_server/calls.c @@ -21,11 +21,11 @@ */ #include "includes.h" +#include "pwd.h" #include "web_server/esp/esp.h" #include "param/loadparm.h" #include "lib/ldb/include/ldb.h" - /* add an indexed array element to a property */ @@ -378,6 +378,74 @@ failed: return -1; } +/* try to authenticate the user/password pair against system auth mechanisms + returns 0 on success + returns -1 on error + + fills in the session structure properly in case of success + NOTE: Currently only PAM Auth is supported +*/ + +static int esp_unixAuth(struct EspRequest *ep, int argc, struct MprVar **argv) +{ + TALLOC_CTX *tmp_ctx = talloc_new(ep); + const char *username; + const char *password; + struct passwd *pwd; + int ret; + + if (argc != 2 || argv[0]->type != MPR_TYPE_STRING || + argv[1]->type != MPR_TYPE_STRING) { + espError(ep, "unixAuth invalid arguments"); + ret = -1; + goto done; + } + + username = mprToString(argv[0]); + password = mprToString(argv[1]); + + if (username == NULL || password == NULL) { + espError(ep, "unixAuth invalid arguments"); + ret = -1; + goto done; + } + + /* TODO: find out how to pass the real client name/address here */ + if (NT_STATUS_IS_OK(unix_passcheck(tmp_ctx, "client", username, password))) { + + pwd = getpwnam(username); + if (!pwd) { + espSetReturn(ep, mprCreateIntegerVar(-1)); + ret = -1; + goto done; + } + + mprSetPropertyValue(&ep->variables[ESP_SESSION_OBJ], + "AUTHENTICATED", mprCreateStringVar("1", 0)); + mprSetPropertyValue(&ep->variables[ESP_SESSION_OBJ], + "USERNAME", mprCreateStringVar(username, 0)); + + if (pwd->pw_uid == 0) { /* we are root */ + + mprSetPropertyValue(&ep->variables[ESP_SESSION_OBJ], + "PRIVILEGE", mprCreateStringVar("ADMIN", 0)); + } else { + mprSetPropertyValue(&ep->variables[ESP_SESSION_OBJ], + "PRIVILEGE", mprCreateStringVar("USER", 0)); + } + + espSetReturn(ep, mprCreateIntegerVar(0)); + } else { + if (mprGetProperty(&ep->variables[ESP_SESSION_OBJ], "AUTHENTICATED", 0) != 0) { + mprDeleteProperty(&ep->variables[ESP_SESSION_OBJ], "AUTHENTICATED"); + } + espSetReturn(ep, mprCreateIntegerVar(-1)); + } + +done: + talloc_free(tmp_ctx); + return ret; +} /* setup the C functions that be called from ejs @@ -388,4 +456,5 @@ void http_setup_ejs_functions(void) espDefineStringCFunction(NULL, "lpServices", esp_lpServices, NULL); espDefineCFunction(NULL, "typeof", esp_typeof, NULL); espDefineCFunction(NULL, "ldbSearch", esp_ldbSearch, NULL); + espDefineCFunction(NULL, "unixAuth", esp_unixAuth, NULL); } diff --git a/source4/web_server/config.m4 b/source4/web_server/config.m4 index 057f193179..7adbfb1721 100644 --- a/source4/web_server/config.m4 +++ b/source4/web_server/config.m4 @@ -11,3 +11,15 @@ fi SMB_EXT_LIB(GNUTLS, $GNUTLS_LIBS) # end SMB_EXT_LIB_GNUTLS ############################### + +############################### +# start SMB_EXT_LIB_PAM +# check for security/pam_appl.h and -lpam +AC_CHECK_HEADERS(security/pam_appl.h) +AC_CHECK_LIB_EXT(pam, PAM_LIBS, pam_start) +if test x"$ac_cv_header_security_pam_appl_h" = x"yes" -a x"$ac_cv_lib_ext_pam_pam_start" = x"yes";then + SMB_EXT_LIB_ENABLE(PAM,YES) +fi +SMB_EXT_LIB(PAM, $PAM_LIBS) +# end SMB_EXT_LIB_PAM +############################### diff --git a/source4/web_server/config.mk b/source4/web_server/config.mk index acaccd7130..bcb5bea0ff 100644 --- a/source4/web_server/config.mk +++ b/source4/web_server/config.mk @@ -36,7 +36,8 @@ ADD_OBJ_FILES = \ web_server/http.o \ web_server/calls.o \ web_server/tls.o \ - web_server/tlscert.o -REQUIRED_SUBSYSTEMS = ESP EXT_LIB_GNUTLS + web_server/tlscert.o \ + web_server/pam.o +REQUIRED_SUBSYSTEMS = ESP EXT_LIB_GNUTLS EXT_LIB_PAM # End SUBSYSTEM WEB ####################### diff --git a/source4/web_server/pam.c b/source4/web_server/pam.c new file mode 100644 index 0000000000..5ee04a3115 --- /dev/null +++ b/source4/web_server/pam.c @@ -0,0 +1,341 @@ +/* + Unix SMB/CIFS implementation. + PAM Password checking + Copyright (C) Andrew Tridgell 1992-2001 + Copyright (C) John H Terpsta 1999-2001 + Copyright (C) Andrew Bartlett 2001 + Copyright (C) Jeremy Allison 2001 + Copyright (C) Simo Sorce 2005 + + 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* + * This module provides PAM based functions for validation of + * username/password pairs. + * Note: This module is a stripped down version of pampass.c of samba 3 + * It has been adapted to perform only pam auth checks and code has + * been shaped out to meet samba4 coding stile + */ + +#include "includes.h" + +#ifdef HAVE_SECURITY_PAM_APPL_H + +/******************************************************************* + * Handle PAM authentication + * - Access, Authentication, Session, Password + * Note: See PAM Documentation and refer to local system PAM implementation + * which determines what actions/limitations/allowances become affected. + *********************************************************************/ + +#include <security/pam_appl.h> + +/* + * Structure used to communicate between the conversation function + * and the server_login/change password functions. + */ + +struct smb_pam_userdata { + const char *PAM_username; + const char *PAM_password; +}; + +typedef int (*smb_pam_conv_fn)(int, const struct pam_message **, struct pam_response **, void *appdata_ptr); + +/******************************************************************* + PAM error handler. + *********************************************************************/ + +static BOOL smb_pam_error_handler(pam_handle_t *pamh, int pam_error, const char *msg, int dbglvl) +{ + + if( pam_error != PAM_SUCCESS) { + DEBUG(dbglvl, ("smb_pam_error_handler: PAM: %s : %s\n", + msg, pam_strerror(pamh, pam_error))); + + return False; + } + return True; +} + +/******************************************************************* + This function is a sanity check, to make sure that we NEVER report + failure as sucess. +*********************************************************************/ + +static BOOL smb_pam_nt_status_error_handler(pam_handle_t *pamh, int pam_error, + const char *msg, int dbglvl, + NTSTATUS *nt_status) +{ + *nt_status = pam_to_nt_status(pam_error); + + if (smb_pam_error_handler(pamh, pam_error, msg, dbglvl)) + return True; + + if (NT_STATUS_IS_OK(*nt_status)) { + /* Complain LOUDLY */ + DEBUG(0, ("smb_pam_nt_status_error_handler: PAM: BUG: PAM and NT_STATUS \ +error MISMATCH, forcing to NT_STATUS_LOGON_FAILURE")); + *nt_status = NT_STATUS_LOGON_FAILURE; + } + return False; +} + +/* + * PAM conversation function + * Here we assume (for now, at least) that echo on means login name, and + * echo off means password. + */ + +static int smb_pam_conv(int num_msg, + const struct pam_message **msg, + struct pam_response **resp, + void *appdata_ptr) +{ + int replies = 0; + struct pam_response *reply = NULL; + struct smb_pam_userdata *udp = (struct smb_pam_userdata *)appdata_ptr; + + *resp = NULL; + + if (num_msg <= 0) + return PAM_CONV_ERR; + + /* + * Apparantly HPUX has a buggy PAM that doesn't support the + * appdata_ptr. Fail if this is the case. JRA. + */ + + if (udp == NULL) { + DEBUG(0,("smb_pam_conv: PAM on this system is broken - appdata_ptr == NULL !\n")); + return PAM_CONV_ERR; + } + + reply = malloc_array_p(struct pam_response, num_msg); + if (!reply) + return PAM_CONV_ERR; + + memset(reply, '\0', sizeof(struct pam_response) * num_msg); + + for (replies = 0; replies < num_msg; replies++) { + switch (msg[replies]->msg_style) { + case PAM_PROMPT_ECHO_ON: + reply[replies].resp_retcode = PAM_SUCCESS; + reply[replies].resp = strdup(udp->PAM_username); + /* PAM frees resp */ + break; + + case PAM_PROMPT_ECHO_OFF: + reply[replies].resp_retcode = PAM_SUCCESS; + reply[replies].resp = strdup(udp->PAM_password); + /* PAM frees resp */ + break; + + case PAM_TEXT_INFO: + /* fall through */ + + case PAM_ERROR_MSG: + /* ignore it... */ + reply[replies].resp_retcode = PAM_SUCCESS; + reply[replies].resp = NULL; + break; + + default: + /* Must be an error of some sort... */ + if (reply) + free(reply); + return PAM_CONV_ERR; + } + } + if (reply) + *resp = reply; + return PAM_SUCCESS; +} + +/*************************************************************************** + Allocate a pam_conv struct. +****************************************************************************/ + +static struct pam_conv *smb_setup_pam_conv(TALLOC_CTX *ctx, + smb_pam_conv_fn smb_pam_conv_fnptr, + const char *username, const char *password) +{ + struct pam_conv *pconv; + struct smb_pam_userdata *udp; + + pconv = talloc(ctx, struct pam_conv); + if (pconv == NULL) + return NULL; + + udp = talloc(ctx, struct smb_pam_userdata); + if (udp == NULL) + return NULL; + + udp->PAM_username = username; + udp->PAM_password = password; + + pconv->conv = smb_pam_conv_fnptr; + pconv->appdata_ptr = (void *)udp; + + return pconv; +} + +/* + * PAM Closing out cleanup handler + */ + +static BOOL smb_pam_end(pam_handle_t *pamh, struct pam_conv *smb_pam_conv_ptr) +{ + int pam_error; + + if( pamh != NULL ) { + pam_error = pam_end(pamh, 0); + if(smb_pam_error_handler(pamh, pam_error, "End Cleanup Failed", 2) == True) { + DEBUG(4, ("smb_pam_end: PAM: PAM_END OK.\n")); + return True; + } + } + DEBUG(2,("smb_pam_end: PAM: not initialised")); + return False; +} + +/* + * Start PAM authentication for specified account + */ + +static BOOL smb_pam_start(pam_handle_t **pamh, const char *user, const char *rhost, struct pam_conv *pconv) +{ + int pam_error; + const char *our_rhost; + + if (user == NULL || rhost == NULL || pconv == NULL) { + return False; + } + + *pamh = (pam_handle_t *)NULL; + + DEBUG(4,("smb_pam_start: PAM: Init user: %s\n", user)); + + pam_error = pam_start("samba", user, pconv, pamh); + if( !smb_pam_error_handler(*pamh, pam_error, "Init Failed", 0)) { + *pamh = (pam_handle_t *)NULL; + return False; + } + +#ifdef PAM_RHOST + DEBUG(4,("smb_pam_start: PAM: setting rhost to: %s\n", rhost)); + pam_error = pam_set_item(*pamh, PAM_RHOST, rhost); + if(!smb_pam_error_handler(*pamh, pam_error, "set rhost failed", 0)) { + smb_pam_end(*pamh, pconv); + *pamh = (pam_handle_t *)NULL; + return False; + } +#endif +#ifdef PAM_TTY + DEBUG(4,("smb_pam_start: PAM: setting tty\n")); + pam_error = pam_set_item(*pamh, PAM_TTY, "samba"); + if (!smb_pam_error_handler(*pamh, pam_error, "set tty failed", 0)) { + smb_pam_end(*pamh, pconv); + *pamh = (pam_handle_t *)NULL; + return False; + } +#endif + DEBUG(4,("smb_pam_start: PAM: Init passed for user: %s\n", user)); + return True; +} + +/* + * PAM Authentication Handler + */ +static NTSTATUS smb_pam_auth(pam_handle_t *pamh, const char *user) +{ + int pam_error; + NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE; + + /* + * To enable debugging set in /etc/pam.d/samba: + * auth required /lib/security/pam_pwdb.so nullok shadow audit + */ + + DEBUG(4,("smb_pam_auth: PAM: Authenticate User: %s\n", user)); + pam_error = pam_authenticate(pamh, PAM_SILENT | lp_null_passwords() ? 0 : PAM_DISALLOW_NULL_AUTHTOK); + switch( pam_error ){ + case PAM_AUTH_ERR: + DEBUG(2, ("smb_pam_auth: PAM: Athentication Error for user %s\n", user)); + break; + case PAM_CRED_INSUFFICIENT: + DEBUG(2, ("smb_pam_auth: PAM: Insufficient Credentials for user %s\n", user)); + break; + case PAM_AUTHINFO_UNAVAIL: + DEBUG(2, ("smb_pam_auth: PAM: Authentication Information Unavailable for user %s\n", user)); + break; + case PAM_USER_UNKNOWN: + DEBUG(2, ("smb_pam_auth: PAM: Username %s NOT known to Authentication system\n", user)); + break; + case PAM_MAXTRIES: + DEBUG(2, ("smb_pam_auth: PAM: One or more authentication modules reports user limit for user %s exceeeded\n", user)); + break; + case PAM_ABORT: + DEBUG(0, ("smb_pam_auth: PAM: One or more PAM modules failed to load for user %s\n", user)); + break; + case PAM_SUCCESS: + DEBUG(4, ("smb_pam_auth: PAM: User %s Authenticated OK\n", user)); + break; + default: + DEBUG(0, ("smb_pam_auth: PAM: UNKNOWN ERROR while authenticating user %s\n", user)); + break; + } + + smb_pam_nt_status_error_handler(pamh, pam_error, "Authentication Failure", 2, &nt_status); + return nt_status; +} + +/* + * PAM Password Validation Suite + */ + +NTSTATUS unix_passcheck(TALLOC_CTX *ctx, const char *client, const char *username, const char *password) +{ + NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE; + pam_handle_t *pamh = NULL; + struct pam_conv *pconv = NULL; + + if ((pconv = smb_setup_pam_conv(ctx, smb_pam_conv, username, password)) == NULL) + return nt_status; + + if (!smb_pam_start(&pamh, username, client, pconv)) { + talloc_free(pconv); + return nt_status; + } + + if (!NT_STATUS_IS_OK(nt_status = smb_pam_auth(pamh, username))) { + DEBUG(0, ("smb_pam_passcheck: PAM: smb_pam_auth failed - Rejecting User %s !\n", username)); + } + + smb_pam_end(pamh, pconv); + talloc_free(pconv); + + return nt_status; +} + +#else + +NTSTATUS unix_passcheck(TALLOC_CTX *ctx, const char *client, const char *username, const char *password) +{ + return NT_STATUS_LOGON_FAILURE; +} + +#endif /* WITH_PAM */ |