3
3
// For the full copyright and license information, please view the LICENSE
4
4
// file that was distributed with this source code.
5
5
6
+ use std:: error:: Error ;
6
7
use std:: path:: Path ;
7
8
8
9
use selinux:: SecurityContext ;
@@ -13,16 +14,16 @@ pub enum SeLinuxError {
13
14
#[ error( "SELinux is not enabled on this system" ) ]
14
15
SELinuxNotEnabled ,
15
16
16
- #[ error( "Failed to open the file: {0}" ) ]
17
+ #[ error( "failed to open the file: {0}" ) ]
17
18
FileOpenFailure ( String ) ,
18
19
19
- #[ error( "Failed to retrieve the security context: {0}" ) ]
20
+ #[ error( "failed to retrieve the security context: {0}" ) ]
20
21
ContextRetrievalFailure ( String ) ,
21
22
22
- #[ error( "Failed to set default file creation context to '{0}': {1}" ) ]
23
+ #[ error( "failed to set default file creation context to '{0}': {1}" ) ]
23
24
ContextSetFailure ( String , String ) ,
24
25
25
- #[ error( "Failed to set default file creation context to '{0}': {1}" ) ]
26
+ #[ error( "failed to set default file creation context to '{0}': {1}" ) ]
26
27
ContextConversionFailure ( String , String ) ,
27
28
}
28
29
@@ -45,6 +46,22 @@ pub fn is_selinux_enabled() -> bool {
45
46
selinux:: kernel_support ( ) != selinux:: KernelSupport :: Unsupported
46
47
}
47
48
49
+ /// Returns a string describing the error and its causes.
50
+ fn selinux_error_description ( mut error : & dyn Error ) ->String {
51
+ let mut description =String :: new ( ) ;
52
+ while let Some ( source) = error. source ( ) {
53
+ let error_text = source. to_string ( ) ;
54
+ // Check if this is an OS error and trim it
55
+ if let Some ( idx) = error_text. find ( " (os error " ) {
56
+ description. push_str ( & error_text[ ..idx] ) ;
57
+ } else {
58
+ description. push_str ( & error_text) ;
59
+ }
60
+ error = source;
61
+ }
62
+ description
63
+ }
64
+
48
65
/// Sets the SELinux security context for the given filesystem path.
49
66
///
50
67
/// If a specific context is provided, it attempts to set this context explicitly.
@@ -99,28 +116,40 @@ pub fn set_selinux_security_context(
99
116
if let Some ( ctx_str) = context{
100
117
// Create a CString from the provided context string
101
118
let c_context = std:: ffi:: CString :: new ( ctx_str. as_str ( ) ) . map_err ( |e|{
102
- SeLinuxError :: ContextConversionFailure ( ctx_str. to_string ( ) , e. to_string ( ) )
119
+ SeLinuxError :: ContextConversionFailure (
120
+ ctx_str. to_string ( ) ,
121
+ selinux_error_description ( & e) ,
122
+ )
103
123
} ) ?;
104
124
105
125
// Convert the CString into an SELinux security context
106
126
let security_context =
107
127
selinux:: OpaqueSecurityContext :: from_c_str ( & c_context) . map_err ( |e|{
108
- SeLinuxError :: ContextConversionFailure ( ctx_str. to_string ( ) , e. to_string ( ) )
128
+ SeLinuxError :: ContextConversionFailure (
129
+ ctx_str. to_string ( ) ,
130
+ selinux_error_description ( & e) ,
131
+ )
109
132
} ) ?;
110
133
111
134
// Set the provided security context on the specified path
112
135
SecurityContext :: from_c_str (
113
136
& security_context. to_c_string ( ) . map_err ( |e|{
114
- SeLinuxError :: ContextConversionFailure ( ctx_str. to_string ( ) , e. to_string ( ) )
137
+ SeLinuxError :: ContextConversionFailure (
138
+ ctx_str. to_string ( ) ,
139
+ selinux_error_description ( & e) ,
140
+ )
115
141
} ) ?,
116
142
false ,
117
143
)
118
144
. set_for_path ( path, false , false )
119
- . map_err ( |e|SeLinuxError :: ContextSetFailure ( ctx_str. to_string ( ) , e. to_string ( ) ) )
145
+ . map_err ( |e|{
146
+ SeLinuxError :: ContextSetFailure ( ctx_str. to_string ( ) , selinux_error_description ( & e) )
147
+ } )
120
148
} else {
121
149
// If no context provided, set the default SELinux context for the path
122
- SecurityContext :: set_default_for_path ( path)
123
- . map_err ( |e|SeLinuxError :: ContextSetFailure ( String :: new ( ) , e. to_string ( ) ) )
150
+ SecurityContext :: set_default_for_path ( path) . map_err ( |e|{
151
+ SeLinuxError :: ContextSetFailure ( String :: new ( ) , selinux_error_description ( & e) )
152
+ } )
124
153
}
125
154
}
126
155
@@ -171,18 +200,23 @@ pub fn get_selinux_security_context(path: &Path) -> Result<String, SeLinuxError>
171
200
return Err ( SeLinuxError :: SELinuxNotEnabled ) ;
172
201
}
173
202
174
- let f = std:: fs:: File :: open ( path) . map_err ( |e|SeLinuxError :: FileOpenFailure ( e. to_string ( ) ) ) ?;
203
+ let f = std:: fs:: File :: open ( path)
204
+ . map_err ( |e|SeLinuxError :: FileOpenFailure ( selinux_error_description ( & e) ) ) ?;
175
205
176
206
// Get the security context of the file
177
207
let context =match SecurityContext :: of_file ( & f, false ) {
178
208
Ok ( Some ( ctx) ) => ctx,
179
209
Ok ( None ) =>return Ok ( String :: new ( ) ) , // No context found, return empty string
180
- Err ( e) =>return Err ( SeLinuxError :: ContextRetrievalFailure ( e. to_string ( ) ) ) ,
210
+ Err ( e) =>{
211
+ return Err ( SeLinuxError :: ContextRetrievalFailure (
212
+ selinux_error_description ( & e) ,
213
+ ) ) ;
214
+ }
181
215
} ;
182
216
183
- let context_c_string = context
184
- . to_c_string ( )
185
- . map_err ( |e| SeLinuxError :: ContextConversionFailure ( String :: new ( ) , e . to_string ( ) ) ) ?;
217
+ let context_c_string = context. to_c_string ( ) . map_err ( |e| {
218
+ SeLinuxError :: ContextConversionFailure ( String :: new ( ) , selinux_error_description ( & e ) )
219
+ } ) ?;
186
220
187
221
if let Some ( c_str) = context_c_string{
188
222
// Convert the C string to a Rust String
@@ -336,7 +370,8 @@ mod tests {
336
370
println ! ( "Context conversion failure for '{}': {}" , ctx, e) ;
337
371
}
338
372
SeLinuxError :: ContextSetFailure ( ctx, e) =>{
339
- assert ! ( false ) ;
373
+ assert ! ( !e. is_empty( ) , "Error message should not be empty" ) ;
374
+ println ! ( "Context conversion failure for '{}': {}" , ctx, e) ;
340
375
}
341
376
SeLinuxError :: FileOpenFailure ( e) =>{
342
377
assert ! (