Пример #1
0
int VBoxGINACredentialsPollerTerminate(void)
{
    if (gThreadPoller == NIL_RTTHREAD)
        return VINF_SUCCESS;

    VBoxGINAVerbose(0, "VBoxGINA::credentialsPollerTerminate\n");

    /* post termination event semaphore */
    int rc = RTThreadUserSignal(gThreadPoller);
    if (RT_SUCCESS(rc))
    {
        VBoxGINAVerbose(0, "VBoxGINA::credentialsPollerTerminate: waiting for thread to terminate\n");
        rc = RTThreadWait(gThreadPoller, RT_INDEFINITE_WAIT, NULL);
    }
    else
        VBoxGINAVerbose(0, "VBoxGINA::credentialsPollerTerminate: thread has terminated? wait rc = %Rrc\n",     rc);

    if (RT_SUCCESS(rc))
    {
        gThreadPoller = NIL_RTTHREAD;
    }

    VBoxGINAVerbose(0, "VBoxGINA::credentialsPollerTerminate: returned with rc=%Rrc)\n", rc);
    return rc;
}
Пример #2
0
/**
 * Reports VBoxGINA's status to the host (treated as a guest facility).
 *
 * @return  IPRT status code.
 * @param   enmStatus               Status to report to the host.
 */
int VBoxGINAReportStatus(VBoxGuestFacilityStatus enmStatus)
{
    VBoxGINAVerbose(0, "VBoxGINA: reporting status %d\n", enmStatus);

    int rc = VbglR3AutoLogonReportStatus(enmStatus);
    if (RT_FAILURE(rc))
        VBoxGINAVerbose(0, "VBoxGINA: failed to report status %d, rc=%Rrc\n", enmStatus, rc);
    return rc;
}
Пример #3
0
void hookDialogBoxes(PVOID pWinlogonFunctions, DWORD dwWlxVersion)
{
    if (!pWinlogonFunctions) /* Needed for testcase. */
        return;

    VBoxGINAVerbose(0, "VBoxGINA::hookDialogBoxes\n");

    /* this is version dependent */
    switch (dwWlxVersion)
    {
        case WLX_VERSION_1_0:
        {
            g_pfnWlxDialogBoxParam = ((PWLX_DISPATCH_VERSION_1_0)pWinlogonFunctions)->WlxDialogBoxParam;
            ((PWLX_DISPATCH_VERSION_1_0)pWinlogonFunctions)->WlxDialogBoxParam = MyWlxDialogBoxParam;
            break;
        }

        case WLX_VERSION_1_1:
        {
            g_pfnWlxDialogBoxParam = ((PWLX_DISPATCH_VERSION_1_1)pWinlogonFunctions)->WlxDialogBoxParam;
            ((PWLX_DISPATCH_VERSION_1_1)pWinlogonFunctions)->WlxDialogBoxParam = MyWlxDialogBoxParam;
            break;
        }

        case WLX_VERSION_1_2:
        {
            g_pfnWlxDialogBoxParam = ((PWLX_DISPATCH_VERSION_1_2)pWinlogonFunctions)->WlxDialogBoxParam;
            ((PWLX_DISPATCH_VERSION_1_2)pWinlogonFunctions)->WlxDialogBoxParam = MyWlxDialogBoxParam;
            break;
        }

        case WLX_VERSION_1_3:
        {
            g_pfnWlxDialogBoxParam = ((PWLX_DISPATCH_VERSION_1_3)pWinlogonFunctions)->WlxDialogBoxParam;
            ((PWLX_DISPATCH_VERSION_1_3)pWinlogonFunctions)->WlxDialogBoxParam = MyWlxDialogBoxParam;
            break;
        }

        case WLX_VERSION_1_4:
        {
            g_pfnWlxDialogBoxParam = ((PWLX_DISPATCH_VERSION_1_4)pWinlogonFunctions)->WlxDialogBoxParam;
            ((PWLX_DISPATCH_VERSION_1_4)pWinlogonFunctions)->WlxDialogBoxParam = MyWlxDialogBoxParam;
            break;
        }

        default:
        {
            VBoxGINAVerbose(0, "VBoxGINA::hookDialogBoxes: unrecognized version '%d', nothing hooked!\n", dwWlxVersion);
            /* not good, don't do anything */
            break;
        }
    }
}
Пример #4
0
int VBoxGINACredentialsPollerCreate(void)
{
    if (!VBoxGINAHandleCurrentSession())
        return VINF_SUCCESS;

    VBoxGINAVerbose(0, "VBoxGINA::credentialsPollerCreate\n");

    /* don't create more than one of them */
    if (gThreadPoller != NIL_RTTHREAD)
    {
        VBoxGINAVerbose(0, "VBoxGINA::credentialsPollerCreate: thread already running, returning!\n");
        return VINF_SUCCESS;
    }

    /* create the poller thread */
    int rc = RTThreadCreate(&gThreadPoller, credentialsPoller, NULL, 0, RTTHREADTYPE_INFREQUENT_POLLER,
                            RTTHREADFLAGS_WAITABLE, "creds");
    if (RT_FAILURE(rc))
        VBoxGINAVerbose(0, "VBoxGINA::credentialsPollerCreate: failed to create thread, rc = %Rrc\n", rc);

    return rc;
}
Пример #5
0
/**
 * Determines whether we should handle the current session or not.
 *
 * @return  bool        true if we should handle this session, false if not.
 */
bool VBoxGINAHandleCurrentSession(void)
{
    /* Load global configuration from registry. */
    int rc = VBoxGINALoadConfiguration();
    if (RT_FAILURE(rc))
        VBoxGINAVerbose(0, "VBoxGINA::handleCurrentSession: Error loading global configuration, rc=%Rrc\n",
                        rc);

    bool fHandle = false;
    if (VbglR3AutoLogonIsRemoteSession())
    {
        if (g_dwHandleRemoteSessions) /* Force remote session handling. */
            fHandle = true;
    }
    else /* No remote session. */
        fHandle = true;

#ifdef DEBUG
    VBoxGINAVerbose(3, "VBoxGINA::handleCurrentSession: Handling current session=%RTbool\n", fHandle);
#endif
    return fHandle;
}
Пример #6
0
int WINAPI MyWlxDialogBoxParam(HANDLE  hWlx,
                               HANDLE  hInst,
                               LPWSTR  lpszTemplate,
                               HWND    hwndOwner,
                               DLGPROC dlgprc,
                               LPARAM  dwInitParam)
{
    VBoxGINAVerbose(0, "VBoxGINA::MyWlxDialogBoxParam: lpszTemplate=%ls\n", lpszTemplate);

    VBoxGINAReportStatus(VBoxGuestFacilityStatus_Active);

    //
    // We only know MSGINA dialogs by identifiers.
    //
    if (!HIWORD((int)(void*)lpszTemplate))
    {
        //
        // Hook appropriate dialog boxes as necessary.
        //
        switch ((DWORD) lpszTemplate)
        {
            case IDD_WLXDIAPLAYSASNOTICE_DIALOG:
                VBoxGINAVerbose(0, "VBoxGINA::MyWlxDialogBoxParam: SAS notice dialog displayed; not handled\n");
                break;

            case IDD_WLXLOGGEDOUTSAS_DIALOG:     /* Windows NT 4.0. */
            case IDD_WLXLOGGEDOUTSAS_DIALOG2:    /* Windows 2000 and up. */
            {
                VBoxGINAVerbose(0, "VBoxGINA::MyWlxDialogBoxParam: returning hooked SAS logged out dialog\n");
                g_pfnWlxLoggedOutSASDlgProc = dlgprc;
                return g_pfnWlxDialogBoxParam(hWlx, hInst, lpszTemplate, hwndOwner,
                                              MyWlxLoggedOutSASDlgProc, dwInitParam);
            }

            case IDD_SECURITY_DIALOG:
                VBoxGINAVerbose(0, "VBoxGINA::MyWlxDialogBoxParam: Security dialog displayed; not handled\n");
                break;

            case IDD_WLXWKSTALOCKEDSAS_DIALOG:   /* Windows NT 4.0. */
            case IDD_WLXWKSTALOCKEDSAS_DIALOG2:  /* Windows 2000 and up. */
            {
                VBoxGINAVerbose(0, "VBoxGINA::MyWlxDialogBoxParam: returning hooked SAS locked dialog\n");
                g_pfnWlxLockedSASDlgProc = dlgprc;
                return g_pfnWlxDialogBoxParam(hWlx, hInst, lpszTemplate, hwndOwner,
                                              MyWlxLockedSASDlgProc, dwInitParam);
            }

            /** @todo Add other hooking stuff here. */

            default:
                VBoxGINAVerbose(0, "VBoxGINA::MyWlxDialogBoxParam: dialog %ld not handled\n", (DWORD)lpszTemplate);
                break;
        }
    }

    /* The rest will be redirected. */
    return g_pfnWlxDialogBoxParam(hWlx, hInst, lpszTemplate,
                                  hwndOwner, dlgprc, dwInitParam);
}
Пример #7
0
/**
 * Poller thread. Checks periodically whether there are credentials.
 */
static DECLCALLBACK(int) credentialsPoller(RTTHREAD ThreadSelf, void *pvUser)
{
    RT_NOREF(pvUser);
    VBoxGINAVerbose(0, "VBoxGINA::credentialsPoller\n");

    do
    {
        int rc = VbglR3CredentialsQueryAvailability();
        if (RT_SUCCESS(rc))
        {
            VBoxGINAVerbose(0, "VBoxGINA::credentialsPoller: got credentials, simulating C-A-D\n");
            /* tell WinLogon to start the attestation process */
            pWlxFuncs->WlxSasNotify(hGinaWlx, WLX_SAS_TYPE_CTRL_ALT_DEL);
            /* time to say goodbye */
            return 0;
        }

        if (   RT_FAILURE(rc)
            && rc != VERR_NOT_FOUND)
        {
            static int s_cBitchedQueryAvail = 0;
            if (s_cBitchedQueryAvail++ < 5)
                VBoxGINAVerbose(0, "VBoxGINA::credentialsPoller: querying for credentials failed with rc=%Rrc\n", rc);
        }

        /* wait a bit */
        if (RTThreadUserWait(ThreadSelf, 500) == VINF_SUCCESS)
        {
            VBoxGINAVerbose(0, "VBoxGINA::credentialsPoller: we were asked to terminate\n");
            /* we were asked to terminate, do that instantly! */
            return 0;
        }
    }
    while (1);

    return 0;
}
Пример #8
0
INT_PTR CALLBACK MyWlxLockedSASDlgProc(HWND   hwndDlg,  // handle to dialog box
                                       UINT   uMsg,     // message
                                       WPARAM wParam,   // first message parameter
                                       LPARAM lParam)   // second message parameter
{
    BOOL bResult;
    static HWND s_hwndPassword = 0;

    /*VBoxGINAVerbose(0, "VBoxGINA::MyWlxLockedSASDlgProc\n");*/

    //
    // Pass on to MSGINA first.
    //
    bResult = g_pfnWlxLockedSASDlgProc(hwndDlg, uMsg, wParam, lParam);

    //
    // We are only interested in the WM_INITDIALOG message.
    //
    switch (uMsg)
    {
        case WM_INITDIALOG:
        {
            VBoxGINAVerbose(0, "VBoxGINA::MyWlxLockedSASDlgProc: WM_INITDIALOG\n");

            /* get the entry fields */
            s_hwndPassword = GetDlgItem(hwndDlg, IDC_WKSTALOCKED_PASSWORD);
            VBoxGINAVerbose(0, "VBoxGINA::MyWlxLockedSASDlgProc: hwndPassword: %d\n", s_hwndPassword);

            /* terminate the credentials poller thread, it's done is job */
            VBoxGINACredentialsPollerTerminate();

            int rc = credentialsHandle(hwndDlg,
                                       NULL /* Username */, s_hwndPassword, NULL /* Domain */,
                                       IDOK /* Button */);
            if (RT_FAILURE(rc))
            {
                /*
                 * The dialog is there but we don't have any credentials.
                 * Create a timer and poll for them.
                 */
                UINT_PTR uTimer = SetTimer(hwndDlg, IDT_LOCKEDDLG_POLL, 200, NULL);
                if (!uTimer)
                    VBoxGINAVerbose(0, "VBoxGINA::MyWlxLockedSASDlgProc: failed creating timer! Last error: %ld\n",
                         GetLastError());
            }
            break;
        }

        case WM_TIMER:
        {
            /* is it our credentials poller timer? */
            if (wParam == IDT_LOCKEDDLG_POLL)
            {
                int rc = credentialsHandle(hwndDlg,
                                           NULL /* Username */, s_hwndPassword, NULL /* Domain */,
                                           IDOK /* Button */);
                if (RT_SUCCESS(rc))
                {
                    /* we don't need the timer any longer */
                    KillTimer(hwndDlg, IDT_LOCKEDDLG_POLL);
                }
            }
            break;
        }

        case WM_DESTROY:
        {
            VBoxGINAVerbose(0, "VBoxGINA::MyWlxLockedSASDlgProc: WM_DESTROY\n");

            /* Because this is the only point where we know within our module that the locked
             * dialog has been closed by a valid unlock password we have to set the appropriate
             * facility status here. */
            VBoxGINAReportStatus(VBoxGuestFacilityStatus_Terminated);

            KillTimer(hwndDlg, IDT_LOCKEDDLG_POLL);
            break;
        }
    }
    return bResult;
}
Пример #9
0
INT_PTR CALLBACK MyWlxLoggedOutSASDlgProc(HWND   hwndDlg,  // handle to dialog box
                                          UINT   uMsg,     // message
                                          WPARAM wParam,   // first message parameter
                                          LPARAM lParam)   // second message parameter
{
    BOOL bResult;
    static HWND s_hwndUserId, s_hwndPassword, s_hwndDomain = 0;

    /*VBoxGINAVerbose(0, "VBoxGINA::MyWlxLoggedOutSASDlgProc\n");*/

    //
    // Pass on to MSGINA first.
    //
    bResult = g_pfnWlxLoggedOutSASDlgProc(hwndDlg, uMsg, wParam, lParam);

    //
    // We are only interested in the WM_INITDIALOG message.
    //
    switch (uMsg)
    {
        case WM_INITDIALOG:
        {
            VBoxGINAVerbose(0, "VBoxGINA::MyWlxLoggedOutSASDlgProc: got WM_INITDIALOG\n");

            /* get the entry fields */
            s_hwndUserId = GetDlgItem(hwndDlg, IDC_WLXLOGGEDOUTSAS_USERNAME);
            if (!s_hwndUserId)
                s_hwndUserId = GetDlgItem(hwndDlg, IDC_WLXLOGGEDOUTSAS_USERNAME2);
            s_hwndPassword = GetDlgItem(hwndDlg, IDC_WLXLOGGEDOUTSAS_PASSWORD);
            if (!s_hwndPassword)
                s_hwndPassword = GetDlgItem(hwndDlg, IDC_WLXLOGGEDOUTSAS_PASSWORD2);
            s_hwndDomain = GetDlgItem(hwndDlg, IDC_WLXLOGGEDOUTSAS_DOMAIN);
            if (!s_hwndDomain)
                s_hwndDomain = GetDlgItem(hwndDlg, IDC_WLXLOGGEDOUTSAS_DOMAIN2);

            VBoxGINAVerbose(0, "VBoxGINA::MyWlxLoggedOutSASDlgProc: hwndUserId: %x, hwndPassword: %d, hwndDomain: %d\n",
                            s_hwndUserId, s_hwndPassword, s_hwndDomain);

            /* terminate the credentials poller thread, it's done is job */
            VBoxGINACredentialsPollerTerminate();

            int rc = credentialsHandle(hwndDlg,
                                       s_hwndUserId, s_hwndPassword, s_hwndDomain,
                                       IDOK /* Button */);
            if (RT_FAILURE(rc))
            {
                /*
                 * The dialog is there but we don't have any credentials.
                 * Create a timer and poll for them.
                 */
                UINT_PTR uTimer = SetTimer(hwndDlg, IDT_LOGGEDONDLG_POLL, 200, NULL);
                if (!uTimer)
                    VBoxGINAVerbose(0, "VBoxGINA::MyWlxLoggedOutSASDlgProc: failed creating timer! Last error: %ld\n",
                                    GetLastError());
            }
            break;
        }

        case WM_TIMER:
        {
            /* is it our credentials poller timer? */
            if (wParam == IDT_LOGGEDONDLG_POLL)
            {
                int rc = credentialsHandle(hwndDlg,
                                           s_hwndUserId, s_hwndPassword, s_hwndDomain,
                                           IDOK /* Button */);
                if (RT_SUCCESS(rc))
                {
                    /* we don't need the timer any longer */
                    KillTimer(hwndDlg, IDT_LOGGEDONDLG_POLL);
                }
            }
            break;
        }

        case WM_DESTROY:
            KillTimer(hwndDlg, IDT_LOGGEDONDLG_POLL);
            break;
    }
    return bResult;
}
Пример #10
0
/**
 * Tries to retrieve credentials and enters them into the specified windows,
 * optionally followed by a button press to confirm/abort the dialog.
 *
 * @return  IPRT status code.
 * @param   hwndDlg                 Handle of dialog to enter credentials into.
 * @param   hwndUserId              Handle of username text field. Optional.
 * @param   hwndPassword            Handle of password text field. Optional.
 * @param   hwndDomain              Handle of domain text field. Optional.
 * @param   wButtonToPress          Button ID of dialog to press after successful
 *                                  retrieval + storage. If set to 0 no button will
 *                                  be pressed.
 */
int credentialsHandle(HWND hwndDlg,
                      HWND hwndUserId, HWND hwndPassword, HWND hwndDomain,
                      WORD wButtonToPress)
{
    int rc = VINF_SUCCESS;

    if (!VBoxGINAHandleCurrentSession())
        rc = VERR_NOT_FOUND;

    if (RT_SUCCESS(rc))
    {
        rc = VbglR3CredentialsQueryAvailability();
        if (RT_FAILURE(rc))
        {
            if (rc != VERR_NOT_FOUND)
                VBoxGINAVerbose(0, "VBoxGINA::credentialsHandle: error querying for credentials, rc=%Rrc\n", rc);
        }
    }

    if (RT_SUCCESS(rc))
    {
        VBoxGINAVerbose(0, "VBoxGINA::credentialsHandle: credentials available\n");

        /*
         * Set status to "terminating" to let the host know this module now
         * tries to receive and use passed credentials so that credentials from
         * the host won't be sent twice.
         */
        VBoxGINAReportStatus(VBoxGuestFacilityStatus_Terminating);

        PRTUTF16 pwszUser, pwszPassword, pwszDomain;
        rc = VbglR3CredentialsRetrieveUtf16(&pwszUser, &pwszPassword, &pwszDomain);
        if (RT_SUCCESS(rc))
        {
    #ifdef DEBUG
            VBoxGINAVerbose(0, "VBoxGINA::credentialsHandle: retrieved credentials: user=%ls, password=%ls, domain=%ls\n",
                            pwszUser, pwszPassword, pwszDomain);
    #else
            VBoxGINAVerbose(0, "VBoxGINA::credentialsHandle: retrieved credentials: user=%ls, password=XXX, domain=%ls\n",
                            pwszUser, pwszDomain);
    #endif
            /* Fill in credentials to appropriate UI elements. */
            rc = credentialsToUI(hwndDlg,
                                 hwndUserId, hwndPassword, hwndDomain,
                                 pwszUser, pwszPassword, pwszDomain);
            if (RT_SUCCESS(rc))
            {
                /* Confirm/cancel the dialog by pressing the appropriate button. */
                if (wButtonToPress)
                {
                    WPARAM wParam = MAKEWPARAM(wButtonToPress, BN_CLICKED);
                    PostMessage(hwndDlg, WM_COMMAND, wParam, 0);
                }
            }

            VbglR3CredentialsDestroyUtf16(pwszUser, pwszPassword, pwszDomain,
                                          3 /* Passes */);
        }
    }

    VBoxGINAVerbose(3, "VBoxGINA::credentialsHandle: returned with rc=%Rrc\n", rc);
    return rc;
}
Пример #11
0
/**
 * Enters credentials into the given text fields.
 *
 * @return  IPRT status code.
 * @param   hwndDlg                 Handle of dialog to enter credentials into.
 * @param   hwndUserId              Handle of username text field. Optional.
 * @param   hwndPassword            Handle of password text field. Optional.
 * @param   hwndDomain              Handle of domain text field. Optional.
 * @param   pwszUser                Username to enter into username text field.
 * @param   pwszPassword            Password to enter into password text field.
 * @param   pwszDomain              Domain to enter into domain text field.
 */
int credentialsToUI(HWND hwndDlg,
                    HWND hwndUserId, HWND hwndPassword, HWND hwndDomain,
                    PCRTUTF16 pwszUser, PCRTUTF16 pwszPassword, PCRTUTF16 pwszDomain)
{
    BOOL bIsFQDN = FALSE;
    wchar_t szUserFQDN[512]; /* VMMDEV_CREDENTIALS_STRLEN + 255 bytes max. for FQDN */
    if (hwndDomain)
    {
        /* search the domain combo box for our required domain and select it */
        VBoxGINAVerbose(0, "VBoxGINA::MyWlxLoggedOutSASDlgProc: Trying to find domain entry in combo box ...\n");
        DWORD dwIndex = (DWORD) SendMessage(hwndDomain, CB_FINDSTRING,
                                            0, (LPARAM)pwszDomain);
        if (dwIndex != CB_ERR)
        {
            VBoxGINAVerbose(0, "VBoxGINA::MyWlxLoggedOutSASDlgProc: Found domain at combo box pos %ld\n", dwIndex);
            SendMessage(hwndDomain, CB_SETCURSEL, (WPARAM) dwIndex, 0);
            EnableWindow(hwndDomain, FALSE);
        }
        else
        {
            VBoxGINAVerbose(0, "VBoxGINA::MyWlxLoggedOutSASDlgProc: Domain not found in combo box ...\n");

            /* If the domain value has a dot (.) in it, it is a FQDN (Fully Qualified Domain Name)
             * which will not work with the combo box selection because Windows only keeps the
             * NETBIOS names to the left most part of the domain name there. Of course a FQDN
             * then will not be found by the search in the block above.
             *
             * To solve this problem the FQDN domain value will be appended at the user name value
             * (Kerberos style) using an "@", e.g. "<user-name>@full.qualified.domain".
             *
             */
            size_t l = wcslen(pwszDomain);
            if (l > 255)
                VBoxGINAVerbose(0, "VBoxGINA::MyWlxLoggedOutSASDlgProc: Warning! FQDN (domain) is too long (max 255 bytes), will be truncated!\n");

            if (wcslen(pwszUser) > 0) /* We need a user name that we can use in caes of a FQDN */
            {
                if (l > 16) /* Domain name is longer than 16 chars, cannot be a NetBIOS name anymore */
                {
                    VBoxGINAVerbose(0, "VBoxGINA::MyWlxLoggedOutSASDlgProc: Domain seems to be a FQDN (length)!\n");
                    bIsFQDN = TRUE;
                }
                else if (   l > 0
                         && wcsstr(pwszDomain, L".") != NULL) /* if we found a dot (.) in the domain name, this has to be a FQDN */
                {
                    VBoxGINAVerbose(0, "VBoxGINA::MyWlxLoggedOutSASDlgProc: Domain seems to be a FQDN (dot)!\n");
                    bIsFQDN = TRUE;
                }

                if (bIsFQDN)
                {
                    swprintf(szUserFQDN, sizeof(szUserFQDN) / sizeof(wchar_t), L"%s@%s", pwszUser, pwszDomain);
                    VBoxGINAVerbose(0, "VBoxGINA::MyWlxLoggedOutSASDlgProc: FQDN user name is now: %s!\n", szUserFQDN);
                }
            }
        }
    }
    if (hwndUserId)
    {
        if (!bIsFQDN)
            SendMessage(hwndUserId, WM_SETTEXT, 0, (LPARAM)pwszUser);
        else
            SendMessage(hwndUserId, WM_SETTEXT, 0, (LPARAM)szUserFQDN);
    }
    if (hwndPassword)
        SendMessage(hwndPassword, WM_SETTEXT, 0, (LPARAM)pwszPassword);

    return VINF_SUCCESS; /** @todo */
}