static DWORD TestAddUser( HANDLE hLsaConnection, PSTR pszUser ) { DWORD dwError = LW_ERROR_SUCCESS; DWORD dwUserInfoLevel = 0; PVOID pUserInfo = NULL; PSTR pszShell = "/bin/sh"; PSTR pszHomedir = "/home"; gid_t gid = 0; LSA_FIND_FLAGS FindFlags = 0; PCSTR pszTestDescription = "Verify LsaAddUser adds a user"; PCSTR pszTestAPIs = "LsaAddUser"; char szTestMsg[512] = { 0 }; dwError = GetGroupId( hLsaConnection, pszUser, &gid); BAIL_ON_TEST_BROKE(dwError); dwError = BuildUserInfo(0, gid, pszUser, pszShell, pszHomedir, (PLSA_USER_INFO_0*)&pUserInfo); BAIL_ON_TEST_BROKE(dwError); dwError = LsaAddUser( hLsaConnection, pUserInfo, dwUserInfoLevel); BAIL_ON_TEST_BROKE(dwError); dwError = LsaFindUserByName( hLsaConnection, pszUser, FindFlags, &pUserInfo); BAIL_ON_TEST_BROKE(dwError); if( !pUserInfo ) { dwError = LW_ERROR_TEST_FAILED; snprintf(szTestMsg, sizeof(szTestMsg), "unexpected result while adding the user %s", pszUser); LWT_LOG_TEST(szTestMsg); } cleanup: if (pUserInfo) { LsaFreeUserInfo(dwUserInfoLevel, pUserInfo); } return dwError; error: goto cleanup; }
NSS_STATUS LsaNssCommonPasswdGetpwnam( PLSA_NSS_CACHED_HANDLE pConnection, const char * pszLoginId, struct passwd * pResultUser, char * pszBuf, size_t bufLen, int * pErrorNumber ) { int ret; HANDLE hLsaConnection = NULL; PVOID pUserInfo = NULL; DWORD dwUserInfoLevel = 0; ret = MAP_LSA_ERROR(NULL, LsaNssCommonEnsureConnected(pConnection)); BAIL_ON_NSS_ERROR(ret); hLsaConnection = pConnection->hLsaConnection; ret = MAP_LSA_ERROR(pErrorNumber, LsaFindUserByName( hLsaConnection, pszLoginId, dwUserInfoLevel, &pUserInfo)); BAIL_ON_NSS_ERROR(ret); ret = MAP_LSA_ERROR(pErrorNumber, LsaNssWriteUserInfo( dwUserInfoLevel, pUserInfo, pResultUser, &pszBuf, bufLen)); BAIL_ON_NSS_ERROR(ret); cleanup: if (pUserInfo) { LsaFreeUserInfo(dwUserInfoLevel, pUserInfo); } return ret; error: if (ret != NSS_STATUS_TRYAGAIN && ret != NSS_STATUS_NOTFOUND) { LsaNssCommonCloseConnection(pConnection); } goto cleanup; }
static DWORD TestDelUser( HANDLE hLsaConnection, PSTR pszUser ) { DWORD dwError = LW_ERROR_SUCCESS; LSA_FIND_FLAGS FindFlags = 0; PVOID pUserInfo = NULL; PCSTR pszTestDescription = "Verify LsaDeleteUserByName adds a user"; PCSTR pszTestAPIs = "LsaDeleteUserByName"; char szTestMsg[512] = { 0 }; dwError = LsaDeleteUserByName( hLsaConnection, pszUser); BAIL_ON_TEST_BROKE(dwError); dwError = LsaFindUserByName( hLsaConnection, pszUser, FindFlags, &pUserInfo); BAIL_ON_TEST_BROKE(dwError); if( pUserInfo ) { dwError = LW_ERROR_TEST_FAILED; snprintf(szTestMsg, sizeof(szTestMsg), "unexpected result while deleting the user %s", pszUser); LWT_LOG_TEST(szTestMsg); } cleanup: return dwError; error: goto cleanup; }
/* * VerifyNullHandling * * Make sure NULL does not crash server. */ static DWORD VerifyNullHandling( HANDLE hLsaConnection ) { PCSTR pszTestDescription = "LsaFindUserByName returns error given NULL user name."; PCSTR pszTestAPIs = "LsaFindUserByName"; char szTestMsg[128] = { 0 }; DWORD dwError = LW_ERROR_SUCCESS; DWORD dwLocalError = LW_ERROR_SUCCESS; LSA_USER_INFO_0 *pUserInfo = NULL; size_t i; for ( i = 0; i < 3; i++ ) { dwLocalError = LsaFindUserByName( hLsaConnection, NULL, i, (void**) &pUserInfo); if ( pUserInfo ) { LsaFreeUserInfo(i, pUserInfo); } if ( dwLocalError != LW_ERROR_INVALID_PARAMETER ) { dwError = LW_ERROR_TEST_FAILED; goto error; } } cleanup: LWT_LOG_TEST(szTestMsg); return dwError; error: goto cleanup; }
/* * This is where we check if the password expired. * If the password is correct, but has expired, we return * PAM_NEW_AUTHTOK_REQD instead of PAM_SUCCESS */ int pam_sm_acct_mgmt( pam_handle_t* pamh, int flags, int argc, const char** argv ) { DWORD dwError = 0; PPAMCONTEXT pPamContext = NULL; HANDLE hLsaConnection = (HANDLE)NULL; PLSA_USER_INFO_2 pUserInfo = NULL; DWORD dwUserInfoLevel = 2; PSTR pszLoginId = NULL; PLSA_PAM_CONFIG pConfig = NULL; int iPamError = 0; PSTR pszExpireDone; LSA_LOG_PAM_DEBUG("pam_sm_acct_mgmt::begin"); dwError = LsaPamGetConfig(&pConfig); BAIL_ON_LSA_ERROR(dwError); LsaPamSetLogLevel(pConfig->dwLogLevel); dwError = LsaPamGetContext( pamh, flags, argc, argv, &pPamContext); BAIL_ON_LSA_ERROR(dwError); dwError = LsaPamGetLoginId( pamh, pPamContext, &pszLoginId, TRUE); BAIL_ON_LSA_ERROR(dwError); if (LsaShouldIgnoreUser(pszLoginId)) { LSA_LOG_PAM_DEBUG("By passing lsassd for local account"); dwError = LW_ERROR_NOT_HANDLED; BAIL_ON_LSA_ERROR(dwError); } dwError = LsaOpenServer(&hLsaConnection); BAIL_ON_LSA_ERROR(dwError); dwError = LsaCheckUserInList( hLsaConnection, pszLoginId, NULL); if (dwError && dwError != LW_ERROR_NO_SUCH_USER) { if (dwError == LW_ERROR_NO_SUCH_USER) { BAIL_ON_LSA_ERROR(dwError); } LSA_LOG_PAM_ERROR("User %s is denied access because they are not in the 'require membership of' list", LSA_SAFE_LOG_STRING(pszLoginId)); if (!LW_IS_NULL_OR_EMPTY_STR(pConfig->pszAccessDeniedMessage)) { LsaPamConverse(pamh, pConfig->pszAccessDeniedMessage, PAM_TEXT_INFO, NULL); } } BAIL_ON_LSA_ERROR(dwError); dwError = LsaValidateUser( hLsaConnection, pszLoginId, NULL); if (dwError == LW_ERROR_PASSWORD_EXPIRED) { dwError = 0; pPamContext->bPasswordExpired = TRUE; } BAIL_ON_LSA_ERROR(dwError); if (pPamContext->bPasswordExpired) { // If during pam_sm_authenticate, // we detected that the password expired, // we handle it here if (!pPamContext->bPasswordMessageShown) { LsaPamConverse( pamh, "Your password has expired", PAM_ERROR_MSG, NULL); pPamContext->bPasswordMessageShown = TRUE; } dwError = LW_ERROR_PASSWORD_EXPIRED; BAIL_ON_LSA_ERROR(dwError); } iPamError = pam_get_data( pamh, PAM_LSASS_EXPIRE_WARNING_DONE, (PAM_GET_DATA_TYPE)&pszExpireDone); if (iPamError == PAM_NO_MODULE_DATA) { dwError = LsaFindUserByName( hLsaConnection, pszLoginId, dwUserInfoLevel, (PVOID*)&pUserInfo); BAIL_ON_LSA_ERROR(dwError); if (pUserInfo->bPromptPasswordChange == TRUE && pUserInfo->bPasswordExpired == FALSE && pUserInfo->bPasswordNeverExpires == FALSE) { CHAR szMessage[512]; switch (pUserInfo->dwDaysToPasswordExpiry) { case 0: sprintf(szMessage, "Your password will expire today\n"); break; case 1: sprintf(szMessage, "Your password will expire in 1 day\n"); break; default: sprintf(szMessage, "Your password will expire in %u days\n", pUserInfo->dwDaysToPasswordExpiry); break; } LsaPamConverse(pamh, szMessage, PAM_TEXT_INFO, NULL); } dwError = LsaPamSetDataString( pamh, PAM_LSASS_EXPIRE_WARNING_DONE, "TRUE"); BAIL_ON_LSA_ERROR(dwError); } cleanup: if (pUserInfo) { LsaFreeUserInfo(dwUserInfoLevel, (PVOID)pUserInfo); } if (hLsaConnection != (HANDLE)NULL) { LsaCloseServer(hLsaConnection); } if (pConfig) { LsaPamFreeConfig(pConfig); } LW_SAFE_FREE_STRING(pszLoginId); LSA_LOG_PAM_DEBUG("pam_sm_acct_mgmt::end"); return LsaPamOpenPamFilterAcctMgmt( LsaPamMapErrorCode(dwError, pPamContext)); error: if (dwError == LW_ERROR_NO_SUCH_USER || dwError == LW_ERROR_NOT_HANDLED) { LSA_LOG_PAM_WARNING("pam_sm_acct_mgmt failed [login:%s][error code:%u]", LSA_SAFE_LOG_STRING(pszLoginId), dwError); } else { LSA_LOG_PAM_ERROR("pam_sm_acct_mgmt failed [login:%s][error code:%u]", LSA_SAFE_LOG_STRING(pszLoginId), dwError); if (pszLoginId && !strcmp(pszLoginId, "root")) { dwError = LW_ERROR_NO_SUCH_USER; LSA_LOG_PAM_ERROR("Converting error to %u for root", dwError); } } goto cleanup; }
/* * ValidateForInvalidParams * * Function validates the API for Invalid function parameters. * */ static DWORD ValidateForInvalidParams( HANDLE hLsaConnection, PTESTDATA pTestData ) { DWORD dwError = LW_ERROR_SUCCESS; DWORD dwLocalError = LW_ERROR_SUCCESS; DWORD dwTest = 0; CHAR szTestMsg[256] = { 0 }; PLWTFAILDATA pInvalidData = NULL; PVOID pUserInfo = NULL; PCSTR pszTestAPIs = "LsaFindUserByName"; PCSTR pszTestDescription = "API returns invalid parameter error for invalid function parameters"; if ( !pTestData || !pTestData->pInvalidDataIface ) { dwLocalError = LW_ERROR_TEST_SKIPPED; BAIL_ON_TEST_BROKE(dwLocalError); } for ( dwTest = 0; dwTest < pTestData->dwNumInvalidDataSet; dwTest++ ) { dwLocalError = GetInvalidDataRecord( pTestData, dwTest, &pInvalidData); BAIL_ON_TEST_BROKE(dwLocalError); if ( LWTUSER_INVALID == pInvalidData->Field ) { dwLocalError = LsaFindUserByName( hLsaConnection, pInvalidData->pszUserName, pInvalidData->dwLevel, &pUserInfo ); if ( dwLocalError != pInvalidData->dwErrorCode ) { dwError = LW_ERROR_TEST_FAILED; snprintf( szTestMsg, sizeof(szTestMsg), "API returned with error code (%lu) for invalid user name parameter", (unsigned long)dwLocalError); LWT_LOG_TEST(szTestMsg); } FreeUserInfo(pInvalidData->dwLevel, pUserInfo); } if ( LWTUSERINFOLEVEL_INVALID == pInvalidData->Field ) { dwLocalError = LsaFindUserByName( hLsaConnection, pInvalidData->pszUserName, pInvalidData->dwLevel, &pUserInfo ); if ( dwLocalError != pInvalidData->dwErrorCode ) { dwError = LW_ERROR_TEST_FAILED; snprintf( szTestMsg, sizeof(szTestMsg), "API returned with error code (%lu) for invalid user name parameter", (unsigned long)dwLocalError); LWT_LOG_TEST(szTestMsg); } FreeUserInfo(pInvalidData->dwLevel, pUserInfo); } FreeInvalidDataRecord(pInvalidData); } error: return dwError; }
/* * FindUserByName1 * * Check that LsaFindUserByName gets LSA_USER_INFO_1 for given user. */ static DWORD FindUserByName1( HANDLE hLsaConnection, PLWTUSER pUser, PCSTR pszLookedUpBy, PLSA_USER_INFO_1 *ppUserInfo1 ) { PCSTR pszTestDescription = "LsaFindUserByName retrieved LSA_USER_INFO_1 for given user."; PCSTR pszTestAPIs = "LsaFindUserByName"; char szTestMsg[128] = { 0 }; DWORD dwError = LW_ERROR_SUCCESS; DWORD dwLocalError = LW_ERROR_SUCCESS; PLSA_USER_INFO_1 pUserInfo1 = NULL; snprintf( szTestMsg, sizeof(szTestMsg), "\n\tAccount %s.\n", pszLookedUpBy); dwLocalError = LsaFindUserByName( hLsaConnection, pszLookedUpBy, 1, (PVOID*)&pUserInfo1); if ( dwLocalError ) { char buf[128]; char szErrorMsg[128]; LwGetErrorString( dwLocalError, szErrorMsg, sizeof(szErrorMsg)); snprintf( buf, sizeof(buf), "\tLsaFindUserByName reports %lu (%s)\n", (unsigned long)dwLocalError, szErrorMsg); Lwt_strcat(szTestMsg, sizeof(szTestMsg), buf); dwError = LW_ERROR_TEST_FAILED; goto error; } cleanup: *ppUserInfo1 = pUserInfo1; LWT_LOG_TEST(szTestMsg); return dwError; error: if ( pUserInfo1 ) { LsaFreeUserInfo(1, pUserInfo1); pUserInfo1 = NULL; } goto cleanup; }
int LsaNssNormalizeUsername( PSTR pszInput, PSTR pszOutput ) { DWORD dwError = LW_ERROR_SUCCESS; PLSA_USER_INFO_0 pInfo = NULL; const DWORD dwInfoLevel = 0; uint64_t qwConvert = 0; int iDigit = 0; PSTR pszPos = NULL; if (strlen(pszInput) < S_NAMELEN) { strcpy(pszOutput, pszInput); goto cleanup; } dwError = LsaNssCommonEnsureConnected(&lsaConnection); BAIL_ON_LSA_ERROR(dwError); dwError = LsaFindUserByName( lsaConnection.hLsaConnection, pszInput, dwInfoLevel, (PVOID*)&pInfo); BAIL_ON_LSA_ERROR(dwError); qwConvert = pInfo->uid; pszPos = pszOutput + S_NAMELEN - 1; *pszPos-- = 0; if (qwConvert < 10000000) { // Mangle the username with the old rules while(pszPos > pszOutput) { iDigit = qwConvert % 10; *pszPos = iDigit + '0'; qwConvert /= 10; pszPos--; } } else { // Mangle the username with the new rules. The mangled user name will // start with _ and the second character will be a letter. The uid // number (with padding) will be in base 32. qwConvert += 10737418240ull; while(pszPos > pszOutput) { iDigit = qwConvert % 32; if (iDigit < 10) { *pszPos = iDigit + '0'; } else { *pszPos = iDigit + 'a' - 10; } qwConvert /= 32; pszPos--; } } *pszPos = '_'; cleanup: if (pInfo != NULL) { LsaFreeUserInfo( dwInfoLevel, (PVOID)pInfo); } if (dwError != LW_ERROR_SUCCESS) { LsaNssMapErrorCode(dwError, &errno); return 0; } return strlen(pszOutput); error: *pszOutput = 0; LsaNssCommonCloseConnection(&lsaConnection); goto cleanup; }
int LsaNssAuthenticate( PSTR pszUser, PSTR pszResponse, int* pReenter, PSTR* ppszOutputMessage ) { int iError = 0; DWORD dwError = LW_ERROR_SUCCESS; PLSA_USER_INFO_0 pInfo = NULL; const DWORD dwInfoLevel = 0; PSTR pszMessage = NULL; PLSA_USER_INFO_2 pInfo2 = NULL; LSA_LOG_PAM_DEBUG("Lsass LAM authenticating user [%s]", pszUser? pszUser: "******"); dwError = LsaNssCommonEnsureConnected(&lsaConnection); BAIL_ON_LSA_ERROR(dwError); dwError = LsaNssFindUserByAixName( lsaConnection.hLsaConnection, pszUser, dwInfoLevel, (PVOID*)&pInfo); BAIL_ON_LSA_ERROR(dwError); dwError = LsaAuthenticateUser( lsaConnection.hLsaConnection, pInfo->pszName, pszResponse, &pszMessage); if (dwError == LW_ERROR_PASSWORD_EXPIRED) { // Double check that the user's password is marked as expired dwError = LsaFindUserByName( lsaConnection.hLsaConnection, pInfo->pszName, 2, (PVOID*)&pInfo2); BAIL_ON_LSA_ERROR(dwError); if (!pInfo2->bPasswordExpired) { // Something went wrong in lsassd -- don't let the user login dwError = LW_ERROR_PASSWORD_EXPIRED; } } BAIL_ON_LSA_ERROR(dwError); dwError = LsaCheckUserInList( lsaConnection.hLsaConnection, pInfo->pszName, NULL); BAIL_ON_LSA_ERROR(dwError); // Need to ensure that home directories are created. dwError = LsaOpenSession( lsaConnection.hLsaConnection, pInfo->pszName); BAIL_ON_LSA_ERROR(dwError); cleanup: if (ppszOutputMessage) { *ppszOutputMessage = pszMessage; } else { LW_SAFE_FREE_STRING(pszMessage); } if (pInfo != NULL) { LsaFreeUserInfo( dwInfoLevel, pInfo); } if (pInfo2 != NULL) { LsaFreeUserInfo( 2, pInfo2); } switch(dwError) { case LW_ERROR_SUCCESS: iError = AUTH_SUCCESS; break; case LW_ERROR_NOT_HANDLED: case LW_ERROR_NO_SUCH_USER: iError = AUTH_NOTFOUND; break; case LW_ERROR_ACCOUNT_EXPIRED: case LW_ERROR_ACCOUNT_DISABLED: case LW_ERROR_ACCOUNT_LOCKED: iError = AUTH_FAILURE; break; default: iError = AUTH_UNAVAIL; break; } LSA_LOG_PAM_DEBUG("Lsass LAM authenticate finishing with likewise code %u and LAM code %d", dwError, iError); return iError; error: LsaNssCommonCloseConnection(&lsaConnection); goto cleanup; }
DWORD ADUKrb5GetUserCachePathAndSID( PCSTR pszUserUPN, PSTR* ppszCachePath, PSTR* ppszHomeDirPath, PSTR* ppszSID, uid_t* pUid ) { DWORD dwError = 0; char szPath[PATH_MAX]; PSTR pszCachePath = NULL; PSTR pszHomeDirPath = NULL; PSTR pszSID = NULL; HANDLE hLsaConnection = (HANDLE) NULL; PLSA_USER_INFO_0 pUserInfo_0 = NULL; dwError = LsaOpenServer(&hLsaConnection); BAIL_ON_MAC_ERROR(dwError); dwError = LsaFindUserByName(hLsaConnection, pszUserUPN, 0, (PVOID*) &pUserInfo_0); BAIL_ON_MAC_ERROR(dwError); memset(szPath, 0, sizeof(szPath)); sprintf(szPath, "FILE:/tmp/krb5cc_%ld",(long)pUserInfo_0->uid); dwError = LwAllocateString(szPath, &pszCachePath); BAIL_ON_MAC_ERROR(dwError); dwError = LwAllocateString(pUserInfo_0->pszSid, &pszSID); BAIL_ON_MAC_ERROR(dwError); dwError = LwAllocateString(pUserInfo_0->pszHomedir, &pszHomeDirPath); BAIL_ON_MAC_ERROR(dwError); if (ppszCachePath) { *ppszCachePath = pszCachePath; pszCachePath = NULL; } if (ppszSID) { *ppszSID = pszSID; pszSID = NULL; } if (ppszHomeDirPath) { *ppszHomeDirPath = pszHomeDirPath; pszHomeDirPath = NULL; } if (pUid) { *pUid = pUserInfo_0->uid; } cleanup: if (pszCachePath) LwFreeString(pszCachePath); if (pszSID) LwFreeString(pszSID); if (pszHomeDirPath) LwFreeString(pszHomeDirPath); if (pUserInfo_0) LsaFreeUserInfo(0, pUserInfo_0); if (hLsaConnection != (HANDLE)NULL) LsaCloseServer(hLsaConnection); return dwError; error: if (ppszCachePath) *ppszCachePath = NULL; if (ppszSID) *ppszSID = NULL; if (ppszHomeDirPath) *ppszHomeDirPath = NULL; if (pUid) *pUid = -1; goto cleanup; }
LSASS_API DWORD LsaGetGidsForUserByName( HANDLE hLsaConnection, PCSTR pszUserName, PDWORD pdwGroupFound, gid_t** ppGidResults ) { DWORD dwError = 0; PVOID pUserInfo = NULL; DWORD dwUserInfoLevel = 0; static const DWORD dwGroupInfoLevel = 0; DWORD dwGroupFound = 0; gid_t* pGidResult = NULL; PVOID* ppGroupInfoList = NULL; DWORD iGroup = 0; BAIL_ON_INVALID_HANDLE(hLsaConnection); BAIL_ON_INVALID_STRING(pszUserName); BAIL_ON_INVALID_POINTER(ppGidResults); dwError = LsaValidateUserName(pszUserName); BAIL_ON_LSA_ERROR(dwError); dwError = LsaFindUserByName( hLsaConnection, pszUserName, dwUserInfoLevel, &pUserInfo); BAIL_ON_LSA_ERROR(dwError); dwError = LsaGetGroupsForUserById( hLsaConnection, ((PLSA_USER_INFO_0)pUserInfo)->uid, LSA_FIND_FLAGS_NSS, dwGroupInfoLevel, &dwGroupFound, &ppGroupInfoList); BAIL_ON_LSA_ERROR(dwError); dwError = LwAllocateMemory( sizeof(gid_t) * dwGroupFound, (PVOID*)&pGidResult); BAIL_ON_LSA_ERROR(dwError); for (iGroup = 0; iGroup < dwGroupFound; iGroup++) { *(pGidResult+iGroup) = ((PLSA_GROUP_INFO_0)(*(ppGroupInfoList+iGroup)))->gid; } *ppGidResults = pGidResult; *pdwGroupFound = dwGroupFound; cleanup: if (pUserInfo) { LsaFreeUserInfo(dwUserInfoLevel, pUserInfo); } if (ppGroupInfoList) { LsaFreeGroupInfoList(dwGroupInfoLevel, (PVOID*)ppGroupInfoList, dwGroupFound); } return dwError; error: *ppGidResults = NULL; *pdwGroupFound = 0; goto cleanup; }