Subversion Repositories Aucun

Rev

Rev 40 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
5 ixe013 1
#include <windows.h>
22 ixe013 2
#include "Settings.h"
5 ixe013 3
#include "UnlockPolicy.h"
91 ixe013 4
#include "trace.h"
5
#include "debug.h"
6
#include "SecurityHelper.h"
5 ixe013 7
 
91 ixe013 8
//Converts a token to an impersonation token, if it is not already one
9
//
40 ixe013 10
HANDLE ConvertToImpersonationToken(HANDLE token)
11
{
12
    HANDLE result = token;
22 ixe013 13
 
40 ixe013 14
    SECURITY_IMPERSONATION_LEVEL sil;
15
    DWORD cbsil = sizeof sil;
22 ixe013 16
 
40 ixe013 17
    //If we are not impersonating
18
    if(GetTokenInformation(token, TokenImpersonationLevel, (LPVOID)&sil, sizeof sil, &cbsil) == 0)
19
    {
20
        HANDLE imptoken = 0;
22 ixe013 21
 
40 ixe013 22
        //Change to an impersonation token
23
        if(DuplicateToken(token, SecurityIdentification, &imptoken))
24
        {
25
            result = imptoken;
26
            CloseHandle(token);
27
        }
28
    }
29
 
30
    return result;
22 ixe013 31
}
32
 
40 ixe013 33
 
91 ixe013 34
EXTERN int ShouldUnlockForUser(HANDLE lsa, HANDLE current_user, const wchar_t *domain, const wchar_t *username, const wchar_t *password)
40 ixe013 35
{
36
    int result = eLetMSGINAHandleIt; //secure by default
22 ixe013 37
    HANDLE token = 0;
38
 
40 ixe013 39
    wchar_t unlock[MAX_GROUPNAME] = L"";
40
    wchar_t logoff[MAX_GROUPNAME] = L"";
22 ixe013 41
 
40 ixe013 42
    //Get the groups early to ensure fail fast if GINA is not configured
43
    GetGroupName(gUnlockGroupName, unlock, sizeof unlock / sizeof *unlock);
44
    GetGroupName(gForceLogoffGroupName, logoff, sizeof logoff / sizeof *logoff);
45
 
46
    //Do we have anything to work with ?
47
    if(*unlock || *logoff)
22 ixe013 48
    {
91 ixe013 49
        BOOL logged_on = FALSE;
50
        DWORD win32Error;
51
        TRACE(L"We have the %s and %s group.\n", (unlock&&*unlock)?unlock:L"--", (logoff&&*logoff)?logoff:L"--");
52
 
22 ixe013 53
        //Let's see if we can authenticate the user (this will generate a event log entry if the policy requires it)
91 ixe013 54
        if(lsa)
22 ixe013 55
        {
91 ixe013 56
            logged_on = CallLsaLogonUser(lsa, domain, username, password, Unlock, 0, &token, 0, &win32Error);
57
        }
58
        else
59
        {
60
            logged_on = LogonUser(username, domain, password, LOGON32_LOGON_UNLOCK, LOGON32_PROVIDER_DEFAULT, &token);
61
            win32Error = GetLastError();
62
        }
22 ixe013 63
 
91 ixe013 64
        if(logged_on)
65
        {
66
            BOOL is_same_user;
40 ixe013 67
 
91 ixe013 68
            TRACE(L"User logged in.\n");
69
            token = ConvertToImpersonationToken(token);
40 ixe013 70
 
91 ixe013 71
            //Sometimes, AUCUN failed to get the current logged on user
72
            //This is a fail safe. If something goes wrong with the detection, then
73
            //the regulare MSGINA logic will take over.
74
            if(current_user)
22 ixe013 75
            {
91 ixe013 76
                IsSameUser(current_user, token, &is_same_user);
77
 
78
                if(is_same_user)
22 ixe013 79
                {
91 ixe013 80
                    TRACE(L"Same user, unlocking.\n");
81
                    result = eUnlock;
22 ixe013 82
                }
91 ixe013 83
                else
40 ixe013 84
                {
91 ixe013 85
                    TRACE(L"Different user, ");
86
                    if(UsagerEstDansGroupe(token, unlock) == S_OK)
87
                    {
88
                        TRACEMORE(L"in the unlock group, unlocking.\n");
89
                        result = eUnlock;
90
                    }
91
                    else if(UsagerEstDansGroupe(token, logoff) == S_OK)
92
                    {
93
                        TRACEMORE(L"in the logoff group, forcing a logoff.\n");
94
                        result = eForceLogoff;
95
                    }
96
                    else
97
                    {
98
                        TRACEMORE(L"no privileges we can handle.\n");
99
                    }
40 ixe013 100
                }
101
            }
22 ixe013 102
 
40 ixe013 103
            CloseHandle(token);
22 ixe013 104
        }
91 ixe013 105
        else
106
        {
107
            TRACEMSG(win32Error);
108
        }
22 ixe013 109
    }
110
 
111
    return result;
112
}
113
 
114
 
5 ixe013 115
//----------------------------------------------------------------------
116
// Name        : UsagerEstDansGroupe
16 ixe013 117
// Description : Genere un SID a partir du nom de groupe puis verifie
5 ixe013 118
//               l'appartenance au groupe de l'usager. Si on nom d'usager
16 ixe013 119
//               est passé au lieu du nom de groupe, cette fonction le
5 ixe013 120
//               traite comme un groupe ne contenant que cet usager.
121
//               Attention au leaks si vous jouez la dedans... les SID
122
//               c'est pas joli
123
// Parametre   : [in] HANDLE usager
124
// Parametre   : [in] BSTR groupe
125
// Returns     : S_OK si l'usager est dans le groupe
126
//               S_FALSE si l'usager n'est pas dans le groupe
127
//               E_FAIL s'il y a un bobo (on ne trouve pas le groupe)
128
//----------------------------------------------------------------------
129
HRESULT UsagerEstDansGroupe(HANDLE usager, const wchar_t *groupe)
130
{
22 ixe013 131
    HRESULT result = E_FAIL;
132
    SID_NAME_USE snu;
133
    WCHAR szDomain[256];
134
    DWORD dwSidSize =0;
5 ixe013 135
 
22 ixe013 136
    DWORD dwSize = sizeof szDomain / sizeof *szDomain;
5 ixe013 137
 
22 ixe013 138
    if ((LookupAccountNameW(NULL, groupe, 0, &dwSidSize, szDomain, &dwSize, &snu) == 0)
139
        && (ERROR_INSUFFICIENT_BUFFER == GetLastError()))
140
    {
141
        SID *pSid = (SID*)malloc(dwSidSize);
5 ixe013 142
 
22 ixe013 143
        if (LookupAccountNameW(NULL, groupe, pSid, &dwSidSize, szDomain, &dwSize, &snu))
144
        {
145
            BOOL b;
40 ixe013 146
 
91 ixe013 147
            if (CheckTokenMembership(usager, pSid, &b))
22 ixe013 148
            {
91 ixe013 149
                 if (b == TRUE)
150
                    result = S_OK;
22 ixe013 151
            }
152
            else
153
            {
154
                result = S_FALSE;
155
            }
156
        }
5 ixe013 157
 
22 ixe013 158
        //Si tout vas bien (la presque totalitée des cas), on delete notre pointeur
159
        //avec le bon operateur.
160
        free(pSid);
161
    }
5 ixe013 162
 
22 ixe013 163
    return result;
5 ixe013 164
}
165
 
40 ixe013 166
 
167
BOOLEAN ShouldHookUnlockPasswordDialog(HANDLE token)
168
{
169
    BOOLEAN result = FALSE;
170
 
171
    wchar_t unlock[MAX_GROUPNAME] = L"";
172
    wchar_t excluded[MAX_GROUPNAME] = L"";
173
    wchar_t forcelogoff[MAX_GROUPNAME] = L"";
174
 
175
    //If there is either an unlock or force logoff group, 
176
    if((GetGroupName(gUnlockGroupName, unlock, sizeof unlock / sizeof *unlock) == S_OK)
177
    || (GetGroupName(gForceLogoffGroupName, forcelogoff, sizeof forcelogoff / sizeof *forcelogoff) == S_OK))
178
    {
91 ixe013 179
        TRACE(L"Groups are set, ");
40 ixe013 180
        //User must not be in the excluded group
181
        if(GetGroupName(gExcludedGroupName, excluded, sizeof excluded / sizeof *excluded) == S_OK)
182
        {
183
            //If is not blacklisted, return TRUE (so the dialog will be hooked)
91 ixe013 184
            if(UsagerEstDansGroupe(token, excluded) != S_OK)
185
            {
186
                TRACEMORE(L"user is not excluded, should hook.\n");
187
                result = TRUE;
188
            }
189
            else
190
            {
191
                TRACEMORE(L"user is excluded and will get standard MSGINA behavior.\n");
192
            }
40 ixe013 193
        }
91 ixe013 194
        else
195
        {
196
            //There is no excluded group, let's hook !
197
            TRACEMORE(L"but there is no excluded group, should hook.\n");
198
            result = TRUE;
199
        }
40 ixe013 200
    }
91 ixe013 201
    else
202
    {
203
        TRACE(L"Neither %s or %s group present, shouldn't hook.\n", gUnlockGroupName, gForceLogoffGroupName);
204
    }
40 ixe013 205
 
206
    return result;
207
}