@@ -3,8 +3,8 @@ use std::slice::{from_raw_parts, from_raw_parts_mut};
3
3
use libc:: { c_ulonglong, c_void} ;
4
4
use num_traits:: cast:: { FromPrimitive , ToPrimitive } ;
5
5
use sspi:: {
6
- BufferType , DataRepresentation , DecryptionFlags , EncryptionFlags , ErrorKind , SecurityBuffer , SecurityBufferRef ,
7
- SecurityBufferType , ServerRequestFlags , Sspi ,
6
+ BufferType , DataRepresentation , DecryptionFlags , EncryptionFlags , Error , ErrorKind , SecurityBuffer ,
7
+ SecurityBufferRef , SecurityBufferType , ServerRequestFlags , Sspi ,
8
8
} ;
9
9
#[ cfg( windows) ]
10
10
use symbol_rename_macro:: rename_symbol;
@@ -25,10 +25,15 @@ use crate::utils::into_raw_ptr;
25
25
pub unsafe extern "system" fn FreeCredentialsHandle ( ph_credential : PCredHandle ) -> SecurityStatus {
26
26
check_null ! ( ph_credential) ;
27
27
28
- let cred_handle = ( * ph_credential) . dw_lower as * mut CredentialsHandle ;
28
+ // SAFETY: `ph_credentials` is not null. We've checked for this above.
29
+ let cred_handle = unsafe { ( * ph_credential) . dw_lower as * mut CredentialsHandle } ;
29
30
check_null ! ( cred_handle) ;
30
31
31
- let _cred_handle = Box :: from_raw ( cred_handle) ;
32
+ // SAFETY: `cred_handle` is not null. We've checked for this above.
33
+ // We create and allocate credentials handles using `Box::into_raw`. Thus,
34
+ // it is safe to deallocate them using `Box::from_raw`.
35
+ // The user have to ensure that the credentials handle was created by us.
36
+ let _cred_handle = unsafe { Box :: from_raw ( cred_handle) } ;
32
37
33
38
0
34
39
}
@@ -58,25 +63,40 @@ pub unsafe extern "system" fn AcceptSecurityContext(
58
63
check_null!( p_output) ;
59
64
check_null!( pf_context_attr) ;
60
65
61
- let credentials_handle = ( * ph_credential) . dw_lower as * mut CredentialsHandle ;
66
+ // SAFETY: `ph_credentials` is not null. We've checked for this above.
67
+ let credentials_handle = unsafe { ( * ph_credential) . dw_lower as * mut CredentialsHandle } ;
62
68
63
- let ( auth_data, security_package_name, attributes) = match transform_credentials_handle( credentials_handle) {
64
- Some ( data) => data,
65
- None => return ErrorKind :: InvalidHandle . to_u32( ) . unwrap( ) ,
69
+ // SAFETY: It's safe to call the function, because it has internal null check and proper error handling.
70
+ let ( auth_data, security_package_name, attributes) = unsafe {
71
+ match transform_credentials_handle( credentials_handle) {
72
+ Some ( data) => data,
73
+ None => return ErrorKind :: InvalidHandle . to_u32( ) . unwrap( ) ,
74
+ }
66
75
} ;
67
76
68
- let sspi_context_ptr = try_execute!( p_ctxt_handle_to_sspi_context(
77
+ // SAFETY: It's safe to call the function, because:
78
+ // *`ph_context` can be null;
79
+ // * the value behind `ph_context` must be initialized by ourself: the user does not have to create the [CtxHandle] values themselves.
80
+ // * other parameters are type checked.
81
+ let mut sspi_context_ptr = try_execute!( unsafe { p_ctxt_handle_to_sspi_context(
69
82
& mut ph_context,
70
83
Some ( security_package_name) ,
71
84
attributes,
72
- ) ) ;
73
-
74
- let sspi_context = sspi_context_ptr
75
- . as_mut( )
76
- . expect( "security context pointer cannot be null" ) ;
77
-
78
- let mut input_tokens =
79
- p_sec_buffers_to_security_buffers( from_raw_parts( ( * p_input) . p_buffers, ( * p_input) . c_buffers as usize ) ) ;
85
+ ) } ) ;
86
+
87
+ // SAFETY: It's safe to call the `as_mut` function, because `sspi_context_ptr` is a local pointer,
88
+ // which is initialized by the `p_ctx_handle_to_sspi_context` function. Thus, the value behind this pointer is valid.
89
+ let sspi_context = unsafe { sspi_context_ptr. as_mut( ) } ;
90
+
91
+ // SAFETY: `p_input` is not null. We've checked for this above. Additionally, we check `p_buffers` for null.
92
+ // All other guarantees must be provided by user.
93
+ let mut input_tokens = try_execute!( unsafe {
94
+ if ( * p_input) . p_buffers. is_null( ) {
95
+ Err ( Error :: new( ErrorKind :: InvalidParameter , "p_buffers cannot be null" ) )
96
+ } else {
97
+ Ok ( p_sec_buffers_to_security_buffers( from_raw_parts( ( * p_input) . p_buffers, ( * p_input) . c_buffers as usize ) ) )
98
+ }
99
+ } ) ;
80
100
81
101
let mut output_tokens = vec![ SecurityBuffer :: new( Vec :: with_capacity( 1024 ) , BufferType :: Token ) ] ;
82
102
@@ -88,12 +108,18 @@ pub unsafe extern "system" fn AcceptSecurityContext(
88
108
. with_output( & mut output_tokens)
89
109
. execute( sspi_context) ;
90
110
91
- copy_to_c_sec_buffer( ( * p_output) . p_buffers, & output_tokens, false ) ;
111
+ // SAFETY: `p_output` is not null. We've checked this above.
112
+ try_execute!( unsafe { copy_to_c_sec_buffer( ( * p_output) . p_buffers, & output_tokens, false ) } ) ;
92
113
93
- ( * ph_new_context) . dw_lower = sspi_context_ptr as c_ulonglong ;
94
- ( * ph_new_context) . dw_upper = into_raw_ptr ( security_package_name . to_owned ( ) ) as c_ulonglong ;
114
+ // SAFETY: ` ph_new_context` is not null. We've checked this above.
115
+ let ph_new_context = unsafe { ph_new_context . as_mut ( ) } . expect ( "ph_new_context should not be null" ) ;
95
116
96
- * pf_context_attr = f_context_req;
117
+ ph_new_context. dw_lower = sspi_context_ptr. as_ptr( ) as c_ulonglong;
118
+ ph_new_context. dw_upper = into_raw_ptr( security_package_name. to_owned( ) ) as c_ulonglong;
119
+ // SAFETY: `pf_context_attr` is not null. We've checked this above.
120
+ unsafe {
121
+ * pf_context_attr = f_context_req;
122
+ }
97
123
98
124
let result = try_execute!( result_status) ;
99
125
result. status. to_u32( ) . unwrap( )
@@ -123,16 +149,27 @@ pub unsafe extern "system" fn CompleteAuthToken(
123
149
check_null!( ph_context) ;
124
150
check_null!( p_token) ;
125
151
126
- let sspi_context = try_execute!( p_ctxt_handle_to_sspi_context(
152
+ // SAFETY: `p_token` is not null. We've checked this above.
153
+ unsafe { check_null!( ( * p_token) . p_buffers) ; }
154
+
155
+ // SAFETY: It's safe to call the function, because:
156
+ // *`ph_context` can be null;
157
+ // * the value behind `ph_context` must be initialized by ourself: the user does not have to create the [CtxHandle] values themselves.
158
+ // * other parameters are type checked.
159
+ let mut sspi_context_ptr = try_execute!( unsafe { p_ctxt_handle_to_sspi_context(
127
160
& mut ph_context,
128
161
None ,
129
162
& CredentialsAttributes :: default ( )
130
- ) )
131
- . as_mut( )
132
- . expect( "security context pointer cannot be null" ) ;
163
+ ) } ) ;
133
164
134
- let raw_buffers = from_raw_parts( ( * p_token) . p_buffers, ( * p_token) . c_buffers as usize ) ;
135
- let mut buffers = p_sec_buffers_to_security_buffers( raw_buffers) ;
165
+ // SAFETY: It's safe to call the `as_mut` function, because `sspi_context_ptr` is a local pointer,
166
+ // which is initialized by the `p_ctx_handle_to_sspi_context` function. Thus, the value behind this pointer is valid.
167
+ let sspi_context = unsafe { sspi_context_ptr. as_mut( ) } ;
168
+
169
+ // SAFETY: This function is safe to call because `p_buffers` is not null. We've checked this above.
170
+ let raw_buffers = unsafe { from_raw_parts( ( * p_token) . p_buffers, ( * p_token) . c_buffers as usize ) } ;
171
+ // SAFETY: This function is safe to call because `raw_buffers` is type checked. All other guarantees must be provided by user.
172
+ let mut buffers = unsafe { p_sec_buffers_to_security_buffers( raw_buffers) } ;
136
173
137
174
sspi_context. complete_auth_token( & mut buffers) . map_or_else(
138
175
|err| err. error_type. to_u32( ) . unwrap( ) ,
@@ -150,14 +187,29 @@ pub unsafe extern "system" fn DeleteSecurityContext(mut ph_context: PCtxtHandle)
150
187
catch_panic ! (
151
188
check_null!( ph_context) ;
152
189
153
- let _context: Box <SspiHandle > = Box :: from_raw( try_execute!( p_ctxt_handle_to_sspi_context(
190
+ // SAFETY: It's safe to call the function, because:
191
+ // * the value behind `ph_context` must be initialized by ourself: the user does not have to create the [CtxHandle] values themselves.
192
+ // * other parameters are type checked.
193
+ let mut sspi_context_ptr = try_execute!( unsafe { p_ctxt_handle_to_sspi_context(
154
194
& mut ph_context,
155
195
None ,
156
196
& CredentialsAttributes :: default ( )
157
- ) ) ) ;
197
+ ) } ) ;
198
+
199
+ // SAFETY: It's safe to constructs a box from a raw pointer because:
200
+ // * the `sspi_context_ptr` is not null;
201
+ // * the value behind `sspi_context_ptr` must be initialized by ourself: the user does not have to create the [CtxHandle] values themselves.
202
+ let _context: Box <SspiHandle > = unsafe {
203
+ Box :: from_raw( sspi_context_ptr. as_mut( ) )
204
+ } ;
158
205
159
- if ( * ph_context) . dw_upper != 0 {
160
- let _name: Box <String > = Box :: from_raw( ( * ph_context) . dw_upper as * mut String ) ;
206
+ // SAFETY: `ph_context` is not null. We've checked for it above.
207
+ let dw_upper = unsafe { ( * ph_context) . dw_upper } ;
208
+ if dw_upper != 0 {
209
+ // SAFETY: It's safe to constructs a box from a raw pointer because:
210
+ // * the `dw_upper` is not equal to zero;
211
+ // * the value behind `dw_upper` pointer must be initialized by ourself: the user does not have to create the [CtxHandle] values themselves.
212
+ let _name: Box <String > = unsafe { Box :: from_raw( dw_upper as * mut String ) } ;
161
213
}
162
214
163
215
0
@@ -226,7 +278,12 @@ pub type VerifySignatureFn = extern "system" fn(PCtxtHandle, PSecBufferDesc, u32
226
278
#[ no_mangle]
227
279
pub unsafe extern "system" fn FreeContextBuffer ( pv_context_buffer : * mut c_void ) -> SecurityStatus {
228
280
// NOTE: see https://github.com/Devolutions/sspi-rs/pull/141 for rationale behind libc usage.
229
- libc:: free ( pv_context_buffer) ;
281
+ // SAFETY: Memory deallocation is safe.
282
+ // The user must call this function to free buffers allocated by ourself. On our side, we always use `malloc`
283
+ // to allocate buffers in in FFI.
284
+ unsafe {
285
+ libc:: free ( pv_context_buffer) ;
286
+ }
230
287
231
288
0
232
289
}
@@ -270,25 +327,43 @@ pub unsafe extern "system" fn EncryptMessage(
270
327
check_null!( ph_context) ;
271
328
check_null!( p_message) ;
272
329
273
- let sspi_context = try_execute!( p_ctxt_handle_to_sspi_context(
330
+ // SAFETY: `p_message` is not null. We've checked this above.
331
+ unsafe { check_null!( ( * p_message) . p_buffers) ; }
332
+
333
+ // SAFETY: It's safe to call the function, because:
334
+ // *`ph_context` can be null;
335
+ // * the value behind `ph_context` must be initialized by ourself: the user does not have to create the [CtxHandle] values themselves.
336
+ // * other parameters are type checked.
337
+ let mut sspi_context_ptr = try_execute!( unsafe { p_ctxt_handle_to_sspi_context(
274
338
& mut ph_context,
275
339
None ,
276
340
& CredentialsAttributes :: default ( )
277
- ) )
278
- . as_mut( )
279
- . expect( "security context pointer cannot be null" ) ;
341
+ ) } ) ;
342
+
343
+ // SAFETY: It's safe to call the `as_mut` function, because `sspi_context_ptr` is a local pointer,
344
+ // which is initialized by the `p_ctx_handle_to_sspi_context` function. Thus, the value behind this pointer is valid.
345
+ let sspi_context = unsafe { sspi_context_ptr. as_mut( ) } ;
280
346
281
- let len = ( * p_message) . c_buffers as usize ;
282
- let raw_buffers = from_raw_parts( ( * p_message) . p_buffers, len) ;
283
- let mut message = try_execute!( p_sec_buffers_to_decrypt_buffers( raw_buffers) ) ;
347
+ // SAFETY: `p_message` is not null. We've checked this above.
348
+ let len = unsafe { ( * p_message) . c_buffers as usize } ;
349
+
350
+ // SAFETY: `p_message` is not null. We've checked this above. Moreover, we've checked `p_buffers` for null above.
351
+ let raw_buffers = unsafe {
352
+ from_raw_parts( ( * p_message) . p_buffers, len)
353
+ } ;
354
+
355
+ // SAFETY: The user must provide guarantees about the correctness of buffers in `raw_buffers'.
356
+ let mut message = try_execute!( unsafe { p_sec_buffers_to_decrypt_buffers( raw_buffers) } ) ;
284
357
285
358
let result_status = sspi_context. encrypt_message(
286
359
EncryptionFlags :: from_bits( f_qop. try_into( ) . unwrap( ) ) . unwrap( ) ,
287
360
& mut message,
288
361
message_seq_no. try_into( ) . unwrap( ) ,
289
362
) ;
290
363
291
- try_execute!( copy_decrypted_buffers( ( * p_message) . p_buffers, message) ) ;
364
+ // SAFETY: `p_message` and `p_buffers` are not null. We've checked this above.
365
+ // All other guarantees must be provided by user.
366
+ try_execute!( unsafe { copy_decrypted_buffers( ( * p_message) . p_buffers, message) } ) ;
292
367
293
368
let result = try_execute!( result_status) ;
294
369
result. to_u32( ) . unwrap( )
@@ -311,28 +386,44 @@ pub unsafe extern "system" fn DecryptMessage(
311
386
check_null!( ph_context) ;
312
387
check_null!( p_message) ;
313
388
314
- let sspi_context = try_execute!( p_ctxt_handle_to_sspi_context(
389
+ // SAFETY: `p_message` is not null. We've checked this above.
390
+ unsafe { check_null!( ( * p_message) . p_buffers) ; }
391
+
392
+ // SAFETY: It's safe to call the function, because:
393
+ // *`ph_context` can be null;
394
+ // * the value behind `ph_context` must be initialized by ourself: the user does not have to create the [CtxHandle] values themselves.
395
+ // * other parameters are type checked.
396
+ let mut sspi_context_ptr = try_execute!( unsafe { p_ctxt_handle_to_sspi_context(
315
397
& mut ph_context,
316
398
None ,
317
399
& CredentialsAttributes :: default ( )
318
- ) )
319
- . as_mut( )
320
- . expect( "security context pointer cannot be null" ) ;
400
+ ) } ) ;
401
+
402
+ // SAFETY: It's safe to call the `as_mut` function, because `sspi_context_ptr` is a local pointer,
403
+ // which is initialized by the `p_ctx_handle_to_sspi_context` function. Thus, the value behind this pointer is valid.
404
+ let sspi_context = unsafe { sspi_context_ptr. as_mut( ) } ;
321
405
322
- let len = ( * p_message) . c_buffers as usize ;
323
- let raw_buffers = from_raw_parts( ( * p_message) . p_buffers, len) ;
324
- let mut message = try_execute!( p_sec_buffers_to_decrypt_buffers( raw_buffers) ) ;
406
+ // SAFETY: `p_message` is not null. We've checked this above.
407
+ let len = unsafe { ( * p_message) . c_buffers as usize } ;
408
+ // SAFETY: `p_message` and `p_buffers` is not null. We've checked this above.
409
+ let raw_buffers = unsafe { from_raw_parts( ( * p_message) . p_buffers, len) } ;
410
+ // SAFETY: The user must provide guarantees about the correctness of buffers in `raw_buffers'.
411
+ let mut message = try_execute!( unsafe { p_sec_buffers_to_decrypt_buffers( raw_buffers) } ) ;
325
412
326
413
let ( decryption_flags, result_status) =
327
414
match sspi_context. decrypt_message( & mut message, message_seq_no. try_into( ) . unwrap( ) ) {
328
415
Ok ( flags) => ( flags, Ok ( ( ) ) ) ,
329
416
Err ( error) => ( DecryptionFlags :: empty( ) , Err ( error) ) ,
330
417
} ;
331
418
332
- try_execute!( copy_decrypted_buffers( ( * p_message) . p_buffers, message) ) ;
419
+ // SAFETY: `p_message` and `p_buffers` is not null. We've checked this above.
420
+ // All other guarantees must be provided by user.
421
+ try_execute!( unsafe { copy_decrypted_buffers( ( * p_message) . p_buffers, message) } ) ;
333
422
// `pf_qop` can be null if this library is used as a CredSsp security package
334
423
if !pf_qop. is_null( ) {
335
- * pf_qop = decryption_flags. bits( ) . try_into( ) . unwrap( ) ;
424
+ let flags = try_execute!( decryption_flags. bits( ) . try_into( ) , ErrorKind :: InternalError ) ;
425
+ // SAFETY: `pf_qop` is not null. We've checked this above.
426
+ unsafe { * pf_qop = flags } ;
336
427
}
337
428
338
429
try_execute!( result_status) ;
0 commit comments