/* //%2006//////////////////////////////////////////////////////////////////////// // // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems. // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.; // IBM Corp.; EMC Corporation, The Open Group. // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.; // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group. // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.; // EMC Corporation; VERITAS Software Corporation; The Open Group. // Copyright (c) 2006 Hewlett-Packard Development Company, L.P.; IBM Corp.; // EMC Corporation; Symantec Corporation; The Open Group. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // //============================================================================== // //%///////////////////////////////////////////////////////////////////////////// */ #ifndef Executor_PAMAuth_h #define Executor_PAMAuth_h #if !defined(PEGASUS_PAM_AUTHENTICATION) # error "Do not include this file without defining PEGASUS_PAM_AUTHENTICATION" #endif #include #include #include #include #include #include #include #include #include #include #include #include /* **============================================================================== ** ** This program is used to authenticate users with the "Basic PAM ** Authentication" scheme. It was originally written to isolate memory ** PAM module errors to an external process. ** ** This header defines two functions that may be called by clients of this ** process (the parent process). ** ** PAMAuthenticate() ** PAMValidateUser() ** ** Depending on the PEGASUS_USE_PAM_STANDALONE_PROC build flag, these ** functions either call PAM directly or fork and execute a child process ** that performs the requested PAM operation and then exits immediately. ** The parent and child proceses communicate over a local domain socket, ** created by the parent just before executing the client program. ** ** These functions are defined in a header file to avoid the need ** to link a separate client library. ** ** CAUTION: This program must not depend on any Pegasus libraries since ** it is used by the executor process. ** **============================================================================== */ /* **============================================================================== ** ** CimserveraStart() ** ** Starts the CIMSERVERA program, returning a socket used to communicate ** with it. ** **============================================================================== */ static int CimserveraStart(int* sock) { int pair[2]; int pid; /* Get absolute path of CIMSERVERA program. */ char path[EXECUTOR_BUFFER_SIZE]; if (PEGASUS_PAM_STANDALONE_PROC_NAME[0] == '/') Strlcpy(path, PEGASUS_PAM_STANDALONE_PROC_NAME, EXECUTOR_BUFFER_SIZE); else { /* Flawfinder: ignore */ const char* home = getenv("PEGASUS_HOME"); if (!home) return -1; Strlcpy(path, home, EXECUTOR_BUFFER_SIZE); Strlcat(path, "/", EXECUTOR_BUFFER_SIZE); Strlcat(path, PEGASUS_PAM_STANDALONE_PROC_NAME, EXECUTOR_BUFFER_SIZE); } /* Create socket pair for communicating with child process. */ if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) != 0) return -1; /* Fork child: */ pid = fork(); if (pid < 0) { close(pair[0]); close(pair[1]); return -1; } /* Child process: */ if (pid == 0) { char sockStr[32]; const char* argv[3]; close(pair[1]); /* Convert socket number to string. */ sprintf(sockStr, "%d", pair[0]); /* Build arguments for execv(). */ argv[0] = CIMSERVERA; argv[1] = sockStr; argv[2] = 0; /* Execute child: */ /* Flawfinder: ignore */ execv(path, (char**)argv); close(pair[0]); _exit(0); } /* Parent process: */ close(pair[0]); *sock = pair[1]; return pid; } /* **============================================================================== ** ** CimserveraRequest ** **============================================================================== */ typedef struct CimserveraRequestStruct { char arg0[EXECUTOR_BUFFER_SIZE]; char arg1[EXECUTOR_BUFFER_SIZE]; char arg2[EXECUTOR_BUFFER_SIZE]; } CimserveraRequest; /* **============================================================================== ** ** CimserveraResponse ** **============================================================================== */ typedef struct CimserveraResponseStruct { /* '0' means authentication successful. '-1' means authentication failed. */ int status; } CimserveraResponse; /* **============================================================================== ** ** CimserveraProcessOperation() ** **============================================================================== */ static int CimserveraProcessOperation( const char* operationName, const char* username, const char* password) { int sock; int pid; int status; /* Create the CIMSERVERA process. */ pid = CimserveraStart(&sock); if (pid == -1) return -1; /* Send request, get response. */ status = 0; do { CimserveraRequest request; CimserveraResponse response; /* Send request to CIMSERVERA process. */ memset(&request, 0, sizeof(request)); Strlcpy(request.arg0, operationName, EXECUTOR_BUFFER_SIZE); Strlcpy(request.arg1, username, EXECUTOR_BUFFER_SIZE); Strlcpy(request.arg2, password, EXECUTOR_BUFFER_SIZE); if (SendBlock(sock, &request, sizeof(request)) != sizeof(request)) { status = -1; break; } /* Receive response from CIMSERVERA process. */ if (RecvBlock(sock, &response, sizeof(response)) != sizeof(response)) { status = -1; break; } /* Check status. */ if (response.status != 0) { status = -1; break; } #if !defined(PEGASUS_ENABLE_PRIVILEGE_SEPARATION) /* When called from the main cimserver process, the cimservera exit status must be harvested explicitly to prevent zombies. */ while ((waitpid(pid, 0, 0) == -1) && (errno == EINTR)) ; #endif } while (0); close(sock); return status; } /* **============================================================================== ** ** struct PAMData ** ** Client data passed to PAM routines. ** **============================================================================== */ typedef struct PAMDataStruct { const char* password; } PAMData; /* **============================================================================== ** ** PAMAuthenticateCallback() ** ** Callback used by PAMAuthenticate(). ** **============================================================================== */ static int PAMAuthenticateCallback( int num_msg, #if defined(PEGASUS_OS_LINUX) const struct pam_message** msg, #else struct pam_message** msg, #endif struct pam_response** resp, void* appdata_ptr) { PAMData* data = (PAMData*)appdata_ptr; int i; if (num_msg > 0) { *resp = (struct pam_response*)calloc( num_msg, sizeof(struct pam_response)); if (*resp == NULL) return PAM_BUF_ERR; } else return PAM_CONV_ERR; for (i = 0; i < num_msg; i++) { switch (msg[i]->msg_style) { case PAM_PROMPT_ECHO_OFF: { resp[i]->resp = (char*)malloc(PAM_MAX_MSG_SIZE); Strlcpy(resp[i]->resp, data->password, PAM_MAX_MSG_SIZE); resp[i]->resp_retcode = 0; break; } default: return PAM_CONV_ERR; } } return PAM_SUCCESS; } /* **============================================================================== ** ** PAMValidateUserCallback() ** ** Callback used by PAMValidateUser(). ** **============================================================================== */ static int PAMValidateUserCallback( int num_msg, #if defined(PEGASUS_OS_LINUX) const struct pam_message** msg, #else struct pam_message** msg, #endif struct pam_response** resp, void* appdata_ptr) { /* Unused */ msg = 0; /* Unused */ appdata_ptr = 0; if (num_msg > 0) { *resp = (struct pam_response*)calloc( num_msg, sizeof(struct pam_response)); if (*resp == NULL) return PAM_BUF_ERR; } else return PAM_CONV_ERR; return PAM_SUCCESS; } /* **============================================================================== ** ** PAMAuthenticateInProcess() ** ** Performs basic PAM authentication on the given username and password. ** **============================================================================== */ static int PAMAuthenticateInProcess( const char* username, const char* password) { PAMData data; struct pam_conv pconv; pam_handle_t* handle; data.password = password; pconv.conv = PAMAuthenticateCallback; pconv.appdata_ptr = &data; if (pam_start("wbem", username, &pconv, &handle) != PAM_SUCCESS) return -1; if (pam_authenticate(handle, 0) != PAM_SUCCESS) { pam_end(handle, 0); return -1; } if (pam_acct_mgmt(handle, 0) != PAM_SUCCESS) { pam_end(handle, 0); return -1; } pam_end(handle, 0); return 0; } /* **============================================================================== ** ** PAMValidateUserInProcess() ** ** Validate that the *username* refers to a valid PAM user. ** **============================================================================== */ static int PAMValidateUserInProcess(const char* username) { PAMData data; struct pam_conv pconv; pam_handle_t* phandle; pconv.conv = PAMValidateUserCallback; pconv.appdata_ptr = &data; if (pam_start("wbem", username, &pconv, &phandle) != PAM_SUCCESS) return -1; if (pam_acct_mgmt(phandle, 0) != PAM_SUCCESS) { pam_end(phandle, 0); return -1; } pam_end(phandle, 0); return 0; } /* **============================================================================== ** ** PAMAuthenticate() ** ** Performs basic PAM authentication on the given username and password. ** **============================================================================== */ static int PAMAuthenticate(const char* username, const char* password) { #ifdef PEGASUS_USE_PAM_STANDALONE_PROC return CimserveraProcessOperation("authenticate", username, password); #else return PAMAuthenticateInProcess(username, password); #endif } /* **============================================================================== ** ** PAMValidateUser() ** ** Validate that the *username* refers to a valid PAM user. ** **============================================================================== */ static int PAMValidateUser(const char* username) { #ifdef PEGASUS_USE_PAM_STANDALONE_PROC return CimserveraProcessOperation("validateUser", username, ""); #else return PAMValidateUserInProcess(username); #endif } #endif /* Executor_PAMAuth_h */