| //****************************************************************************** |
| // @@@ START COPYRIGHT @@@ |
| // |
| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| // |
| // @@@ END COPYRIGHT @@@ |
| //****************************************************************************** |
| |
| // LCOV_EXCL_START -- lets be a little paranoid and not let any in-line funcs |
| // from the header files slip into the coverage count |
| |
| #include "dbUserAuth.h" |
| #include "token.h" |
| #include "tokenkey.h" |
| #include "ldapconfignode.h" |
| #include <stdio.h> |
| #include <stddef.h> |
| #include <stdlib.h> |
| #include <limits.h> |
| #include <string.h> |
| #include <string> |
| #include <vector> |
| #include <exception> |
| #include <ctype.h> |
| |
| #include <iostream> |
| #include <sys/types.h> |
| #include <linux/unistd.h> // gettid |
| #include "../../../sqf/inc/cextdecs/cextdecs.h" |
| |
| // Used to disable and enable dumps via setrlimit in a release env. |
| #ifndef DBSECURITY_DEBUG |
| #include <sys/resource.h> |
| #endif |
| |
| #include "authEvents.h" |
| #include "ldapconfignode.h" |
| |
| #include "common/evl_sqlog_eventnum.h" |
| #include "sqevlog/evl_sqlog_writer.h" |
| #include "seabed/int/types.h" |
| #include "seabed/pctl.h" |
| #include "seabed/ms.h" |
| #include "seabed/fserr.h" |
| class ComDiagsArea; |
| class Queue; |
| #include "SQLCLIdev.h" |
| #ifndef Lng32 |
| typedef int Lng32; |
| #endif |
| #include "ComSmallDefs.h" |
| #include "NAUserId.h" |
| #include "ExExeUtilCli.h" |
| enum {INTERNAL_QUERY_FROM_EXEUTIL = 0x20000}; |
| // LCOV_EXCL_STOP |
| |
| #define ZFIL_ERR_BADPARMVALUE 590 |
| #define ZFIL_ERR_BOUNDSERR 22 |
| #define ZFIL_ERR_OK 0 |
| #define ZFIL_ERR_SECVIOL 48 |
| #ifndef SEABASE_AUTHS |
| #define SEABASE_AUTHS "AUTHS" |
| #endif |
| |
| using namespace std; |
| |
| class UserCacheContents; |
| class ClientContents; |
| |
| static void authenticateUser( |
| DBUserAuthContents & self, |
| const char * username, |
| const char * password, |
| ClientContents & clientInfo, |
| AUTHENTICATION_INFO & authenticationInfo, |
| PERFORMANCE_INFO & performanceInfo); |
| |
| void cacheUserInfo( |
| const char * username, |
| const char * databaseUsername, |
| int32_t userID, |
| bool isValid, |
| int64_t redefTime); |
| |
| static LDAuthStatus executeLDAPAuthentication( |
| DBUserAuthContents & self, |
| const char * username, |
| const char * password, |
| LDAPConfigNode::LDAPConfigType configType, |
| PERFORMANCE_INFO & performanceInfo); |
| |
| inline static const UserCacheContents * fetchFromCacheByUsername(const char * username); |
| |
| inline static const UserCacheContents * fetchFromCacheByUserID(long userID); |
| |
| static int32_t fetchFromAUTHSTable( |
| const char * externalUsername, |
| char * databaseUsername, |
| int32_t & userID, |
| bool & isValid, |
| int64_t & redefTime); |
| |
| static int32_t fetchFromAUTHSTable( |
| int32_t userID, |
| char * databaseUsername, |
| char * externalUsername, |
| bool & isValid, |
| int64_t & redefTime); |
| |
| |
| static void logAuthenticationErrors(std::vector<AuthEvent> & authEvents); |
| |
| static void logAuthenticationOutcome( |
| const string & external_user_name, |
| const string & internal_user_name, |
| const int32_t user_id, |
| ClientContents & clientInfo, |
| const AUTH_OUTCOME outcome); |
| |
| static void logAuthenticationRetries( |
| int nodeID, |
| const char * username); |
| |
| static void logToEventTable( |
| int nodeID, |
| DB_SECURITY_EVENTID eventID, |
| posix_sqlog_severity_t severity, |
| const char * msg); |
| |
| static void prepareUserNameForQuery( |
| char *nameForQuery, |
| const char *extName); |
| |
| static void stripAllTrailingBlanks( |
| char * buf, |
| size_t len); |
| |
| static void timeDiff ( |
| struct timespec t1, |
| struct timespec t2, |
| struct timespec &tDiff); |
| |
| inline static void upshiftString( |
| const char * inputString, |
| char * outputString); |
| |
| static void writeLog(const char * text); |
| |
| class ClientContents |
| { |
| public: |
| char clientName[257]; |
| char clientUserName[257]; |
| char applicationName[257]; |
| }; |
| |
| |
| class BlackBox |
| { |
| public: |
| USERS_INFO usersInfo; |
| int error; //ACH do we need this? |
| UA_Status errorDetail; |
| bool isAuthenticated; |
| }; |
| |
| class DBUserAuthContents |
| { |
| public: |
| BlackBox bb; |
| int nodeID; |
| std::vector<AuthEvent> authEvents; |
| |
| int bypassAuthentication( |
| Token & token, |
| AUTHENTICATION_INFO & authenticationInfo); |
| |
| std::vector<AuthEvent> &getAuthEvents() { return authEvents; } |
| |
| void deserialize(Token &token); |
| void reset(); |
| }; |
| |
| class UserCacheContents |
| { |
| public: |
| char externalUsername[257]; |
| char databaseUsername[257]; |
| int32_t userID; |
| bool isValid; |
| int64_t redefTime; |
| }; |
| |
| static std::vector<UserCacheContents> userCache; |
| |
| #define gettid() static_cast<pid_t>(syscall(__NR_gettid)) |
| |
| static DBUserAuth * me = NULL; |
| |
| #pragma page "DBUserAuth::CloseConnection" |
| // ***************************************************************************** |
| // * * |
| // * Function: DBUserAuth::CloseConnection * |
| // * * |
| // * Closes any open LDAP connections. * |
| // * * |
| // ***************************************************************************** |
| |
| void DBUserAuth::CloseConnection() |
| |
| { |
| |
| LDAPConfigNode::CloseConnection(); |
| |
| } |
| //******************** End of DBUserAuth::CloseConnection ********************** |
| |
| #pragma page "DBUserAuth::FreeInstance" |
| // ***************************************************************************** |
| // * * |
| // * Function: DBUserAuth::FreeInstance * |
| // * * |
| // * Destroys the singleton instance of a DBUserAuth object. * |
| // * * |
| // ***************************************************************************** |
| |
| void DBUserAuth::FreeInstance() |
| |
| { |
| |
| if (me != NULL) |
| delete me; |
| |
| } |
| //********************* End of DBUserAuth::FreeInstance ************************* |
| |
| #pragma page "DBUserAuth::GetInstance" |
| // ***************************************************************************** |
| // * * |
| // * Function: DBUserAuth::GetInstance * |
| // * Constructs or returns the singleton instance of a DBUserAuth object. * |
| // * * |
| // ***************************************************************************** |
| |
| DBUserAuth * DBUserAuth::GetInstance() |
| |
| { |
| |
| if (me != NULL) |
| return me; |
| |
| me = new DBUserAuth(); |
| return me; |
| |
| } |
| //********************** End of DBUserAuth::GetInstance ************************ |
| |
| #pragma page "DBUserAuth::GetBlackBox" |
| // ***************************************************************************** |
| // * * |
| // * Function: DBUserAuth::GetBlackBox * |
| // * * |
| // * Returns the black box data associated with this session. If there is * |
| // * no black box associated with this session, an empty string is returned. * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Parameters: * |
| // * * |
| // * <blackBox> char * Out * |
| // * is the external username (not the database username). * |
| // * * |
| // * <pretendTokenIsNull> bool In * |
| // * is a minivan boolean used in testing. * |
| // * * |
| // ***************************************************************************** |
| void DBUserAuth::GetBlackBox( |
| char *blackBox, |
| bool pretendTokenIsNull) |
| |
| { |
| |
| Token *token = Token::Obtain(); |
| |
| // |
| // The only way Token::Obtain could return a NULL is if we were unable to |
| // allocate memory (a couple hundred bytes), which either means there is a |
| // serious memory leak somewhere or the heap is corrupted. Neither is very |
| // likely, but good coding practice dictates we check for NULL anyway. So |
| // why would we ever want to pretend the token is NULL? Just to take a |
| // different branch and execute a few lines? Count on it. |
| // |
| |
| if (pretendTokenIsNull) |
| token = NULL; |
| |
| // |
| // If token is NULL, either real or pretend, return an empty black box. |
| // |
| |
| if (token == NULL) |
| { |
| blackBox[0] = 0; |
| return; |
| } |
| |
| token->getData(blackBox); |
| |
| } |
| //********************** End of DBUserAuth::GetBlackBox ************************ |
| |
| |
| #pragma page "DBUserAuth::GetBlackBoxSize" |
| // ***************************************************************************** |
| // * * |
| // * Function: DBUserAuth::GetBlackBoxSize * |
| // * Returns the size of the black box data associated with this session. * |
| // * If there is no black box associated with this session, zero is returned. * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Parameter: * |
| // * * |
| // * <pretendTokenIsNull> bool In * |
| // * is a minivan boolean used in testing. * |
| // * * |
| // ***************************************************************************** |
| size_t DBUserAuth::GetBlackBoxSize(bool pretendTokenIsNull) |
| |
| { |
| |
| Token *token = Token::Obtain(); |
| |
| if (pretendTokenIsNull) |
| token = NULL; |
| |
| if (token == NULL) |
| return 0; |
| |
| return token->getDataSize(); |
| |
| } |
| //******************** End of DBUserAuth::GetBlackBoxSize ********************** |
| |
| #pragma page "DBUserAuth::FormatStatusMsg" |
| // ***************************************************************************** |
| // * * |
| // * Function: DBUserAuth::FormatStatusMsg * |
| // * Formats a status error or warning as a message. * |
| // * * |
| // * * |
| // * If there is no black box associated with this session, zero is returned. * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Parameters: * |
| // * * |
| // * <status> UA_Status In * |
| // * is the status code to be formatted. * |
| // * * |
| // * <statusMsg> char * Out * |
| // * returns the formatted message. * |
| // * * |
| // ***************************************************************************** |
| void DBUserAuth::FormatStatusMsg( |
| UA_Status status, |
| char * statusMsg) |
| |
| { |
| |
| switch (status) |
| { |
| case UA_STATUS_OK: |
| strcpy(statusMsg,"OK, no warnings"); |
| break; |
| case UA_STATUS_ERR_INVALID: |
| strcpy(statusMsg,"Username or password is invalid"); |
| break; |
| case UA_STATUS_ERR_SYSTEM: |
| strcpy(statusMsg,"Resource or internal error occurred"); |
| break; |
| default: |
| strcpy(statusMsg,"Resource or internal error occurred"); |
| break; |
| } |
| |
| } |
| //******************** End of DBUserAuth::FormatStatusMsg ********************** |
| |
| #pragma page "DBUserAuth::CheckExternalUsernameDefined" |
| // ***************************************************************************** |
| // * * |
| // * Function: DBUserAuth::CheckExternalUsernameDefined * |
| // * * |
| // * Determines if an external username of the form expected by the * |
| // * identity during authentication is defined on the identity store. * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Parameters: * |
| // * * |
| // * <externalUsername> const char * In * |
| // * is the external username to be checked on the identity. * |
| // * * |
| // * <configurationOrdinal> AuthenticationConfiguration In * |
| // * specifies which configuration to use when searching for the username. * |
| // * If Unknown, LDAPConfigNode will use the default specified in the * |
| // * config file (.traf_authentication_config). * |
| // * * |
| // * <foundConfigurationOrdinal> AuthenticationConfiguration & Out * |
| // * passes back the configuration where the user was found, or zero if the * |
| // * user was not found. * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Returns: CheckUserResult * |
| // * * |
| // * UserExists -- User was found on LDAP server * |
| // * UserDoesNotExist -- User was not found on LDAP server * |
| // * ErrorInCheck -- An error prevented checking * |
| // * * |
| // ***************************************************************************** |
| DBUserAuth::CheckUserResult DBUserAuth::CheckExternalUsernameDefined( |
| const char * externalUsername, |
| AuthenticationConfiguration configurationOrdinal, |
| AuthenticationConfiguration & foundConfigurationOrdinal) |
| |
| { |
| |
| #ifdef __SQ_LDAP_NO_SECURITY_CHECKING |
| return CheckUserResult_UserExists; |
| #else |
| |
| char *authEnv; |
| std::vector<AuthEvent> authEvents; |
| |
| authEnv = getenv("TRAFODION_ENABLE_AUTHENTICATION"); |
| if (authEnv == NULL || strcmp(authEnv,"YES") != 0) |
| { |
| foundConfigurationOrdinal = PrimaryConfiguration; |
| return UserExists; |
| } |
| |
| string userDN = ""; // User DN, used to bind to LDAP serer |
| LDAPConfigNode *searchNode; |
| |
| LDAPConfigNode::LDAPConfigType configType = LDAPConfigNode::UnknownConfiguration; |
| |
| switch (configurationOrdinal) |
| { |
| case 1: |
| configType = LDAPConfigNode::PrimaryConfiguration; |
| break; |
| case 2: |
| configType = LDAPConfigNode::SecondaryConfiguration; |
| break; |
| default: |
| configType = LDAPConfigNode::UnknownConfiguration; |
| } |
| |
| searchNode = LDAPConfigNode::GetLDAPConnection(authEvents,configType,SearchConnection); |
| |
| if (searchNode == NULL) |
| return ErrorDuringCheck; |
| |
| LDSearchStatus searchStatus = searchNode->lookupUser(authEvents,externalUsername,userDN); |
| |
| if (searchStatus == LDSearchNotFound) |
| return UserDoesNotExist; |
| |
| // didn't get "found" or "not found", so we have problems! |
| if (searchStatus != LDSearchFound) |
| return ErrorDuringCheck; |
| |
| // External username was found. But where? |
| switch (searchNode->getConfigType()) |
| { |
| case LDAPConfigNode::UnknownConfiguration: |
| foundConfigurationOrdinal = DefaultConfiguration; |
| break; |
| case LDAPConfigNode::PrimaryConfiguration: |
| foundConfigurationOrdinal = PrimaryConfiguration; |
| break; |
| case LDAPConfigNode::SecondaryConfiguration: |
| foundConfigurationOrdinal = SecondaryConfiguration; |
| break; |
| default: |
| foundConfigurationOrdinal = DefaultConfiguration; |
| } |
| |
| return UserExists; |
| |
| #endif |
| |
| } |
| //************** End of DBUserAuth::CheckExternalUsernameDefined *************** |
| |
| #pragma page "void DBUserAuth::DBUserAuth" |
| // ***************************************************************************** |
| // * * |
| // * Function: DBUserAuth::DBUserAuth * |
| // * This function constructs a DBUserAuth object and its contents. * |
| // * * |
| // ***************************************************************************** |
| DBUserAuth::DBUserAuth() |
| : self(*new DBUserAuthContents()) |
| |
| { |
| |
| self.reset(); |
| |
| char processName[MS_MON_MAX_PROCESS_NAME+1]; // +1 for trailing null |
| |
| // obtain our node ID from Seabed |
| msg_mon_get_my_info(&self.nodeID, // nodeID |
| NULL, // mon process-id |
| processName, // mon name |
| MS_MON_MAX_PROCESS_NAME, // mon name-len |
| NULL, // mon process-type |
| NULL, // mon zone-id |
| NULL, // os process-id |
| NULL); // os thread-id |
| |
| } |
| //********************** End of DBUserAuth::DBUserAuth ************************* |
| |
| |
| #pragma page "void DBUserAuth::~DBUserAuth" |
| // ***************************************************************************** |
| // * * |
| // * Function: DBUserAuth::~DBUserAuth * |
| // * This function destroysa DBUserAuth object and its contents. * |
| // * * |
| // ***************************************************************************** |
| DBUserAuth::~DBUserAuth() |
| |
| { |
| |
| delete &self; |
| |
| } |
| //********************** End of DBUserAuth::~DBUserAuth ************************ |
| |
| |
| #pragma page "DBUserAuth::getAuthFunction" |
| // ***************************************************************************** |
| // * * |
| // * Function: DBUserAuth::getAuthFunction * |
| // * * |
| // * Returns the token verification function set by MXOSRVR. * |
| // * * |
| // ***************************************************************************** |
| AuthFunction DBUserAuth::getAuthFunction() |
| |
| { |
| |
| return validateTokenFunc; |
| |
| } |
| //******************* End of DBUserAuth::getAuthFunction *********************** |
| #pragma page "DBUserAuth::getUserID" |
| // ***************************************************************************** |
| // * * |
| // * Function: DBUserAuth::getUserID * |
| // * * |
| // * Returns the database user ID for the user. * |
| // * * |
| // ***************************************************************************** |
| int32_t DBUserAuth::getUserID() const |
| |
| { |
| |
| return self.bb.usersInfo.effectiveUserID; |
| |
| } |
| //************************ End of DBUserAuth::getUserID ************************ |
| |
| #pragma page "DBUserAuth::getDBUserName" |
| // ***************************************************************************** |
| // * * |
| // * Function: DBUserAuth::getDBUserName * |
| // * * |
| // * Returns the database username for the user. * |
| // * * |
| // * Parameters: * |
| // * * |
| // * <databaseUsername> char * Out * |
| // * returns the user name as a null terminated string. * |
| // * <maxLen> size_t In * |
| // * maximum size of the null terminated string. * |
| // * * |
| // ***************************************************************************** |
| void DBUserAuth::getDBUserName(char *databaseUsername, size_t maxLen) const |
| |
| { |
| |
| memset(databaseUsername, '\0', maxLen); |
| strncpy(databaseUsername,self.bb.usersInfo.databaseUsername, maxLen - 1); |
| databaseUsername[maxLen -1] = '\0'; |
| |
| } |
| //********************** End of DBUserAuth::getDBUserName ********************** |
| |
| #pragma page "DBUserAuth::getExternalUsername" |
| // ***************************************************************************** |
| // * * |
| // * Function: DBUserAuth::getExternalUsername * |
| // * * |
| // * Returns the external username for the user. * |
| // * * |
| // * Parameters: * |
| // * * |
| // * <externalUsername> char * Out * |
| // * passes back the external username as a null terminated string. * |
| // * * |
| // * <maxLen> size_t In * |
| // * maximum size of the null terminated string. * |
| // * * |
| // ***************************************************************************** |
| void DBUserAuth::getExternalUsername( |
| char * externalUsername, |
| size_t maxLen) const |
| |
| { |
| |
| memset(externalUsername,'\0',maxLen); |
| strncpy(externalUsername,self.bb.usersInfo.externalUsername,maxLen - 1); |
| externalUsername[maxLen - 1] = '\0'; |
| |
| } |
| //****************** End of DBUserAuth::getExternalUsername ******************** |
| |
| |
| #pragma page "DBUserAuth::getTokenKeyAsString" |
| // ***************************************************************************** |
| // * * |
| // * Function: DBUserAuth::getTokenKeyAsString * |
| // * Returns the Token Key as a formatted ASCII string. * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Parameters: * |
| // * * |
| // * <tokenKeyString> char * Out * |
| // * returns the Token Key as a formatted ASCII string. * |
| // * * |
| // ***************************************************************************** |
| |
| void DBUserAuth::getTokenKeyAsString(char *tokenKeyString) const |
| |
| { |
| |
| Token *token = Token::Obtain(); |
| |
| // LCOV_EXCL_START |
| if (token == NULL) |
| { |
| tokenKeyString[0] = 0; |
| return; |
| } |
| // LCOV_EXCL_STOP |
| |
| token->getTokenKeyAsString(tokenKeyString); |
| |
| } |
| //***************** End of DBUserAuth::getTokenKeyAsString ********************* |
| |
| |
| |
| |
| #pragma page "Token::getTokenKeySize" |
| // ***************************************************************************** |
| // * * |
| // * Function: DBUserAuth::getTokenKeySize * |
| // * * |
| // * Returns the token key size. Only used in testing. * |
| // * * |
| // ***************************************************************************** |
| size_t DBUserAuth::getTokenKeySize() const |
| |
| { |
| |
| Token *token = Token::Obtain(); |
| |
| if (token == NULL) |
| return 0; |
| |
| return token->getTokenKeySize(); |
| |
| } |
| //******************* End of DBUserAuth:getTokenKeySize ************************ |
| |
| |
| #pragma page "DBUserAuth::setAuthFunction" |
| // ***************************************************************************** |
| // * * |
| // * Function: DBUserAuth::setAuthFunction * |
| // * * |
| // * Sets the token verification function. * |
| // * * |
| // ***************************************************************************** |
| void DBUserAuth::setAuthFunction(AuthFunction somefunc) |
| |
| { |
| |
| validateTokenFunc = somefunc; |
| |
| } |
| //******************** End of DBUserAuth::setAuthFunction ********************** |
| |
| |
| #pragma page "DBUserAuth::verify" |
| // ***************************************************************************** |
| // * * |
| // * Function: DBUserAuth::verify * |
| // * * |
| // * Verifies a username and password on a database instance. * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Parameters: * |
| // * * |
| // * <username> const char * In * |
| // * is the external username (not the database username). * |
| // * * |
| // * <credentials> char * In/Out * |
| // * is the password for the user or a token that represents the user * |
| // * session. On return is a token. * |
| // * * |
| // * <errorDetail> UA_Status & Out * |
| // * passes back which input parameter is at fault on failure. * |
| // * * |
| // * <authenticationInfo AUTHENTICATION_INFO & Out * |
| // * passes back user and error data related to the authentication. * |
| // * * |
| // * <client_info> const CLIENT_INFO & In * |
| // * is the client related information needed for audit logging. * |
| // * * |
| // * <performanceInfo> PERFORMANCE_INFO & Out * |
| // * passes back elapsed time for authentication suboperations. * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Returns: int * |
| // * * |
| // * 0 - Authentication completed. * |
| // * 22 - Bounds error. Number of param in error returned in errorDetail. * |
| // * 590 - NULL param. Number of param in error returned in errorDetail. * |
| // * * |
| // ***************************************************************************** |
| int DBUserAuth::verify( |
| const char * externalUsername, |
| char * credentials, |
| UA_Status & errorDetail, |
| AUTHENTICATION_INFO & authenticationInfo, |
| const CLIENT_INFO & client_info, |
| PERFORMANCE_INFO & performanceInfo) |
| |
| |
| { |
| |
| char buf[500]; |
| |
| memset((void *)&performanceInfo, '\0', sizeof(performanceInfo)); |
| |
| |
| if (externalUsername == NULL) |
| { |
| errorDetail = UA_STATUS_PARAM1; |
| return ZFIL_ERR_BADPARMVALUE; |
| } |
| |
| if (credentials == NULL) |
| { |
| errorDetail = UA_STATUS_PARAM2; |
| return ZFIL_ERR_BADPARMVALUE; |
| } |
| |
| if (strlen(externalUsername) > MAX_EXTUSERNAME_LEN) |
| { |
| errorDetail = UA_STATUS_PARAM1; |
| return ZFIL_ERR_BOUNDSERR; |
| } |
| |
| if (strlen(credentials) > MAX_EXTPASSWORD_LEN) |
| { |
| errorDetail = UA_STATUS_PARAM2; |
| return ZFIL_ERR_BOUNDSERR; |
| } |
| |
| static ClientContents clientInfo; |
| |
| memset((void *)&clientInfo, '\0', sizeof(clientInfo)); |
| |
| if (client_info.client_name != NULL) |
| strncpy(clientInfo.clientName, |
| client_info.client_name, |
| sizeof(clientInfo.clientName) - 1); |
| if (client_info.client_user_name != NULL) |
| strncpy(clientInfo.clientUserName, |
| client_info.client_user_name, |
| sizeof(clientInfo.clientUserName) - 1); |
| if (client_info.application_name != NULL) |
| strncpy(clientInfo.applicationName, |
| client_info.application_name, |
| sizeof(clientInfo.applicationName) - 1); |
| |
| |
| errorDetail = UA_STATUS_OK; |
| self.reset(); |
| |
| Token *token = Token::Verify(credentials,validateTokenFunc); |
| |
| // If we have a valid token, we need to deserialize the black box data |
| if (token != NULL) |
| { |
| self.deserialize(*token); //ACH load auth info from black box data. |
| |
| //Need to set performance info |
| return ZFIL_ERR_OK; |
| } |
| |
| // |
| // Credentials are not a valid token; must be a password. Proceed with normal |
| // authentication. First, obtain a token to store authentication results. |
| // |
| |
| token = Token::Obtain(); |
| |
| if (token == NULL) |
| return ZFIL_ERR_BOUNDSERR; //ACH better error? |
| |
| token->reset(); |
| char *authEnv; |
| |
| authEnv = getenv("TRAFODION_ENABLE_AUTHENTICATION"); |
| if (authEnv == NULL || strcmp(authEnv,"YES") != 0) |
| return self.bypassAuthentication(*token,authenticationInfo); |
| |
| // |
| // Ok, let's actually verify the username and password. |
| // |
| |
| authenticateUser(self,externalUsername,credentials,clientInfo, |
| authenticationInfo,performanceInfo); |
| |
| // Convert password to a token key. Note this is done for all authentications, |
| // both successful and unsuccessful. |
| |
| token->getTokenKey(authenticationInfo.tokenKey); |
| authenticationInfo.tokenKeySize = token->getTokenKeySize(); |
| |
| // Save authentication results in black box within token container |
| token->setData((char *)&self.bb,sizeof(self.bb)); |
| |
| return ZFIL_ERR_OK; |
| |
| } |
| //************************* End of DBUserAuth::verify ************************** |
| |
| #pragma page "DBUserAuth::verifyChild" |
| // ***************************************************************************** |
| // * * |
| // * Function: DBUserAuth::verifyChild * |
| // * * |
| // * Verifies the token key sent by a child MXOSRVR and returns the * |
| // * blackbox data. * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Parameters: * |
| // * * |
| // * <credentials> const char * In * |
| // * is the token sent by the child server. * |
| // * * |
| // * <data> char * Out * |
| // * passes back the authentication data (black box) associated with * |
| // * this token. * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Returns: size_t * |
| // * * |
| // * The number of bytes in <data>. * |
| // * * |
| // ***************************************************************************** |
| size_t DBUserAuth::verifyChild( |
| const char * credentials, |
| char * data) |
| |
| { |
| |
| // Compare the token key sent with the one stored in this server |
| Token *token = Token::Verify(credentials); |
| |
| if (token == NULL) |
| return 0; |
| |
| token->getData(data); |
| |
| return token->getDataSize(); |
| |
| } |
| //********************* End of DBUserAuth::verifyChild ********************** |
| |
| // DBUserAuthContents functions |
| |
| #pragma page "DBUserAuthContents::bypassAuthentication" |
| // ***************************************************************************** |
| // * * |
| // * Function: DBUserAuthContents::bypassAuthentication * |
| // * * |
| // * Skip authentication, populate fields as if DB__ROOT logged on * |
| // * successfully. * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Parameters: * |
| // * * |
| // * <token> Token & In * |
| // * is a reference to the token containing the data to be deserialized. * |
| // * * |
| // * <authenticationInfo AUTHENTICATION_INFO & Out * |
| // * passes back user and error data related to the authentication. * |
| // * * |
| // ***************************************************************************** |
| int DBUserAuthContents::bypassAuthentication( |
| Token & token, |
| AUTHENTICATION_INFO & authenticationInfo) |
| |
| { |
| |
| bb.error = ZFIL_ERR_OK; |
| bb.isAuthenticated = true; |
| bb.errorDetail = UA_STATUS_OK; |
| bb.usersInfo.effectiveUserID = SUPER_USER; |
| bb.usersInfo.sessionUserID = SUPER_USER; |
| strcpy(bb.usersInfo.databaseUsername,"DB__ROOT"); |
| strcpy(bb.usersInfo.externalUsername,"DB__ROOT"); |
| token.setData((char *)&bb,sizeof(bb)); |
| |
| authenticationInfo.error = bb.error; |
| authenticationInfo.errorDetail = bb.errorDetail; |
| authenticationInfo.usersInfo.effectiveUserID = SUPER_USER; |
| authenticationInfo.usersInfo.sessionUserID = SUPER_USER; |
| strcpy(authenticationInfo.usersInfo.databaseUsername,"DB__ROOT"); |
| strcpy(authenticationInfo.usersInfo.externalUsername,"DB__ROOT"); |
| authenticationInfo.tokenKeySize = token.getTokenKeySize(); |
| token.getTokenKey(authenticationInfo.tokenKey); |
| |
| return ZFIL_ERR_OK; |
| |
| } |
| //************* End of DBUserAuthContents::bypassAuthentication **************** |
| |
| |
| |
| #pragma page "DBUserAuthContents::deserialize" |
| // ***************************************************************************** |
| // * * |
| // * Function: DBUserAuthContents::deserialize * |
| // * Sets all member values from a serialized token blackbox. * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Parameters: * |
| // * * |
| // * <token> Token & In * |
| // * is a reference to the token containing the data to be deserialized. * |
| // * * |
| // ***************************************************************************** |
| |
| void DBUserAuthContents::deserialize(Token &token) |
| |
| { |
| |
| size_t blackBoxSize = token.getDataSize(); |
| |
| char *blackBox = new char[blackBoxSize]; |
| |
| token.getData(blackBox); |
| |
| memcpy((char *)(&bb),blackBox,blackBoxSize); |
| |
| delete [] blackBox; |
| |
| } |
| //***************** End of DBUserAuthContents::deserialize ********************* |
| |
| #pragma page "DBUserAuthContents::reset" |
| // ***************************************************************************** |
| // * * |
| // * Function: DBUserAuthContents::reset * |
| // * Resets all the member values to their default. * |
| // * * |
| // ***************************************************************************** |
| void DBUserAuthContents::reset() |
| |
| { |
| |
| bb.usersInfo.effectiveUserID = 0;//ACH can we reserve value for NO_SUCH_USER? |
| bb.usersInfo.sessionUserID = 0;//ACH can we reserve value for NO_SUCH_USER? |
| bb.usersInfo.externalUsername[0] = 0; |
| bb.usersInfo.databaseUsername[0] = 0; |
| bb.usersInfo.redefTime = 0; |
| bb.isAuthenticated = false; |
| bb.error = 0; |
| bb.errorDetail = UA_STATUS_OK; |
| |
| } |
| //********************* End of DBUserAuthContents::reset *********************** |
| |
| // Begin private functions |
| |
| |
| #pragma page "authenticateUser" |
| // ***************************************************************************** |
| // * * |
| // * Function: authenticateUser * |
| // * * |
| // * Validates user is registered on Trafodion, and the username and * |
| // * password are valid on the directory server. * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Parameters: * |
| // * * |
| // * <self> DBUserAuthContents & In/Out * |
| // * is a reference to a DBUserAuthContents object. Results of the * |
| // * authentication are stored here. * |
| // * * |
| // * <externalUsername> const char * In * |
| // * is the username. Username must be registered (in AUTHS table) and * |
| // * defined on LDAP server. * |
| // * * |
| // * <password> const char * In * |
| // * is the password for username. Password is authenticated on LDAP server* |
| // * * |
| // * <authenticationInfo AUTHENTICATION_INFO & Out * |
| // * passes back user and error data related to the authentication. * |
| // * * |
| // * <client_info> const CLIENT_INFO & In * |
| // * is the client related information needed for audit logging. * |
| // * * |
| // * <performanceInfo> PERFORMANCE_INFO & Out * |
| // * passes back elapsed time for authentication suboperations. * |
| // * * |
| // ***************************************************************************** |
| |
| static void authenticateUser( |
| DBUserAuthContents & self, |
| const char * externalUsername, |
| const char * password, |
| ClientContents & clientInfo, |
| AUTHENTICATION_INFO & authenticationInfo, |
| PERFORMANCE_INFO & performanceInfo) |
| |
| { |
| |
| self.bb.isAuthenticated = false; |
| |
| long retCode; |
| bool isValid; |
| AuthConfigType authType; |
| USERS_INFO usersInfo; |
| |
| char eventMsg[MAX_EVENT_MSG_SIZE]; |
| |
| // |
| // First step; is the user registered. If not, no sense bothering the |
| // LDAP server. |
| // |
| memset(usersInfo.databaseUsername,' ',sizeof(usersInfo.databaseUsername)); |
| strcpy(usersInfo.externalUsername,externalUsername); |
| |
| int64_t startTime = JULIANTIMESTAMP(); |
| |
| retCode = fetchFromAUTHSTable(externalUsername,usersInfo.databaseUsername, |
| usersInfo.sessionUserID,isValid, |
| usersInfo.redefTime); |
| |
| performanceInfo.sqlUserTime = JULIANTIMESTAMP() - startTime; |
| if (retCode != 0) |
| { |
| authenticationInfo.error = self.bb.error = ZFIL_ERR_SECVIOL; |
| // Error 100 (NOT FOUND) means user isn't a registered SQ user. |
| // For now this is an error, in the future there could be an |
| // option to auto-register users. |
| if (retCode == 100) |
| self.bb.errorDetail = UA_STATUS_ERR_INVALID; |
| |
| else//ACH Should we log other SQL errors here? |
| self.bb.errorDetail = UA_STATUS_ERR_SYSTEM; |
| |
| authenticationInfo.errorDetail = self.bb.errorDetail; |
| |
| logAuthenticationOutcome(usersInfo.externalUsername, |
| usersInfo.databaseUsername, |
| usersInfo.sessionUserID,clientInfo, |
| (retCode = 100) ? AUTH_NOT_REGISTERED : AUTH_MD_NOT_AVAILABLE); |
| return; |
| } |
| |
| // |
| // User is registered, but is the account still valid? Users can be |
| // marked offline by ALTER USER command or possibly in the future when |
| // we detect a registered user is no longer defined on the directory server. |
| // |
| if (!isValid) |
| { |
| authenticationInfo.error = self.bb.error = ZFIL_ERR_SECVIOL; |
| authenticationInfo.errorDetail = self.bb.errorDetail = UA_STATUS_ERR_INVALID; |
| |
| logAuthenticationOutcome(usersInfo.externalUsername, |
| usersInfo.databaseUsername, |
| usersInfo.sessionUserID,clientInfo,AUTH_USER_INVALID); |
| return; |
| } |
| |
| // |
| // User is registered and valid, but is the authentication type recognized? |
| // If not, reject the authentication. |
| // |
| //ACH not in metadata currently. |
| /* |
| if (authType == AuthUnknownConfiguration) |
| { |
| self.bb.error = ZFIL_ERR_SECVIOL; |
| self.bb.errorDetail = UA_STATUS_ERR_INVALID; |
| |
| logAuthenticationOutcome(usersInfo.externalUsername, |
| usersInfo.databaseUsername, |
| usersInfo.sessionUserID,clientInfo,AUTH_USER_INVALID); |
| return; |
| } |
| */ |
| // |
| // Let's check on the credentials first. |
| // |
| if (strlen(password) == 0) |
| { |
| // zero len password is a non-auth bind in LDAP, so we treat it |
| // as a failed authorization |
| authenticationInfo.error = self.bb.error = ZFIL_ERR_SECVIOL; |
| authenticationInfo.errorDetail = self.bb.errorDetail = UA_STATUS_ERR_INVALID; |
| logAuthenticationOutcome(usersInfo.externalUsername, |
| usersInfo.databaseUsername, |
| usersInfo.sessionUserID,clientInfo,AUTH_NO_PASSWORD); |
| return; |
| } |
| |
| LDAuthStatus authStatus = LDAuthSuccessful; |
| |
| // |
| // Next step, see if the user is defined on the LDAP server. |
| // |
| |
| //ACH For now, only support primary configuration |
| authStatus = executeLDAPAuthentication(self,usersInfo.externalUsername, |
| password, |
| LDAPConfigNode::PrimaryConfiguration, |
| performanceInfo); |
| |
| |
| // |
| // If all is well, save all the relevant user data in our container. |
| // |
| if (authStatus == LDAuthSuccessful) |
| { |
| // Logging retries when the authentication was successful allows |
| // operations to be aware of potential problems. |
| // Retries are logged later for unsuccessful authentications. |
| logAuthenticationRetries(self.nodeID,externalUsername); |
| |
| // Strings returned from SQL could have trailing blanks and nulls |
| // Remove all trailing blanks so callers have an accurate length |
| // for comparison. |
| stripAllTrailingBlanks(usersInfo.databaseUsername,256); |
| //ACH copy from BB usersInfo to authenticationInfo.usersInfo? |
| strcpy(authenticationInfo.usersInfo.databaseUsername,usersInfo.databaseUsername); |
| strcpy(authenticationInfo.usersInfo.externalUsername,externalUsername); |
| usersInfo.effectiveUserID = usersInfo.sessionUserID; |
| |
| // Copy USERS_INFO fields. Class, = operator, byte copy |
| authenticationInfo.usersInfo.effectiveUserID = usersInfo.effectiveUserID; |
| authenticationInfo.usersInfo.sessionUserID = usersInfo.sessionUserID; |
| authenticationInfo.usersInfo.redefTime = usersInfo.redefTime; |
| authenticationInfo.error = ZFIL_ERR_OK; |
| authenticationInfo.errorDetail = UA_STATUS_OK; |
| |
| |
| // copy user info to black box |
| self.bb.error = ZFIL_ERR_OK; |
| self.bb.errorDetail = UA_STATUS_OK; |
| self.bb.usersInfo.effectiveUserID = usersInfo.effectiveUserID; |
| self.bb.usersInfo.sessionUserID = usersInfo.sessionUserID; |
| self.bb.usersInfo.redefTime = usersInfo.redefTime; |
| strcpy(self.bb.usersInfo.databaseUsername,usersInfo.databaseUsername); |
| strcpy(self.bb.usersInfo.externalUsername,externalUsername); |
| self.bb.isAuthenticated = true; |
| |
| // Log the successful authentication to the log repository. |
| logAuthenticationOutcome(externalUsername,usersInfo.databaseUsername, |
| usersInfo.sessionUserID,clientInfo,AUTH_OK); |
| |
| return; |
| } |
| |
| // |
| // Rejected! |
| // |
| // Either the provided password does not match the one stored on the LDAP |
| // server or we had internal problems with the server. |
| // |
| // No soup for you. |
| // |
| |
| authenticationInfo.error = ZFIL_ERR_SECVIOL; |
| self.bb.error = ZFIL_ERR_SECVIOL; |
| if (authStatus == LDAuthRejected) |
| self.bb.errorDetail = UA_STATUS_ERR_INVALID; |
| else |
| { |
| self.bb.errorDetail = UA_STATUS_ERR_SYSTEM; |
| } |
| authenticationInfo.errorDetail = self.bb.errorDetail; |
| |
| // Log the failed authentication to the log repository. |
| logAuthenticationOutcome(externalUsername,usersInfo.databaseUsername, |
| usersInfo.sessionUserID,clientInfo, |
| (authStatus = LDAuthRejected) ? AUTH_REJECTED : AUTH_FAILED); |
| // Log any events generated |
| logAuthenticationErrors(self.authEvents); |
| |
| } |
| //************************** End of authenticateUser *************************** |
| |
| |
| // ***************************************************************************** |
| // * * |
| // * Function: cacheUserInfo * |
| // * * |
| // * Stores information for the user in local cache. * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Parameters: * |
| // * * |
| // * <externalUsername> const char * In * |
| // * is the external username. * |
| // * * |
| // * <databaseUsername> const char * In * |
| // * is the database username associated with the external username. * |
| // * * |
| // * <userID> int32_t In * |
| // * passes back the numeric ID of the database user associated * |
| // * with the external username. * |
| // * * |
| // * <isValid> bool In * |
| // * is true if the user is online, false if offline. * |
| // * * |
| // * <redefTime> int64_t In * |
| // * is the time the user record was last written. * |
| // * * |
| // ***************************************************************************** |
| void cacheUserInfo( |
| const char * externalUsername, |
| const char * databaseUsername, |
| int32_t userID, |
| bool isValid, |
| int64_t redefTime) |
| |
| { |
| |
| UserCacheContents userInfo; |
| |
| strcpy(userInfo.externalUsername,externalUsername); |
| strcpy(userInfo.databaseUsername,databaseUsername); |
| userInfo.userID = userID; |
| userInfo.isValid = isValid; |
| userInfo.redefTime = redefTime; |
| |
| userCache.push_back(userInfo); |
| |
| } |
| //*************************** End of cacheUserInfo ***************************** |
| |
| |
| |
| #pragma page "executeLDAPAuthentication" |
| // ***************************************************************************** |
| // * * |
| // * Function: executeLDAPAuthentication * |
| // * * |
| // * Sends request to LDAP server (via LDAPConfigNode class) to authenticate* |
| // * the provided username and password. * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Parameters: * |
| // * * |
| // * <self> DBUserAuthContents & In/Out * |
| // * is a reference to a DBUserAuthContents object. Results of the * |
| // * authentication are stored here. * |
| // * * |
| // * <username> const char * In * |
| // * is the username. Username must be defined on LDAP server. * |
| // * * |
| // * <password> const char * In * |
| // * is the password for username. Password is authenticated on LDAP server* |
| // * * |
| // * <configType> LDAPConfigNode::LDAPConfigType In * |
| // * is the LDAP configuration to use, either primary or secondary. * |
| // * * |
| // ***************************************************************************** |
| |
| static LDAuthStatus executeLDAPAuthentication( |
| DBUserAuthContents & self, |
| const char * username, |
| const char * password, |
| LDAPConfigNode::LDAPConfigType configType, |
| PERFORMANCE_INFO & performanceInfo) |
| |
| { |
| |
| LDAPConfigNode::ClearRetryCounts(); |
| self.getAuthEvents().clear(); |
| |
| // |
| // First get a search connection for the specified configuration. |
| // If we can't get a search connection, could be network problem or a |
| // bad configuration. Either way, tough luck for the user. |
| // |
| |
| int64_t startTime = JULIANTIMESTAMP(); |
| LDAPConfigNode *searchNode = LDAPConfigNode::GetLDAPConnection(self.authEvents,configType, |
| SearchConnection); |
| |
| performanceInfo.searchConnectionTime = JULIANTIMESTAMP() - startTime; |
| |
| char eventMsg[MAX_EVENT_MSG_SIZE]; |
| |
| if (searchNode == NULL) |
| { |
| self.bb.error = ZFIL_ERR_SECVIOL; |
| self.bb.errorDetail = UA_STATUS_ERR_SYSTEM; |
| snprintf(eventMsg, MAX_EVENT_MSG_SIZE, |
| "Failed to get LDAP connection for user %s",username); |
| insertAuthEvent(self.authEvents,DBS_NO_LDAP_SEARCH_CONNECTION,eventMsg, LL_ERROR); |
| |
| return LDAuthResourceFailure; |
| } |
| |
| string userDN = ""; // User DN, used to bind to LDAP serer |
| |
| startTime = JULIANTIMESTAMP(); |
| |
| LDSearchStatus searchStatus = searchNode->lookupUser(self.authEvents,username,userDN); |
| |
| performanceInfo.searchTime = JULIANTIMESTAMP() - startTime; |
| |
| if (searchStatus == LDSearchNotFound) |
| { |
| self.bb.error = ZFIL_ERR_SECVIOL; |
| self.bb.errorDetail = UA_STATUS_ERR_INVALID; |
| snprintf(eventMsg, MAX_EVENT_MSG_SIZE, |
| "Failed LDAP search for user %s",username); |
| insertAuthEvent(self.authEvents,DBS_NO_LDAP_SEARCH_CONNECTION,eventMsg, LL_ERROR); |
| |
| return LDAuthRejected; |
| } |
| |
| if (searchStatus != LDSearchFound) |
| { |
| self.bb.error = ZFIL_ERR_SECVIOL; |
| self.bb.errorDetail = UA_STATUS_ERR_SYSTEM; |
| snprintf(eventMsg, MAX_EVENT_MSG_SIZE, |
| "Failed LDAP search for user %s",username); |
| insertAuthEvent(self.authEvents,DBS_NO_LDAP_SEARCH_CONNECTION,eventMsg, LL_ERROR); |
| return LDAuthResourceFailure; |
| } |
| |
| // (searchStatus == LDSearchFound) |
| // ACH: Should we compare UUIDOnLDAP and dsUUID and give "not registered" |
| // (or some other) error if they don't match? |
| |
| // |
| // User is defined here and there. But is their password correct? |
| // Let's get an authentication connection to check on the password |
| // |
| startTime = JULIANTIMESTAMP(); |
| |
| LDAPConfigNode *authNode = LDAPConfigNode::GetLDAPConnection(self.authEvents,configType, |
| AuthenticationConnection); |
| |
| performanceInfo.authenticationConnectionTime = JULIANTIMESTAMP() - startTime; |
| |
| if (authNode == NULL) |
| { |
| self.bb.error = ZFIL_ERR_SECVIOL; |
| self.bb.errorDetail = UA_STATUS_ERR_SYSTEM; |
| snprintf(eventMsg, MAX_EVENT_MSG_SIZE, |
| "Failed LDAP search on password for user %s",username); |
| insertAuthEvent(self.authEvents,DBS_NO_LDAP_SEARCH_CONNECTION,eventMsg, LL_ERROR); |
| return LDAuthResourceFailure; |
| } |
| |
| // |
| // Non-blank password, a user we know about, let's validate that password! |
| // |
| startTime = JULIANTIMESTAMP(); |
| |
| LDAuthStatus authStatus = authNode->authenticateUser(self.authEvents,userDN.c_str(),password); |
| |
| performanceInfo.authenticationTime = JULIANTIMESTAMP() - startTime; |
| |
| return authStatus; |
| |
| } |
| //********************** End of executeLDAPAuthentication ********************** |
| |
| #pragma page "fetchFromAUTHSTable" |
| // ***************************************************************************** |
| // * * |
| // * Function: fetchFromAUTHSTable * |
| // * * |
| // * Fetches the requested columns from the row of the AUTHS table * |
| // * containing the provided external username. * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Parameters: * |
| // * * |
| // * <externalUsername> const char * In * |
| // * is the external username. * |
| // * * |
| // * <databaseUsername> char * Out * |
| // * passes back the database username associated with the external * |
| // * username. * |
| // * * |
| // * <userID> long & Out * |
| // * passes back the numeric ID of the database user associated * |
| // * with the external username. * |
| // * * |
| // * <isValid> long * Out * |
| // * passes back the status (valid Y/N) of the database user associated * |
| // * with the external username. * |
| // * * |
| // * <redefTime> int64_t & Out * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Returns: int32_t/SQL error code * |
| // * * |
| // * 0 - External username found, all return parameters set. * |
| // * 100 - External username not found. * |
| // * * - Query error * |
| // * * |
| // ***************************************************************************** |
| static int32_t fetchFromAUTHSTable( |
| const char * externalUsername, |
| char * databaseUsername, |
| int32_t & userID, |
| bool & isValid, |
| int64_t & redefTime) |
| |
| { |
| |
| const UserCacheContents *userInfo = fetchFromCacheByUsername(externalUsername); |
| |
| if (userInfo != NULL) |
| { |
| strcpy(databaseUsername,userInfo->databaseUsername); |
| userID = userInfo->userID; |
| isValid = userInfo->isValid; |
| redefTime = userInfo->redefTime; |
| return 0; |
| } |
| |
| ExeCliInterface cliInterface; |
| char stmt[2000]; |
| |
| sprintf(stmt,"SELECT AUTH_TYPE,AUTH_ID,AUTH_DB_NAME,AUTH_IS_VALID," |
| "AUTH_REDEF_TIME" |
| // ",AUTH_IS_IMMUTABLE" |
| // ",AUTH_CONFIGURATION" |
| " FROM %s.\"%s\".%s WHERE AUTH_EXT_NAME = '%s' ", |
| "TRAFODION",SEABASE_MD_SCHEMA,SEABASE_AUTHS,externalUsername); |
| |
| uint32_t savedParserFlags; |
| int32_t cliRC = 0; |
| |
| SQL_EXEC_GetParserFlagsForExSqlComp_Internal(savedParserFlags); |
| |
| try |
| { |
| SQL_EXEC_SetParserFlagsForExSqlComp_Internal(INTERNAL_QUERY_FROM_EXEUTIL); |
| cliRC = cliInterface.fetchRowsPrologue(stmt,true/*no exec*/); |
| SQL_EXEC_AssignParserFlagsForExSqlComp_Internal(savedParserFlags); |
| } |
| catch (...) |
| { |
| SQL_EXEC_AssignParserFlagsForExSqlComp_Internal(savedParserFlags); |
| throw; |
| } |
| |
| if (cliRC < 0) |
| return cliRC; |
| |
| cliRC = cliInterface.clearExecFetchClose(NULL,0); |
| if (cliRC < 0) |
| return cliRC; |
| |
| if (cliRC == 100) // did not find the row |
| return cliRC; |
| |
| char *ptr = NULL; |
| int32_t len = 0; |
| |
| cliInterface.getPtrAndLen(1,ptr,len); |
| if (ptr[0] != 'U') |
| return 100; |
| |
| cliInterface.getPtrAndLen(2,ptr,len); |
| userID = *reinterpret_cast<int32_t *>(ptr); |
| |
| cliInterface.getPtrAndLen(3,ptr,len); |
| strncpy(databaseUsername,ptr,len); |
| databaseUsername[len] = '\0'; |
| |
| cliInterface.getPtrAndLen(4,ptr,len); |
| |
| if (ptr[0] == 'Y') |
| isValid = true; |
| else |
| isValid = false; |
| |
| cliInterface.getPtrAndLen(5,ptr,len); |
| redefTime = *reinterpret_cast<int64_t *>(ptr); |
| |
| //ACH Add support for immutable users |
| /* |
| cliInterface.getPtrAndLen(6,ptr,len); |
| |
| if (ptr[0] == 'Y') |
| cacheUserInfo(externalUsername,databaseUsername,userID,isValid,redefTime); |
| */ |
| //ACH add support for configuration number |
| /* |
| cliInterface.getPtrAndLen(7,ptr,len); |
| configurationNumber = *reinterpret_cast<int32_t *>(ptr); |
| */ |
| cliInterface.fetchRowsEpilogue(NULL,true); |
| return 0; |
| |
| } |
| //************************* End of fetchFromAUTHSTable ************************* |
| |
| |
| |
| #pragma page "fetchFromAUTHSTable" |
| // ***************************************************************************** |
| // * * |
| // * Function: fetchFromAUTHSTable * |
| // * * |
| // * Fetches the requested columns from the row of the AUTHS table * |
| // * containing the provided database user ID. * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Parameters: * |
| // * * |
| // * <userID> int32_t In * |
| // * is the nummeric ID of the database user. * |
| // * * |
| // * <databaseUsername> char * Out * |
| // * passes back the database username associated with the numeric user ID. * |
| // * * |
| // * <externalUsername> char * Out * |
| // * passes back the external username associated with the numeric user ID. * |
| // * * |
| // * <isValid> bool & Out * |
| // * passes back the status of the database user associated with the * |
| // * numeric user ID. * |
| // * * |
| // * <redefTime> int64_t & Out * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Returns: int32_t/SQL error code * |
| // * * |
| // * 0 - External username found, all return parameters set. * |
| // * 100 - External username not found. * |
| // * * - Query error * |
| // * * |
| // ***************************************************************************** |
| static int32_t fetchFromAUTHSTable( |
| int32_t userID, |
| char * databaseUsername, |
| char * externalUsername, |
| bool & isValid, |
| int64_t & redefTime) |
| |
| { |
| |
| const UserCacheContents *userInfo = fetchFromCacheByUserID(userID); |
| |
| if (userInfo != NULL) |
| { |
| strcpy(databaseUsername,userInfo->databaseUsername); |
| strcpy(externalUsername,userInfo->externalUsername); |
| isValid = userInfo->isValid; |
| redefTime = userInfo->redefTime; |
| return 0; |
| } |
| |
| ExeCliInterface cliInterface; |
| char stmt[2000]; |
| |
| sprintf(stmt,"SELECT AUTH_TYPE,AUTH_EXT_NAME,AUTH_DB_NAME,AUTH_IS_VALID," |
| "AUTH_REDEF_TIME" |
| // ",AUTH_IS_IMMUTABLE" |
| " FROM %s.\"%s\".%s WHERE AUTH_ID = %ld ", |
| "TRAFODION",SEABASE_MD_SCHEMA,SEABASE_AUTHS,userID); |
| |
| uint32_t savedParserFlags; |
| int32_t cliRC = 0; |
| |
| SQL_EXEC_GetParserFlagsForExSqlComp_Internal(savedParserFlags); |
| |
| try |
| { |
| SQL_EXEC_SetParserFlagsForExSqlComp_Internal(INTERNAL_QUERY_FROM_EXEUTIL); |
| int32_t cliRC = cliInterface.fetchRowsPrologue(stmt,true/*no exec*/); |
| SQL_EXEC_AssignParserFlagsForExSqlComp_Internal(savedParserFlags); |
| } |
| catch (...) |
| { |
| SQL_EXEC_AssignParserFlagsForExSqlComp_Internal(savedParserFlags); |
| throw; |
| } |
| |
| if (cliRC < 0) |
| return cliRC; |
| |
| cliRC = cliInterface.clearExecFetchClose(NULL,0); |
| if (cliRC < 0) |
| return cliRC; |
| |
| if (cliRC == 100) // did not find the row |
| return cliRC; |
| |
| char *ptr = NULL; |
| int32_t len = 0; |
| |
| cliInterface.getPtrAndLen(1,ptr,len); |
| if (ptr[0] != 'U') |
| return 100; |
| |
| cliInterface.getPtrAndLen(2,ptr,len); |
| strncpy(externalUsername,ptr,len); |
| databaseUsername[len] = '\0'; |
| |
| cliInterface.getPtrAndLen(3,ptr,len); |
| strncpy(databaseUsername,ptr,len); |
| databaseUsername[len] = '\0'; |
| |
| cliInterface.getPtrAndLen(4,ptr,len); |
| |
| if (ptr[0] == 'Y') |
| isValid = true; |
| else |
| isValid = false; |
| |
| cliInterface.getPtrAndLen(5,ptr,len); |
| redefTime = *reinterpret_cast<int64_t *>(ptr); |
| //ACH Add support for immutable users |
| /* |
| cliInterface.getPtrAndLen(6,ptr,len); |
| |
| if (ptr[0] == 'Y') |
| cacheUserInfo(externalUsername,databaseUsername,userID,isValid,redefTime); |
| */ |
| cliInterface.fetchRowsEpilogue(NULL,true); |
| return 0; |
| |
| } |
| //************************* End of fetchFromAUTHSTable ************************* |
| |
| |
| |
| // ***************************************************************************** |
| // * * |
| // * Function: fetchFromCacheByUsername * |
| // * * |
| // * Searches local cache for user information. If found, a record with * |
| // * the data is returned, otherwise NULL is returned. * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Parameters: * |
| // * * |
| // * <externalUsername> const char * In * |
| // * is the external username to search for in cache. * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Returns: const UserCacheContents * * |
| // * * |
| // * NULL - External username not found in cache. * |
| // * Not NULL - External username was found, cached record returned. * |
| // * * |
| // ***************************************************************************** |
| inline static const UserCacheContents * fetchFromCacheByUsername(const char * externalUsername) |
| |
| { |
| |
| size_t cacheCount = userCache.size(); |
| char upperUsername[129] = {0}; |
| |
| upshiftString(externalUsername,upperUsername); |
| |
| for (size_t index = 0; index < cacheCount; index++) |
| if (strcmp(userCache[index].externalUsername,upperUsername) == 0) |
| return &userCache[index]; |
| |
| return NULL; |
| |
| } |
| //********************** End of fetchFromCacheByUsername *********************** |
| |
| |
| |
| |
| // ***************************************************************************** |
| // * * |
| // * Function: fetchFromCacheByUserID * |
| // * * |
| // * Searches local cache for user information. If found, a record with * |
| // * the data is returned, otherwise NULL is returned. * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Parameters: * |
| // * * |
| // * <userID> long In * |
| // * is the database userID to search for in cache. * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Returns: const UserCacheContents * * |
| // * * |
| // * NULL - Database userID not found in cache. * |
| // * Not NULL - Database userID was found, cached record returned. * |
| // * * |
| // ***************************************************************************** |
| inline static const UserCacheContents * fetchFromCacheByUserID(long userID) |
| |
| { |
| |
| size_t cacheCount = userCache.size(); |
| |
| for (size_t index = 0; index < cacheCount; index++) |
| if (userCache[index].userID == userID) |
| return &userCache[index]; |
| |
| return NULL; |
| |
| } |
| //*********************** End of fetchFromCacheByUserID ************************ |
| |
| |
| |
| |
| #pragma page "logAuthenticationErrors" |
| // ***************************************************************************** |
| // * * |
| // * Function: logAuthenticationErrors * |
| // * * |
| // * Logs resource failure errors encountered during authentication. * |
| // * Resource failure errors include problems with the * |
| // * configuration in .traf_authrntication_config, network issues, * |
| // * LDAP server issues, or coding blunders. * |
| // * * |
| // * Resource failures have already been inserted into authEvents structure * |
| // * * |
| // ***************************************************************************** |
| static void logAuthenticationErrors(std::vector<AuthEvent> &authEvents) |
| |
| { |
| size_t errorCount = authEvents.size(); |
| |
| for (size_t i = 0; i < errorCount; i++) |
| { |
| AuthEvent authEvent = authEvents[i]; |
| authEvent.setCallerName("mxosrvr"); |
| authEvent.logAuthEvent(); |
| } |
| } |
| //************************ End of logAuthenticationErrors ********************** |
| |
| #pragma page "logAuthenticationOutcome" |
| // ***************************************************************************** |
| // * * |
| // * Function: logAuthenticationOutcome * |
| // * * |
| // * Logs the outcome. * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Parameters: * |
| // * * |
| // * <external_user_name> string & In * |
| // * is the external username. * |
| // * * |
| // * <internal_user_name> string & In * |
| // * internal user name * |
| // * * |
| // * <userID> long In * |
| // * is the numeric ID of the database user associated * |
| // * with the external username. * |
| // * * |
| // * <outcome> string & In * |
| // * the outcome of the authentication * |
| // * * |
| // ***************************************************************************** |
| static void logAuthenticationOutcome( |
| const string & external_user_name, |
| const string & internal_user_name, |
| const int32_t user_id, |
| ClientContents & clientInfo, |
| const AUTH_OUTCOME outcome) |
| |
| { |
| string internalUser("??"); |
| if (user_id > 0) |
| internalUser = internal_user_name; |
| logLevel severity = (outcome == AUTH_FAILED) ? LL_ERROR : LL_INFO; |
| |
| // Currently this code has hard coded error messages in many places, this |
| // need to be fixed in order to allow errors to be reported in different |
| // languages. |
| string outcomeDesc = getAuthOutcome(outcome); |
| |
| char buf[MAX_EVENT_MSG_SIZE]; |
| snprintf(buf, MAX_EVENT_MSG_SIZE, |
| "Authentication request: externalUser %s, " |
| "databaseUser %s, userID %u, " |
| "clientName %s, clientUserName %s, " |
| "result %d (%s)", |
| external_user_name.c_str(), |
| internalUser.c_str(), user_id, |
| clientInfo.clientName, clientInfo.clientUserName, |
| (int)outcome, outcomeDesc.c_str()); |
| std::string msg(buf); |
| AuthEvent authEvent (DBS_AUTHENTICATION_ATTEMPT,msg,severity); |
| authEvent.setCallerName("mxosrvr"); |
| authEvent.logAuthEvent(); |
| } |
| //*********************** End of logAuthenticationOutcome ********************** |
| |
| |
| |
| #pragma page "logAuthenticationRetries" |
| // ***************************************************************************** |
| // * * |
| // * Function: logAuthenticationRetries * |
| // * * |
| // * Logs retries encountered during authentication. * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Parameters: * |
| // * * |
| // * <nodeID> int In * |
| // * is the ID of the node this process is executing on. The node ID is * |
| // * needed to log to the EVENT_TEXT_TABLE table. * |
| // * * |
| // * <username> char * In * |
| // * is the name of the user that we attempted to authenticate. * |
| // * * |
| // ***************************************************************************** |
| static void logAuthenticationRetries( |
| int nodeID, |
| const char * username) |
| |
| { |
| size_t bindRetryCount = LDAPConfigNode::GetBindRetryCount(); |
| size_t searchRetryCount = LDAPConfigNode::GetSearchRetryCount(); |
| |
| // If there were no retries, there is nothing to log. |
| if (bindRetryCount == 0 && searchRetryCount == 0) |
| return; |
| |
| char buf[MAX_EVENT_MSG_SIZE]; |
| |
| // Log if the search (name lookup) operation had to be retried. |
| if (searchRetryCount > 0) |
| { |
| snprintf(buf,MAX_EVENT_MSG_SIZE, |
| "Authentication for user %s required %d search retries. ", |
| username,searchRetryCount); |
| |
| std::string msg(buf); |
| AuthEvent authEvent (DBS_AUTH_RETRY_SEARCH, msg, LL_INFO); |
| authEvent.setCallerName("mxosrvr"); |
| authEvent.logAuthEvent(); |
| } |
| |
| // Log if the bind (password authentication) operation had to be retried. |
| if (bindRetryCount > 0) |
| { |
| snprintf(buf,MAX_EVENT_MSG_SIZE, |
| "Authentication for user %s required %d bind retries. ", |
| username,bindRetryCount); |
| |
| std::string msg(buf); |
| AuthEvent authEvent (DBS_AUTH_RETRY_BIND, msg, LL_INFO); |
| authEvent.setCallerName("mxosrvr"); |
| authEvent.logAuthEvent(); |
| } |
| } |
| //*********************** End of logAuthenticationRetries ********************** |
| |
| |
| |
| #pragma page "logToEventTable" |
| // ***************************************************************************** |
| // * * |
| // * Function: logToEventTable * |
| // * * |
| // * Logs to the EVENT_TEXT_TABLE table in the INSTANCE_REPOSITORY schema. * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Parameters: * |
| // * * |
| // * <nodeID> int In * |
| // * is the ID of the node this process is executing on. * |
| // * * |
| // * <eventID> DB_SECURITY_EVENTID In * |
| // * is the ID of the event to be logged. * |
| // * * |
| // * <severity> posix_sqlog_severity_t In * |
| // * is the severity of the event. * |
| // * * |
| // * <msg> char * In * |
| // * is the message text to be logged. * |
| // * * |
| // ***************************************************************************** |
| static void logToEventTable( |
| int nodeID, |
| DB_SECURITY_EVENTID eventID, |
| posix_sqlog_severity_t severity, |
| const char * msg) |
| |
| { |
| } |
| //**************************** End of logToEventTable ************************** |
| |
| |
| |
| |
| #pragma page "prepareUserNameForQuery" |
| // ***************************************************************************** |
| // * * |
| // * Function: prepareUserNameForQuery * |
| // * * |
| // * Converts a username into uppercase and escapes any single quote * |
| // * chars to match SQL string literal rules (by replacing each single * |
| // * quote char with a pair of single quote chars). * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Parameters: * |
| // * * |
| // * <nameForQuery> char * Out * |
| // * is the converted username. * |
| // * * |
| // * <extName> const char * In * |
| // * is the external username to be converted. * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Returns: int * |
| // * * |
| // * 0 - Validation successful. * |
| // * 22 - Bounds error. Number of param in error returned in status. * |
| // * 590 - NULL param. Number of param in error returned in status. * |
| // * * |
| // ***************************************************************************** |
| static void prepareUserNameForQuery( |
| char * nameForQuery, |
| const char * extName) |
| |
| { |
| |
| while (*extName != '\0') |
| { |
| if (*extName == '\'') |
| { |
| // replace original single quote with a pair of single quotes |
| *(nameForQuery++) = '\''; |
| *(nameForQuery++) = '\''; |
| } |
| else |
| *(nameForQuery++) = toupper(*extName); |
| |
| extName++; |
| } |
| *nameForQuery = '\0'; |
| |
| } |
| //*********************** End of prepareUserNameForQuery *********************** |
| |
| #pragma page "stripAllTrailingBlanks" |
| // ***************************************************************************** |
| // * * |
| // * Function: stripAllTrailingBlanks * |
| // * * |
| // * Removes trailing blanks (replaces with null). String may have embedded * |
| // * NULLs; trailing blanks are replaced with NULL until first non-blank, * |
| // * non-null character. * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Parameters: * |
| // * * |
| // * <buf> char * In/Out * |
| // * is a character buffer whose trailing blanks are to be trimmed. * |
| // * * |
| // * <len> size_t In * |
| // * is the size of <buf>. * |
| // * * |
| // * * |
| // * * |
| // ***************************************************************************** |
| static void stripAllTrailingBlanks( |
| char * buf, |
| size_t len) |
| |
| { |
| |
| char *ptr = &buf[len]; |
| |
| while (*ptr == ' ' || *ptr == 0) |
| { |
| *ptr = 0; |
| ptr--; |
| } |
| |
| } |
| //****************** End of trimLeadingandTrailingBlanks *********************** |
| |
| #pragma page "timeDiff" |
| // ***************************************************************************** |
| // * * |
| // * Function: timeDiff * |
| // * * |
| // * Find the difference between two timestamps * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Parameters: * |
| // * * |
| // * <t1> timespec In * |
| // * First timestamp * |
| // * * |
| // * <t2> timespec In * |
| // * Second timestamp * |
| // * * |
| // * <tDiff> timespec Out * |
| // * Difference between t1 and t2 * |
| // ***************************************************************************** |
| |
| static void timeDiff ( |
| struct timespec t1, |
| struct timespec t2, |
| struct timespec &tDiff) |
| |
| { |
| if ( (t2.tv_nsec - t1.tv_nsec ) < 0 ) |
| { |
| tDiff.tv_sec = t2.tv_sec - t1.tv_sec - 1; |
| tDiff.tv_nsec = 1000000000 + t2.tv_nsec - t1.tv_nsec; |
| } |
| else |
| { |
| tDiff.tv_sec = t2.tv_sec - t1.tv_sec; |
| tDiff.tv_nsec = t2.tv_nsec - t1.tv_nsec; |
| } |
| } |
| //*************************** End of timeDiff ********************************** |
| |
| // ***************************************************************************** |
| // * * |
| // * Function: upshiftString * |
| // * * |
| // * Convert all characters of a string to upper case. * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Parameters: * |
| // * * |
| // * <inputString> const char * In * |
| // * is the string to be converted to upper case. * |
| // * * |
| // * <outputString> char * Out * |
| // * passes back the converted string. * |
| // * * |
| // ***************************************************************************** |
| inline static void upshiftString( |
| const char * inputString, |
| char * outputString) |
| |
| { |
| |
| while (*inputString != '\0') |
| { |
| *(outputString++) = toupper(*inputString); |
| |
| inputString++; |
| } |
| *outputString = '\0'; |
| |
| } |
| //************************* End of upshiftString ******************************* |
| |
| // ***************************************************************************** |
| // * * |
| // * Function: writeLog * |
| // * * |
| // * Logging for testing ODBC authentications. * |
| // * * |
| // ***************************************************************************** |
| // * * |
| // * Parameters: * |
| // * * |
| // * <text> const char * In * |
| // * is the string to be written to the log file. * |
| // * * |
| // ***************************************************************************** |
| static void writeLog(const char * text) |
| |
| { |
| } |
| //*************************** End of writeLog ********************************** |