/* //%LICENSE//////////////////////////////////////////////////////////////// // // Licensed to The Open Group (TOG) under one or more contributor license // agreements. Refer to the OpenPegasusNOTICE.txt file distributed with // this work for additional information regarding copyright ownership. // Each contributor licenses this file to you under the OpenPegasus Open // Source License; you may not use this file except in compliance with the // License. // // 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; } } while (0); #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 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 */