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;
}
示例#2
0
NSS_STATUS
LsaNssCommonPasswdGetpwuid(
    PLSA_NSS_CACHED_HANDLE pConnection,
    uid_t uid,
    struct passwd * pResultUser,
    char * pszBuf,
    size_t bufLen,
    int * pErrorNumber
    )
{
    int ret = NSS_STATUS_SUCCESS;
    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,
                        LsaFindUserById(
                            hLsaConnection,
                            uid,
                            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;
}
示例#3
0
int
LsaNssChangePassword(
        PSTR pszUser,
        PSTR pszOldPass,
        PSTR pszNewPass,
        PSTR* ppszError)
{
    DWORD dwError = LW_ERROR_SUCCESS;
    PLSA_USER_INFO_0 pInfo = NULL;
    const DWORD dwInfoLevel = 0;

    *ppszError = NULL;

    dwError = LsaNssCommonEnsureConnected(&lsaConnection);
    BAIL_ON_LSA_ERROR(dwError);

    dwError = LsaNssFindUserByAixName(
                lsaConnection.hLsaConnection,
                pszUser,
                dwInfoLevel,
                (PVOID*)&pInfo);
    BAIL_ON_LSA_ERROR(dwError);

    dwError = LsaChangePassword(
                lsaConnection.hLsaConnection,
                pInfo->pszName,
                pszNewPass,
                pszOldPass);
    BAIL_ON_LSA_ERROR(dwError);

cleanup:

    if (pInfo != NULL)
    {
        LsaFreeUserInfo(
                dwInfoLevel,
                (PVOID)pInfo);
    }
    if(dwError != LW_ERROR_SUCCESS)
    {
        LsaNssMapErrorCode(dwError, &errno);
        return -1;
    }
    return 0;

error:
    LsaNssCommonCloseConnection(&lsaConnection);

    goto cleanup;
}
static
DWORD
BuildUserInfo(
    uid_t uid,
    gid_t gid,
    PCSTR pszLoginId,
    PCSTR pszShell,
    PCSTR pszHomedir,
    PLSA_USER_INFO_0* ppUserInfo
    )
{
    DWORD dwError = 0;
    PLSA_USER_INFO_0 pUserInfo = NULL;
    DWORD dwUserInfoLevel = 0;

    dwError = LwAllocateMemory(
                   sizeof(LSA_USER_INFO_0),
                   (PVOID*)&pUserInfo
                   );
    BAIL_ON_TEST_BROKE(dwError);

    pUserInfo->uid = uid;
    pUserInfo->gid = gid;

    dwError = LwAllocateString(pszLoginId, &pUserInfo->pszName);
    BAIL_ON_TEST_BROKE(dwError);

    dwError = LwAllocateString(pszShell, &pUserInfo->pszShell);
    BAIL_ON_TEST_BROKE(dwError);

    dwError = LwAllocateString(pszHomedir, &pUserInfo->pszHomedir);
    BAIL_ON_TEST_BROKE(dwError);

    // TODO: Gecos

    *ppUserInfo = pUserInfo;

cleanup:

    return dwError;

error:

    if (pUserInfo) {
        LsaFreeUserInfo(dwUserInfoLevel, pUserInfo);
    }

    goto cleanup;
}
static
VOID
FreeUserInfo(
    DWORD dwLevel,
    PVOID pUserInfo
    )
{
    if ( pUserInfo )
    {
        LsaFreeUserInfo(
                    dwLevel, 
                    pUserInfo);
        pUserInfo = NULL;
    }
    return;
}
/*
 * 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;    
}
示例#7
0
/*
 * 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;
}
/*
 * 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;
}
DWORD
Lwt_LsaFindUserByName(
    HANDLE hLsaConnection,
    PTESTDATA pTestData
    )
{
    DWORD dwError = LW_ERROR_SUCCESS;
    DWORD dwLocalError = LW_ERROR_SUCCESS;
    size_t nCurrentUser;
    PLWTUSER pUser = NULL;
    PLSA_USER_INFO_0 pUserInfo0 = NULL;
    PLSA_USER_INFO_1 pUserInfo1 = NULL;

    if ( ! pTestData )
    {
        dwError = LW_ERROR_TEST_SKIPPED;
        goto error;
    }

    /* For each user (line), verify the information is correct. */
    for ( nCurrentUser = 0; 
          nCurrentUser < pTestData->dwNumUsers; 
          nCurrentUser++ )
    {
        dwLocalError = GetUser( pTestData, 
                                nCurrentUser, 
                                &pUser);
        BAIL_ON_TEST_BROKE(dwLocalError);

        if ( pUser->pszNTName )
        {
            dwLocalError = FindUserByName0( hLsaConnection,
                                            pUser,
                                            pUser->pszNTName,
                                            &pUserInfo0);
            BAIL_ON_TEST_BROKE(dwLocalError);
        }

        if ( pUserInfo0 )
        {
            dwLocalError = MatchUserInfo0( pUser,
                                           pUser->pszNTName,
                                           pUserInfo0);
            BAIL_ON_TEST_BROKE(dwLocalError);

            LsaFreeUserInfo(0, pUserInfo0);
            pUserInfo0 = NULL;
        }


        if ( pUser->pszUserPrincipalName )
        {
            dwLocalError = FindUserByName0( hLsaConnection,
                                            pUser,
                                            pUser->pszUserPrincipalName,
                                            &pUserInfo0);
            BAIL_ON_TEST_BROKE(dwLocalError);
        }

        if ( pUserInfo0 )
        {
            dwLocalError = MatchUserInfo0( pUser,
                                           pUser->pszUserPrincipalName,
                                           pUserInfo0);
            BAIL_ON_TEST_BROKE(dwLocalError);

            LsaFreeUserInfo(0, pUserInfo0);
            pUserInfo0 = NULL;
        }


        if ( pUser->pszNTName )
        {
            dwLocalError = FindUserByName1( hLsaConnection,
                                            pUser,
                                            pUser->pszNTName,
                                            &pUserInfo1);
            BAIL_ON_TEST_BROKE(dwLocalError);
        }

        if ( pUserInfo1 )
        {
            LsaFreeUserInfo(1, pUserInfo1);
            pUserInfo1 = NULL;
        }

        FreeUser(&pUser);
    }

    dwLocalError = VerifyNullHandling(hLsaConnection);
    BAIL_ON_TEST_BROKE(dwLocalError);

    dwLocalError = ValidateForInvalidParams(hLsaConnection, pTestData);
    BAIL_ON_TEST_BROKE(dwLocalError);

cleanup:

    if ( pUserInfo0 )
    {
        LsaFreeUserInfo(0, pUserInfo0);
        pUserInfo0 = NULL;
    }

    if ( pUserInfo1 )
    {
        LsaFreeUserInfo(1, pUserInfo1);
        pUserInfo1 = NULL;
    }

    if ( pUser )
    {
        FreeUser(&pUser);
    }

    return dwError;

error:
    goto cleanup;

}
示例#10
0
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;
}
示例#11
0
int
LsaNssIsPasswordExpired(
        PSTR pszUser,
        PSTR* ppszMessage
        )
{
    PLSA_USER_INFO_2 pInfo = NULL;
    const DWORD dwInfoLevel = 2;
    DWORD dwError = LW_ERROR_SUCCESS;
    int iError = 0;

    LSA_LOG_PAM_DEBUG("Lsass LAM checking expired password for user [%s]",
            pszUser? pszUser: "******");
    *ppszMessage = NULL;

    dwError = LsaNssCommonEnsureConnected(&lsaConnection);
    BAIL_ON_LSA_ERROR(dwError);

    dwError = LsaNssFindUserByAixName(
                lsaConnection.hLsaConnection,
                pszUser,
                dwInfoLevel,
                (PVOID*)&pInfo);
    BAIL_ON_LSA_ERROR(dwError);

    if (pInfo->bPasswordExpired)
    {
        dwError = LwAllocateStringPrintf(
                ppszMessage,
                "%s's password is expired",
                pszUser);
        BAIL_ON_LSA_ERROR(dwError);

        dwError = LW_ERROR_PASSWORD_EXPIRED;
        BAIL_ON_LSA_ERROR(dwError);
    }

    if (pInfo->bPromptPasswordChange &&
        pInfo->dwDaysToPasswordExpiry)
    {
        dwError = LwAllocateStringPrintf(
                ppszMessage,
                "Your password will expire in %u days\n",
                pInfo->dwDaysToPasswordExpiry);
        BAIL_ON_LSA_ERROR(dwError);
    }

cleanup:

    if (pInfo != NULL)
    {
        LsaFreeUserInfo(
                dwInfoLevel,
                (PVOID)pInfo);
    }
    switch(dwError)
    {
        case LW_ERROR_SUCCESS:
            iError = 0;
            break;
        case LW_ERROR_PASSWORD_EXPIRED:
            iError = 1;
            break;
        case LW_ERROR_NO_SUCH_USER:
            iError = -1;
            errno = ENOENT;
            break;
        default:
            // password is expired and cannot login
            LsaNssMapErrorCode(dwError, &errno);
            iError = 2;
            break;
    }
    LSA_LOG_PAM_DEBUG("Lsass LAM expired password check finishing with likewise code %u and LAM code %d",
            dwError,
            iError);
    return iError;

error:
    LsaNssCommonCloseConnection(&lsaConnection);

    goto cleanup;
}
示例#12
0
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;
}
示例#13
0
DWORD
LsaMarshalUserInfo(
    PLSA_SECURITY_OBJECT pUser,
    DWORD       dwUserInfoLevel,
    PVOID*      ppUserInfo
    )
{
    DWORD dwError = 0;
    PVOID pUserInfo = NULL;
    /* These variables represent pUserInfo casted to different types. Do not
     * free these values directly, free pUserInfo instead.
     */
    PLSA_USER_INFO_0 pUserInfo0 = NULL;
    PLSA_USER_INFO_1 pUserInfo1 = NULL;
    PLSA_USER_INFO_2 pUserInfo2 = NULL;

    *ppUserInfo = NULL;

    BAIL_ON_INVALID_POINTER(pUser);

    if (pUser->type != LSA_OBJECT_TYPE_USER)
    {
        dwError = LW_ERROR_INVALID_PARAMETER;
        BAIL_ON_LSA_ERROR(dwError);
    }

    if (!pUser->enabled)
    {
        dwError = LW_ERROR_NO_SUCH_USER;
        BAIL_ON_LSA_ERROR(dwError);
    }

    switch(dwUserInfoLevel)
    {
        case 0:
            dwError = LwAllocateMemory(
                            sizeof(LSA_USER_INFO_0),
                            (PVOID*)&pUserInfo);
            BAIL_ON_LSA_ERROR(dwError);
            pUserInfo0 = (PLSA_USER_INFO_0) pUserInfo;
            break;
        case 1:
            dwError = LwAllocateMemory(
                            sizeof(LSA_USER_INFO_1),
                            (PVOID*)&pUserInfo);
            BAIL_ON_LSA_ERROR(dwError);
            pUserInfo0 = (PLSA_USER_INFO_0) pUserInfo;
            pUserInfo1 = (PLSA_USER_INFO_1) pUserInfo;
            break;
        case 2:
            dwError = LwAllocateMemory(
                            sizeof(LSA_USER_INFO_2),
                            (PVOID*)&pUserInfo);
            BAIL_ON_LSA_ERROR(dwError);
            pUserInfo0 = (PLSA_USER_INFO_0) pUserInfo;
            pUserInfo1 = (PLSA_USER_INFO_1) pUserInfo;
            pUserInfo2 = (PLSA_USER_INFO_2) pUserInfo;
            break;
        default:
            dwError = LW_ERROR_INVALID_PARAMETER;
            BAIL_ON_LSA_ERROR(dwError);
            break;
    }

    if (pUserInfo0 != NULL)
    {
        pUserInfo0->uid = pUser->userInfo.uid;
        pUserInfo0->gid = pUser->userInfo.gid;

        dwError = LwAllocateString(
            pUser->userInfo.pszUnixName,
            &pUserInfo0->pszName);
        BAIL_ON_LSA_ERROR(dwError);

        // Optional values use LwStrDupOrNull. Required values use
        // LwAllocateString.
        dwError = LwStrDupOrNull(
                    pUser->userInfo.pszPasswd,
                    &pUserInfo0->pszPasswd);
        BAIL_ON_LSA_ERROR(dwError);

        dwError = LwStrDupOrNull(
                    pUser->userInfo.pszGecos,
                    &pUserInfo0->pszGecos);
        BAIL_ON_LSA_ERROR(dwError);

        dwError = LwAllocateString(
                    pUser->userInfo.pszShell,
                    &pUserInfo0->pszShell);
        BAIL_ON_LSA_ERROR(dwError);

        dwError = LwAllocateString(
                    pUser->userInfo.pszHomedir,
                    &pUserInfo0->pszHomedir);
        BAIL_ON_LSA_ERROR(dwError);

        dwError = LwAllocateString(
                    pUser->pszObjectSid,
                    &pUserInfo0->pszSid);
        BAIL_ON_LSA_ERROR(dwError);
    }

    if (pUserInfo1 != NULL)
    {
        dwError = LwStrDupOrNull(
                      pUser->pszDN,
                      &pUserInfo1->pszDN);
        BAIL_ON_LSA_ERROR(dwError);

        dwError = LwStrDupOrNull(
                      pUser->userInfo.pszUPN,
                      &pUserInfo1->pszUPN);
        BAIL_ON_LSA_ERROR(dwError);

        pUserInfo1->bIsGeneratedUPN = pUser->userInfo.bIsGeneratedUPN;
        pUserInfo1->bIsLocalUser = pUser->bIsLocal;
        pUserInfo1->pLMHash = NULL;
        pUserInfo1->dwLMHashLen = 0;
        pUserInfo1->pNTHash = NULL;
        pUserInfo1->dwNTHashLen = 0;
    }

    if (pUserInfo2 != NULL)
    {
        struct timeval current_tv;
        UINT64 u64current_NTtime = 0;

        if (pUser->userInfo.bIsAccountInfoKnown)
        {
            if (gettimeofday(&current_tv, NULL) < 0)
            {
                dwError = LwMapErrnoToLwError(errno);
                BAIL_ON_LSA_ERROR(dwError);
            }
            LsaConvertTimeUnix2Nt(current_tv.tv_sec,
                                 &u64current_NTtime);

            if (pUser->userInfo.bPasswordNeverExpires ||
                pUser->userInfo.qwPwdExpires == 0)
            {
                //password never expires
                pUserInfo2->dwDaysToPasswordExpiry = 0LL;
            }
            else if (pUser->userInfo.bPasswordExpired ||
                     u64current_NTtime >= pUser->userInfo.qwPwdExpires)
            {
                //password is expired already
                pUserInfo2->dwDaysToPasswordExpiry = 0LL;
            }
            else
            {
                pUserInfo2->dwDaysToPasswordExpiry =
                    (pUser->userInfo.qwPwdExpires - u64current_NTtime) /
                    (10000000LL * 24*60*60);
            }

            pUserInfo2->bPasswordNeverExpires = pUser->userInfo.bPasswordNeverExpires;

            pUserInfo2->bPasswordExpired = pUser->userInfo.bPasswordExpired;
            pUserInfo2->bPromptPasswordChange = pUser->userInfo.bPromptPasswordChange;
            pUserInfo2->bUserCanChangePassword = pUser->userInfo.bUserCanChangePassword;
            pUserInfo2->bAccountDisabled = pUser->userInfo.bAccountDisabled;
            pUserInfo2->bAccountExpired = pUser->userInfo.bAccountExpired;
            pUserInfo2->bAccountLocked = pUser->userInfo.bAccountLocked;
        }
        else
        {
            pUserInfo2->dwDaysToPasswordExpiry = 0LL;
            pUserInfo2->bPasswordExpired = FALSE;
            pUserInfo2->bPasswordNeverExpires = TRUE;
            pUserInfo2->bPromptPasswordChange = FALSE;
            pUserInfo2->bUserCanChangePassword = FALSE;
            pUserInfo2->bAccountDisabled = FALSE;
            pUserInfo2->bAccountExpired = FALSE;
            pUserInfo2->bAccountLocked = FALSE;
        }
    }

    *ppUserInfo = pUserInfo;

cleanup:

    return dwError;


error:
    if (pUserInfo) {
        LsaFreeUserInfo(dwUserInfoLevel, pUserInfo);
        pUserInfo = NULL;
    }

    *ppUserInfo = NULL;

    goto cleanup;
}
示例#14
0
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;
}
示例#15
0
PVOID
LADSFindUserById(
    PVOID pData
    )
{
    DWORD dwError = 0;
    PVOID pResult = NULL;
    uid_t userId = 0;
    DWORD dwInfoLevel = gLADSStressData[LADS_FIND_USER_BY_ID].dwInfoLevel;
    PVOID pUserInfo = NULL;
    HANDLE hProvider = (HANDLE)NULL;

    while (!LADSProcessShouldStop())
    {
        DWORD iUid = 0;

        for (iUid = 0;
             (!LADSProcessShouldStop() &&
              (iUid < gLADSStressData[LADS_FIND_USER_BY_ID].dwNumItems));
             iUid++)
        {
            userId = gLADSStressData[LADS_FIND_USER_BY_ID].data.pUidArray[iUid];

            dwError = gpAuthProvider->pFnTable->pfnOpenHandle(
                                          geteuid(),
                                          getegid(),
                                          getpid(),
                                          &hProvider);
            BAIL_ON_LSA_ERROR(dwError);

            dwError = gpAuthProvider->pFnTable->pfnLookupUserById(
                                          hProvider,
                                          userId,
                                          dwInfoLevel,
                                          &pUserInfo);
            BAIL_ON_LSA_ERROR(dwError);

            gpAuthProvider->pFnTable->pfnCloseHandle(hProvider);
            hProvider = (HANDLE)NULL;

            LsaFreeUserInfo(dwInfoLevel, pUserInfo);
            pUserInfo = NULL;

            if (gLADSStressData[LADS_FIND_USER_BY_ID].dwSleepMSecs)
            {
                sleep(gLADSStressData[LADS_FIND_USER_BY_ID].dwSleepMSecs);
            }
        }
    }

cleanup:

    if (pUserInfo)
    {
        LsaFreeUserInfo(dwInfoLevel, pUserInfo);
    }

    if (hProvider != (HANDLE)NULL)
    {
        gpAuthProvider->pFnTable->pfnCloseHandle(hProvider);
    }

    return pResult;

error:

    LSA_LOG_ERROR("Failed to find user by id [%ld] [error code: %u]", (long)userId, dwError);

    LADSStopProcess();

    goto cleanup;
}
示例#16
0
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;
}
示例#17
0
PVOID
LADSFindUserByName(
    PVOID pData
    )
{
    DWORD dwError = 0;
    PVOID pResult = NULL;
    PCSTR pszName = NULL;
    DWORD dwInfoLevel = gLADSStressData[LADS_FIND_USER_BY_NAME].dwInfoLevel;
    PVOID pUserInfo = NULL;
    HANDLE hProvider = (HANDLE)NULL;

    while (!LADSProcessShouldStop())
    {
        DWORD iName = 0;

        for (iName = 0;
             (!LADSProcessShouldStop() &&
              (iName < gLADSStressData[LADS_FIND_USER_BY_NAME].dwNumItems));
             iName++)
        {
            pszName = gLADSStressData[LADS_FIND_USER_BY_NAME].data.ppszNames[iName];

            dwError = gpAuthProvider->pFnTable->pfnOpenHandle(
                                          geteuid(),
                                          getegid(),
                                          getpid(),
                                          &hProvider);
            BAIL_ON_LSA_ERROR(dwError);

            dwError = gpAuthProvider->pFnTable->pfnLookupUserByName(
                                          hProvider,
                                          pszName,
                                          dwInfoLevel,
                                          &pUserInfo);
            BAIL_ON_LSA_ERROR(dwError);

            gpAuthProvider->pFnTable->pfnCloseHandle(hProvider);
            hProvider = (HANDLE)NULL;

            LsaFreeUserInfo(dwInfoLevel, pUserInfo);
            pUserInfo = NULL;

            if (gLADSStressData[LADS_FIND_USER_BY_NAME].dwSleepMSecs)
            {
                sleep(gLADSStressData[LADS_FIND_USER_BY_NAME].dwSleepMSecs);
            }
        }
    }

cleanup:

    if (pUserInfo)
    {
        LsaFreeUserInfo(dwInfoLevel, pUserInfo);
    }

    if (hProvider != (HANDLE)NULL)
    {
        gpAuthProvider->pFnTable->pfnCloseHandle(hProvider);
    }

    return pResult;

error:

    LSA_LOG_ERROR("Failed to find user by name [%s] [error code: %u]",
                  (LW_IS_NULL_OR_EMPTY_STR(pszName) ? "" : pszName), dwError);

    LADSStopProcess();

    goto cleanup;
}
示例#18
0
int
main(int argc, const char **argv)
{
    poptContext poptContext;
    int poptResult;
    uid_t uid;
    int kq;
    HANDLE lsaConnection = (HANDLE) NULL;
    PVOID pUserInfo = NULL;
    struct kevent event = { 0 };
    int numChanges = 1;
    krb5_context krb5Context = NULL;
    char krb5FileCachePath[PATH_MAX];
    krb5_ccache krb5FileCache = NULL;
    krb5_ccache krb5MemoryCache = NULL;
    krb5_cc_cursor krb5Cursor = NULL;
    krb5_creds krb5Credentials = { 0 };
    krb5_principal krb5Principal = NULL;
    krb5_error_code krb5Error;
    int exitStatus = 0;
    DWORD dwError = LW_ERROR_SUCCESS;

    poptContext = poptGetContext(NULL, argc, argv, Options, 0);
    while ((poptResult = poptGetNextOpt(poptContext)) >= 0)
    {
        /* All options are processed automatically. */
    }

    if (poptResult < -1)
    {
        fprintf(stderr, "%s: %s: %s\n", getprogname(),
                poptBadOption(poptContext, POPT_BADOPTION_NOALIAS),
                poptStrerror(poptResult));
        exitStatus = 1;
        goto error;
    }

    uid = getuid();

    /* Make sure we're running as an AD user. */
    dwError = LsaOpenServer(&lsaConnection);
    BAIL_ON_LSA_ERROR(dwError);

    dwError = LsaFindUserById(
                  lsaConnection,
                  uid,
                  0,
                  &pUserInfo);
    if (dwError == LW_ERROR_NO_SUCH_USER)
    {
        /*
         * Running as a non-AD user; exit 0 so launchd doesn't restart
         * the ticketcopy program (see com.beyondtrust.pbis.ticketcopy.plist).
         */
        LSA_LOG_DEBUG(
            "uid %lu is not an AD user; exiting",
            (unsigned long) uid);
        dwError = LW_ERROR_SUCCESS;
        goto cleanup;
    }
    BAIL_ON_LSA_ERROR(dwError);

    kq = kqueue();
    BAIL_ON_UNIX_ERROR(kq == -1);

    krb5Error = krb5_init_context(&krb5Context);
    BAIL_ON_KRB5_ERROR(krb5Context, krb5Error, dwError);

    krb5Error = krb5_cc_default(krb5Context, &krb5MemoryCache);
    BAIL_ON_KRB5_ERROR(krb5Context, krb5Error, dwError);

    snprintf(
        krb5FileCachePath,
        sizeof(krb5FileCachePath),
        "FILE:/tmp/krb5cc_%lu",
        (unsigned long) uid);

    while (1) /* Forever (or until an error occurs) */
    {
        while ((event.ident = open(krb5FileCachePath + 5, O_RDONLY)) == -1)
        {
            sleep(5);
        }

        event.filter = EVFILT_VNODE;
        event.flags = EV_ADD | EV_ENABLE | EV_CLEAR;
        event.fflags = NOTE_DELETE | NOTE_WRITE;
        numChanges = 1;

        krb5Error = krb5_cc_resolve(
                        krb5Context,
                        krb5FileCachePath,
                        &krb5FileCache);
        BAIL_ON_KRB5_ERROR(krb5Context, krb5Error, dwError);

        while (1) /* While the file continues to exist. */
        {
            /*
             * Turn off KRB5_TC_OPENCLOSE so the file will be opened once
             * and kept open.  This causes it to actually attempt to open
             * the file, so this is where we check for the file not
             * existing and retry after sleeping a bit.
             */
            krb5Error = krb5_cc_set_flags(krb5Context, krb5FileCache, 0);
            if (krb5Error == KRB5_FCC_NOFILE)
            {
                break;
            }
            BAIL_ON_KRB5_ERROR(krb5Context, krb5Error, dwError);

            /* Copy all credentials from the file to the memory cache. */
            krb5Error = krb5_cc_start_seq_get(
                            krb5Context,
                            krb5FileCache,
                            &krb5Cursor);
            BAIL_ON_KRB5_ERROR(krb5Context, krb5Error, dwError);

            while ((krb5Error = krb5_cc_next_cred(
                                    krb5Context,
                                    krb5FileCache,
                                    &krb5Cursor,
                                    &krb5Credentials)) == 0)
            {
                krb5Error = krb5_cc_store_cred(
                                krb5Context,
                                krb5MemoryCache,
                                &krb5Credentials);
                if (krb5Error == KRB5_FCC_NOFILE)
                {
                    krb5Error = krb5_cc_get_principal(
                                    krb5Context,
                                    krb5FileCache,
                                    &krb5Principal);
                    BAIL_ON_KRB5_ERROR(krb5Context, krb5Error, dwError);

                    /* The memory cache was destroyed; re-create it. */
                    krb5Error = krb5_cc_initialize(
                                    krb5Context,
                                    krb5MemoryCache,
                                    krb5Principal);
                    BAIL_ON_KRB5_ERROR(krb5Context, krb5Error, dwError);

                    krb5_free_principal(krb5Context, krb5Principal);
                    krb5Principal = NULL;

                    krb5Error = krb5_cc_store_cred(
                                    krb5Context,
                                    krb5MemoryCache,
                                    &krb5Credentials);
                }
                BAIL_ON_KRB5_ERROR(krb5Context, krb5Error, dwError);

                krb5_free_cred_contents(krb5Context, &krb5Credentials);
            }

            if (krb5Error != KRB5_CC_END)
            {
                BAIL_ON_KRB5_ERROR(krb5Context, krb5Error, dwError);
            }

            krb5Error = krb5_cc_end_seq_get(
                            krb5Context,
                            krb5FileCache,
                            &krb5Cursor);
            krb5Cursor = NULL;
            BAIL_ON_KRB5_ERROR(krb5Context, krb5Error, dwError);

            /*
             * Turn KRB5_TC_OPENCLOSE back on; this will cause
             * the file to be closed and any locks to be
             * released.
             */
            krb5Error = krb5_cc_set_flags(
                            krb5Context,
                            krb5FileCache,
                            KRB5_TC_OPENCLOSE);
            BAIL_ON_KRB5_ERROR(krb5Context, krb5Error, dwError);

            /*
             * Wait for the file to be modified or deleted.  The first
             * time this is called after the file is opened, numChanges
             * will be 1, which will install the fd into the event
             * list.  After that numChanges is changed to 0, so it will
             * just report events from the existing list.
             */
            if (kevent(kq, &event, numChanges, &event, 1, NULL) != 1)
            {
                fprintf(stderr, "kevent failed\n");
                exitStatus = 1;
                goto cleanup;
            }

            if (event.fflags & NOTE_DELETE)
            {
                break;
            }

            numChanges = 0;
        }

        krb5Error = krb5_cc_close(krb5Context, krb5FileCache);
        BAIL_ON_KRB5_ERROR(krb5Context, krb5Error, dwError);
        krb5FileCache = NULL;

        close(event.ident);
        event.ident = -1;

        /*
         * The cache file is usually removed as part of a
         * rename(2) system call, so only wait a short
         * time before the first attempt to re-open it.
         */
        usleep(100000);
    }

error:
cleanup:
    krb5_free_cred_contents(krb5Context, &krb5Credentials);

    if (krb5Cursor)
    {
        krb5_cc_end_seq_get(krb5Context, krb5FileCache, &krb5Cursor);
    }

    if (krb5FileCache)
    {
        krb5_cc_close(krb5Context, krb5FileCache);
    }

    if (krb5Principal)
    {
        krb5_free_principal(krb5Context, krb5Principal);
    }

    if (krb5Context)
    {
        krb5_free_context(krb5Context);
    }

    if (event.ident != -1)
    {
        close(event.ident);
    }

    if (pUserInfo)
    {
        LsaFreeUserInfo(0, pUserInfo);
    }

    if (lsaConnection != (HANDLE) NULL)
    {
        LsaCloseServer(lsaConnection);
    }

    if (dwError)
    {
        exitStatus = 1;
    }

    return exitStatus;
}