@@ -4,6 +4,7 @@ use anyhow::Context as _;
44use win_api_wrappers:: identity:: account:: { enumerate_account_rights, get_username, lookup_account_by_name} ;
55use win_api_wrappers:: identity:: sid:: { Sid , SidAndAttributes } ;
66use win_api_wrappers:: process:: Process ;
7+ use win_api_wrappers:: raw:: core:: HRESULT ;
78use win_api_wrappers:: raw:: Win32 :: Foundation :: LUID ;
89use win_api_wrappers:: raw:: Win32 :: Security ;
910use win_api_wrappers:: raw:: Win32 :: System :: SystemServices ;
@@ -25,32 +26,63 @@ fn main() -> anyhow::Result<()> {
2526 . context ( "open current process token" ) ?;
2627
2728 // Verify that the current account is assigned with the SE_CREATE_TOKEN_NAME privilege.
28- let account_username = get_username ( Security :: Authentication :: Identity :: NameSamCompatible ) . unwrap ( ) ;
29+ println ! ( "Retrieve the current account name..." ) ;
30+ let account_username =
31+ get_username ( Security :: Authentication :: Identity :: NameSamCompatible ) . context ( "retrieve account username" ) ?;
2932 println ! ( "Account name: {account_username:?}" ) ;
30- let account = lookup_account_by_name ( & account_username) . unwrap ( ) ;
31- let rights = enumerate_account_rights ( & account. sid ) . unwrap ( ) ;
32- let has_create_token_right = rights. iter ( ) . any ( |right| right == u16cstr ! ( "SeCreateTokenPrivilege" ) ) ;
3333
34- if expect_elevation {
35- assert ! ( has_create_token_right) ;
36-
37- // SE_CREATE_TOKEN_NAME is required for performing the elevation.
38- let se_create_token_name_luid = privilege:: lookup_privilege_value ( None , privilege:: SE_CREATE_TOKEN_NAME )
39- . context ( "lookup SE_CREATE_TOKEN_NAME privilege" ) ?;
40- token
41- . adjust_privileges ( & TokenPrivilegesAdjustment :: Enable ( vec ! [ se_create_token_name_luid] ) )
42- . context ( "enable SE_CREATE_TOKEN_NAME privilege" ) ?;
43-
44- // Verify the SE_CREATE_TOKEN_NAME privilege is actually enabled.
45- let se_create_token_name_is_enabled = token
46- . privileges ( )
47- . context ( "list token privileges" ) ?
48- . as_slice ( )
49- . iter ( )
50- . find ( |privilege| privilege. Luid == se_create_token_name_luid)
51- . is_some ( ) ;
52-
53- assert ! ( se_create_token_name_is_enabled) ;
34+ match lookup_account_by_name ( & account_username) {
35+ Ok ( account) => {
36+ // Verify that the current account is assigned with the SE_CREATE_TOKEN_NAME privilege.
37+ println ! (
38+ "Attempting to verify whether the current account is assigned with the SE_CREATE_TOKEN_NAME privilege"
39+ ) ;
40+
41+ let rights = enumerate_account_rights ( & account. sid )
42+ . with_context ( || format ! ( "enumerate account rights for {account_username:?}" ) ) ?;
43+ let has_create_token_right = rights. iter ( ) . any ( |right| right == u16cstr ! ( "SeCreateTokenPrivilege" ) ) ;
44+ println ! ( "Has SeCreateTokenPrivilege right? {has_create_token_right}" ) ;
45+
46+ if expect_elevation {
47+ assert ! ( has_create_token_right) ;
48+ println ! ( "Current user is assigned the SeCreateTokenPrivilege right. Enabling it..." ) ;
49+
50+ // SE_CREATE_TOKEN_NAME is required for performing the elevation.
51+ let se_create_token_name_luid =
52+ privilege:: lookup_privilege_value ( None , privilege:: SE_CREATE_TOKEN_NAME )
53+ . context ( "lookup SE_CREATE_TOKEN_NAME privilege" ) ?;
54+ token
55+ . adjust_privileges ( & TokenPrivilegesAdjustment :: Enable ( vec ! [ se_create_token_name_luid] ) )
56+ . context ( "enable SE_CREATE_TOKEN_NAME privilege" ) ?;
57+
58+ // Verify the SE_CREATE_TOKEN_NAME privilege is actually enabled.
59+ let se_create_token_name_is_enabled = token
60+ . privileges ( )
61+ . context ( "list token privileges" ) ?
62+ . as_slice ( )
63+ . iter ( )
64+ . find ( |privilege| privilege. Luid == se_create_token_name_luid)
65+ . is_some ( ) ;
66+
67+ assert ! ( se_create_token_name_is_enabled) ;
68+ }
69+ }
70+ Err ( e) => {
71+ println ! ( "Failed to look up account for {account_username:?}: {e}" ) ;
72+
73+ // Possible issue when running this program using psexec -s, under `NT AUTHORITY\SYSTEM` (LocalSystem):
74+ // - There is no direct domain credentials by default, unless the machine is domain joined and has a line-of-sight to the DC.
75+ // - This context may not be able to see the same network resources or DC that the interactive user.
76+ // Causing LookupAccountNameW to fail with a "no mapping" error.
77+ // Let’s just go ahead with the elevation in this case, assuming LocalSystem is enough for all intents and purposes at this point.
78+ if e. code ( ) == HRESULT ( 0x80070534u32 as i32 ) {
79+ println ! ( "Got the 'no mapping' error; continuing..." )
80+ } else {
81+ return Err ( anyhow:: Error :: new ( e) . context ( format ! (
82+ "unexpected error when looking up the account for {account_username:?}"
83+ ) ) ) ;
84+ }
85+ }
5486 }
5587
5688 let token_source = build_token_source ( LADM_SRC_NAME , LADM_SRC_LUID ) ;
@@ -122,7 +154,7 @@ fn main() -> anyhow::Result<()> {
122154 } else {
123155 match res {
124156 Ok ( _) => {
125- anyhow:: bail!( "admin token creation should have failed, because the current process is not elevated " )
157+ anyhow:: bail!( "admin token creation succeded, but this was not expected " )
126158 }
127159 Err ( e) => {
128160 assert_eq ! ( e. to_string( ) , "no token found for SE_CREATE_TOKEN_NAME privilege" ) ;
0 commit comments