1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // This file contains unit tests for the RestrictedToken.
7 #define _ATL_NO_EXCEPTIONS
9 #include <atlsecurity.h>
11 #include "sandbox/win/src/restricted_token.h"
12 #include "sandbox/win/src/sid.h"
13 #include "testing/gtest/include/gtest/gtest.h"
17 // Tests the initializatioin with an invalid token handle.
18 TEST(RestrictedTokenTest
, InvalidHandle
) {
19 RestrictedToken token
;
20 ASSERT_EQ(ERROR_INVALID_HANDLE
, token
.Init(reinterpret_cast<HANDLE
>(0x5555)));
23 // Tests the initialization with NULL as parameter.
24 TEST(RestrictedTokenTest
, DefaultInit
) {
25 // Get the current process token.
26 HANDLE token_handle
= INVALID_HANDLE_VALUE
;
27 ASSERT_TRUE(::OpenProcessToken(::GetCurrentProcess(), TOKEN_ALL_ACCESS
,
30 ASSERT_NE(INVALID_HANDLE_VALUE
, token_handle
);
32 ATL::CAccessToken access_token
;
33 access_token
.Attach(token_handle
);
35 // Create the token using the current token.
36 RestrictedToken token_default
;
37 ASSERT_EQ(ERROR_SUCCESS
, token_default
.Init(NULL
));
39 // Get the handle to the restricted token.
41 HANDLE restricted_token_handle
= NULL
;
42 ASSERT_EQ(ERROR_SUCCESS
,
43 token_default
.GetRestrictedTokenHandle(&restricted_token_handle
));
45 ATL::CAccessToken restricted_token
;
46 restricted_token
.Attach(restricted_token_handle
);
48 ATL::CSid sid_user_restricted
;
49 ATL::CSid sid_user_default
;
50 ATL::CSid sid_owner_restricted
;
51 ATL::CSid sid_owner_default
;
52 ASSERT_TRUE(restricted_token
.GetUser(&sid_user_restricted
));
53 ASSERT_TRUE(access_token
.GetUser(&sid_user_default
));
54 ASSERT_TRUE(restricted_token
.GetOwner(&sid_owner_restricted
));
55 ASSERT_TRUE(access_token
.GetOwner(&sid_owner_default
));
57 // Check if both token have the same owner and user.
58 ASSERT_EQ(sid_user_restricted
, sid_user_default
);
59 ASSERT_EQ(sid_owner_restricted
, sid_owner_default
);
62 // Tests the initialization with a custom token as parameter.
63 TEST(RestrictedTokenTest
, CustomInit
) {
64 // Get the current process token.
65 HANDLE token_handle
= INVALID_HANDLE_VALUE
;
66 ASSERT_TRUE(::OpenProcessToken(::GetCurrentProcess(), TOKEN_ALL_ACCESS
,
69 ASSERT_NE(INVALID_HANDLE_VALUE
, token_handle
);
71 ATL::CAccessToken access_token
;
72 access_token
.Attach(token_handle
);
74 // Change the primary group.
75 access_token
.SetPrimaryGroup(ATL::Sids::World());
77 // Create the token using the current token.
78 RestrictedToken token
;
79 ASSERT_EQ(ERROR_SUCCESS
, token
.Init(access_token
.GetHandle()));
81 // Get the handle to the restricted token.
83 HANDLE restricted_token_handle
= NULL
;
84 ASSERT_EQ(ERROR_SUCCESS
,
85 token
.GetRestrictedTokenHandle(&restricted_token_handle
));
87 ATL::CAccessToken restricted_token
;
88 restricted_token
.Attach(restricted_token_handle
);
90 ATL::CSid sid_restricted
;
91 ATL::CSid sid_default
;
92 ASSERT_TRUE(restricted_token
.GetPrimaryGroup(&sid_restricted
));
93 ASSERT_TRUE(access_token
.GetPrimaryGroup(&sid_default
));
95 // Check if both token have the same owner.
96 ASSERT_EQ(sid_restricted
, sid_default
);
99 // Verifies that the token created by the object are valid.
100 TEST(RestrictedTokenTest
, ResultToken
) {
101 RestrictedToken token
;
102 ASSERT_EQ(ERROR_SUCCESS
, token
.Init(NULL
));
104 ASSERT_EQ(ERROR_SUCCESS
,
105 token
.AddRestrictingSid(ATL::Sids::World().GetPSID()));
107 HANDLE restricted_token
;
108 ASSERT_EQ(ERROR_SUCCESS
, token
.GetRestrictedTokenHandle(&restricted_token
));
110 ASSERT_TRUE(::IsTokenRestricted(restricted_token
));
114 ASSERT_TRUE(::GetTokenInformation(restricted_token
,
120 ASSERT_EQ(type
, TokenPrimary
);
122 HANDLE impersonation_token
;
123 ASSERT_EQ(ERROR_SUCCESS
,
124 token
.GetRestrictedTokenHandleForImpersonation(&impersonation_token
));
126 ASSERT_TRUE(::IsTokenRestricted(impersonation_token
));
128 ASSERT_TRUE(::GetTokenInformation(impersonation_token
,
134 ASSERT_EQ(type
, TokenImpersonation
);
136 ::CloseHandle(impersonation_token
);
137 ::CloseHandle(restricted_token
);
140 // Verifies that the token created has "Restricted" in its default dacl.
141 TEST(RestrictedTokenTest
, DefaultDacl
) {
142 RestrictedToken token
;
143 ASSERT_EQ(ERROR_SUCCESS
, token
.Init(NULL
));
145 ASSERT_EQ(ERROR_SUCCESS
,
146 token
.AddRestrictingSid(ATL::Sids::World().GetPSID()));
149 ASSERT_EQ(ERROR_SUCCESS
, token
.GetRestrictedTokenHandle(&handle
));
151 ATL::CAccessToken restricted_token
;
152 restricted_token
.Attach(handle
);
155 ASSERT_TRUE(restricted_token
.GetDefaultDacl(&dacl
));
157 bool restricted_found
= false;
159 unsigned int ace_count
= dacl
.GetAceCount();
160 for (unsigned int i
= 0; i
< ace_count
; ++i
) {
162 ACCESS_MASK mask
= 0;
163 dacl
.GetAclEntry(i
, &sid
, &mask
);
164 if (sid
== ATL::Sids::RestrictedCode() && mask
== GENERIC_ALL
) {
165 restricted_found
= true;
170 ASSERT_TRUE(restricted_found
);
173 // Tests the method "AddSidForDenyOnly".
174 TEST(RestrictedTokenTest
, DenySid
) {
175 RestrictedToken token
;
176 HANDLE token_handle
= NULL
;
178 ASSERT_EQ(ERROR_SUCCESS
, token
.Init(NULL
));
179 ASSERT_EQ(ERROR_SUCCESS
, token
.AddSidForDenyOnly(Sid(WinWorldSid
)));
180 ASSERT_EQ(ERROR_SUCCESS
, token
.GetRestrictedTokenHandle(&token_handle
));
182 ATL::CAccessToken restricted_token
;
183 restricted_token
.Attach(token_handle
);
185 ATL::CTokenGroups groups
;
186 ASSERT_TRUE(restricted_token
.GetGroups(&groups
));
188 ATL::CSid::CSidArray sids
;
189 ATL::CAtlArray
<DWORD
> attributes
;
190 groups
.GetSidsAndAttributes(&sids
, &attributes
);
192 for (unsigned int i
= 0; i
< sids
.GetCount(); i
++) {
193 if (ATL::Sids::World() == sids
[i
]) {
194 ASSERT_EQ(SE_GROUP_USE_FOR_DENY_ONLY
,
195 attributes
[i
] & SE_GROUP_USE_FOR_DENY_ONLY
);
200 // Tests the method "AddAllSidsForDenyOnly".
201 TEST(RestrictedTokenTest
, DenySids
) {
202 RestrictedToken token
;
203 HANDLE token_handle
= NULL
;
205 ASSERT_EQ(ERROR_SUCCESS
, token
.Init(NULL
));
206 ASSERT_EQ(ERROR_SUCCESS
, token
.AddAllSidsForDenyOnly(NULL
));
207 ASSERT_EQ(ERROR_SUCCESS
, token
.GetRestrictedTokenHandle(&token_handle
));
209 ATL::CAccessToken restricted_token
;
210 restricted_token
.Attach(token_handle
);
212 ATL::CTokenGroups groups
;
213 ASSERT_TRUE(restricted_token
.GetGroups(&groups
));
215 ATL::CSid::CSidArray sids
;
216 ATL::CAtlArray
<DWORD
> attributes
;
217 groups
.GetSidsAndAttributes(&sids
, &attributes
);
219 // Verify that all sids are really gone.
220 for (unsigned int i
= 0; i
< sids
.GetCount(); i
++) {
221 if ((attributes
[i
] & SE_GROUP_LOGON_ID
) == 0 &&
222 (attributes
[i
] & SE_GROUP_INTEGRITY
) == 0) {
223 ASSERT_EQ(SE_GROUP_USE_FOR_DENY_ONLY
,
224 attributes
[i
] & SE_GROUP_USE_FOR_DENY_ONLY
);
229 // Tests the method "AddAllSidsForDenyOnly" using an exception list.
230 TEST(RestrictedTokenTest
, DenySidsException
) {
231 RestrictedToken token
;
232 HANDLE token_handle
= NULL
;
234 std::vector
<Sid
> sids_exception
;
235 sids_exception
.push_back(Sid(WinWorldSid
));
237 ASSERT_EQ(ERROR_SUCCESS
, token
.Init(NULL
));
238 ASSERT_EQ(ERROR_SUCCESS
, token
.AddAllSidsForDenyOnly(&sids_exception
));
239 ASSERT_EQ(ERROR_SUCCESS
, token
.GetRestrictedTokenHandle(&token_handle
));
241 ATL::CAccessToken restricted_token
;
242 restricted_token
.Attach(token_handle
);
244 ATL::CTokenGroups groups
;
245 ASSERT_TRUE(restricted_token
.GetGroups(&groups
));
247 ATL::CSid::CSidArray sids
;
248 ATL::CAtlArray
<DWORD
> attributes
;
249 groups
.GetSidsAndAttributes(&sids
, &attributes
);
251 // Verify that all sids are really gone.
252 for (unsigned int i
= 0; i
< sids
.GetCount(); i
++) {
253 if ((attributes
[i
] & SE_GROUP_LOGON_ID
) == 0 &&
254 (attributes
[i
] & SE_GROUP_INTEGRITY
) == 0) {
255 if (ATL::Sids::World() == sids
[i
]) {
256 ASSERT_EQ(NULL
, attributes
[i
] & SE_GROUP_USE_FOR_DENY_ONLY
);
258 ASSERT_EQ(SE_GROUP_USE_FOR_DENY_ONLY
,
259 attributes
[i
] & SE_GROUP_USE_FOR_DENY_ONLY
);
265 // Tests test method AddOwnerSidForDenyOnly.
266 TEST(RestrictedTokenTest
, DenyOwnerSid
) {
267 RestrictedToken token
;
268 HANDLE token_handle
= NULL
;
270 ASSERT_EQ(ERROR_SUCCESS
, token
.Init(NULL
));
271 ASSERT_EQ(ERROR_SUCCESS
, token
.AddUserSidForDenyOnly());
272 ASSERT_EQ(ERROR_SUCCESS
, token
.GetRestrictedTokenHandle(&token_handle
));
274 ATL::CAccessToken restricted_token
;
275 restricted_token
.Attach(token_handle
);
277 ATL::CTokenGroups groups
;
278 ASSERT_TRUE(restricted_token
.GetGroups(&groups
));
280 ATL::CSid::CSidArray sids
;
281 ATL::CAtlArray
<DWORD
> attributes
;
282 groups
.GetSidsAndAttributes(&sids
, &attributes
);
285 ASSERT_TRUE(restricted_token
.GetUser(&user_sid
));
287 for (unsigned int i
= 0; i
< sids
.GetCount(); ++i
) {
288 if (user_sid
== sids
[i
]) {
289 ASSERT_EQ(SE_GROUP_USE_FOR_DENY_ONLY
,
290 attributes
[i
] & SE_GROUP_USE_FOR_DENY_ONLY
);
295 // Tests test method AddOwnerSidForDenyOnly with a custom effective token.
296 TEST(RestrictedTokenTest
, DenyOwnerSidCustom
) {
297 // Get the current process token.
298 HANDLE token_handle
= INVALID_HANDLE_VALUE
;
299 ASSERT_TRUE(::OpenProcessToken(::GetCurrentProcess(), TOKEN_ALL_ACCESS
,
302 ASSERT_NE(INVALID_HANDLE_VALUE
, token_handle
);
304 ATL::CAccessToken access_token
;
305 access_token
.Attach(token_handle
);
307 RestrictedToken token
;
308 ASSERT_EQ(ERROR_SUCCESS
, token
.Init(access_token
.GetHandle()));
309 ASSERT_EQ(ERROR_SUCCESS
, token
.AddUserSidForDenyOnly());
310 ASSERT_EQ(ERROR_SUCCESS
, token
.GetRestrictedTokenHandle(&token_handle
));
312 ATL::CAccessToken restricted_token
;
313 restricted_token
.Attach(token_handle
);
315 ATL::CTokenGroups groups
;
316 ASSERT_TRUE(restricted_token
.GetGroups(&groups
));
318 ATL::CSid::CSidArray sids
;
319 ATL::CAtlArray
<DWORD
> attributes
;
320 groups
.GetSidsAndAttributes(&sids
, &attributes
);
323 ASSERT_TRUE(restricted_token
.GetUser(&user_sid
));
325 for (unsigned int i
= 0; i
< sids
.GetCount(); ++i
) {
326 if (user_sid
== sids
[i
]) {
327 ASSERT_EQ(SE_GROUP_USE_FOR_DENY_ONLY
,
328 attributes
[i
] & SE_GROUP_USE_FOR_DENY_ONLY
);
333 // Tests the method DeleteAllPrivileges.
334 TEST(RestrictedTokenTest
, DeleteAllPrivileges
) {
335 RestrictedToken token
;
336 HANDLE token_handle
= NULL
;
338 ASSERT_EQ(ERROR_SUCCESS
, token
.Init(NULL
));
339 ASSERT_EQ(ERROR_SUCCESS
, token
.DeleteAllPrivileges(NULL
));
340 ASSERT_EQ(ERROR_SUCCESS
, token
.GetRestrictedTokenHandle(&token_handle
));
342 ATL::CAccessToken restricted_token
;
343 restricted_token
.Attach(token_handle
);
345 ATL::CTokenPrivileges privileges
;
346 ASSERT_TRUE(restricted_token
.GetPrivileges(&privileges
));
348 ASSERT_EQ(0, privileges
.GetCount());
351 // Tests the method DeleteAllPrivileges with an exception list.
352 TEST(RestrictedTokenTest
, DeleteAllPrivilegesException
) {
353 RestrictedToken token
;
354 HANDLE token_handle
= NULL
;
356 std::vector
<base::string16
> exceptions
;
357 exceptions
.push_back(SE_CHANGE_NOTIFY_NAME
);
359 ASSERT_EQ(ERROR_SUCCESS
, token
.Init(NULL
));
360 ASSERT_EQ(ERROR_SUCCESS
, token
.DeleteAllPrivileges(&exceptions
));
361 ASSERT_EQ(ERROR_SUCCESS
, token
.GetRestrictedTokenHandle(&token_handle
));
363 ATL::CAccessToken restricted_token
;
364 restricted_token
.Attach(token_handle
);
366 ATL::CTokenPrivileges privileges
;
367 ASSERT_TRUE(restricted_token
.GetPrivileges(&privileges
));
369 ATL::CTokenPrivileges::CNames privilege_names
;
370 ATL::CTokenPrivileges::CAttributes privilege_name_attributes
;
371 privileges
.GetNamesAndAttributes(&privilege_names
,
372 &privilege_name_attributes
);
374 ASSERT_EQ(1, privileges
.GetCount());
376 for (unsigned int i
= 0; i
< privileges
.GetCount(); ++i
) {
377 ASSERT_EQ(privilege_names
[i
], SE_CHANGE_NOTIFY_NAME
);
381 // Tests the method DeletePrivilege.
382 TEST(RestrictedTokenTest
, DeletePrivilege
) {
383 RestrictedToken token
;
384 HANDLE token_handle
= NULL
;
386 ASSERT_EQ(ERROR_SUCCESS
, token
.Init(NULL
));
387 ASSERT_EQ(ERROR_SUCCESS
, token
.DeletePrivilege(SE_CHANGE_NOTIFY_NAME
));
388 ASSERT_EQ(ERROR_SUCCESS
, token
.GetRestrictedTokenHandle(&token_handle
));
390 ATL::CAccessToken restricted_token
;
391 restricted_token
.Attach(token_handle
);
393 ATL::CTokenPrivileges privileges
;
394 ASSERT_TRUE(restricted_token
.GetPrivileges(&privileges
));
396 ATL::CTokenPrivileges::CNames privilege_names
;
397 ATL::CTokenPrivileges::CAttributes privilege_name_attributes
;
398 privileges
.GetNamesAndAttributes(&privilege_names
,
399 &privilege_name_attributes
);
401 for (unsigned int i
= 0; i
< privileges
.GetCount(); ++i
) {
402 ASSERT_NE(privilege_names
[i
], SE_CHANGE_NOTIFY_NAME
);
406 // Checks if a sid is in the restricting list of the restricted token.
407 // Asserts if it's not the case. If count is a positive number, the number of
408 // elements in the restricting sids list has to be equal.
409 void CheckRestrictingSid(const ATL::CAccessToken
&restricted_token
,
410 ATL::CSid sid
, int count
) {
412 BYTE
*memory
= new BYTE
[length
];
413 TOKEN_GROUPS
*groups
= reinterpret_cast<TOKEN_GROUPS
*>(memory
);
414 ASSERT_TRUE(::GetTokenInformation(restricted_token
.GetHandle(),
420 ATL::CTokenGroups
atl_groups(*groups
);
424 ASSERT_EQ(count
, atl_groups
.GetCount());
426 ATL::CSid::CSidArray sids
;
427 ATL::CAtlArray
<DWORD
> attributes
;
428 atl_groups
.GetSidsAndAttributes(&sids
, &attributes
);
430 bool present
= false;
431 for (unsigned int i
= 0; i
< sids
.GetCount(); ++i
) {
432 if (sids
[i
] == sid
) {
438 ASSERT_TRUE(present
);
441 // Tests the method AddRestrictingSid.
442 TEST(RestrictedTokenTest
, AddRestrictingSid
) {
443 RestrictedToken token
;
444 HANDLE token_handle
= NULL
;
446 ASSERT_EQ(ERROR_SUCCESS
, token
.Init(NULL
));
447 ASSERT_EQ(ERROR_SUCCESS
,
448 token
.AddRestrictingSid(ATL::Sids::World().GetPSID()));
449 ASSERT_EQ(ERROR_SUCCESS
, token
.GetRestrictedTokenHandle(&token_handle
));
451 ATL::CAccessToken restricted_token
;
452 restricted_token
.Attach(token_handle
);
454 CheckRestrictingSid(restricted_token
, ATL::Sids::World(), 1);
457 // Tests the method AddRestrictingSidCurrentUser.
458 TEST(RestrictedTokenTest
, AddRestrictingSidCurrentUser
) {
459 RestrictedToken token
;
460 HANDLE token_handle
= NULL
;
462 ASSERT_EQ(ERROR_SUCCESS
, token
.Init(NULL
));
463 ASSERT_EQ(ERROR_SUCCESS
, token
.AddRestrictingSidCurrentUser());
464 ASSERT_EQ(ERROR_SUCCESS
, token
.GetRestrictedTokenHandle(&token_handle
));
466 ATL::CAccessToken restricted_token
;
467 restricted_token
.Attach(token_handle
);
469 restricted_token
.GetUser(&user
);
471 CheckRestrictingSid(restricted_token
, user
, 1);
474 // Tests the method AddRestrictingSidCurrentUser with a custom effective token.
475 TEST(RestrictedTokenTest
, AddRestrictingSidCurrentUserCustom
) {
476 // Get the current process token.
477 HANDLE token_handle
= INVALID_HANDLE_VALUE
;
478 ASSERT_TRUE(::OpenProcessToken(::GetCurrentProcess(), TOKEN_ALL_ACCESS
,
481 ASSERT_NE(INVALID_HANDLE_VALUE
, token_handle
);
483 ATL::CAccessToken access_token
;
484 access_token
.Attach(token_handle
);
486 RestrictedToken token
;
487 ASSERT_EQ(ERROR_SUCCESS
, token
.Init(access_token
.GetHandle()));
488 ASSERT_EQ(ERROR_SUCCESS
, token
.AddRestrictingSidCurrentUser());
489 ASSERT_EQ(ERROR_SUCCESS
, token
.GetRestrictedTokenHandle(&token_handle
));
491 ATL::CAccessToken restricted_token
;
492 restricted_token
.Attach(token_handle
);
494 restricted_token
.GetUser(&user
);
496 CheckRestrictingSid(restricted_token
, user
, 1);
499 // Tests the method AddRestrictingSidLogonSession.
500 TEST(RestrictedTokenTest
, AddRestrictingSidLogonSession
) {
501 RestrictedToken token
;
502 HANDLE token_handle
= NULL
;
504 ASSERT_EQ(ERROR_SUCCESS
, token
.Init(NULL
));
505 ASSERT_EQ(ERROR_SUCCESS
, token
.AddRestrictingSidLogonSession());
506 ASSERT_EQ(ERROR_SUCCESS
, token
.GetRestrictedTokenHandle(&token_handle
));
508 ATL::CAccessToken restricted_token
;
509 restricted_token
.Attach(token_handle
);
511 restricted_token
.GetLogonSid(&session
);
513 CheckRestrictingSid(restricted_token
, session
, 1);
516 // Tests adding a lot of restricting sids.
517 TEST(RestrictedTokenTest
, AddMultipleRestrictingSids
) {
518 RestrictedToken token
;
519 HANDLE token_handle
= NULL
;
521 ASSERT_EQ(ERROR_SUCCESS
, token
.Init(NULL
));
522 ASSERT_EQ(ERROR_SUCCESS
, token
.AddRestrictingSidCurrentUser());
523 ASSERT_EQ(ERROR_SUCCESS
, token
.AddRestrictingSidLogonSession());
524 ASSERT_EQ(ERROR_SUCCESS
,
525 token
.AddRestrictingSid(ATL::Sids::World().GetPSID()));
526 ASSERT_EQ(ERROR_SUCCESS
, token
.GetRestrictedTokenHandle(&token_handle
));
528 ATL::CAccessToken restricted_token
;
529 restricted_token
.Attach(token_handle
);
531 restricted_token
.GetLogonSid(&session
);
534 BYTE
*memory
= new BYTE
[length
];
535 TOKEN_GROUPS
*groups
= reinterpret_cast<TOKEN_GROUPS
*>(memory
);
536 ASSERT_TRUE(::GetTokenInformation(restricted_token
.GetHandle(),
542 ATL::CTokenGroups
atl_groups(*groups
);
545 ASSERT_EQ(3, atl_groups
.GetCount());
548 // Tests the method "AddRestrictingSidAllSids".
549 TEST(RestrictedTokenTest
, AddAllSidToRestrictingSids
) {
550 RestrictedToken token
;
551 HANDLE token_handle
= NULL
;
553 ASSERT_EQ(ERROR_SUCCESS
, token
.Init(NULL
));
554 ASSERT_EQ(ERROR_SUCCESS
, token
.AddRestrictingSidAllSids());
555 ASSERT_EQ(ERROR_SUCCESS
, token
.GetRestrictedTokenHandle(&token_handle
));
557 ATL::CAccessToken restricted_token
;
558 restricted_token
.Attach(token_handle
);
560 ATL::CTokenGroups groups
;
561 ASSERT_TRUE(restricted_token
.GetGroups(&groups
));
563 ATL::CSid::CSidArray sids
;
564 ATL::CAtlArray
<DWORD
> attributes
;
565 groups
.GetSidsAndAttributes(&sids
, &attributes
);
567 // Verify that all group sids are in the restricting sid list.
568 for (unsigned int i
= 0; i
< sids
.GetCount(); i
++) {
569 if ((attributes
[i
] & SE_GROUP_INTEGRITY
) == 0) {
570 CheckRestrictingSid(restricted_token
, sids
[i
], -1);
574 // Verify that the user is in the restricting sid list.
576 restricted_token
.GetUser(&user
);
577 CheckRestrictingSid(restricted_token
, user
, -1);
580 // Checks the error code when the object is initialized twice.
581 TEST(RestrictedTokenTest
, DoubleInit
) {
582 RestrictedToken token
;
583 ASSERT_EQ(ERROR_SUCCESS
, token
.Init(NULL
));
585 ASSERT_EQ(ERROR_ALREADY_INITIALIZED
, token
.Init(NULL
));
588 } // namespace sandbox