1 /*
2  * Schannel tests
3  *
4  * Copyright 2006 Yuval Fledel
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #include <stdio.h>
22 #include <stdarg.h>
23 #include "ntstatus.h"
24 #define WIN32_NO_STATUS
25 #include <windef.h>
26 #include <winbase.h>
27 #define SECURITY_WIN32
28 #include <security.h>
29 #include <schannel.h>
30 #include <ntsecapi.h>
31 #include <ntsecpkg.h>
32 
33 #include "wine/test.h"
34 
35 /* Helper macros to find the size of SECPKG_FUNCTION_TABLE */
36 #define SECPKG_FUNCTION_TABLE_SIZE_1 FIELD_OFFSET(SECPKG_FUNCTION_TABLE, \
37     SetContextAttributes)
38 #define SECPKG_FUNCTION_TABLE_SIZE_2 FIELD_OFFSET(SECPKG_FUNCTION_TABLE, \
39     SetCredentialsAttributes)
40 #define SECPKG_FUNCTION_TABLE_SIZE_3 FIELD_OFFSET(SECPKG_FUNCTION_TABLE, \
41     ChangeAccountPassword)
42 #define SECPKG_FUNCTION_TABLE_SIZE_4 FIELD_OFFSET(SECPKG_FUNCTION_TABLE, \
43     QueryMetaData)
44 #define SECPKG_FUNCTION_TABLE_SIZE_5 FIELD_OFFSET(SECPKG_FUNCTION_TABLE, \
45     ValidateTargetInfo)
46 #define SECPKG_FUNCTION_TABLE_SIZE_6 FIELD_OFFSET(SECPKG_FUNCTION_TABLE, \
47     PostLogonUser)
48 #define SECPKG_FUNCTION_TABLE_SIZE_7 sizeof(SECPKG_FUNCTION_TABLE)
49 
50 #define LSA_BASE_CAPS ( \
51     SECPKG_FLAG_INTEGRITY         | \
52     SECPKG_FLAG_PRIVACY           | \
53     SECPKG_FLAG_CONNECTION        | \
54     SECPKG_FLAG_MULTI_REQUIRED    | \
55     SECPKG_FLAG_EXTENDED_ERROR    | \
56     SECPKG_FLAG_IMPERSONATION     | \
57     SECPKG_FLAG_ACCEPT_WIN32_NAME | \
58     SECPKG_FLAG_STREAM            | \
59     SECPKG_FLAG_MUTUAL_AUTH )
60 
61 static NTSTATUS (NTAPI *pSpLsaModeInitialize)(ULONG, PULONG,
62     PSECPKG_FUNCTION_TABLE*, PULONG);
63 static NTSTATUS (NTAPI *pSpUserModeInitialize)(ULONG, PULONG,
64     PSECPKG_USER_FUNCTION_TABLE*, PULONG);
65 
66 static void testInitialize(void)
67 {
68     PSECPKG_USER_FUNCTION_TABLE pUserTables, pUserTables2;
69     PSECPKG_FUNCTION_TABLE pTables, pTables2;
70     ULONG cTables = 0, cUserTables = 0, Version = 0;
71     NTSTATUS status;
72 
73     /* Passing NULL into one of the parameters of SpLsaModeInitialize or
74        SpUserModeInitialize causes a crash. */
75 
76     /* SpLsaModeInitialize does not care about the LSA version. */
77     status = pSpLsaModeInitialize(0, &Version, &pTables2, &cTables);
78     ok(status == STATUS_SUCCESS, "status: 0x%x\n", status);
79     ok(cTables == 2 ||
80        broken(cTables == 1), /* Win2k */
81        "cTables: %d\n", cTables);
82     ok(pTables2 != NULL,"pTables: %p\n", pTables2);
83 
84     /* We can call it as many times we want. */
85     status = pSpLsaModeInitialize(0x10000, &Version, &pTables, &cTables);
86     ok(status == STATUS_SUCCESS, "status: 0x%x\n", status);
87     ok(cTables == 2 ||
88        broken(cTables == 1), /* Win2k */
89        "cTables: %d\n", cTables);
90     ok(pTables != NULL, "pTables: %p\n", pTables);
91     /* It will always return the same pointer. */
92     ok(pTables == pTables2, "pTables: %p, pTables2: %p\n", pTables, pTables2);
93 
94     status = pSpLsaModeInitialize(0x23456, &Version, &pTables, &cTables);
95     ok(status == STATUS_SUCCESS, "status: 0x%x\n", status);
96     ok(cTables == 2 ||
97        broken(cTables == 1), /* Win2k */
98        "cTables: %d\n", cTables);
99     ok(pTables != NULL, "pTables: %p\n", pTables);
100     ok(pTables == pTables2, "pTables: %p, pTables2: %p\n", pTables, pTables2);
101 
102     /* Bad versions to SpUserModeInitialize. Parameters unchanged */
103     Version = 0xdead;
104     cUserTables = 0xdead;
105     pUserTables = NULL;
106     status = pSpUserModeInitialize(0, &Version, &pUserTables, &cUserTables);
107     ok(status == STATUS_INVALID_PARAMETER, "status: 0x%x\n", status);
108     ok(Version == 0xdead, "Version: 0x%x\n", Version);
109     ok(cUserTables == 0xdead, "cTables: %d\n", cUserTables);
110     ok(pUserTables == NULL, "pUserTables: %p\n", pUserTables);
111 
112     status = pSpUserModeInitialize(0x20000, &Version, &pUserTables,
113                                    &cUserTables);
114     ok(status == STATUS_INVALID_PARAMETER, "status: 0x%x\n", status);
115     ok(Version == 0xdead, "Version: 0x%x\n", Version);
116     ok(cUserTables == 0xdead, "cTables: %d\n", cUserTables);
117     ok(pUserTables == NULL, "pUserTables: %p\n", pUserTables);
118 
119     /* Good version to SpUserModeInitialize */
120     status = pSpUserModeInitialize(SECPKG_INTERFACE_VERSION, &Version,
121                                    &pUserTables, &cUserTables);
122     ok(status == STATUS_SUCCESS, "status: 0x%x\n", status);
123     ok(Version == SECPKG_INTERFACE_VERSION, "Version: 0x%x\n", Version);
124     ok(cUserTables == 2 ||
125        broken(cUserTables == 4), /* Win2k */
126        "cUserTables: %d\n", cUserTables);
127     ok(pUserTables != NULL, "pUserTables: %p\n", pUserTables);
128 
129     /* Initializing user again */
130     status = pSpUserModeInitialize(SECPKG_INTERFACE_VERSION, &Version,
131                                    &pUserTables2, &cTables);
132     ok(status == STATUS_SUCCESS, "status: 0x%x\n", status);
133     ok(pUserTables == pUserTables2, "pUserTables: %p, pUserTables2: %p\n",
134        pUserTables, pUserTables2);
135 }
136 
137 /* A helper function to find the dispatch table of the next package.
138    Needed because SECPKG_FUNCTION_TABLE's size depend on the version */
139 static PSECPKG_FUNCTION_TABLE getNextSecPkgTable(PSECPKG_FUNCTION_TABLE pTable,
140                                                  ULONG Version)
141 {
142     size_t size;
143     PSECPKG_FUNCTION_TABLE pNextTable;
144 
145     if (Version == SECPKG_INTERFACE_VERSION)
146         size = SECPKG_FUNCTION_TABLE_SIZE_1;
147     else if (Version == SECPKG_INTERFACE_VERSION_2)
148         size = SECPKG_FUNCTION_TABLE_SIZE_2;
149     else if (Version == SECPKG_INTERFACE_VERSION_3)
150         size = SECPKG_FUNCTION_TABLE_SIZE_3;
151     else if (Version == SECPKG_INTERFACE_VERSION_4)
152         size = SECPKG_FUNCTION_TABLE_SIZE_4;
153     else if (Version == SECPKG_INTERFACE_VERSION_5)
154         size = SECPKG_FUNCTION_TABLE_SIZE_5;
155     else if (Version == SECPKG_INTERFACE_VERSION_6)
156         size = SECPKG_FUNCTION_TABLE_SIZE_6;
157     else if (Version == SECPKG_INTERFACE_VERSION_7)
158         size = SECPKG_FUNCTION_TABLE_SIZE_7;
159     else {
160         ok(FALSE, "Unknown package version 0x%x\n", Version);
161         return NULL;
162     }
163 
164     pNextTable = (PSECPKG_FUNCTION_TABLE)((PBYTE)pTable + size);
165     /* Win7 function tables appear to be SECPKG_INTERFACE_VERSION_6 format,
166        but unfortunately SpLsaModeInitialize returns SECPKG_INTERFACE_VERSION_3.
167        We detect that by comparing the "Initialize" pointer from the old table
168        to the "FreeCredentialsHandle" pointer of the new table. These functions
169        have different numbers of arguments, so they can't possibly point to the
170        same implementation */
171     if (broken((void *) pTable->Initialize == (void *) pNextTable->FreeCredentialsHandle &&
172                pNextTable->FreeCredentialsHandle != NULL))
173     {
174         win_skip("Invalid function pointers for next package\n");
175         return NULL;
176     }
177 
178     return pNextTable;
179 }
180 
181 static void testGetInfo(void)
182 {
183     PSECPKG_FUNCTION_TABLE pTables;
184     SecPkgInfoW PackageInfo;
185     ULONG cTables, Version;
186     NTSTATUS status;
187 
188     /* Get the dispatch table */
189     status = pSpLsaModeInitialize(0, &Version, &pTables, &cTables);
190     ok(status == STATUS_SUCCESS, "status: 0x%x\n", status);
191 
192     /* Passing NULL into ->GetInfo causes a crash. */
193 
194     /* First package: Unified */
195     status = pTables->GetInfo(&PackageInfo);
196     ok(status == STATUS_SUCCESS, "status: 0x%x\n", status);
197     ok(PackageInfo.fCapabilities == LSA_BASE_CAPS ||
198        PackageInfo.fCapabilities == (LSA_BASE_CAPS|SECPKG_FLAG_APPCONTAINER_PASSTHROUGH),
199        "fCapabilities: 0x%x\n", PackageInfo.fCapabilities);
200     ok(PackageInfo.wVersion == 1, "wVersion: %d\n", PackageInfo.wVersion);
201     ok(PackageInfo.wRPCID == 14, "wRPCID: %d\n", PackageInfo.wRPCID);
202     ok(PackageInfo.cbMaxToken == 0x4000 ||
203        PackageInfo.cbMaxToken == 0x6000, /* Vista */
204        "cbMaxToken: 0x%x\n",
205        PackageInfo.cbMaxToken);
206 
207     /* Second package */
208     if (cTables == 1)
209     {
210         win_skip("Second package missing\n");
211         return;
212     }
213     pTables = getNextSecPkgTable(pTables, Version);
214     if (!pTables)
215         return;
216     if (!pTables->GetInfo)
217     {
218         win_skip("GetInfo function missing\n");
219         return;
220     }
221     status = pTables->GetInfo(&PackageInfo);
222     ok(SUCCEEDED(status) ||
223        status == SEC_E_UNSUPPORTED_FUNCTION, /* win2k3 */
224        "status: 0x%x\n", status);
225 
226     if (SUCCEEDED(status))
227     {
228         ok(PackageInfo.fCapabilities == LSA_BASE_CAPS ||
229            PackageInfo.fCapabilities == (LSA_BASE_CAPS|SECPKG_FLAG_APPCONTAINER_PASSTHROUGH),
230            "fCapabilities: 0x%x\n", PackageInfo.fCapabilities);
231         ok(PackageInfo.wVersion == 1, "wVersion: %d\n", PackageInfo.wVersion);
232         ok(PackageInfo.wRPCID == 14, "wRPCID: %d\n", PackageInfo.wRPCID);
233         ok(PackageInfo.cbMaxToken == 0x4000 ||
234            PackageInfo.cbMaxToken == 0x6000, /* Win7 */
235            "cbMaxToken: 0x%x\n",
236            PackageInfo.cbMaxToken);
237     }
238 }
239 
240 START_TEST(main)
241 {
242     HMODULE hMod = LoadLibraryA("schannel.dll");
243     if (!hMod) {
244         win_skip("schannel.dll not available\n");
245         return;
246     }
247 
248     pSpLsaModeInitialize  = (void *)GetProcAddress(hMod, "SpLsaModeInitialize");
249     pSpUserModeInitialize = (void *)GetProcAddress(hMod, "SpUserModeInitialize");
250 
251     if (pSpLsaModeInitialize && pSpUserModeInitialize)
252     {
253         testInitialize();
254         testGetInfo();
255     }
256     else win_skip( "schannel functions not found\n" );
257 
258     FreeLibrary(hMod);
259 }
260