Subversion Repositories Aucun

Rev

Rev 213 | Rev 217 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 Copyright (c) 2008, Guillaume Seguin ([email protected])
 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions
 are met:

 1. Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.

 2. Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.

 THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 SUCH DAMAGE.
*/


#include <windows.h>
#include <wincrypt.h>
#include "loggedout_dlg.h"
#include "dlgdefs.h"
#include "trace.h"
#include "settings.h"
#include "global.h"

#define _SECURE_ATL 1

#include <atlbase.h>
#include "atlapp.h"
#include "atlctrls.h"
#include "StaticPrompt.h"

#include "randpasswd.h"
#include "securityhelper.h"


wchar_t gUsername[512] = L"";
size_t gUsername_len = sizeof gUsername / sizeof * gUsername;

//We want a long password (16 chars) that changes at every boot
//But we also need a beacon (5 chars) to know if its a left over password
//from a previous boot.
const wchar_t gEncryptedTag[] = L"AUCUN";
const size_t gEncryptedTag_len = sizeof gEncryptedTag / sizeof * gEncryptedTag;
#define TAGGED_AUCUN_PWLEN (AUCUN_PWLEN+gEncryptedTag_len)
//And the buffer must be multiple of the  block size (I guess)
wchar_t gEncryptedRandomSelfservePassword[CRYPTPROTECTMEMORY_BLOCK_SIZE * (((TAGGED_AUCUN_PWLEN - 1) / CRYPTPROTECTMEMORY_BLOCK_SIZE) + 1)] = L"";
const size_t gEncryptedRandomSelfservePassword_len = CRYPTPROTECTMEMORY_BLOCK_SIZE * (((TAGGED_AUCUN_PWLEN - 1) / CRYPTPROTECTMEMORY_BLOCK_SIZE) + 1);

static CStaticPromptCtrl gStaticPrompt;

enum
{
    IDC_SELFSERVE_FIRST = 1000,
    IDC_SELFSERVEPROMPT
};

//Moves a control in a dialog
void MoveControl(HWND hwndDlg, int id, int xoffset, int yoffset)
{
    HWND control = GetDlgItem(hwndDlg, id);
    RECT rect;
    //Move the bottom row controls (Ok, Cancel, Options, etc.)
    GetWindowRect(control, &rect);
    POINT p;
    p.x = rect.left;
    p.y = rect.top;
    ScreenToClient(hwndDlg, &p);
    MoveWindow(control, p.x + xoffset, p.y + yoffset, rect.right - rect.left, rect.bottom - rect.top, TRUE);
}

// Gets the margin between the control and the parent's window border
int GetDialogLeftMargin(HWND hwndDlg, int control)
{
    RECT rect;
    POINT p;
    //As far left as the static controls
    GetWindowRect(GetDlgItem(hwndDlg, control), &rect);
    p.x = rect.left;
    p.y = rect.top;
    ScreenToClient(hwndDlg, &p);
    return p.x;
}


// Add a static control under between the password field and the ok button
HWND AddStaticPrompt(HWND hwndDlg)
{
    HWND hwndPrompt = 0;
    wchar_t prompt[2048];

    if (GetSelfServeSetting(L"Text", prompt, sizeof prompt / sizeof * prompt) == S_OK)
    {
        RECT rect;
        POINT p;
        int increase = 0;
        int margin =  GetDialogLeftMargin(hwndDlg, 1506); //Username label
        //On the same line as the ok buttons (they will be moved)
        GetWindowRect(GetDlgItem(hwndDlg, IDOK), &rect);
        p.x = rect.left;
        p.y = rect.top;
        //As far right as the Option button
        GetWindowRect(GetDlgItem(hwndDlg, 1514), &rect);
        //As far left as the Ok button
        rect.left = p.x;
        //Here, rect contains the outer rectangle including all buttons from the bottom row
        //rect = left, top and bottom of IDOK,   right of 1514 (options);
        //Now convert the top-left coordinate in client for CreateWindow
        ScreenToClient(hwndDlg, &p);
        //We have the top left corner and the width. Let's create the dialog so we can
        //compute the height of the text
        hwndPrompt = CreateWindowEx(0, L"STATIC", InterpretCarriageReturn(prompt), SS_LEFT | SS_NOTIFY | WS_CHILD, //|WS_VISIBLE,
                                    p.x, p.y, rect.right - rect.left, 100, hwndDlg, (HMENU)IDC_SELFSERVEPROMPT, 0, 0);
        gStaticPrompt.SubclassWindow(hwndPrompt);
        increase = gStaticPrompt.ComputeRequiredHeight();
        gStaticPrompt.MoveWindow(p.x, p.y, rect.right - rect.left, increase);
        //Get the original window's dimension
        GetWindowRect(hwndDlg, &rect);
        //Make it bigger
        SetWindowPos(hwndDlg, 0, 0, 0, rect.right - rect.left, rect.bottom - rect.top + increase + margin, SWP_NOMOVE | SWP_NOZORDER);
        //Move the bottom row controls (Ok, Cancel, Options, etc.)
        MoveControl(hwndDlg, 24064, 0, increase + margin); //Bitmap (shows current keyboard layout)
        MoveControl(hwndDlg, IDOK, 0, increase + margin); //OK button
        MoveControl(hwndDlg, IDCANCEL, 0, increase + margin); //Cancel button
        MoveControl(hwndDlg, 1501, 0, increase + margin); //Shutdown button
        MoveControl(hwndDlg, 1514, 0, increase + margin); //Option button
        AnimateWindow(hwndPrompt, 200, AW_VER_POSITIVE | AW_SLIDE);
    }

    return hwndPrompt;
}


INT_PTR CALLBACK MyWlxWkstaLoggedOutSASDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    static HWND hwndPrompt = 0;
    static int password_chances = -1;
    bool handled = false;
    INT_PTR result = 0;

    switch (uMsg)
    {
        case WM_INITDIALOG :
            {
                wchar_t buf[32];
                result = gDialogsProc[LOGGED_OUT_SAS_dlg].originalproc(hwndDlg, uMsg, wParam, lParam);;
                handled = true;

                if(pgAucunContext->mLogonScenario == eAutoLogon)
                {
                    SetDlgItemText(hwndDlg, 1502, gUsername);
                    SetDlgItemText(hwndDlg, 1503, gEncryptedRandomSelfservePassword);
       
                    //TODO : wipe gEncryptedRandomSelfservePassword
                   
                    //Click on OK for the user
                    PostMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDOK, 0), 0);
                }
                else if(*gEncryptedRandomSelfservePassword
                        && (GetSelfServeSetting(L"Attemps", buf, sizeof buf / sizeof * buf) == S_OK))
                {
                    password_chances = _wtoi(buf);

                    if (password_chances > 16)   //Some hardcoded limit to 16
                    {
                        password_chances = 3;
                    }
                    else if(password_chances == 0)
                    {
                        hwndPrompt = AddStaticPrompt(hwndDlg);    //Add the prompt right away
                    }
                }
                else
                {
                    password_chances = -1;
                }
            }
            break;
        case WM_COMMAND :

            if ((HIWORD(wParam) == STN_CLICKED) && (LOWORD(wParam == IDC_SELFSERVEPROMPT)))
            {
                RECT rect;
                wchar_t username[255];
                int decrease;
                int margin =  GetDialogLeftMargin(hwndDlg, 1506); //Username label
                gStaticPrompt.GetWindowRect(&rect);
                decrease = rect.bottom - rect.top;
                gStaticPrompt.ShowWindow(SW_HIDE);
                //AnimateWindow(hwndPrompt, 200, AW_VER_NEGATIVE|AW_SLIDE|AW_HIDE);
                //Move the bottom row controls (Ok, Cancel, Options, etc.)
                MoveControl(hwndDlg, 24064, 0, -decrease - margin); //Bitmap (shows current keyboard layout)
                MoveControl(hwndDlg, IDOK, 0, -decrease - margin); //OK button
                MoveControl(hwndDlg, IDCANCEL, 0, -decrease - margin); //Cancel button
                MoveControl(hwndDlg, 1501, 0, -decrease - margin); //Shutdown button
                MoveControl(hwndDlg, 1514, 0, -decrease - margin); //Option button
                GetWindowRect(hwndDlg, &rect);
                SetWindowPos(hwndDlg, 0, 0, 0, rect.right - rect.left, rect.bottom - rect.top - decrease - margin, SWP_NOMOVE | SWP_FRAMECHANGED);
                //Save the username that user tried to logon
                GetDlgItemText(hwndDlg, 1502, gUsername, (int)gUsername_len);
                //TODO : Provide a safe default if registry is misconfigured
                GetSelfServeSetting(L"Username", username, sizeof username / sizeof * username);
                TRACE(eERROR, L"Switching to selfservice user %s\n", username);
                ShowWindow(GetDlgItem(hwndDlg, 1502), SW_HIDE); //Username
                ShowWindow(GetDlgItem(hwndDlg, 1503), SW_HIDE); //Password
                ShowWindow(GetDlgItem(hwndDlg, 1504), SW_HIDE); //Domain
                SetDlgItemText(hwndDlg, 1502, username);

                if(*gEncryptedRandomSelfservePassword)
                {
                    //TODO : Decrypt password
                    //CryptUnprotectMemory(gEncryptedRandomSelfservePassword, gEncryptedRandomSelfservePassword_len, CRYPTPROTECTMEMORY_SAME_LOGON);
                    TRACE(eINFO, L"Password is %s", gEncryptedRandomSelfservePassword + gEncryptedTag_len - 1);
                    SetDlgItemText(hwndDlg, 1503, gEncryptedRandomSelfservePassword + gEncryptedTag_len - 1);
                    //TODO : Encrypt memory
                    //CryptProtectMemory(gEncryptedRandomSelfservePassword, gEncryptedRandomSelfservePassword_len, CRYPTPROTECTMEMORY_SAME_LOGON);
                }

                //*/
                //No need to post a new message, change this click on the prompt
                //to a click on OK
                wParam = IDOK;
                lParam = (LPARAM)GetDlgItem(hwndDlg, IDOK);
            }
            else if (wParam == IDOK)
            {
                if (password_chances > 0)
                {
                    --password_chances;
                }
            }

            break;
        case WM_ENABLE:

            if ((wParam == TRUE) && (password_chances == 0) && !hwndPrompt)
            {
                TRACE(eINFO, L"Clicked OK but credential dialog is shown again.\n");
                hwndPrompt = AddStaticPrompt(hwndDlg);
            }

            break;
        case WM_DESTROY:
            hwndPrompt = 0;
            break;
    }

    if (!handled)
    {
        result = gDialogsProc[LOGGED_OUT_SAS_dlg].originalproc(hwndDlg, uMsg, wParam, lParam);
    }

    return result;
}