3
3
4
4
/// Various types to identify entities.
5
5
pub mod identity {
6
- /// A unix user id as obtained from the file system.
7
- #[ cfg( not( windows) ) ]
8
- pub type UserId = u32 ;
9
-
10
- /// A windows [security identifier](https://docs.microsoft.com/en-us/windows/security/identity-protection/access-control/security-identifiers)
11
- /// in its stringified form.
12
- #[ cfg( windows) ]
13
- pub type UserId = String ;
14
6
15
7
#[ derive( PartialEq , Eq , Debug , Hash , Ord , PartialOrd , Clone ) ]
16
8
#[ cfg_attr( feature = "serde1" , derive( serde:: Serialize , serde:: Deserialize ) ) ]
@@ -25,56 +17,119 @@ pub mod identity {
25
17
use std:: borrow:: Cow ;
26
18
use std:: path:: Path ;
27
19
28
- /// Obtain the owner of the given `path`.
29
- pub fn from_path ( path : Cow < ' _ , Path > ) -> std:: io:: Result < UserId > {
30
- impl_:: from_path ( path)
31
- }
32
-
33
- /// Obtain the of the currently running process.
34
- pub fn from_process ( ) -> Result < UserId , from_process:: Error > {
35
- impl_:: from_process ( )
36
- }
37
-
20
+ /// Returns true if the given `path` is owned by the user who is executing the current process.
38
21
///
39
- pub mod from_process {
40
- use crate :: identity:: impl_;
41
-
42
- /// The error returned by [from_process()][super::from_process()].
43
- pub type Error = impl_:: FromProcessError ;
22
+ /// Note that this method is very specific to avoid having to deal with any operating system types.
23
+ pub fn is_path_owned_by_current_user ( path : Cow < ' _ , Path > ) -> std:: io:: Result < bool > {
24
+ impl_:: is_path_owned_by_current_user ( path)
44
25
}
45
26
46
27
#[ cfg( not( windows) ) ]
47
28
mod impl_ {
48
- use crate :: identity:: UserId ;
49
29
use std:: borrow:: Cow ;
50
30
use std:: path:: Path ;
51
31
52
- pub fn from_path ( path : Cow < ' _ , Path > ) -> std:: io:: Result < UserId > {
53
- use std:: os:: unix:: fs:: MetadataExt ;
54
- let meta = std:: fs:: symlink_metadata ( path) ?;
55
- Ok ( meta. uid ( ) )
56
- }
32
+ pub fn is_path_owned_by_current_user ( path : Cow < ' _ , Path > ) -> std:: io:: Result < bool > {
33
+ fn from_path ( path : Cow < ' _ , Path > ) -> std:: io:: Result < u32 > {
34
+ use std:: os:: unix:: fs:: MetadataExt ;
35
+ let meta = std:: fs:: symlink_metadata ( path) ?;
36
+ Ok ( meta. uid ( ) )
37
+ }
57
38
58
- pub type FromProcessError = std:: convert:: Infallible ;
59
- pub fn from_process ( ) -> Result < UserId , FromProcessError > {
60
- // SAFETY: there is no documented possibility for failure
61
- #[ allow( unsafe_code) ]
62
- let uid = unsafe { libc:: geteuid ( ) } ;
63
- Ok ( uid)
39
+ fn from_process ( ) -> std:: io:: Result < u32 > {
40
+ // SAFETY: there is no documented possibility for failure
41
+ #[ allow( unsafe_code) ]
42
+ let uid = unsafe { libc:: geteuid ( ) } ;
43
+ Ok ( uid)
44
+ }
45
+
46
+ Ok ( from_path ( path) ? == from_process ( ) ?)
64
47
}
65
48
}
66
49
67
50
#[ cfg( windows) ]
68
51
mod impl_ {
69
- use crate :: identity:: UserId ;
70
52
use std:: borrow:: Cow ;
71
53
use std:: path:: Path ;
72
54
73
- pub fn from_path ( path : Cow < ' _ , Path > ) -> std:: io:: Result < UserId > {
74
- todo ! ( "unix" )
55
+ fn err ( msg : & str ) -> std:: io:: Error {
56
+ std :: io :: Error :: new ( std :: io :: ErrorKind :: Other , msg )
75
57
}
76
- pub fn from_process ( ) -> std:: io:: Result < UserId > {
77
- todo ! ( "process" )
58
+
59
+ pub fn is_path_owned_by_current_user ( path : Cow < ' _ , Path > ) -> std:: io:: Result < bool > {
60
+ use windows:: Win32 :: {
61
+ Foundation :: { CloseHandle , ERROR_SUCCESS , HANDLE , PSID } ,
62
+ Security ,
63
+ Security :: Authorization :: SE_FILE_OBJECT ,
64
+ System :: Threading ,
65
+ } ;
66
+ let mut handle = HANDLE :: default ( ) ;
67
+ let mut descriptor = Security :: PSECURITY_DESCRIPTOR :: default ( ) ;
68
+ let mut err_msg = None ;
69
+ let mut is_owned = false ;
70
+
71
+ #[ allow( unsafe_code) ]
72
+ unsafe {
73
+ Threading :: OpenProcessToken ( Threading :: GetCurrentProcess ( ) , Security :: TOKEN_QUERY , & mut handle)
74
+ . ok ( )
75
+ . map_err ( |_| err ( "Failed to open process token" ) ) ?;
76
+
77
+ let mut len = 0_u32 ;
78
+ if Security :: GetTokenInformation ( & handle, Security :: TokenUser , std:: ptr:: null_mut ( ) , 0 , & mut len)
79
+ . as_bool ( )
80
+ {
81
+ let mut token_user = Security :: TOKEN_USER :: default ( ) ;
82
+ if Security :: GetTokenInformation (
83
+ & handle,
84
+ Security :: TokenUser ,
85
+ & mut token_user as * mut _ as * mut std:: ffi:: c_void ,
86
+ len,
87
+ & mut len,
88
+ )
89
+ . as_bool ( )
90
+ {
91
+ // NOTE: we avoid to copy the sid or cache it in any way for now, even though it should be possible
92
+ // with a custom allocation/vec/box and it's just very raw. Can the `windows` crate do better?
93
+ // When/If yes, then let's improve this.
94
+ if Security :: IsValidSid ( token_user. User . Sid ) . as_bool ( ) {
95
+ use std:: os:: windows:: ffi:: OsStrExt ;
96
+ let mut wide_path: Vec < _ > = path. as_ref ( ) . as_os_str ( ) . encode_wide ( ) . collect ( ) ;
97
+ // err = GetNamedSecurityInfoW(wpath, SE_FILE_OBJECT,
98
+ // OWNER_SECURITY_INFORMATION |
99
+ // DACL_SECURITY_INFORMATION,
100
+ // &sid, NULL, NULL, NULL, &descriptor);
101
+ let mut path_sid = PSID :: default ( ) ;
102
+ let res = Security :: Authorization :: GetNamedSecurityInfoW (
103
+ windows:: core:: PCWSTR ( wide_path. as_mut_ptr ( ) ) ,
104
+ SE_FILE_OBJECT ,
105
+ Security :: OWNER_SECURITY_INFORMATION | Security :: DACL_SECURITY_INFORMATION ,
106
+ & mut path_sid,
107
+ std:: ptr:: null_mut ( ) ,
108
+ std:: ptr:: null_mut ( ) ,
109
+ std:: ptr:: null_mut ( ) ,
110
+ & mut descriptor,
111
+ ) ;
112
+
113
+ if res == ERROR_SUCCESS . 0 && Security :: IsValidSid ( path_sid) . as_bool ( ) {
114
+ is_owned = Security :: EqualSid ( path_sid, token_user. User . Sid ) . as_bool ( ) ;
115
+ } else {
116
+ err_msg = "couldn't get owner for path or it wasn't valid" . into ( ) ;
117
+ }
118
+ } else {
119
+ err_msg = "owner id of current process wasn't set or valid" . into ( ) ;
120
+ }
121
+ } else {
122
+ err_msg = "Could not get information about the token user" . into ( ) ;
123
+ }
124
+ } else {
125
+ err_msg = "Could not get token information for length of token user" . into ( ) ;
126
+ }
127
+ CloseHandle ( handle) ;
128
+ if !descriptor. is_invalid ( ) {
129
+ windows:: core:: heap_free ( descriptor. 0 ) ;
130
+ }
131
+ }
132
+ err_msg. map ( |msg| Err ( err ( msg) ) ) . unwrap_or ( Ok ( is_owned) )
78
133
}
79
134
}
80
135
}
0 commit comments