2 * Unix interface for libkrb5/libgssapi_krb5
4 * Copyright 2017 Dmitry Timoshkov
5 * Copyright 2017 George Popoff
6 * Copyright 2008 Robert Shearman for CodeWeavers
7 * Copyright 2017,2021 Hans Leidekker for CodeWeavers
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 #if defined(SONAME_LIBKRB5) && defined(SONAME_LIBGSSAPI_KRB5)
33 #include <sys/types.h>
36 #ifdef HAVE_KRB5_KRB5_H
37 # include <krb5/krb5.h>
39 #ifdef HAVE_GSSAPI_GSSAPI_H
40 # include <gssapi/gssapi.h>
42 #ifdef HAVE_GSSAPI_GSSAPI_EXT_H
43 # include <gssapi/gssapi_ext.h>
47 #define WIN32_NO_STATUS
56 #include "wine/debug.h"
59 WINE_DEFAULT_DEBUG_CHANNEL(kerberos
);
60 WINE_DECLARE_DEBUG_CHANNEL(winediag
);
62 static void *libkrb5_handle
;
64 #define MAKE_FUNCPTR(f) static typeof(f) * p_##f
65 MAKE_FUNCPTR( krb5_cc_close
);
66 MAKE_FUNCPTR( krb5_cc_default
);
67 MAKE_FUNCPTR( krb5_cc_end_seq_get
);
68 MAKE_FUNCPTR( krb5_cc_initialize
);
69 MAKE_FUNCPTR( krb5_cc_next_cred
);
70 MAKE_FUNCPTR( krb5_cc_start_seq_get
);
71 MAKE_FUNCPTR( krb5_cc_store_cred
);
72 MAKE_FUNCPTR( krb5_cccol_cursor_free
);
73 MAKE_FUNCPTR( krb5_cccol_cursor_new
);
74 MAKE_FUNCPTR( krb5_cccol_cursor_next
);
75 MAKE_FUNCPTR( krb5_decode_ticket
);
76 MAKE_FUNCPTR( krb5_free_context
);
77 MAKE_FUNCPTR( krb5_free_cred_contents
);
78 MAKE_FUNCPTR( krb5_free_principal
);
79 MAKE_FUNCPTR( krb5_free_ticket
);
80 MAKE_FUNCPTR( krb5_free_unparsed_name
);
81 MAKE_FUNCPTR( krb5_get_init_creds_opt_alloc
);
82 MAKE_FUNCPTR( krb5_get_init_creds_opt_free
);
83 MAKE_FUNCPTR( krb5_get_init_creds_opt_set_out_ccache
);
84 MAKE_FUNCPTR( krb5_get_init_creds_password
);
85 MAKE_FUNCPTR( krb5_init_context
);
86 MAKE_FUNCPTR( krb5_is_config_principal
);
87 MAKE_FUNCPTR( krb5_parse_name_flags
);
88 MAKE_FUNCPTR( krb5_unparse_name_flags
);
91 static BOOL
load_krb5(void)
93 if (!(libkrb5_handle
= dlopen( SONAME_LIBKRB5
, RTLD_NOW
)))
95 WARN_(winediag
)( "failed to load %s, Kerberos support will be disabled\n", SONAME_LIBKRB5
);
99 #define LOAD_FUNCPTR(f) \
100 if (!(p_##f = dlsym( libkrb5_handle, #f ))) \
102 ERR( "failed to load %s\n", #f ); \
106 LOAD_FUNCPTR( krb5_cc_close
)
107 LOAD_FUNCPTR( krb5_cc_default
)
108 LOAD_FUNCPTR( krb5_cc_end_seq_get
)
109 LOAD_FUNCPTR( krb5_cc_initialize
)
110 LOAD_FUNCPTR( krb5_cc_next_cred
)
111 LOAD_FUNCPTR( krb5_cc_start_seq_get
)
112 LOAD_FUNCPTR( krb5_cc_store_cred
)
113 LOAD_FUNCPTR( krb5_cccol_cursor_free
)
114 LOAD_FUNCPTR( krb5_cccol_cursor_new
)
115 LOAD_FUNCPTR( krb5_cccol_cursor_next
)
116 LOAD_FUNCPTR( krb5_decode_ticket
)
117 LOAD_FUNCPTR( krb5_free_context
)
118 LOAD_FUNCPTR( krb5_free_cred_contents
)
119 LOAD_FUNCPTR( krb5_free_principal
)
120 LOAD_FUNCPTR( krb5_free_ticket
)
121 LOAD_FUNCPTR( krb5_free_unparsed_name
)
122 LOAD_FUNCPTR( krb5_get_init_creds_opt_alloc
)
123 LOAD_FUNCPTR( krb5_get_init_creds_opt_free
)
124 LOAD_FUNCPTR( krb5_get_init_creds_opt_set_out_ccache
)
125 LOAD_FUNCPTR( krb5_get_init_creds_password
)
126 LOAD_FUNCPTR( krb5_init_context
)
127 LOAD_FUNCPTR( krb5_is_config_principal
)
128 LOAD_FUNCPTR( krb5_parse_name_flags
)
129 LOAD_FUNCPTR( krb5_unparse_name_flags
)
134 dlclose( libkrb5_handle
);
135 libkrb5_handle
= NULL
;
139 static void unload_krb5(void)
141 dlclose( libkrb5_handle
);
142 libkrb5_handle
= NULL
;
145 static NTSTATUS
krb5_error_to_status( krb5_error_code err
)
149 case 0: return STATUS_SUCCESS
;
150 default: return STATUS_UNSUCCESSFUL
; /* FIXME */
158 KERB_TICKET_CACHE_INFO_EX
*tickets
;
161 static void utf8_to_wstr( UNICODE_STRING
*strW
, const char *src
)
163 ULONG dstlen
, srclen
= strlen( src
) + 1;
165 strW
->Buffer
= malloc( srclen
* sizeof(WCHAR
) );
166 RtlUTF8ToUnicodeN( strW
->Buffer
, srclen
* sizeof(WCHAR
), &dstlen
, src
, srclen
);
167 strW
->MaximumLength
= dstlen
;
168 strW
->Length
= dstlen
- sizeof(WCHAR
);
171 static void principal_to_name_and_realm(char *name_with_realm
, char **name
, char **realm
)
175 separator
= strchr( name_with_realm
, '@' );
178 ERR( "got a name without a @\n" );
179 *name
= name_with_realm
;
180 *realm
= *name
+ strlen(*name
); /* point it to a null byte */
185 *name
= name_with_realm
;
186 *realm
= separator
+ 1; /* character after a @ */
187 TRACE( "name: %s, realm: %s\n", debugstr_a(*name
), debugstr_a(*realm
) );
190 static NTSTATUS
copy_tickets_from_cache( krb5_context ctx
, krb5_ccache cache
, struct ticket_list
*list
)
193 krb5_cc_cursor cursor
;
197 char *server_name_with_realm
, *server_name
, *server_realm
;
198 char *client_name_with_realm
, *client_name
, *client_realm
;
200 if ((err
= p_krb5_cc_start_seq_get( ctx
, cache
, &cursor
))) return krb5_error_to_status( err
);
203 if ((err
= p_krb5_cc_next_cred( ctx
, cache
, &cursor
, &creds
)))
205 if (err
== KRB5_CC_END
)
206 status
= STATUS_SUCCESS
;
208 status
= krb5_error_to_status( err
);
212 if (p_krb5_is_config_principal( ctx
, creds
.server
))
214 p_krb5_free_cred_contents( ctx
, &creds
);
218 if (list
->count
== list
->allocated
)
220 ULONG new_allocated
= max( 16, list
->allocated
* 2 );
221 KERB_TICKET_CACHE_INFO_EX
*new_tickets
= realloc( list
->tickets
, sizeof(*new_tickets
) * new_allocated
);
224 p_krb5_free_cred_contents( ctx
, &creds
);
225 status
= STATUS_NO_MEMORY
;
228 list
->tickets
= new_tickets
;
229 list
->allocated
= new_allocated
;
232 if ((err
= p_krb5_unparse_name_flags( ctx
, creds
.server
, 0, &server_name_with_realm
)))
234 p_krb5_free_cred_contents( ctx
, &creds
);
235 status
= krb5_error_to_status( err
);
238 TRACE( "server_name_with_realm: %s\n", debugstr_a(server_name_with_realm
) );
240 principal_to_name_and_realm( server_name_with_realm
, &server_name
, &server_realm
);
242 utf8_to_wstr( &list
->tickets
[list
->count
].ServerName
, server_name
);
243 utf8_to_wstr( &list
->tickets
[list
->count
].ServerRealm
, server_realm
);
245 if ((err
= p_krb5_unparse_name_flags( ctx
, creds
.client
, 0, &client_name_with_realm
)))
247 p_krb5_free_cred_contents( ctx
, &creds
);
248 status
= krb5_error_to_status( err
);
251 TRACE( "client_name_with_realm: %s\n", debugstr_a(client_name_with_realm
) );
253 principal_to_name_and_realm( client_name_with_realm
, &client_name
, &client_realm
);
255 utf8_to_wstr( &list
->tickets
[list
->count
].ClientName
, client_name
);
256 utf8_to_wstr( &list
->tickets
[list
->count
].ClientRealm
, client_realm
);
258 if (!creds
.times
.starttime
) creds
.times
.starttime
= creds
.times
.authtime
;
260 /* TODO: if krb5_is_config_principal = true */
262 /* note: store times as seconds, they will be converted to NT timestamps on the PE side */
263 list
->tickets
[list
->count
].StartTime
.QuadPart
= creds
.times
.starttime
;
264 list
->tickets
[list
->count
].EndTime
.QuadPart
= creds
.times
.endtime
;
265 list
->tickets
[list
->count
].RenewTime
.QuadPart
= creds
.times
.renew_till
;
266 list
->tickets
[list
->count
].TicketFlags
= creds
.ticket_flags
;
268 err
= p_krb5_decode_ticket( &creds
.ticket
, &ticket
);
269 p_krb5_free_unparsed_name( ctx
, server_name_with_realm
);
270 p_krb5_free_unparsed_name( ctx
, client_name_with_realm
);
271 p_krb5_free_cred_contents( ctx
, &creds
);
274 status
= krb5_error_to_status( err
);
278 list
->tickets
[list
->count
].EncryptionType
= ticket
->enc_part
.enctype
;
279 p_krb5_free_ticket( ctx
, ticket
);
283 p_krb5_cc_end_seq_get( ctx
, cache
, &cursor
);
287 static NTSTATUS
copy_tickets_to_client( struct ticket_list
*list
, KERB_QUERY_TKT_CACHE_EX_RESPONSE
*resp
,
291 ULONG i
, size
= offsetof( KERB_QUERY_TKT_CACHE_EX_RESPONSE
, Tickets
[list
->count
] );
293 for (i
= 0; i
< list
->count
; i
++)
295 size
+= list
->tickets
[i
].ClientRealm
.MaximumLength
;
296 size
+= list
->tickets
[i
].ClientName
.MaximumLength
;
297 size
+= list
->tickets
[i
].ServerRealm
.MaximumLength
;
298 size
+= list
->tickets
[i
].ServerName
.MaximumLength
;
300 if (!resp
|| size
> *out_size
)
303 return STATUS_BUFFER_TOO_SMALL
;
307 resp
->MessageType
= KerbQueryTicketCacheMessage
;
308 resp
->CountOfTickets
= list
->count
;
309 memcpy( resp
->Tickets
, list
->tickets
, list
->count
* sizeof(list
->tickets
[0]) );
310 client_str
= (char *)&resp
->Tickets
[list
->count
];
312 for (i
= 0; i
< list
->count
; i
++)
314 resp
->Tickets
[i
].ClientRealm
.Buffer
= (WCHAR
*)client_str
;
315 memcpy( client_str
, list
->tickets
[i
].ClientRealm
.Buffer
, list
->tickets
[i
].ClientRealm
.MaximumLength
);
316 client_str
+= list
->tickets
[i
].ClientRealm
.MaximumLength
;
317 resp
->Tickets
[i
].ClientName
.Buffer
= (WCHAR
*)client_str
;
318 memcpy( client_str
, list
->tickets
[i
].ClientName
.Buffer
, list
->tickets
[i
].ClientName
.MaximumLength
);
319 client_str
+= list
->tickets
[i
].ClientName
.MaximumLength
;
320 resp
->Tickets
[i
].ServerRealm
.Buffer
= (WCHAR
*)client_str
;
321 memcpy( client_str
, list
->tickets
[i
].ServerRealm
.Buffer
, list
->tickets
[i
].ServerRealm
.MaximumLength
);
322 client_str
+= list
->tickets
[i
].ServerRealm
.MaximumLength
;
323 resp
->Tickets
[i
].ServerName
.Buffer
= (WCHAR
*)client_str
;
324 memcpy( client_str
, list
->tickets
[i
].ServerName
.Buffer
, list
->tickets
[i
].ServerName
.MaximumLength
);
325 client_str
+= list
->tickets
[i
].ServerName
.MaximumLength
;
327 return STATUS_SUCCESS
;
330 static NTSTATUS
kerberos_fill_ticket_list( struct ticket_list
*list
)
332 NTSTATUS status
= STATUS_SUCCESS
;
335 krb5_cccol_cursor cursor
= NULL
;
338 if ((err
= p_krb5_init_context( &ctx
))) return krb5_error_to_status( err
);
339 if ((err
= p_krb5_cccol_cursor_new( ctx
, &cursor
)))
341 status
= krb5_error_to_status( err
);
347 if ((err
= p_krb5_cccol_cursor_next( ctx
, cursor
, &cache
)))
349 status
= krb5_error_to_status( err
);
354 status
= copy_tickets_from_cache( ctx
, cache
, list
);
355 p_krb5_cc_close( ctx
, cache
);
356 if (status
!= STATUS_SUCCESS
) goto done
;
360 if (cursor
) p_krb5_cccol_cursor_free( ctx
, &cursor
);
361 if (ctx
) p_krb5_free_context( ctx
);
366 static void free_tickets_in_list( struct ticket_list
*list
)
370 for (i
= 0; i
< list
->count
; i
++)
372 free( list
->tickets
[i
].ClientRealm
.Buffer
);
373 free( list
->tickets
[i
].ClientName
.Buffer
);
374 free( list
->tickets
[i
].ServerRealm
.Buffer
);
375 free( list
->tickets
[i
].ServerName
.Buffer
);
378 free( list
->tickets
);
381 static NTSTATUS
query_ticket_cache( void *args
)
383 struct query_ticket_cache_params
*params
= args
;
384 struct ticket_list list
= { 0 };
387 status
= kerberos_fill_ticket_list( &list
);
389 if (status
== STATUS_SUCCESS
) status
= copy_tickets_to_client( &list
, params
->resp
, params
->out_size
);
391 free_tickets_in_list( &list
);
395 static void *libgssapi_krb5_handle
;
397 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
398 MAKE_FUNCPTR( gss_accept_sec_context
);
399 MAKE_FUNCPTR( gss_acquire_cred
);
400 MAKE_FUNCPTR( gss_delete_sec_context
);
401 MAKE_FUNCPTR( gss_display_status
);
402 MAKE_FUNCPTR( gss_get_mic
);
403 MAKE_FUNCPTR( gss_import_name
);
404 MAKE_FUNCPTR( gss_init_sec_context
);
405 MAKE_FUNCPTR( gss_inquire_context
);
406 MAKE_FUNCPTR( gss_inquire_sec_context_by_oid
);
407 MAKE_FUNCPTR( gss_release_buffer
);
408 MAKE_FUNCPTR( gss_release_buffer_set
);
409 MAKE_FUNCPTR( gss_release_cred
);
410 MAKE_FUNCPTR( gss_release_iov_buffer
);
411 MAKE_FUNCPTR( gss_release_name
);
412 MAKE_FUNCPTR( gss_unwrap
);
413 MAKE_FUNCPTR( gss_unwrap_iov
);
414 MAKE_FUNCPTR( gss_verify_mic
);
415 MAKE_FUNCPTR( gss_wrap
);
416 MAKE_FUNCPTR( gss_wrap_iov
);
419 static BOOL
load_gssapi_krb5(void)
421 if (!(libgssapi_krb5_handle
= dlopen( SONAME_LIBGSSAPI_KRB5
, RTLD_NOW
)))
423 WARN_(winediag
)( "failed to load %s, Kerberos support will be disabled\n", SONAME_LIBGSSAPI_KRB5
);
427 #define LOAD_FUNCPTR(f) \
428 if (!(p##f = dlsym( libgssapi_krb5_handle, #f ))) \
430 ERR( "failed to load %s\n", #f ); \
434 LOAD_FUNCPTR( gss_accept_sec_context
)
435 LOAD_FUNCPTR( gss_acquire_cred
)
436 LOAD_FUNCPTR( gss_delete_sec_context
)
437 LOAD_FUNCPTR( gss_display_status
)
438 LOAD_FUNCPTR( gss_get_mic
)
439 LOAD_FUNCPTR( gss_import_name
)
440 LOAD_FUNCPTR( gss_init_sec_context
)
441 LOAD_FUNCPTR( gss_inquire_context
)
442 LOAD_FUNCPTR( gss_inquire_sec_context_by_oid
)
443 LOAD_FUNCPTR( gss_release_buffer
)
444 LOAD_FUNCPTR( gss_release_buffer_set
)
445 LOAD_FUNCPTR( gss_release_cred
)
446 LOAD_FUNCPTR( gss_release_iov_buffer
)
447 LOAD_FUNCPTR( gss_release_name
)
448 LOAD_FUNCPTR( gss_unwrap
)
449 LOAD_FUNCPTR( gss_unwrap_iov
)
450 LOAD_FUNCPTR( gss_verify_mic
)
451 LOAD_FUNCPTR( gss_wrap
)
452 LOAD_FUNCPTR( gss_wrap_iov
)
457 dlclose( libgssapi_krb5_handle
);
458 libgssapi_krb5_handle
= NULL
;
462 static BOOL
is_dce_style_context( gss_ctx_id_t ctx
)
464 OM_uint32 ret
, minor_status
, flags
;
465 ret
= pgss_inquire_context( &minor_status
, ctx
, NULL
, NULL
, NULL
, NULL
, &flags
, NULL
, NULL
);
466 return (ret
== GSS_S_COMPLETE
&& (flags
& GSS_C_DCE_STYLE
));
469 static NTSTATUS
status_gss_to_sspi( OM_uint32 status
)
473 case GSS_S_COMPLETE
: return SEC_E_OK
;
474 case GSS_S_BAD_MECH
: return SEC_E_SECPKG_NOT_FOUND
;
475 case GSS_S_BAD_SIG
: return SEC_E_MESSAGE_ALTERED
;
476 case GSS_S_NO_CRED
: return SEC_E_NO_CREDENTIALS
;
477 case GSS_S_NO_CONTEXT
: return SEC_E_INVALID_HANDLE
;
478 case GSS_S_DEFECTIVE_TOKEN
: return SEC_E_INVALID_TOKEN
;
479 case GSS_S_DEFECTIVE_CREDENTIAL
: return SEC_E_NO_CREDENTIALS
;
480 case GSS_S_CREDENTIALS_EXPIRED
: return SEC_E_CONTEXT_EXPIRED
;
481 case GSS_S_CONTEXT_EXPIRED
: return SEC_E_CONTEXT_EXPIRED
;
482 case GSS_S_BAD_QOP
: return SEC_E_QOP_NOT_SUPPORTED
;
483 case GSS_S_CONTINUE_NEEDED
: return SEC_I_CONTINUE_NEEDED
;
484 case GSS_S_DUPLICATE_TOKEN
: return SEC_E_INVALID_TOKEN
;
485 case GSS_S_OLD_TOKEN
: return SEC_E_INVALID_TOKEN
;
486 case GSS_S_UNSEQ_TOKEN
: return SEC_E_OUT_OF_SEQUENCE
;
487 case GSS_S_GAP_TOKEN
: return SEC_E_OUT_OF_SEQUENCE
;
488 case GSS_S_FAILURE
: return SEC_E_INTERNAL_ERROR
;
491 FIXME( "couldn't convert status %#x to NTSTATUS\n", status
);
492 return SEC_E_INTERNAL_ERROR
;
496 static void trace_gss_status_ex( OM_uint32 code
, int type
)
498 OM_uint32 ret
, minor_status
;
500 OM_uint32 msg_ctx
= 0;
504 ret
= pgss_display_status( &minor_status
, code
, type
, GSS_C_NULL_OID
, &msg_ctx
, &buf
);
505 if (GSS_ERROR( ret
))
507 TRACE( "gss_display_status(%#x, %d) returned %#x minor status %#x\n", code
, type
, ret
, minor_status
);
510 TRACE( "GSS-API error: %#x: %s\n", code
, debugstr_an(buf
.value
, buf
.length
) );
511 pgss_release_buffer( &minor_status
, &buf
);
512 if (!msg_ctx
) return;
516 static void trace_gss_status( OM_uint32 major_status
, OM_uint32 minor_status
)
518 if (TRACE_ON(kerberos
))
520 trace_gss_status_ex( major_status
, GSS_C_GSS_CODE
);
521 trace_gss_status_ex( minor_status
, GSS_C_MECH_CODE
);
525 static inline gss_ctx_id_t
ctxhandle_sspi_to_gss( UINT64 handle
)
527 return (gss_ctx_id_t
)(ULONG_PTR
)handle
;
530 static inline gss_cred_id_t
credhandle_sspi_to_gss( UINT64 handle
)
532 return (gss_cred_id_t
)(ULONG_PTR
)handle
;
535 static inline void ctxhandle_gss_to_sspi( gss_ctx_id_t handle
, UINT64
*ctx
)
537 *ctx
= (ULONG_PTR
)handle
;
540 static inline void credhandle_gss_to_sspi( gss_cred_id_t handle
, UINT64
*cred
)
542 *cred
= (ULONG_PTR
)handle
;
545 static ULONG
flags_gss_to_asc_ret( ULONG flags
)
548 if (flags
& GSS_C_DELEG_FLAG
) ret
|= ASC_RET_DELEGATE
;
549 if (flags
& GSS_C_MUTUAL_FLAG
) ret
|= ASC_RET_MUTUAL_AUTH
;
550 if (flags
& GSS_C_REPLAY_FLAG
) ret
|= ASC_RET_REPLAY_DETECT
;
551 if (flags
& GSS_C_SEQUENCE_FLAG
) ret
|= ASC_RET_SEQUENCE_DETECT
;
552 if (flags
& GSS_C_CONF_FLAG
) ret
|= ASC_RET_CONFIDENTIALITY
;
553 if (flags
& GSS_C_INTEG_FLAG
) ret
|= ASC_RET_INTEGRITY
;
554 if (flags
& GSS_C_ANON_FLAG
) ret
|= ASC_RET_NULL_SESSION
;
555 if (flags
& GSS_C_DCE_STYLE
) ret
|= ASC_RET_USED_DCE_STYLE
;
556 if (flags
& GSS_C_IDENTIFY_FLAG
) ret
|= ASC_RET_IDENTIFY
;
560 static NTSTATUS
accept_context( void *args
)
562 struct accept_context_params
*params
= args
;
563 OM_uint32 ret
, minor_status
, ret_flags
= 0, expiry_time
;
564 gss_cred_id_t cred_handle
= credhandle_sspi_to_gss( params
->credential
);
565 gss_ctx_id_t ctx_handle
= ctxhandle_sspi_to_gss( params
->context
);
566 gss_buffer_desc input_token
, output_token
;
568 input_token
.length
= params
->input_token_length
;
569 input_token
.value
= params
->input_token
;
570 output_token
.length
= 0;
571 output_token
.value
= NULL
;
573 ret
= pgss_accept_sec_context( &minor_status
, &ctx_handle
, cred_handle
, &input_token
, GSS_C_NO_CHANNEL_BINDINGS
,
574 NULL
, NULL
, &output_token
, &ret_flags
, &expiry_time
, NULL
);
575 TRACE( "gss_accept_sec_context returned %#x minor status %#x ret_flags %#x\n", ret
, minor_status
, ret_flags
);
576 if (GSS_ERROR( ret
)) trace_gss_status( ret
, minor_status
);
577 if (ret
== GSS_S_COMPLETE
|| ret
== GSS_S_CONTINUE_NEEDED
)
579 if (output_token
.length
> *params
->output_token_length
) /* FIXME: check if larger buffer exists */
581 TRACE( "buffer too small %lu > %u\n",
582 (SIZE_T
)output_token
.length
, (unsigned int)*params
->output_token_length
);
583 pgss_release_buffer( &minor_status
, &output_token
);
584 pgss_delete_sec_context( &minor_status
, &ctx_handle
, GSS_C_NO_BUFFER
);
585 return SEC_E_BUFFER_TOO_SMALL
;
587 *params
->output_token_length
= output_token
.length
;
588 memcpy( params
->output_token
, output_token
.value
, output_token
.length
);
589 pgss_release_buffer( &minor_status
, &output_token
);
591 ctxhandle_gss_to_sspi( ctx_handle
, params
->new_context
);
592 if (params
->context_attr
) *params
->context_attr
= flags_gss_to_asc_ret( ret_flags
);
593 *params
->expiry
= expiry_time
;
596 return status_gss_to_sspi( ret
);
599 static NTSTATUS
init_creds( const char *user_at_domain
, const char *password
)
602 krb5_principal principal
= NULL
;
603 krb5_get_init_creds_opt
*options
= NULL
;
604 krb5_ccache cache
= NULL
;
608 if (!user_at_domain
) return STATUS_SUCCESS
;
609 if ((err
= p_krb5_init_context( &ctx
))) return krb5_error_to_status( err
);
610 if ((err
= p_krb5_parse_name_flags( ctx
, user_at_domain
, 0, &principal
))) goto done
;
611 if ((err
= p_krb5_cc_default( ctx
, &cache
))) goto done
;
612 if ((err
= p_krb5_get_init_creds_opt_alloc( ctx
, &options
))) goto done
;
613 if ((err
= p_krb5_get_init_creds_opt_set_out_ccache( ctx
, options
, cache
))) goto done
;
614 if ((err
= p_krb5_get_init_creds_password( ctx
, &creds
, principal
, password
, 0, NULL
, 0, NULL
, 0 ))) goto done
;
615 if ((err
= p_krb5_cc_initialize( ctx
, cache
, principal
))) goto done
;
616 if ((err
= p_krb5_cc_store_cred( ctx
, cache
, &creds
))) goto done
;
618 TRACE( "success\n" );
619 p_krb5_free_cred_contents( ctx
, &creds
);
622 if (cache
) p_krb5_cc_close( ctx
, cache
);
623 if (principal
) p_krb5_free_principal( ctx
, principal
);
624 if (options
) p_krb5_get_init_creds_opt_free( ctx
, options
);
625 p_krb5_free_context( ctx
);
626 return krb5_error_to_status( err
);
629 static NTSTATUS
import_name( const char *src
, gss_name_t
*dst
)
631 OM_uint32 ret
, minor_status
;
634 buf
.length
= strlen( src
);
635 buf
.value
= (void *)src
;
636 ret
= pgss_import_name( &minor_status
, &buf
, GSS_C_NO_OID
, dst
);
637 TRACE( "gss_import_name returned %#x minor status %#x\n", ret
, minor_status
);
638 if (GSS_ERROR( ret
)) trace_gss_status( ret
, minor_status
);
639 return status_gss_to_sspi( ret
);
642 static NTSTATUS
acquire_credentials_handle( void *args
)
644 struct acquire_credentials_handle_params
*params
= args
;
645 OM_uint32 ret
, minor_status
, expiry_time
;
646 gss_name_t name
= GSS_C_NO_NAME
;
647 gss_cred_usage_t cred_usage
;
648 gss_cred_id_t cred_handle
;
651 switch (params
->credential_use
)
653 case SECPKG_CRED_INBOUND
:
654 cred_usage
= GSS_C_ACCEPT
;
657 case SECPKG_CRED_OUTBOUND
:
658 if ((status
= init_creds( params
->username
, params
->password
)) != STATUS_SUCCESS
) return status
;
659 cred_usage
= GSS_C_INITIATE
;
663 FIXME( "SECPKG_CRED_BOTH not supported\n" );
664 return SEC_E_UNKNOWN_CREDENTIALS
;
667 if (params
->principal
&& (status
= import_name( params
->principal
, &name
))) return status
;
669 ret
= pgss_acquire_cred( &minor_status
, name
, GSS_C_INDEFINITE
, GSS_C_NULL_OID_SET
, cred_usage
, &cred_handle
,
670 NULL
, &expiry_time
);
671 TRACE( "gss_acquire_cred returned %#x minor status %#x\n", ret
, minor_status
);
672 if (GSS_ERROR( ret
)) trace_gss_status( ret
, minor_status
);
673 if (ret
== GSS_S_COMPLETE
)
675 credhandle_gss_to_sspi( cred_handle
, params
->credential
);
676 *params
->expiry
= expiry_time
;
679 if (name
!= GSS_C_NO_NAME
) pgss_release_name( &minor_status
, &name
);
680 return status_gss_to_sspi( ret
);
683 static NTSTATUS
delete_context( void *args
)
685 const struct delete_context_params
*params
= args
;
686 OM_uint32 ret
, minor_status
;
687 gss_ctx_id_t ctx_handle
= ctxhandle_sspi_to_gss( params
->context
);
689 ret
= pgss_delete_sec_context( &minor_status
, &ctx_handle
, GSS_C_NO_BUFFER
);
690 TRACE( "gss_delete_sec_context returned %#x minor status %#x\n", ret
, minor_status
);
691 if (GSS_ERROR( ret
)) trace_gss_status( ret
, minor_status
);
692 return status_gss_to_sspi( ret
);
695 static NTSTATUS
free_credentials_handle( void *args
)
697 const struct free_credentials_handle_params
*params
= args
;
698 OM_uint32 ret
, minor_status
;
699 gss_cred_id_t cred
= credhandle_sspi_to_gss( params
->credential
);
701 ret
= pgss_release_cred( &minor_status
, &cred
);
702 TRACE( "gss_release_cred returned %#x minor status %#x\n", ret
, minor_status
);
703 if (GSS_ERROR( ret
)) trace_gss_status( ret
, minor_status
);
704 return status_gss_to_sspi( ret
);
707 static ULONG
flags_isc_req_to_gss( ULONG flags
)
710 if (flags
& ISC_REQ_DELEGATE
) ret
|= GSS_C_DELEG_FLAG
;
711 if (flags
& ISC_REQ_MUTUAL_AUTH
) ret
|= GSS_C_MUTUAL_FLAG
;
712 if (flags
& ISC_REQ_REPLAY_DETECT
) ret
|= GSS_C_REPLAY_FLAG
;
713 if (flags
& ISC_REQ_SEQUENCE_DETECT
) ret
|= GSS_C_SEQUENCE_FLAG
;
714 if (flags
& ISC_REQ_CONFIDENTIALITY
) ret
|= GSS_C_CONF_FLAG
;
715 if (flags
& ISC_REQ_INTEGRITY
) ret
|= GSS_C_INTEG_FLAG
;
716 if (flags
& ISC_REQ_NULL_SESSION
) ret
|= GSS_C_ANON_FLAG
;
717 if (flags
& ISC_REQ_USE_DCE_STYLE
) ret
|= GSS_C_DCE_STYLE
;
718 if (flags
& ISC_REQ_IDENTIFY
) ret
|= GSS_C_IDENTIFY_FLAG
;
722 static ULONG
flags_gss_to_isc_ret( ULONG flags
)
725 if (flags
& GSS_C_DELEG_FLAG
) ret
|= ISC_RET_DELEGATE
;
726 if (flags
& GSS_C_MUTUAL_FLAG
) ret
|= ISC_RET_MUTUAL_AUTH
;
727 if (flags
& GSS_C_REPLAY_FLAG
) ret
|= ISC_RET_REPLAY_DETECT
;
728 if (flags
& GSS_C_SEQUENCE_FLAG
) ret
|= ISC_RET_SEQUENCE_DETECT
;
729 if (flags
& GSS_C_CONF_FLAG
) ret
|= ISC_RET_CONFIDENTIALITY
;
730 if (flags
& GSS_C_INTEG_FLAG
) ret
|= ISC_RET_INTEGRITY
;
731 if (flags
& GSS_C_ANON_FLAG
) ret
|= ISC_RET_NULL_SESSION
;
732 if (flags
& GSS_C_DCE_STYLE
) ret
|= ISC_RET_USED_DCE_STYLE
;
733 if (flags
& GSS_C_IDENTIFY_FLAG
) ret
|= ISC_RET_IDENTIFY
;
737 static NTSTATUS
initialize_context( void *args
)
739 struct initialize_context_params
*params
= args
;
740 OM_uint32 ret
, minor_status
, ret_flags
= 0, expiry_time
, req_flags
= flags_isc_req_to_gss( params
->context_req
);
741 gss_cred_id_t cred_handle
= credhandle_sspi_to_gss( params
->credential
);
742 gss_ctx_id_t ctx_handle
= ctxhandle_sspi_to_gss( params
->context
);
743 gss_buffer_desc input_token
, output_token
;
744 gss_name_t target
= GSS_C_NO_NAME
;
747 input_token
.length
= params
->input_token_length
;
748 input_token
.value
= params
->input_token
;
749 output_token
.length
= 0;
750 output_token
.value
= NULL
;
752 if (params
->target_name
&& (status
= import_name( params
->target_name
, &target
))) return status
;
754 ret
= pgss_init_sec_context( &minor_status
, cred_handle
, &ctx_handle
, target
, GSS_C_NO_OID
, req_flags
, 0,
755 GSS_C_NO_CHANNEL_BINDINGS
, &input_token
, NULL
, &output_token
, &ret_flags
,
757 TRACE( "gss_init_sec_context returned %#x minor status %#x ret_flags %#x\n", ret
, minor_status
, ret_flags
);
758 if (GSS_ERROR( ret
)) trace_gss_status( ret
, minor_status
);
759 if (ret
== GSS_S_COMPLETE
|| ret
== GSS_S_CONTINUE_NEEDED
)
761 if (output_token
.length
> *params
->output_token_length
) /* FIXME: check if larger buffer exists */
763 TRACE( "buffer too small %lu > %u\n", (SIZE_T
)output_token
.length
, (unsigned int)*params
->output_token_length
);
764 pgss_release_buffer( &minor_status
, &output_token
);
765 pgss_delete_sec_context( &minor_status
, &ctx_handle
, GSS_C_NO_BUFFER
);
766 return SEC_E_INCOMPLETE_MESSAGE
;
768 *params
->output_token_length
= output_token
.length
;
769 memcpy( params
->output_token
, output_token
.value
, output_token
.length
);
770 pgss_release_buffer( &minor_status
, &output_token
);
772 ctxhandle_gss_to_sspi( ctx_handle
, params
->new_context
);
773 if (params
->context_attr
) *params
->context_attr
= flags_gss_to_isc_ret( ret_flags
);
774 *params
->expiry
= expiry_time
;
777 if (target
!= GSS_C_NO_NAME
) pgss_release_name( &minor_status
, &target
);
778 return status_gss_to_sspi( ret
);
781 static NTSTATUS
make_signature( void *args
)
783 struct make_signature_params
*params
= args
;
784 OM_uint32 ret
, minor_status
;
785 gss_buffer_desc data_buffer
, token_buffer
;
786 gss_ctx_id_t ctx_handle
= ctxhandle_sspi_to_gss( params
->context
);
788 data_buffer
.length
= params
->data_length
;
789 data_buffer
.value
= params
->data
;
790 token_buffer
.length
= 0;
791 token_buffer
.value
= NULL
;
793 ret
= pgss_get_mic( &minor_status
, ctx_handle
, GSS_C_QOP_DEFAULT
, &data_buffer
, &token_buffer
);
794 TRACE( "gss_get_mic returned %#x minor status %#x\n", ret
, minor_status
);
795 if (GSS_ERROR( ret
)) trace_gss_status( ret
, minor_status
);
796 if (ret
== GSS_S_COMPLETE
)
798 memcpy( params
->token
, token_buffer
.value
, token_buffer
.length
);
799 *params
->token_length
= token_buffer
.length
;
800 pgss_release_buffer( &minor_status
, &token_buffer
);
803 return status_gss_to_sspi( ret
);
806 #define KERBEROS_MAX_SIGNATURE 37
807 #define KERBEROS_SECURITY_TRAILER 49
808 #define KERBEROS_MAX_SIGNATURE_DCE 28
809 #define KERBEROS_SECURITY_TRAILER_DCE 76
811 static NTSTATUS
get_session_key( gss_ctx_id_t ctx
, SecPkgContext_SessionKey
*key
)
813 gss_OID_desc GSS_C_INQ_SSPI_SESSION_KEY
=
814 { 11, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x05" }; /* 1.2.840.113554.1.2.2.5.5 */
815 OM_uint32 ret
, minor_status
;
816 gss_buffer_set_t buffer_set
= GSS_C_NO_BUFFER_SET
;
818 ret
= pgss_inquire_sec_context_by_oid( &minor_status
, ctx
, &GSS_C_INQ_SSPI_SESSION_KEY
, &buffer_set
);
819 if (GSS_ERROR( ret
)) trace_gss_status( ret
, minor_status
);
820 if (ret
!= GSS_S_COMPLETE
) return STATUS_INTERNAL_ERROR
;
822 if (buffer_set
== GSS_C_NO_BUFFER_SET
|| buffer_set
->count
!= 2)
824 pgss_release_buffer_set( &minor_status
, &buffer_set
);
825 return STATUS_INTERNAL_ERROR
;
828 if (key
->SessionKeyLength
< buffer_set
->elements
[0].length
)
830 key
->SessionKeyLength
= buffer_set
->elements
[0].length
;
831 pgss_release_buffer_set( &minor_status
, &buffer_set
);
832 return STATUS_BUFFER_TOO_SMALL
;
835 memcpy( key
->SessionKey
, buffer_set
->elements
[0].value
, buffer_set
->elements
[0].length
);
836 key
->SessionKeyLength
= buffer_set
->elements
[0].length
;
838 pgss_release_buffer_set( &minor_status
, &buffer_set
);
839 return STATUS_SUCCESS
;
842 static NTSTATUS
query_context_attributes( void *args
)
844 struct query_context_attributes_params
*params
= args
;
845 switch (params
->attr
)
847 case SECPKG_ATTR_SESSION_KEY
:
849 SecPkgContext_SessionKey
*key
= (SecPkgContext_SessionKey
*)params
->buf
;
850 gss_ctx_id_t ctx
= ctxhandle_sspi_to_gss( params
->context
);
852 return get_session_key( ctx
, key
);
854 case SECPKG_ATTR_SIZES
:
856 SecPkgContext_Sizes
*sizes
= (SecPkgContext_Sizes
*)params
->buf
;
857 ULONG size_max_signature
, size_security_trailer
;
858 gss_ctx_id_t ctx
= ctxhandle_sspi_to_gss( params
->context
);
860 if (is_dce_style_context( ctx
))
862 size_max_signature
= KERBEROS_MAX_SIGNATURE_DCE
;
863 size_security_trailer
= KERBEROS_SECURITY_TRAILER_DCE
;
867 size_max_signature
= KERBEROS_MAX_SIGNATURE
;
868 size_security_trailer
= KERBEROS_SECURITY_TRAILER
;
870 sizes
->cbMaxToken
= KERBEROS_MAX_BUF
;
871 sizes
->cbMaxSignature
= size_max_signature
;
872 sizes
->cbBlockSize
= 1;
873 sizes
->cbSecurityTrailer
= size_security_trailer
;
877 FIXME( "unhandled attribute %u\n", params
->attr
);
881 return SEC_E_UNSUPPORTED_FUNCTION
;
884 static NTSTATUS
seal_message_vector( gss_ctx_id_t ctx
, const struct seal_message_params
*params
)
886 gss_iov_buffer_desc iov
[4];
887 OM_uint32 ret
, minor_status
;
888 int conf_flag
, conf_state
;
891 conf_flag
= 1; /* confidentiality + integrity */
892 else if (params
->qop
== SECQOP_WRAP_NO_ENCRYPT
)
893 conf_flag
= 0; /* only integrity */
896 FIXME( "QOP %#x not supported\n", params
->qop
);
897 return SEC_E_UNSUPPORTED_FUNCTION
;
900 iov
[0].type
= GSS_IOV_BUFFER_TYPE_SIGN_ONLY
| GSS_IOV_BUFFER_FLAG_ALLOCATE
;
901 iov
[0].buffer
.length
= 0;
902 iov
[0].buffer
.value
= NULL
;
904 iov
[1].type
= GSS_IOV_BUFFER_TYPE_DATA
;
905 iov
[1].buffer
.length
= params
->data_length
;
906 iov
[1].buffer
.value
= params
->data
;
908 iov
[2].type
= GSS_IOV_BUFFER_TYPE_SIGN_ONLY
| GSS_IOV_BUFFER_FLAG_ALLOCATE
;
909 iov
[2].buffer
.length
= 0;
910 iov
[2].buffer
.value
= NULL
;
912 iov
[3].type
= GSS_IOV_BUFFER_TYPE_HEADER
| GSS_IOV_BUFFER_FLAG_ALLOCATE
;
913 iov
[3].buffer
.length
= 0;
914 iov
[3].buffer
.value
= NULL
;
916 ret
= pgss_wrap_iov( &minor_status
, ctx
, conf_flag
, GSS_C_QOP_DEFAULT
, &conf_state
, iov
, 4 );
917 TRACE( "gss_wrap_iov returned %#x minor status %#x\n", ret
, minor_status
);
918 if (GSS_ERROR( ret
)) trace_gss_status( ret
, minor_status
);
919 if (ret
== GSS_S_COMPLETE
)
921 memcpy( params
->token
, iov
[3].buffer
.value
, iov
[3].buffer
.length
);
922 *params
->token_length
= iov
[3].buffer
.length
;
923 pgss_release_iov_buffer( &minor_status
, iov
, 4 );
926 return status_gss_to_sspi( ret
);
929 static NTSTATUS
seal_message_no_vector( gss_ctx_id_t ctx
, const struct seal_message_params
*params
)
931 gss_buffer_desc input
, output
;
932 OM_uint32 ret
, minor_status
;
933 int conf_flag
, conf_state
;
936 conf_flag
= 1; /* confidentiality + integrity */
937 else if (params
->qop
== SECQOP_WRAP_NO_ENCRYPT
)
938 conf_flag
= 0; /* only integrity */
941 FIXME( "QOP %#x not supported\n", params
->qop
);
942 return SEC_E_UNSUPPORTED_FUNCTION
;
945 input
.length
= params
->data_length
;
946 input
.value
= params
->data
;
948 ret
= pgss_wrap( &minor_status
, ctx
, conf_flag
, GSS_C_QOP_DEFAULT
, &input
, &conf_state
, &output
);
949 TRACE( "gss_wrap returned %#x minor status %#x\n", ret
, minor_status
);
950 if (GSS_ERROR( ret
)) trace_gss_status( ret
, minor_status
);
951 if (ret
== GSS_S_COMPLETE
)
953 unsigned len_data
= params
->data_length
, len_token
= *params
->token_length
;
954 if (len_token
< output
.length
- len_data
)
956 TRACE( "buffer too small %lu > %u\n", (SIZE_T
)output
.length
- len_data
, len_token
);
957 pgss_release_buffer( &minor_status
, &output
);
958 return SEC_E_BUFFER_TOO_SMALL
;
960 memcpy( params
->data
, output
.value
, len_data
);
961 memcpy( params
->token
, (char *)output
.value
+ len_data
, output
.length
- len_data
);
962 *params
->token_length
= output
.length
- len_data
;
963 pgss_release_buffer( &minor_status
, &output
);
966 return status_gss_to_sspi( ret
);
969 static NTSTATUS
seal_message( void *args
)
971 struct seal_message_params
*params
= args
;
972 gss_ctx_id_t ctx
= ctxhandle_sspi_to_gss( params
->context
);
974 if (is_dce_style_context( ctx
)) return seal_message_vector( ctx
, params
);
975 return seal_message_no_vector( ctx
, params
);
978 static NTSTATUS
unseal_message_vector( gss_ctx_id_t ctx
, const struct unseal_message_params
*params
)
980 gss_iov_buffer_desc iov
[4];
981 OM_uint32 ret
, minor_status
;
984 iov
[0].type
= GSS_IOV_BUFFER_TYPE_SIGN_ONLY
;
985 iov
[0].buffer
.length
= 0;
986 iov
[0].buffer
.value
= NULL
;
988 iov
[1].type
= GSS_IOV_BUFFER_TYPE_DATA
;
989 iov
[1].buffer
.length
= params
->data_length
;
990 iov
[1].buffer
.value
= params
->data
;
992 iov
[2].type
= GSS_IOV_BUFFER_TYPE_SIGN_ONLY
;
993 iov
[2].buffer
.length
= 0;
994 iov
[2].buffer
.value
= NULL
;
996 iov
[3].type
= GSS_IOV_BUFFER_TYPE_HEADER
;
997 iov
[3].buffer
.length
= params
->token_length
;
998 iov
[3].buffer
.value
= params
->token
;
1000 ret
= pgss_unwrap_iov( &minor_status
, ctx
, &conf_state
, NULL
, iov
, 4 );
1001 TRACE( "gss_unwrap_iov returned %#x minor status %#x\n", ret
, minor_status
);
1002 if (GSS_ERROR( ret
)) trace_gss_status( ret
, minor_status
);
1003 if (ret
== GSS_S_COMPLETE
&& params
->qop
)
1005 *params
->qop
= (conf_state
? 0 : SECQOP_WRAP_NO_ENCRYPT
);
1007 return status_gss_to_sspi( ret
);
1010 static NTSTATUS
unseal_message_no_vector( gss_ctx_id_t ctx
, const struct unseal_message_params
*params
)
1012 gss_buffer_desc input
, output
;
1013 OM_uint32 ret
, minor_status
;
1014 DWORD len_data
, len_token
;
1017 len_data
= params
->data_length
;
1018 len_token
= params
->token_length
;
1020 input
.length
= len_data
+ len_token
;
1021 if (!(input
.value
= malloc( input
.length
))) return SEC_E_INSUFFICIENT_MEMORY
;
1022 memcpy( input
.value
, params
->data
, len_data
);
1023 memcpy( (char *)input
.value
+ len_data
, params
->token
, len_token
);
1025 ret
= pgss_unwrap( &minor_status
, ctx
, &input
, &output
, &conf_state
, NULL
);
1026 free( input
.value
);
1027 TRACE( "gss_unwrap returned %#x minor status %#x\n", ret
, minor_status
);
1028 if (GSS_ERROR( ret
)) trace_gss_status( ret
, minor_status
);
1029 if (ret
== GSS_S_COMPLETE
)
1031 if (params
->qop
) *params
->qop
= (conf_state
? 0 : SECQOP_WRAP_NO_ENCRYPT
);
1032 memcpy( params
->data
, output
.value
, len_data
);
1033 pgss_release_buffer( &minor_status
, &output
);
1036 return status_gss_to_sspi( ret
);
1039 static NTSTATUS
unseal_message( void *args
)
1041 struct unseal_message_params
*params
= args
;
1042 gss_ctx_id_t ctx
= ctxhandle_sspi_to_gss( params
->context
);
1044 if (is_dce_style_context( ctx
)) return unseal_message_vector( ctx
, params
);
1045 return unseal_message_no_vector( ctx
, params
);
1048 static NTSTATUS
verify_signature( void *args
)
1050 struct verify_signature_params
*params
= args
;
1051 OM_uint32 ret
, minor_status
;
1052 gss_buffer_desc data_buffer
, token_buffer
;
1053 gss_ctx_id_t ctx_handle
= ctxhandle_sspi_to_gss( params
->context
);
1055 data_buffer
.length
= params
->data_length
;
1056 data_buffer
.value
= params
->data
;
1057 token_buffer
.length
= params
->token_length
;
1058 token_buffer
.value
= params
->token
;
1060 ret
= pgss_verify_mic( &minor_status
, ctx_handle
, &data_buffer
, &token_buffer
, NULL
);
1061 TRACE( "gss_verify_mic returned %#x minor status %#x\n", ret
, minor_status
);
1062 if (GSS_ERROR( ret
)) trace_gss_status( ret
, minor_status
);
1063 if (ret
== GSS_S_COMPLETE
&& params
->qop
) *params
->qop
= 0;
1065 return status_gss_to_sspi( ret
);
1068 static NTSTATUS
process_attach( void *args
)
1070 if (load_krb5() && load_gssapi_krb5()) return STATUS_SUCCESS
;
1071 if (libkrb5_handle
) unload_krb5();
1072 return STATUS_DLL_NOT_FOUND
;
1075 const unixlib_entry_t __wine_unix_call_funcs
[] =
1079 acquire_credentials_handle
,
1081 free_credentials_handle
,
1084 query_context_attributes
,
1091 C_ASSERT( ARRAYSIZE(__wine_unix_call_funcs
) == unix_funcs_count
);
1095 typedef ULONG PTR32
;
1097 static NTSTATUS
wow64_accept_context( void *args
)
1104 ULONG input_token_length
;
1107 PTR32 output_token_length
;
1110 } const *params32
= args
;
1111 struct accept_context_params params
=
1113 params32
->credential
,
1115 ULongToPtr(params32
->input_token
),
1116 params32
->input_token_length
,
1117 ULongToPtr(params32
->new_context
),
1118 ULongToPtr(params32
->output_token
),
1119 ULongToPtr(params32
->output_token_length
),
1120 ULongToPtr(params32
->context_attr
),
1121 ULongToPtr(params32
->expiry
),
1123 return accept_context( ¶ms
);
1126 static NTSTATUS
wow64_acquire_credentials_handle( void *args
)
1131 ULONG credential_use
;
1136 } const *params32
= args
;
1137 struct acquire_credentials_handle_params params
=
1139 ULongToPtr(params32
->principal
),
1140 params32
->credential_use
,
1141 ULongToPtr(params32
->username
),
1142 ULongToPtr(params32
->password
),
1143 ULongToPtr(params32
->credential
),
1144 ULongToPtr(params32
->expiry
),
1146 return acquire_credentials_handle( ¶ms
);
1149 static NTSTATUS
wow64_delete_context( void *args
)
1154 } const *params32
= args
;
1155 struct delete_context_params params
=
1159 return delete_context( ¶ms
);
1162 static NTSTATUS
wow64_free_credentials_handle( void *args
)
1167 } const *params32
= args
;
1168 struct free_credentials_handle_params params
=
1170 params32
->credential
,
1172 return free_credentials_handle( ¶ms
);
1175 static NTSTATUS
wow64_initialize_context( void *args
)
1184 ULONG input_token_length
;
1186 PTR32 output_token_length
;
1190 } const *params32
= args
;
1191 struct initialize_context_params params
=
1193 params32
->credential
,
1195 ULongToPtr(params32
->target_name
),
1196 params32
->context_req
,
1197 ULongToPtr(params32
->input_token
),
1198 params32
->input_token_length
,
1199 ULongToPtr(params32
->output_token
),
1200 ULongToPtr(params32
->output_token_length
),
1201 ULongToPtr(params32
->new_context
),
1202 ULongToPtr(params32
->context_attr
),
1203 ULongToPtr(params32
->expiry
),
1205 return initialize_context( ¶ms
);
1208 static NTSTATUS
wow64_make_signature( void *args
)
1217 } const *params32
= args
;
1218 struct make_signature_params params
=
1221 ULongToPtr(params32
->data
),
1222 params32
->data_length
,
1223 ULongToPtr(params32
->token
),
1224 ULongToPtr(params32
->token_length
),
1226 return make_signature( ¶ms
);
1229 static NTSTATUS
wow64_query_context_attributes( void *args
)
1236 } const *params32
= args
;
1237 struct query_context_attributes_params params
=
1241 ULongToPtr(params32
->buf
),
1243 return query_context_attributes( ¶ms
);
1246 struct KERB_TICKET_CACHE_INFO_EX32
1248 UNICODE_STRING32 ClientName
;
1249 UNICODE_STRING32 ClientRealm
;
1250 UNICODE_STRING32 ServerName
;
1251 UNICODE_STRING32 ServerRealm
;
1252 LARGE_INTEGER StartTime
;
1253 LARGE_INTEGER EndTime
;
1254 LARGE_INTEGER RenewTime
;
1255 LONG EncryptionType
;
1259 struct KERB_QUERY_TKT_CACHE_EX_RESPONSE32
1261 KERB_PROTOCOL_MESSAGE_TYPE MessageType
;
1262 ULONG CountOfTickets
;
1263 struct KERB_TICKET_CACHE_INFO_EX32 Tickets
[ANYSIZE_ARRAY
];
1266 static void copy_ticket_ustr_64to32( const UNICODE_STRING
*str
, UNICODE_STRING32
*str32
, ULONG
*client_str
)
1268 str32
->Length
= str
->Length
;
1269 str32
->MaximumLength
= str
->MaximumLength
;
1270 str32
->Buffer
= *client_str
;
1271 memcpy( ULongToPtr(str32
->Buffer
), str
->Buffer
, str
->MaximumLength
);
1272 *client_str
+= str
->MaximumLength
;
1275 static NTSTATUS
copy_tickets_to_client32( struct ticket_list
*list
, struct KERB_QUERY_TKT_CACHE_EX_RESPONSE32
*resp
,
1278 ULONG i
, size
, size_fixed
;
1281 size
= size_fixed
= offsetof( struct KERB_QUERY_TKT_CACHE_EX_RESPONSE32
, Tickets
[list
->count
] );
1282 for (i
= 0; i
< list
->count
; i
++)
1284 size
+= list
->tickets
[i
].ServerRealm
.MaximumLength
;
1285 size
+= list
->tickets
[i
].ServerName
.MaximumLength
;
1287 if (!resp
|| size
> *out_size
)
1290 return STATUS_BUFFER_TOO_SMALL
;
1294 resp
->MessageType
= KerbQueryTicketCacheMessage
;
1295 resp
->CountOfTickets
= list
->count
;
1296 client_str
= PtrToUlong(resp
) + size_fixed
;
1298 for (i
= 0; i
< list
->count
; i
++)
1300 copy_ticket_ustr_64to32( &list
->tickets
[i
].ServerName
, &resp
->Tickets
[i
].ServerName
, &client_str
);
1301 copy_ticket_ustr_64to32( &list
->tickets
[i
].ServerRealm
, &resp
->Tickets
[i
].ServerRealm
, &client_str
);
1302 resp
->Tickets
[i
].StartTime
= list
->tickets
[i
].StartTime
;
1303 resp
->Tickets
[i
].EndTime
= list
->tickets
[i
].EndTime
;
1304 resp
->Tickets
[i
].RenewTime
= list
->tickets
[i
].RenewTime
;
1305 resp
->Tickets
[i
].EncryptionType
= list
->tickets
[i
].EncryptionType
;
1306 resp
->Tickets
[i
].TicketFlags
= list
->tickets
[i
].TicketFlags
;
1308 return STATUS_SUCCESS
;
1311 static NTSTATUS
wow64_query_ticket_cache( void *args
)
1317 } const *params32
= args
;
1318 struct ticket_list list
= { 0 };
1321 status
= kerberos_fill_ticket_list( &list
);
1322 if (status
== STATUS_SUCCESS
)
1323 status
= copy_tickets_to_client32( &list
, ULongToPtr(params32
->resp
), ULongToPtr(params32
->out_size
) );
1325 free_tickets_in_list( &list
);
1330 static NTSTATUS
wow64_seal_message( void *args
)
1339 } const *params32
= args
;
1340 struct seal_message_params params
=
1343 ULongToPtr(params32
->data
),
1344 params32
->data_length
,
1345 ULongToPtr(params32
->token
),
1346 ULongToPtr(params32
->token_length
),
1348 return seal_message( ¶ms
);
1351 static NTSTATUS
wow64_unseal_message( void *args
)
1361 } const *params32
= args
;
1362 struct unseal_message_params params
=
1365 ULongToPtr(params32
->data
),
1366 params32
->data_length
,
1367 ULongToPtr(params32
->token
),
1368 params32
->token_length
,
1369 ULongToPtr(params32
->qop
),
1371 return unseal_message( ¶ms
);
1374 static NTSTATUS
wow64_verify_signature( void *args
)
1384 } const *params32
= args
;
1385 struct verify_signature_params params
=
1388 ULongToPtr(params32
->data
),
1389 params32
->data_length
,
1390 ULongToPtr(params32
->token
),
1391 params32
->token_length
,
1392 ULongToPtr(params32
->qop
),
1394 return verify_signature( ¶ms
);
1397 const unixlib_entry_t __wine_unix_call_wow64_funcs
[] =
1400 wow64_accept_context
,
1401 wow64_acquire_credentials_handle
,
1402 wow64_delete_context
,
1403 wow64_free_credentials_handle
,
1404 wow64_initialize_context
,
1405 wow64_make_signature
,
1406 wow64_query_context_attributes
,
1407 wow64_query_ticket_cache
,
1409 wow64_unseal_message
,
1410 wow64_verify_signature
,
1413 C_ASSERT( ARRAYSIZE(__wine_unix_call_wow64_funcs
) == unix_funcs_count
);
1417 #endif /* defined(SONAME_LIBKRB5) && defined(SONAME_LIBGSSAPI_KRB5) */