2 * Copyright 2017 Dmitry Timoshkov
3 * Copyright 2017 George Popoff
4 * Copyright 2008 Robert Shearman for CodeWeavers
5 * Copyright 2017 Hans Leidekker for CodeWeavers
7 * Kerberos5 Authentication Package
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
25 #include "wine/port.h"
28 #ifdef HAVE_KRB5_KRB5_H
29 #include <krb5/krb5.h>
31 #ifdef SONAME_LIBGSSAPI_KRB5
32 # include <gssapi/gssapi.h>
33 # include <gssapi/gssapi_ext.h>
37 #define WIN32_NO_STATUS
46 #include "wine/heap.h"
47 #include "wine/debug.h"
48 #include "wine/unicode.h"
50 WINE_DEFAULT_DEBUG_CHANNEL(kerberos
);
52 #define KERBEROS_MAX_BUF 12000
54 #define KERBEROS_CAPS \
55 ( SECPKG_FLAG_INTEGRITY \
56 | SECPKG_FLAG_PRIVACY \
57 | SECPKG_FLAG_TOKEN_ONLY \
58 | SECPKG_FLAG_DATAGRAM \
59 | SECPKG_FLAG_CONNECTION \
60 | SECPKG_FLAG_MULTI_REQUIRED \
61 | SECPKG_FLAG_EXTENDED_ERROR \
62 | SECPKG_FLAG_IMPERSONATION \
63 | SECPKG_FLAG_ACCEPT_WIN32_NAME \
64 | SECPKG_FLAG_NEGOTIABLE \
65 | SECPKG_FLAG_GSS_COMPATIBLE \
67 | SECPKG_FLAG_MUTUAL_AUTH \
68 | SECPKG_FLAG_DELEGATION \
69 | SECPKG_FLAG_READONLY_WITH_CHECKSUM \
70 | SECPKG_FLAG_RESTRICTED_TOKENS \
71 | SECPKG_FLAG_APPCONTAINER_CHECKS)
73 static WCHAR kerberos_name_W
[] = {'K','e','r','b','e','r','o','s',0};
74 static WCHAR kerberos_comment_W
[] = {'M','i','c','r','o','s','o','f','t',' ','K','e','r','b','e','r','o','s',' ','V','1','.','0',0};
75 static const SecPkgInfoW infoW
=
79 RPC_C_AUTHN_GSS_KERBEROS
,
85 static ULONG kerberos_package_id
;
86 static LSA_DISPATCH_TABLE lsa_dispatch
;
90 static void *libkrb5_handle
;
92 #define MAKE_FUNCPTR(f) static typeof(f) * p_##f
93 MAKE_FUNCPTR(krb5_cc_close
);
94 MAKE_FUNCPTR(krb5_cc_default
);
95 MAKE_FUNCPTR(krb5_cc_end_seq_get
);
96 MAKE_FUNCPTR(krb5_cc_initialize
);
97 MAKE_FUNCPTR(krb5_cc_next_cred
);
98 MAKE_FUNCPTR(krb5_cc_start_seq_get
);
99 MAKE_FUNCPTR(krb5_cc_store_cred
);
100 MAKE_FUNCPTR(krb5_cccol_cursor_free
);
101 MAKE_FUNCPTR(krb5_cccol_cursor_new
);
102 MAKE_FUNCPTR(krb5_cccol_cursor_next
);
103 MAKE_FUNCPTR(krb5_decode_ticket
);
104 MAKE_FUNCPTR(krb5_free_context
);
105 MAKE_FUNCPTR(krb5_free_cred_contents
);
106 MAKE_FUNCPTR(krb5_free_principal
);
107 MAKE_FUNCPTR(krb5_free_ticket
);
108 MAKE_FUNCPTR(krb5_free_unparsed_name
);
109 MAKE_FUNCPTR(krb5_get_init_creds_opt_alloc
);
110 MAKE_FUNCPTR(krb5_get_init_creds_opt_free
);
111 MAKE_FUNCPTR(krb5_get_init_creds_opt_set_out_ccache
);
112 MAKE_FUNCPTR(krb5_get_init_creds_password
);
113 MAKE_FUNCPTR(krb5_init_context
);
114 MAKE_FUNCPTR(krb5_is_config_principal
);
115 MAKE_FUNCPTR(krb5_parse_name_flags
);
116 MAKE_FUNCPTR(krb5_unparse_name_flags
);
119 static void load_krb5(void)
121 if (!(libkrb5_handle
= dlopen(SONAME_LIBKRB5
, RTLD_NOW
)))
123 WARN("Failed to load %s, Kerberos support will be disabled\n", SONAME_LIBKRB5
);
127 #define LOAD_FUNCPTR(f) \
128 if (!(p_##f = dlsym(libkrb5_handle, #f))) \
130 ERR("Failed to load %s\n", #f); \
134 LOAD_FUNCPTR(krb5_cc_close
)
135 LOAD_FUNCPTR(krb5_cc_default
)
136 LOAD_FUNCPTR(krb5_cc_end_seq_get
)
137 LOAD_FUNCPTR(krb5_cc_initialize
)
138 LOAD_FUNCPTR(krb5_cc_next_cred
)
139 LOAD_FUNCPTR(krb5_cc_start_seq_get
)
140 LOAD_FUNCPTR(krb5_cc_store_cred
)
141 LOAD_FUNCPTR(krb5_cccol_cursor_free
)
142 LOAD_FUNCPTR(krb5_cccol_cursor_new
)
143 LOAD_FUNCPTR(krb5_cccol_cursor_next
)
144 LOAD_FUNCPTR(krb5_decode_ticket
)
145 LOAD_FUNCPTR(krb5_free_context
)
146 LOAD_FUNCPTR(krb5_free_cred_contents
)
147 LOAD_FUNCPTR(krb5_free_principal
)
148 LOAD_FUNCPTR(krb5_free_ticket
)
149 LOAD_FUNCPTR(krb5_free_unparsed_name
)
150 LOAD_FUNCPTR(krb5_get_init_creds_opt_alloc
)
151 LOAD_FUNCPTR(krb5_get_init_creds_opt_free
)
152 LOAD_FUNCPTR(krb5_get_init_creds_opt_set_out_ccache
)
153 LOAD_FUNCPTR(krb5_get_init_creds_password
)
154 LOAD_FUNCPTR(krb5_init_context
)
155 LOAD_FUNCPTR(krb5_is_config_principal
)
156 LOAD_FUNCPTR(krb5_parse_name_flags
)
157 LOAD_FUNCPTR(krb5_unparse_name_flags
)
163 dlclose(libkrb5_handle
);
164 libkrb5_handle
= NULL
;
167 #else /* SONAME_LIBKRB5 */
169 static void load_krb5(void)
171 WARN("Kerberos support was not provided at compile time\n");
174 #endif /* SONAME_LIBKRB5 */
176 static const char *debugstr_us( const UNICODE_STRING
*us
)
178 if (!us
) return "<null>";
179 return debugstr_wn( us
->Buffer
, us
->Length
/ sizeof(WCHAR
) );
182 static NTSTATUS NTAPI
kerberos_LsaApInitializePackage(ULONG package_id
, PLSA_DISPATCH_TABLE dispatch
,
183 PLSA_STRING database
, PLSA_STRING confidentiality
, PLSA_STRING
*package_name
)
189 kerberos_package_id
= package_id
;
190 lsa_dispatch
= *dispatch
;
192 kerberos_name
= lsa_dispatch
.AllocateLsaHeap(sizeof(MICROSOFT_KERBEROS_NAME_A
));
193 if (!kerberos_name
) return STATUS_NO_MEMORY
;
195 memcpy(kerberos_name
, MICROSOFT_KERBEROS_NAME_A
, sizeof(MICROSOFT_KERBEROS_NAME_A
));
197 *package_name
= lsa_dispatch
.AllocateLsaHeap(sizeof(**package_name
));
200 lsa_dispatch
.FreeLsaHeap(kerberos_name
);
201 return STATUS_NO_MEMORY
;
204 RtlInitString(*package_name
, kerberos_name
);
206 return STATUS_SUCCESS
;
209 #ifdef SONAME_LIBKRB5
213 ULONG count
, allocated
;
214 KERB_TICKET_CACHE_INFO
*info
;
217 static NTSTATUS
krb5_error_to_status(krb5_error_code error
)
221 case 0: return STATUS_SUCCESS
;
224 return STATUS_UNSUCCESSFUL
;
228 static void free_ticket_info(struct ticket_info
*info
)
232 for (i
= 0; i
< info
->count
; i
++)
234 heap_free(info
->info
[i
].RealmName
.Buffer
);
235 heap_free(info
->info
[i
].ServerName
.Buffer
);
238 heap_free(info
->info
);
241 static WCHAR
*utf8_to_wstr(const char *utf8
)
246 len
= MultiByteToWideChar(CP_UTF8
, 0, utf8
, -1, NULL
, 0);
247 wstr
= heap_alloc(len
* sizeof(WCHAR
));
249 MultiByteToWideChar(CP_UTF8
, 0, utf8
, -1, wstr
, len
);
254 static NTSTATUS
copy_tickets_from_cache(krb5_context context
, krb5_ccache cache
, struct ticket_info
*info
)
257 krb5_cc_cursor cursor
;
258 krb5_error_code error
;
259 krb5_creds credentials
;
261 char *name_with_realm
, *name_without_realm
, *realm_name
;
262 WCHAR
*realm_nameW
, *name_without_realmW
;
264 error
= p_krb5_cc_start_seq_get(context
, cache
, &cursor
);
265 if (error
) return krb5_error_to_status(error
);
269 error
= p_krb5_cc_next_cred(context
, cache
, &cursor
, &credentials
);
272 if (error
== KRB5_CC_END
)
273 status
= STATUS_SUCCESS
;
275 status
= krb5_error_to_status(error
);
279 if (p_krb5_is_config_principal(context
, credentials
.server
))
281 p_krb5_free_cred_contents(context
, &credentials
);
285 if (info
->count
== info
->allocated
)
287 KERB_TICKET_CACHE_INFO
*new_info
;
292 new_allocated
= info
->allocated
* 2;
293 new_info
= heap_realloc(info
->info
, sizeof(*new_info
) * new_allocated
);
298 new_info
= heap_alloc(sizeof(*new_info
) * new_allocated
);
302 p_krb5_free_cred_contents(context
, &credentials
);
303 status
= STATUS_NO_MEMORY
;
307 info
->info
= new_info
;
308 info
->allocated
= new_allocated
;
311 error
= p_krb5_unparse_name_flags(context
, credentials
.server
, 0, &name_with_realm
);
314 p_krb5_free_cred_contents(context
, &credentials
);
315 status
= krb5_error_to_status(error
);
319 TRACE("name_with_realm: %s\n", debugstr_a(name_with_realm
));
321 error
= p_krb5_unparse_name_flags(context
, credentials
.server
,
322 KRB5_PRINCIPAL_UNPARSE_NO_REALM
, &name_without_realm
);
325 p_krb5_free_unparsed_name(context
, name_with_realm
);
326 p_krb5_free_cred_contents(context
, &credentials
);
327 status
= krb5_error_to_status(error
);
331 TRACE("name_without_realm: %s\n", debugstr_a(name_without_realm
));
333 name_without_realmW
= utf8_to_wstr(name_without_realm
);
334 RtlInitUnicodeString(&info
->info
[info
->count
].ServerName
, name_without_realmW
);
336 realm_name
= strchr(name_with_realm
, '@');
339 ERR("wrong name with realm %s\n", debugstr_a(name_with_realm
));
340 realm_name
= name_with_realm
;
345 /* realm_name - now contains only realm! */
347 realm_nameW
= utf8_to_wstr(realm_name
);
348 RtlInitUnicodeString(&info
->info
[info
->count
].RealmName
, realm_nameW
);
350 if (!credentials
.times
.starttime
)
351 credentials
.times
.starttime
= credentials
.times
.authtime
;
353 /* TODO: if krb5_is_config_principal = true */
354 RtlSecondsSince1970ToTime(credentials
.times
.starttime
, &info
->info
[info
->count
].StartTime
);
355 RtlSecondsSince1970ToTime(credentials
.times
.endtime
, &info
->info
[info
->count
].EndTime
);
356 RtlSecondsSince1970ToTime(credentials
.times
.renew_till
, &info
->info
[info
->count
].RenewTime
);
358 info
->info
[info
->count
].TicketFlags
= credentials
.ticket_flags
;
360 error
= p_krb5_decode_ticket(&credentials
.ticket
, &ticket
);
362 p_krb5_free_unparsed_name(context
, name_with_realm
);
363 p_krb5_free_unparsed_name(context
, name_without_realm
);
364 p_krb5_free_cred_contents(context
, &credentials
);
368 status
= krb5_error_to_status(error
);
372 info
->info
[info
->count
].EncryptionType
= ticket
->enc_part
.enctype
;
374 p_krb5_free_ticket(context
, ticket
);
379 p_krb5_cc_end_seq_get(context
, cache
, &cursor
);
384 static inline void init_client_us(UNICODE_STRING
*dst
, void *client_ws
, const UNICODE_STRING
*src
)
386 dst
->Buffer
= client_ws
;
387 dst
->Length
= src
->Length
;
388 dst
->MaximumLength
= src
->MaximumLength
;
391 static NTSTATUS
copy_to_client(PLSA_CLIENT_REQUEST lsa_req
, struct ticket_info
*info
, void **out
, ULONG
*out_size
)
395 SIZE_T size
, client_str_off
;
396 char *client_resp
, *client_ticket
, *client_str
;
397 KERB_QUERY_TKT_CACHE_RESPONSE resp
;
399 size
= sizeof(KERB_QUERY_TKT_CACHE_RESPONSE
);
400 if (info
->count
!= 0)
401 size
+= (info
->count
- 1) * sizeof(KERB_TICKET_CACHE_INFO
);
403 client_str_off
= size
;
405 for (i
= 0; i
< info
->count
; i
++)
407 size
+= info
->info
[i
].RealmName
.MaximumLength
;
408 size
+= info
->info
[i
].ServerName
.MaximumLength
;
411 status
= lsa_dispatch
.AllocateClientBuffer(lsa_req
, size
, (void **)&client_resp
);
412 if (status
!= STATUS_SUCCESS
) return status
;
414 resp
.MessageType
= KerbQueryTicketCacheMessage
;
415 resp
.CountOfTickets
= info
->count
;
416 size
= FIELD_OFFSET(KERB_QUERY_TKT_CACHE_RESPONSE
, Tickets
);
417 status
= lsa_dispatch
.CopyToClientBuffer(lsa_req
, size
, client_resp
, &resp
);
418 if (status
!= STATUS_SUCCESS
) goto fail
;
423 *out_size
= sizeof(resp
);
424 return STATUS_SUCCESS
;
429 client_ticket
= client_resp
+ size
;
430 client_str
= client_resp
+ client_str_off
;
432 for (i
= 0; i
< info
->count
; i
++)
434 KERB_TICKET_CACHE_INFO ticket
;
436 ticket
= info
->info
[i
];
438 init_client_us(&ticket
.RealmName
, client_str
, &info
->info
[i
].RealmName
);
440 size
= info
->info
[i
].RealmName
.MaximumLength
;
441 status
= lsa_dispatch
.CopyToClientBuffer(lsa_req
, size
, client_str
, info
->info
[i
].RealmName
.Buffer
);
442 if (status
!= STATUS_SUCCESS
) goto fail
;
446 init_client_us(&ticket
.ServerName
, client_str
, &info
->info
[i
].ServerName
);
448 size
= info
->info
[i
].ServerName
.MaximumLength
;
449 status
= lsa_dispatch
.CopyToClientBuffer(lsa_req
, size
, client_str
, info
->info
[i
].ServerName
.Buffer
);
450 if (status
!= STATUS_SUCCESS
) goto fail
;
454 status
= lsa_dispatch
.CopyToClientBuffer(lsa_req
, sizeof(ticket
), client_ticket
, &ticket
);
455 if (status
!= STATUS_SUCCESS
) goto fail
;
457 client_ticket
+= sizeof(ticket
);
458 *out_size
+= sizeof(ticket
);
462 return STATUS_SUCCESS
;
465 lsa_dispatch
.FreeClientBuffer(lsa_req
, client_resp
);
469 static NTSTATUS
query_ticket_cache(PLSA_CLIENT_REQUEST lsa_req
, void *in
, ULONG in_len
, void **out
, ULONG
*out_len
)
472 KERB_QUERY_TKT_CACHE_REQUEST
*query
;
473 struct ticket_info info
;
474 krb5_error_code error
;
475 krb5_context context
= NULL
;
476 krb5_cccol_cursor cursor
= NULL
;
479 if (!in
|| in_len
!= sizeof(KERB_QUERY_TKT_CACHE_REQUEST
) || !out
|| !out_len
)
480 return STATUS_INVALID_PARAMETER
;
482 query
= (KERB_QUERY_TKT_CACHE_REQUEST
*)in
;
484 if (query
->LogonId
.HighPart
!= 0 || query
->LogonId
.LowPart
!= 0)
485 return STATUS_ACCESS_DENIED
;
491 error
= p_krb5_init_context(&context
);
494 status
= krb5_error_to_status(error
);
498 error
= p_krb5_cccol_cursor_new(context
, &cursor
);
501 status
= krb5_error_to_status(error
);
507 error
= p_krb5_cccol_cursor_next(context
, cursor
, &cache
);
510 status
= krb5_error_to_status(error
);
515 status
= copy_tickets_from_cache(context
, cache
, &info
);
517 p_krb5_cc_close(context
, cache
);
519 if (status
!= STATUS_SUCCESS
)
523 status
= copy_to_client(lsa_req
, &info
, out
, out_len
);
527 p_krb5_cccol_cursor_free(context
, &cursor
);
530 p_krb5_free_context(context
);
532 free_ticket_info(&info
);
537 #else /* SONAME_LIBKRB5 */
539 static NTSTATUS
query_ticket_cache(PLSA_CLIENT_REQUEST lsa_req
, void *in
, ULONG in_len
, void **out
, ULONG
*out_len
)
541 FIXME("%p,%p,%u,%p,%p: stub\n", lsa_req
, in
, in_len
, out
, out_len
);
542 return STATUS_NOT_IMPLEMENTED
;
545 #endif /* SONAME_LIBKRB5 */
547 static NTSTATUS NTAPI
kerberos_LsaApCallPackageUntrusted(PLSA_CLIENT_REQUEST request
,
548 PVOID in_buffer
, PVOID client_buffer_base
, ULONG in_buffer_length
,
549 PVOID
*out_buffer
, PULONG out_buffer_length
, PNTSTATUS status
)
551 KERB_PROTOCOL_MESSAGE_TYPE msg
;
553 TRACE("%p,%p,%p,%u,%p,%p,%p\n", request
, in_buffer
, client_buffer_base
,
554 in_buffer_length
, out_buffer
, out_buffer_length
, status
);
556 if (!in_buffer
|| in_buffer_length
< sizeof(msg
))
557 return STATUS_INVALID_PARAMETER
;
559 msg
= *(KERB_PROTOCOL_MESSAGE_TYPE
*)in_buffer
;
563 case KerbQueryTicketCacheMessage
:
564 *status
= query_ticket_cache(request
, in_buffer
, in_buffer_length
, out_buffer
, out_buffer_length
);
567 case KerbRetrieveTicketMessage
:
568 FIXME("KerbRetrieveTicketMessage stub\n");
569 *status
= STATUS_NOT_IMPLEMENTED
;
572 case KerbPurgeTicketCacheMessage
:
573 FIXME("KerbPurgeTicketCacheMessage stub\n");
574 *status
= STATUS_NOT_IMPLEMENTED
;
577 default: /* All other requests should call LsaApCallPackage */
578 WARN("%u => access denied\n", msg
);
579 *status
= STATUS_ACCESS_DENIED
;
586 static NTSTATUS NTAPI
kerberos_SpGetInfo(SecPkgInfoW
*info
)
590 /* LSA will make a copy before forwarding the structure, so
591 * it's safe to put pointers to dynamic or constant data there.
595 return STATUS_SUCCESS
;
598 #ifdef SONAME_LIBGSSAPI_KRB5
600 WINE_DECLARE_DEBUG_CHANNEL(winediag
);
601 static void *libgssapi_krb5_handle
;
603 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
604 MAKE_FUNCPTR(gss_accept_sec_context
);
605 MAKE_FUNCPTR(gss_acquire_cred
);
606 MAKE_FUNCPTR(gss_delete_sec_context
);
607 MAKE_FUNCPTR(gss_display_status
);
608 MAKE_FUNCPTR(gss_get_mic
);
609 MAKE_FUNCPTR(gss_import_name
);
610 MAKE_FUNCPTR(gss_init_sec_context
);
611 MAKE_FUNCPTR(gss_inquire_context
);
612 MAKE_FUNCPTR(gss_release_buffer
);
613 MAKE_FUNCPTR(gss_release_cred
);
614 MAKE_FUNCPTR(gss_release_iov_buffer
);
615 MAKE_FUNCPTR(gss_release_name
);
616 MAKE_FUNCPTR(gss_unwrap
);
617 MAKE_FUNCPTR(gss_unwrap_iov
);
618 MAKE_FUNCPTR(gss_verify_mic
);
619 MAKE_FUNCPTR(gss_wrap
);
620 MAKE_FUNCPTR(gss_wrap_iov
);
623 static BOOL
load_gssapi_krb5(void)
625 if (!(libgssapi_krb5_handle
= dlopen( SONAME_LIBGSSAPI_KRB5
, RTLD_NOW
)))
627 ERR_(winediag
)( "Failed to load libgssapi_krb5, Kerberos SSP support will not be available.\n" );
631 #define LOAD_FUNCPTR(f) \
632 if (!(p##f = dlsym( libgssapi_krb5_handle, #f ))) \
634 ERR( "Failed to load %s\n", #f ); \
638 LOAD_FUNCPTR(gss_accept_sec_context
)
639 LOAD_FUNCPTR(gss_acquire_cred
)
640 LOAD_FUNCPTR(gss_delete_sec_context
)
641 LOAD_FUNCPTR(gss_display_status
)
642 LOAD_FUNCPTR(gss_get_mic
)
643 LOAD_FUNCPTR(gss_import_name
)
644 LOAD_FUNCPTR(gss_init_sec_context
)
645 LOAD_FUNCPTR(gss_inquire_context
)
646 LOAD_FUNCPTR(gss_release_buffer
)
647 LOAD_FUNCPTR(gss_release_cred
)
648 LOAD_FUNCPTR(gss_release_iov_buffer
)
649 LOAD_FUNCPTR(gss_release_name
)
650 LOAD_FUNCPTR(gss_unwrap
)
651 LOAD_FUNCPTR(gss_unwrap_iov
)
652 LOAD_FUNCPTR(gss_verify_mic
)
653 LOAD_FUNCPTR(gss_wrap
)
654 LOAD_FUNCPTR(gss_wrap_iov
)
660 dlclose( libgssapi_krb5_handle
);
661 libgssapi_krb5_handle
= NULL
;
665 static void unload_gssapi_krb5(void)
667 dlclose( libgssapi_krb5_handle
);
668 libgssapi_krb5_handle
= NULL
;
671 static inline gss_cred_id_t
credhandle_sspi_to_gss( LSA_SEC_HANDLE cred
)
673 if (!cred
) return GSS_C_NO_CREDENTIAL
;
674 return (gss_cred_id_t
)cred
;
677 static inline void credhandle_gss_to_sspi( gss_cred_id_t handle
, LSA_SEC_HANDLE
*cred
)
679 *cred
= (LSA_SEC_HANDLE
)handle
;
682 static inline gss_ctx_id_t
ctxthandle_sspi_to_gss( LSA_SEC_HANDLE ctxt
)
684 if (!ctxt
) return GSS_C_NO_CONTEXT
;
685 return (gss_ctx_id_t
)ctxt
;
688 static inline void ctxthandle_gss_to_sspi( gss_ctx_id_t handle
, LSA_SEC_HANDLE
*ctxt
)
690 *ctxt
= (LSA_SEC_HANDLE
)handle
;
693 static NTSTATUS
status_gss_to_sspi( OM_uint32 status
)
697 case GSS_S_COMPLETE
: return SEC_E_OK
;
698 case GSS_S_BAD_MECH
: return SEC_E_SECPKG_NOT_FOUND
;
699 case GSS_S_BAD_SIG
: return SEC_E_MESSAGE_ALTERED
;
700 case GSS_S_NO_CRED
: return SEC_E_NO_CREDENTIALS
;
701 case GSS_S_NO_CONTEXT
: return SEC_E_INVALID_HANDLE
;
702 case GSS_S_DEFECTIVE_TOKEN
: return SEC_E_INVALID_TOKEN
;
703 case GSS_S_DEFECTIVE_CREDENTIAL
: return SEC_E_NO_CREDENTIALS
;
704 case GSS_S_CREDENTIALS_EXPIRED
: return SEC_E_CONTEXT_EXPIRED
;
705 case GSS_S_CONTEXT_EXPIRED
: return SEC_E_CONTEXT_EXPIRED
;
706 case GSS_S_BAD_QOP
: return SEC_E_QOP_NOT_SUPPORTED
;
707 case GSS_S_CONTINUE_NEEDED
: return SEC_I_CONTINUE_NEEDED
;
708 case GSS_S_DUPLICATE_TOKEN
: return SEC_E_INVALID_TOKEN
;
709 case GSS_S_OLD_TOKEN
: return SEC_E_INVALID_TOKEN
;
710 case GSS_S_UNSEQ_TOKEN
: return SEC_E_OUT_OF_SEQUENCE
;
711 case GSS_S_GAP_TOKEN
: return SEC_E_OUT_OF_SEQUENCE
;
712 case GSS_S_FAILURE
: return SEC_E_INTERNAL_ERROR
;
715 FIXME( "couldn't convert status 0x%08x to NTSTATUS\n", status
);
716 return SEC_E_INTERNAL_ERROR
;
720 static void trace_gss_status_ex( OM_uint32 code
, int type
)
722 OM_uint32 ret
, minor_status
;
724 OM_uint32 message_context
= 0;
728 ret
= pgss_display_status( &minor_status
, code
, type
, GSS_C_NULL_OID
, &message_context
, &buf
);
731 TRACE( "gss_display_status(0x%08x,%d) returned %08x minor status %08x\n",
732 code
, type
, ret
, minor_status
);
735 TRACE( "GSS-API error: 0x%08x: %s\n", code
, debugstr_an(buf
.value
, buf
.length
) );
736 pgss_release_buffer( &minor_status
, &buf
);
738 if (!message_context
) return;
742 static void trace_gss_status( OM_uint32 major_status
, OM_uint32 minor_status
)
744 if (TRACE_ON(kerberos
))
746 trace_gss_status_ex( major_status
, GSS_C_GSS_CODE
);
747 trace_gss_status_ex( minor_status
, GSS_C_MECH_CODE
);
751 static void expirytime_gss_to_sspi( OM_uint32 expirytime
, TimeStamp
*timestamp
)
756 GetSystemTimeAsFileTime( &filetime
);
757 FileTimeToLocalFileTime( &filetime
, &filetime
);
758 tmp
.QuadPart
= ((ULONGLONG
)filetime
.dwLowDateTime
| (ULONGLONG
)filetime
.dwHighDateTime
<< 32) + expirytime
;
759 timestamp
->LowPart
= tmp
.QuadPart
;
760 timestamp
->HighPart
= tmp
.QuadPart
>> 32;
763 static NTSTATUS
name_sspi_to_gss( const UNICODE_STRING
*name_str
, gss_name_t
*name
)
765 OM_uint32 ret
, minor_status
;
766 gss_OID type
= GSS_C_NO_OID
; /* FIXME: detect the appropriate value for this ourselves? */
769 buf
.length
= WideCharToMultiByte( CP_UNIXCP
, 0, name_str
->Buffer
, name_str
->Length
/ sizeof(WCHAR
), NULL
, 0, NULL
, NULL
);
770 if (!(buf
.value
= heap_alloc( buf
.length
))) return SEC_E_INSUFFICIENT_MEMORY
;
771 WideCharToMultiByte( CP_UNIXCP
, 0, name_str
->Buffer
, name_str
->Length
/ sizeof(WCHAR
), buf
.value
, buf
.length
, NULL
, NULL
);
773 ret
= pgss_import_name( &minor_status
, &buf
, type
, name
);
774 TRACE( "gss_import_name returned %08x minor status %08x\n", ret
, minor_status
);
775 if (GSS_ERROR(ret
)) trace_gss_status( ret
, minor_status
);
777 heap_free( buf
.value
);
778 return status_gss_to_sspi( ret
);
781 static ULONG
flags_isc_req_to_gss( ULONG flags
)
784 if (flags
& ISC_REQ_DELEGATE
) ret
|= GSS_C_DELEG_FLAG
;
785 if (flags
& ISC_REQ_MUTUAL_AUTH
) ret
|= GSS_C_MUTUAL_FLAG
;
786 if (flags
& ISC_REQ_REPLAY_DETECT
) ret
|= GSS_C_REPLAY_FLAG
;
787 if (flags
& ISC_REQ_SEQUENCE_DETECT
) ret
|= GSS_C_SEQUENCE_FLAG
;
788 if (flags
& ISC_REQ_CONFIDENTIALITY
) ret
|= GSS_C_CONF_FLAG
;
789 if (flags
& ISC_REQ_INTEGRITY
) ret
|= GSS_C_INTEG_FLAG
;
790 if (flags
& ISC_REQ_NULL_SESSION
) ret
|= GSS_C_ANON_FLAG
;
791 if (flags
& ISC_REQ_USE_DCE_STYLE
) ret
|= GSS_C_DCE_STYLE
;
792 if (flags
& ISC_REQ_IDENTIFY
) ret
|= GSS_C_IDENTIFY_FLAG
;
796 static ULONG
flags_gss_to_isc_ret( ULONG flags
)
799 if (flags
& GSS_C_DELEG_FLAG
) ret
|= ISC_RET_DELEGATE
;
800 if (flags
& GSS_C_MUTUAL_FLAG
) ret
|= ISC_RET_MUTUAL_AUTH
;
801 if (flags
& GSS_C_REPLAY_FLAG
) ret
|= ISC_RET_REPLAY_DETECT
;
802 if (flags
& GSS_C_SEQUENCE_FLAG
) ret
|= ISC_RET_SEQUENCE_DETECT
;
803 if (flags
& GSS_C_CONF_FLAG
) ret
|= ISC_RET_CONFIDENTIALITY
;
804 if (flags
& GSS_C_INTEG_FLAG
) ret
|= ISC_RET_INTEGRITY
;
805 if (flags
& GSS_C_ANON_FLAG
) ret
|= ISC_RET_NULL_SESSION
;
806 if (flags
& GSS_C_DCE_STYLE
) ret
|= ISC_RET_USED_DCE_STYLE
;
807 if (flags
& GSS_C_IDENTIFY_FLAG
) ret
|= ISC_RET_IDENTIFY
;
811 static ULONG
flags_gss_to_asc_ret( ULONG flags
)
814 if (flags
& GSS_C_DELEG_FLAG
) ret
|= ASC_RET_DELEGATE
;
815 if (flags
& GSS_C_MUTUAL_FLAG
) ret
|= ASC_RET_MUTUAL_AUTH
;
816 if (flags
& GSS_C_REPLAY_FLAG
) ret
|= ASC_RET_REPLAY_DETECT
;
817 if (flags
& GSS_C_SEQUENCE_FLAG
) ret
|= ASC_RET_SEQUENCE_DETECT
;
818 if (flags
& GSS_C_CONF_FLAG
) ret
|= ASC_RET_CONFIDENTIALITY
;
819 if (flags
& GSS_C_INTEG_FLAG
) ret
|= ASC_RET_INTEGRITY
;
820 if (flags
& GSS_C_ANON_FLAG
) ret
|= ASC_RET_NULL_SESSION
;
821 if (flags
& GSS_C_DCE_STYLE
) ret
|= ASC_RET_USED_DCE_STYLE
;
822 if (flags
& GSS_C_IDENTIFY_FLAG
) ret
|= ASC_RET_IDENTIFY
;
826 static BOOL
is_dce_style_context( gss_ctx_id_t ctxt_handle
)
828 OM_uint32 ret
, minor_status
, flags
;
829 ret
= pgss_inquire_context( &minor_status
, ctxt_handle
, NULL
, NULL
, NULL
, NULL
, &flags
, NULL
, NULL
);
830 return (ret
== GSS_S_COMPLETE
&& (flags
& GSS_C_DCE_STYLE
));
833 static int get_buffer_index( SecBufferDesc
*desc
, DWORD type
)
836 if (!desc
) return -1;
837 for (i
= 0; i
< desc
->cBuffers
; i
++)
839 if (desc
->pBuffers
[i
].BufferType
== type
) return i
;
844 static char *get_user_at_domain( const WCHAR
*user
, ULONG user_len
, const WCHAR
*domain
, ULONG domain_len
)
846 int len_user
, len_domain
;
849 len_user
= WideCharToMultiByte( CP_UNIXCP
, 0, user
, user_len
, NULL
, 0, NULL
, NULL
);
850 len_domain
= WideCharToMultiByte( CP_UNIXCP
, 0, domain
, domain_len
, NULL
, 0, NULL
, NULL
);
851 if (!(ret
= heap_alloc( len_user
+ len_domain
+ 2 ))) return NULL
;
853 WideCharToMultiByte( CP_UNIXCP
, 0, user
, user_len
, ret
, len_user
, NULL
, NULL
);
855 WideCharToMultiByte( CP_UNIXCP
, 0, domain
, domain_len
, ret
+ len_user
+ 1, len_domain
, NULL
, NULL
);
856 ret
[len_user
+ len_domain
+ 1] = 0;
860 static char *get_password( const WCHAR
*passwd
, ULONG passwd_len
)
865 len
= WideCharToMultiByte( CP_UNIXCP
, WC_NO_BEST_FIT_CHARS
, passwd
, passwd_len
, NULL
, 0, NULL
, NULL
);
866 if (!(ret
= heap_alloc( len
+ 1 ))) return NULL
;
867 WideCharToMultiByte( CP_UNIXCP
, 0, passwd
, passwd_len
, ret
, len
, NULL
, NULL
);
872 static NTSTATUS
init_creds( const SEC_WINNT_AUTH_IDENTITY_W
*id
)
874 char *user_at_domain
, *password
;
876 krb5_principal principal
= NULL
;
877 krb5_get_init_creds_opt
*options
= NULL
;
878 krb5_ccache cache
= NULL
;
882 if (!id
) return STATUS_SUCCESS
;
883 if (id
->Flags
& SEC_WINNT_AUTH_IDENTITY_ANSI
)
885 FIXME( "ANSI identity not supported\n" );
886 return SEC_E_UNSUPPORTED_FUNCTION
;
888 if (!(user_at_domain
= get_user_at_domain( id
->User
, id
->UserLength
, id
->Domain
, id
->DomainLength
)))
890 return SEC_E_INSUFFICIENT_MEMORY
;
892 if (!(password
= get_password( id
->Password
, id
->PasswordLength
)))
894 heap_free( user_at_domain
);
895 return SEC_E_INSUFFICIENT_MEMORY
;
898 if ((err
= p_krb5_init_context( &ctx
)))
900 heap_free( password
);
901 heap_free( user_at_domain
);
902 return krb5_error_to_status( err
);
904 if ((err
= p_krb5_parse_name_flags( ctx
, user_at_domain
, 0, &principal
))) goto done
;
905 if ((err
= p_krb5_cc_default( ctx
, &cache
))) goto done
;
906 if ((err
= p_krb5_get_init_creds_opt_alloc( ctx
, &options
))) goto done
;
907 if ((err
= p_krb5_get_init_creds_opt_set_out_ccache( ctx
, options
, cache
))) goto done
;
908 if ((err
= p_krb5_get_init_creds_password( ctx
, &creds
, principal
, password
, 0, NULL
, 0, NULL
, 0 ))) goto done
;
909 if ((err
= p_krb5_cc_initialize( ctx
, cache
, principal
))) goto done
;
910 if ((err
= p_krb5_cc_store_cred( ctx
, cache
, &creds
))) goto done
;
912 TRACE( "success\n" );
913 p_krb5_free_cred_contents( ctx
, &creds
);
916 if (cache
) p_krb5_cc_close( ctx
, cache
);
917 if (principal
) p_krb5_free_principal( ctx
, principal
);
918 if (options
) p_krb5_get_init_creds_opt_free( ctx
, options
);
919 p_krb5_free_context( ctx
);
920 heap_free( user_at_domain
);
921 heap_free( password
);
923 return krb5_error_to_status( err
);
926 static NTSTATUS
acquire_credentials_handle( UNICODE_STRING
*principal_us
, gss_cred_usage_t cred_usage
,
927 LSA_SEC_HANDLE
*credential
, TimeStamp
*ts_expiry
)
929 OM_uint32 ret
, minor_status
, expiry_time
;
930 gss_name_t principal
= GSS_C_NO_NAME
;
931 gss_cred_id_t cred_handle
;
934 if (principal_us
&& ((status
= name_sspi_to_gss( principal_us
, &principal
)) != SEC_E_OK
)) return status
;
936 ret
= pgss_acquire_cred( &minor_status
, principal
, GSS_C_INDEFINITE
, GSS_C_NULL_OID_SET
, cred_usage
,
937 &cred_handle
, NULL
, &expiry_time
);
938 TRACE( "gss_acquire_cred returned %08x minor status %08x\n", ret
, minor_status
);
939 if (GSS_ERROR(ret
)) trace_gss_status( ret
, minor_status
);
940 if (ret
== GSS_S_COMPLETE
)
942 credhandle_gss_to_sspi( cred_handle
, credential
);
943 expirytime_gss_to_sspi( expiry_time
, ts_expiry
);
946 if (principal
!= GSS_C_NO_NAME
) pgss_release_name( &minor_status
, &principal
);
948 return status_gss_to_sspi( ret
);
950 #endif /* SONAME_LIBGSSAPI_KRB5 */
952 static NTSTATUS NTAPI
kerberos_SpAcquireCredentialsHandle(
953 UNICODE_STRING
*principal_us
, ULONG credential_use
, LUID
*logon_id
, void *auth_data
,
954 void *get_key_fn
, void *get_key_arg
, LSA_SEC_HANDLE
*credential
, TimeStamp
*ts_expiry
)
956 #ifdef SONAME_LIBGSSAPI_KRB5
957 gss_cred_usage_t cred_usage
;
960 TRACE( "(%s 0x%08x %p %p %p %p %p %p)\n", debugstr_us(principal_us
), credential_use
,
961 logon_id
, auth_data
, get_key_fn
, get_key_arg
, credential
, ts_expiry
);
963 switch (credential_use
)
965 case SECPKG_CRED_INBOUND
:
966 cred_usage
= GSS_C_ACCEPT
;
969 case SECPKG_CRED_OUTBOUND
:
970 if ((status
= init_creds( auth_data
)) != STATUS_SUCCESS
) return status
;
971 cred_usage
= GSS_C_INITIATE
;
974 case SECPKG_CRED_BOTH
:
975 cred_usage
= GSS_C_BOTH
;
979 return SEC_E_UNKNOWN_CREDENTIALS
;
982 return acquire_credentials_handle( principal_us
, cred_usage
, credential
, ts_expiry
);
984 FIXME( "(%s 0x%08x %p %p %p %p %p %p)\n", debugstr_us(principal_us
), credential_use
,
985 logon_id
, auth_data
, get_key_fn
, get_key_arg
, credential
, ts_expiry
);
986 FIXME( "Wine was built without Kerberos support.\n" );
987 return SEC_E_UNSUPPORTED_FUNCTION
;
991 static NTSTATUS NTAPI
kerberos_SpFreeCredentialsHandle( LSA_SEC_HANDLE credential
)
993 #ifdef SONAME_LIBGSSAPI_KRB5
994 OM_uint32 ret
, minor_status
;
995 gss_cred_id_t cred_handle
;
997 TRACE( "(%lx)\n", credential
);
999 if (!credential
) return SEC_E_INVALID_HANDLE
;
1000 if (!(cred_handle
= credhandle_sspi_to_gss( credential
))) return SEC_E_OK
;
1002 ret
= pgss_release_cred( &minor_status
, &cred_handle
);
1003 TRACE( "gss_release_cred returned %08x minor status %08x\n", ret
, minor_status
);
1004 if (GSS_ERROR(ret
)) trace_gss_status( ret
, minor_status
);
1006 return status_gss_to_sspi( ret
);
1008 FIXME( "(%lx)\n", credential
);
1009 return SEC_E_UNSUPPORTED_FUNCTION
;
1013 static NTSTATUS NTAPI
kerberos_SpInitLsaModeContext( LSA_SEC_HANDLE credential
, LSA_SEC_HANDLE context
,
1014 UNICODE_STRING
*target_name
, ULONG context_req
, ULONG target_data_rep
, SecBufferDesc
*input
,
1015 LSA_SEC_HANDLE
*new_context
, SecBufferDesc
*output
, ULONG
*context_attr
, TimeStamp
*ts_expiry
,
1016 BOOLEAN
*mapped_context
, SecBuffer
*context_data
)
1018 #ifdef SONAME_LIBGSSAPI_KRB5
1019 static const ULONG supported
= ISC_REQ_CONFIDENTIALITY
| ISC_REQ_INTEGRITY
| ISC_REQ_SEQUENCE_DETECT
|
1020 ISC_REQ_REPLAY_DETECT
| ISC_REQ_MUTUAL_AUTH
| ISC_REQ_USE_DCE_STYLE
|
1021 ISC_REQ_IDENTIFY
| ISC_REQ_CONNECTION
;
1022 OM_uint32 ret
, minor_status
, ret_flags
= 0, expiry_time
, req_flags
= flags_isc_req_to_gss( context_req
);
1023 gss_cred_id_t cred_handle
;
1024 gss_ctx_id_t ctxt_handle
;
1025 gss_buffer_desc input_token
, output_token
;
1026 gss_name_t target
= GSS_C_NO_NAME
;
1030 TRACE( "(%lx %lx %s 0x%08x %u %p %p %p %p %p %p %p)\n", credential
, context
, debugstr_us(target_name
),
1031 context_req
, target_data_rep
, input
, new_context
, output
, context_attr
, ts_expiry
,
1032 mapped_context
, context_data
);
1033 if (context_req
& ~supported
)
1034 FIXME( "flags 0x%08x not supported\n", context_req
& ~supported
);
1036 if (!context
&& !input
&& !credential
) return SEC_E_INVALID_HANDLE
;
1037 cred_handle
= credhandle_sspi_to_gss( credential
);
1038 ctxt_handle
= ctxthandle_sspi_to_gss( context
);
1040 if ((idx
= get_buffer_index( input
, SECBUFFER_TOKEN
)) == -1) input_token
.length
= 0;
1043 input_token
.length
= input
->pBuffers
[idx
].cbBuffer
;
1044 input_token
.value
= input
->pBuffers
[idx
].pvBuffer
;
1047 if ((idx
= get_buffer_index( output
, SECBUFFER_TOKEN
)) == -1) return SEC_E_INVALID_TOKEN
;
1048 output_token
.length
= 0;
1049 output_token
.value
= NULL
;
1051 if (target_name
&& ((status
= name_sspi_to_gss( target_name
, &target
)) != SEC_E_OK
)) return status
;
1053 ret
= pgss_init_sec_context( &minor_status
, cred_handle
, &ctxt_handle
, target
, GSS_C_NO_OID
, req_flags
, 0,
1054 GSS_C_NO_CHANNEL_BINDINGS
, &input_token
, NULL
, &output_token
, &ret_flags
,
1056 TRACE( "gss_init_sec_context returned %08x minor status %08x ret_flags %08x\n", ret
, minor_status
, ret_flags
);
1057 if (GSS_ERROR(ret
)) trace_gss_status( ret
, minor_status
);
1058 if (ret
== GSS_S_COMPLETE
|| ret
== GSS_S_CONTINUE_NEEDED
)
1060 if (output_token
.length
> output
->pBuffers
[idx
].cbBuffer
) /* FIXME: check if larger buffer exists */
1062 TRACE( "buffer too small %lu > %u\n", (SIZE_T
)output_token
.length
, output
->pBuffers
[idx
].cbBuffer
);
1063 pgss_release_buffer( &minor_status
, &output_token
);
1064 pgss_delete_sec_context( &minor_status
, &ctxt_handle
, GSS_C_NO_BUFFER
);
1065 return SEC_E_INCOMPLETE_MESSAGE
;
1067 output
->pBuffers
[idx
].cbBuffer
= output_token
.length
;
1068 memcpy( output
->pBuffers
[idx
].pvBuffer
, output_token
.value
, output_token
.length
);
1069 pgss_release_buffer( &minor_status
, &output_token
);
1071 ctxthandle_gss_to_sspi( ctxt_handle
, new_context
);
1072 if (context_attr
) *context_attr
= flags_gss_to_isc_ret( ret_flags
);
1073 expirytime_gss_to_sspi( expiry_time
, ts_expiry
);
1076 if (target
!= GSS_C_NO_NAME
) pgss_release_name( &minor_status
, &target
);
1078 /* we do support user mode SSP/AP functions */
1079 *mapped_context
= TRUE
;
1080 /* FIXME: initialize context_data */
1082 return status_gss_to_sspi( ret
);
1084 FIXME( "(%lx %lx %s 0x%08x %u %p %p %p %p %p %p %p)\n", credential
, context
, debugstr_us(target_name
),
1085 context_req
, target_data_rep
, input
, new_context
, output
, context_attr
, ts_expiry
,
1086 mapped_context
, context_data
);
1087 return SEC_E_UNSUPPORTED_FUNCTION
;
1091 static NTSTATUS NTAPI
kerberos_SpAcceptLsaModeContext( LSA_SEC_HANDLE credential
, LSA_SEC_HANDLE context
,
1092 SecBufferDesc
*input
, ULONG context_req
, ULONG target_data_rep
, LSA_SEC_HANDLE
*new_context
,
1093 SecBufferDesc
*output
, ULONG
*context_attr
, TimeStamp
*ts_expiry
, BOOLEAN
*mapped_context
, SecBuffer
*context_data
)
1095 #ifdef SONAME_LIBGSSAPI_KRB5
1096 OM_uint32 ret
, minor_status
, ret_flags
= 0, expiry_time
;
1097 gss_cred_id_t cred_handle
;
1098 gss_ctx_id_t ctxt_handle
;
1099 gss_buffer_desc input_token
, output_token
;
1100 gss_name_t target
= GSS_C_NO_NAME
;
1103 TRACE( "(%lx %lx 0x%08x %u %p %p %p %p %p %p %p)\n", credential
, context
, context_req
,
1104 target_data_rep
, input
, new_context
, output
, context_attr
, ts_expiry
,
1105 mapped_context
, context_data
);
1106 if (context_req
) FIXME( "ignoring flags 0x%08x\n", context_req
);
1108 if (!context
&& !input
&& !credential
) return SEC_E_INVALID_HANDLE
;
1109 cred_handle
= credhandle_sspi_to_gss( credential
);
1110 ctxt_handle
= ctxthandle_sspi_to_gss( context
);
1112 if (!input
) input_token
.length
= 0;
1115 if ((idx
= get_buffer_index( input
, SECBUFFER_TOKEN
)) == -1) return SEC_E_INVALID_TOKEN
;
1116 input_token
.length
= input
->pBuffers
[idx
].cbBuffer
;
1117 input_token
.value
= input
->pBuffers
[idx
].pvBuffer
;
1120 if ((idx
= get_buffer_index( output
, SECBUFFER_TOKEN
)) == -1) return SEC_E_INVALID_TOKEN
;
1121 output_token
.length
= 0;
1122 output_token
.value
= NULL
;
1124 ret
= pgss_accept_sec_context( &minor_status
, &ctxt_handle
, cred_handle
, &input_token
, GSS_C_NO_CHANNEL_BINDINGS
,
1125 &target
, NULL
, &output_token
, &ret_flags
, &expiry_time
, NULL
);
1126 TRACE( "gss_accept_sec_context returned %08x minor status %08x ret_flags %08x\n", ret
, minor_status
, ret_flags
);
1127 if (GSS_ERROR(ret
)) trace_gss_status( ret
, minor_status
);
1128 if (ret
== GSS_S_COMPLETE
|| ret
== GSS_S_CONTINUE_NEEDED
)
1130 if (output_token
.length
> output
->pBuffers
[idx
].cbBuffer
) /* FIXME: check if larger buffer exists */
1132 TRACE( "buffer too small %lu > %u\n", (SIZE_T
)output_token
.length
, output
->pBuffers
[idx
].cbBuffer
);
1133 pgss_release_buffer( &minor_status
, &output_token
);
1134 pgss_delete_sec_context( &minor_status
, &ctxt_handle
, GSS_C_NO_BUFFER
);
1135 return SEC_E_BUFFER_TOO_SMALL
;
1137 output
->pBuffers
[idx
].cbBuffer
= output_token
.length
;
1138 memcpy( output
->pBuffers
[idx
].pvBuffer
, output_token
.value
, output_token
.length
);
1139 pgss_release_buffer( &minor_status
, &output_token
);
1141 ctxthandle_gss_to_sspi( ctxt_handle
, new_context
);
1142 if (context_attr
) *context_attr
= flags_gss_to_asc_ret( ret_flags
);
1143 expirytime_gss_to_sspi( expiry_time
, ts_expiry
);
1146 /* we do support user mode SSP/AP functions */
1147 *mapped_context
= TRUE
;
1148 /* FIXME: initialize context_data */
1150 return status_gss_to_sspi( ret
);
1152 FIXME( "(%lx %lx 0x%08x %u %p %p %p %p %p %p %p)\n", credential
, context
, context_req
,
1153 target_data_rep
, input
, new_context
, output
, context_attr
, ts_expiry
,
1154 mapped_context
, context_data
);
1155 return SEC_E_UNSUPPORTED_FUNCTION
;
1159 static NTSTATUS NTAPI
kerberos_SpDeleteContext( LSA_SEC_HANDLE context
)
1161 #ifdef SONAME_LIBGSSAPI_KRB5
1162 OM_uint32 ret
, minor_status
;
1163 gss_ctx_id_t ctxt_handle
;
1165 TRACE( "(%lx)\n", context
);
1166 if (!context
) return SEC_E_INVALID_HANDLE
;
1167 if (!(ctxt_handle
= ctxthandle_sspi_to_gss( context
))) return SEC_E_OK
;
1169 ret
= pgss_delete_sec_context( &minor_status
, &ctxt_handle
, GSS_C_NO_BUFFER
);
1170 TRACE( "gss_delete_sec_context returned %08x minor status %08x\n", ret
, minor_status
);
1171 if (GSS_ERROR(ret
)) trace_gss_status( ret
, minor_status
);
1173 return status_gss_to_sspi( ret
);
1175 FIXME( "(%lx)\n", context
);
1176 return SEC_E_UNSUPPORTED_FUNCTION
;
1180 static SecPkgInfoW
*build_package_info( const SecPkgInfoW
*info
)
1183 DWORD size_name
= (strlenW(info
->Name
) + 1) * sizeof(WCHAR
);
1184 DWORD size_comment
= (strlenW(info
->Comment
) + 1) * sizeof(WCHAR
);
1186 if (!(ret
= heap_alloc( sizeof(*ret
) + size_name
+ size_comment
))) return NULL
;
1187 ret
->fCapabilities
= info
->fCapabilities
;
1188 ret
->wVersion
= info
->wVersion
;
1189 ret
->wRPCID
= info
->wRPCID
;
1190 ret
->cbMaxToken
= info
->cbMaxToken
;
1191 ret
->Name
= (SEC_WCHAR
*)(ret
+ 1);
1192 memcpy( ret
->Name
, info
->Name
, size_name
);
1193 ret
->Comment
= (SEC_WCHAR
*)((char *)ret
->Name
+ size_name
);
1194 memcpy( ret
->Comment
, info
->Comment
, size_comment
);
1198 static NTSTATUS NTAPI
kerberos_SpQueryContextAttributes( LSA_SEC_HANDLE context
, ULONG attribute
, void *buffer
)
1200 TRACE( "(%lx %u %p)\n", context
, attribute
, buffer
);
1202 if (!context
) return SEC_E_INVALID_HANDLE
;
1206 #define X(x) case (x) : FIXME(#x" stub\n"); break
1207 X(SECPKG_ATTR_ACCESS_TOKEN
);
1208 X(SECPKG_ATTR_AUTHORITY
);
1209 X(SECPKG_ATTR_DCE_INFO
);
1210 X(SECPKG_ATTR_KEY_INFO
);
1211 X(SECPKG_ATTR_LIFESPAN
);
1212 X(SECPKG_ATTR_NAMES
);
1213 X(SECPKG_ATTR_NATIVE_NAMES
);
1214 X(SECPKG_ATTR_PACKAGE_INFO
);
1215 X(SECPKG_ATTR_PASSWORD_EXPIRY
);
1216 X(SECPKG_ATTR_SESSION_KEY
);
1217 X(SECPKG_ATTR_STREAM_SIZES
);
1218 X(SECPKG_ATTR_TARGET_INFORMATION
);
1219 case SECPKG_ATTR_SIZES
:
1221 SecPkgContext_Sizes
*sizes
= (SecPkgContext_Sizes
*)buffer
;
1222 ULONG size_max_signature
= 37, size_security_trailer
= 49;
1223 #ifdef SONAME_LIBGSSAPI_KRB5
1224 gss_ctx_id_t ctxt_handle
;
1226 if (!(ctxt_handle
= ctxthandle_sspi_to_gss( context
))) return SEC_E_INVALID_HANDLE
;
1227 if (is_dce_style_context( ctxt_handle
))
1229 size_max_signature
= 28;
1230 size_security_trailer
= 76;
1233 sizes
->cbMaxToken
= KERBEROS_MAX_BUF
;
1234 sizes
->cbMaxSignature
= size_max_signature
;
1235 sizes
->cbBlockSize
= 1;
1236 sizes
->cbSecurityTrailer
= size_security_trailer
;
1239 case SECPKG_ATTR_NEGOTIATION_INFO
:
1241 SecPkgContext_NegotiationInfoW
*info
= (SecPkgContext_NegotiationInfoW
*)buffer
;
1242 if (!(info
->PackageInfo
= build_package_info( &infoW
))) return SEC_E_INSUFFICIENT_MEMORY
;
1243 info
->NegotiationState
= SECPKG_NEGOTIATION_COMPLETE
;
1248 FIXME( "unknown attribute %u\n", attribute
);
1252 return SEC_E_UNSUPPORTED_FUNCTION
;
1255 static NTSTATUS NTAPI
kerberos_SpInitialize(ULONG_PTR package_id
, SECPKG_PARAMETERS
*params
,
1256 LSA_SECPKG_FUNCTION_TABLE
*lsa_function_table
)
1258 TRACE("%lu,%p,%p\n", package_id
, params
, lsa_function_table
);
1260 #ifdef SONAME_LIBGSSAPI_KRB5
1261 if (load_gssapi_krb5()) return STATUS_SUCCESS
;
1264 return STATUS_UNSUCCESSFUL
;
1267 static NTSTATUS NTAPI
kerberos_SpShutdown(void)
1271 #ifdef SONAME_LIBGSSAPI_KRB5
1272 unload_gssapi_krb5();
1275 return STATUS_SUCCESS
;
1278 static SECPKG_FUNCTION_TABLE kerberos_table
=
1280 kerberos_LsaApInitializePackage
, /* InitializePackage */
1281 NULL
, /* LsaLogonUser */
1282 NULL
, /* CallPackage */
1283 NULL
, /* LogonTerminated */
1284 kerberos_LsaApCallPackageUntrusted
, /* CallPackageUntrusted */
1285 NULL
, /* CallPackagePassthrough */
1286 NULL
, /* LogonUserEx */
1287 NULL
, /* LogonUserEx2 */
1288 kerberos_SpInitialize
,
1289 kerberos_SpShutdown
,
1291 NULL
, /* AcceptCredentials */
1292 kerberos_SpAcquireCredentialsHandle
,
1293 NULL
, /* SpQueryCredentialsAttributes */
1294 kerberos_SpFreeCredentialsHandle
,
1295 NULL
, /* SaveCredentials */
1296 NULL
, /* GetCredentials */
1297 NULL
, /* DeleteCredentials */
1298 kerberos_SpInitLsaModeContext
,
1299 kerberos_SpAcceptLsaModeContext
,
1300 kerberos_SpDeleteContext
,
1301 NULL
, /* ApplyControlToken */
1302 NULL
, /* GetUserInfo */
1303 NULL
, /* GetExtendedInformation */
1304 kerberos_SpQueryContextAttributes
,
1305 NULL
, /* SpAddCredentials */
1306 NULL
, /* SetExtendedInformation */
1307 NULL
, /* SetContextAttributes */
1308 NULL
, /* SetCredentialsAttributes */
1309 NULL
, /* ChangeAccountPassword */
1310 NULL
, /* QueryMetaData */
1311 NULL
, /* ExchangeMetaData */
1312 NULL
, /* GetCredUIContext */
1313 NULL
, /* UpdateCredentials */
1314 NULL
, /* ValidateTargetInfo */
1315 NULL
, /* PostLogonUser */
1318 NTSTATUS NTAPI
SpLsaModeInitialize(ULONG lsa_version
, PULONG package_version
,
1319 PSECPKG_FUNCTION_TABLE
*table
, PULONG table_count
)
1321 TRACE("%#x,%p,%p,%p\n", lsa_version
, package_version
, table
, table_count
);
1323 *package_version
= SECPKG_INTERFACE_VERSION
;
1324 *table
= &kerberos_table
;
1327 return STATUS_SUCCESS
;
1330 static NTSTATUS NTAPI
kerberos_SpInstanceInit(ULONG version
, SECPKG_DLL_FUNCTIONS
*dll_function_table
, void **user_functions
)
1332 TRACE("%#x,%p,%p\n", version
, dll_function_table
, user_functions
);
1334 return STATUS_SUCCESS
;
1337 static NTSTATUS SEC_ENTRY
kerberos_SpMakeSignature( LSA_SEC_HANDLE context
, ULONG quality_of_protection
,
1338 SecBufferDesc
*message
, ULONG message_seq_no
)
1340 #ifdef SONAME_LIBGSSAPI_KRB5
1341 OM_uint32 ret
, minor_status
;
1342 gss_buffer_desc data_buffer
, token_buffer
;
1343 gss_ctx_id_t ctxt_handle
;
1344 int data_idx
, token_idx
;
1346 TRACE( "(%lx 0x%08x %p %u)\n", context
, quality_of_protection
, message
, message_seq_no
);
1347 if (quality_of_protection
) FIXME( "ignoring quality_of_protection 0x%08x\n", quality_of_protection
);
1348 if (message_seq_no
) FIXME( "ignoring message_seq_no %u\n", message_seq_no
);
1350 if (!context
) return SEC_E_INVALID_HANDLE
;
1351 ctxt_handle
= ctxthandle_sspi_to_gss( context
);
1353 /* FIXME: multiple data buffers, read-only buffers */
1354 if ((data_idx
= get_buffer_index( message
, SECBUFFER_DATA
)) == -1) return SEC_E_INVALID_TOKEN
;
1355 data_buffer
.length
= message
->pBuffers
[data_idx
].cbBuffer
;
1356 data_buffer
.value
= message
->pBuffers
[data_idx
].pvBuffer
;
1358 if ((token_idx
= get_buffer_index( message
, SECBUFFER_TOKEN
)) == -1) return SEC_E_INVALID_TOKEN
;
1359 token_buffer
.length
= 0;
1360 token_buffer
.value
= NULL
;
1362 ret
= pgss_get_mic( &minor_status
, ctxt_handle
, GSS_C_QOP_DEFAULT
, &data_buffer
, &token_buffer
);
1363 TRACE( "gss_get_mic returned %08x minor status %08x\n", ret
, minor_status
);
1364 if (GSS_ERROR(ret
)) trace_gss_status( ret
, minor_status
);
1365 if (ret
== GSS_S_COMPLETE
)
1367 memcpy( message
->pBuffers
[token_idx
].pvBuffer
, token_buffer
.value
, token_buffer
.length
);
1368 message
->pBuffers
[token_idx
].cbBuffer
= token_buffer
.length
;
1369 pgss_release_buffer( &minor_status
, &token_buffer
);
1372 return status_gss_to_sspi( ret
);
1374 FIXME( "(%lx 0x%08x %p %u)\n", context
, quality_of_protection
, message
, message_seq_no
);
1375 return SEC_E_UNSUPPORTED_FUNCTION
;
1379 static NTSTATUS NTAPI
kerberos_SpVerifySignature( LSA_SEC_HANDLE context
, SecBufferDesc
*message
,
1380 ULONG message_seq_no
, ULONG
*quality_of_protection
)
1382 #ifdef SONAME_LIBGSSAPI_KRB5
1383 OM_uint32 ret
, minor_status
;
1384 gss_buffer_desc data_buffer
, token_buffer
;
1385 gss_ctx_id_t ctxt_handle
;
1386 int data_idx
, token_idx
;
1388 TRACE( "(%lx %p %u %p)\n", context
, message
, message_seq_no
, quality_of_protection
);
1389 if (message_seq_no
) FIXME( "ignoring message_seq_no %u\n", message_seq_no
);
1391 if (!context
) return SEC_E_INVALID_HANDLE
;
1392 ctxt_handle
= ctxthandle_sspi_to_gss( context
);
1394 if ((data_idx
= get_buffer_index( message
, SECBUFFER_DATA
)) == -1) return SEC_E_INVALID_TOKEN
;
1395 data_buffer
.length
= message
->pBuffers
[data_idx
].cbBuffer
;
1396 data_buffer
.value
= message
->pBuffers
[data_idx
].pvBuffer
;
1398 if ((token_idx
= get_buffer_index( message
, SECBUFFER_TOKEN
)) == -1) return SEC_E_INVALID_TOKEN
;
1399 token_buffer
.length
= message
->pBuffers
[token_idx
].cbBuffer
;
1400 token_buffer
.value
= message
->pBuffers
[token_idx
].pvBuffer
;
1402 ret
= pgss_verify_mic( &minor_status
, ctxt_handle
, &data_buffer
, &token_buffer
, NULL
);
1403 TRACE( "gss_verify_mic returned %08x minor status %08x\n", ret
, minor_status
);
1404 if (GSS_ERROR(ret
)) trace_gss_status( ret
, minor_status
);
1405 if (ret
== GSS_S_COMPLETE
&& quality_of_protection
) *quality_of_protection
= 0;
1407 return status_gss_to_sspi( ret
);
1409 FIXME( "(%lx %p %u %p)\n", context
, message
, message_seq_no
, quality_of_protection
);
1410 return SEC_E_UNSUPPORTED_FUNCTION
;
1414 #ifdef SONAME_LIBGSSAPI_KRB5
1415 static NTSTATUS
seal_message_iov( gss_ctx_id_t ctxt_handle
, SecBufferDesc
*message
, ULONG quality_of_protection
)
1417 gss_iov_buffer_desc iov
[4];
1418 OM_uint32 ret
, minor_status
;
1419 int token_idx
, data_idx
, conf_flag
, conf_state
;
1421 if (!quality_of_protection
)
1422 conf_flag
= 1; /* confidentiality + integrity */
1423 else if (quality_of_protection
== SECQOP_WRAP_NO_ENCRYPT
)
1424 conf_flag
= 0; /* only integrity */
1427 FIXME( "QOP %08x not supported\n", quality_of_protection
);
1428 return SEC_E_UNSUPPORTED_FUNCTION
;
1431 /* FIXME: multiple data buffers, read-only buffers */
1432 if ((data_idx
= get_buffer_index( message
, SECBUFFER_DATA
)) == -1) return SEC_E_INVALID_TOKEN
;
1433 if ((token_idx
= get_buffer_index( message
, SECBUFFER_TOKEN
)) == -1) return SEC_E_INVALID_TOKEN
;
1435 iov
[0].type
= GSS_IOV_BUFFER_TYPE_SIGN_ONLY
| GSS_IOV_BUFFER_FLAG_ALLOCATE
;
1436 iov
[0].buffer
.length
= 0;
1437 iov
[0].buffer
.value
= NULL
;
1439 iov
[1].type
= GSS_IOV_BUFFER_TYPE_DATA
;
1440 iov
[1].buffer
.length
= message
->pBuffers
[data_idx
].cbBuffer
;
1441 iov
[1].buffer
.value
= message
->pBuffers
[data_idx
].pvBuffer
;
1443 iov
[2].type
= GSS_IOV_BUFFER_TYPE_SIGN_ONLY
| GSS_IOV_BUFFER_FLAG_ALLOCATE
;
1444 iov
[2].buffer
.length
= 0;
1445 iov
[2].buffer
.value
= NULL
;
1447 iov
[3].type
= GSS_IOV_BUFFER_TYPE_HEADER
| GSS_IOV_BUFFER_FLAG_ALLOCATE
;
1448 iov
[3].buffer
.length
= 0;
1449 iov
[3].buffer
.value
= NULL
;
1451 ret
= pgss_wrap_iov( &minor_status
, ctxt_handle
, conf_flag
, GSS_C_QOP_DEFAULT
, &conf_state
, iov
, 4 );
1452 TRACE( "gss_wrap_iov returned %08x minor status %08x\n", ret
, minor_status
);
1453 if (GSS_ERROR(ret
)) trace_gss_status( ret
, minor_status
);
1454 if (ret
== GSS_S_COMPLETE
)
1456 memcpy( message
->pBuffers
[token_idx
].pvBuffer
, iov
[3].buffer
.value
, iov
[3].buffer
.length
);
1457 message
->pBuffers
[token_idx
].cbBuffer
= iov
[3].buffer
.length
;
1458 pgss_release_iov_buffer( &minor_status
, iov
, 4 );
1461 return status_gss_to_sspi( ret
);
1464 static NTSTATUS
seal_message( gss_ctx_id_t ctxt_handle
, SecBufferDesc
*message
, ULONG quality_of_protection
)
1466 gss_buffer_desc input
, output
;
1467 OM_uint32 ret
, minor_status
;
1468 int token_idx
, data_idx
, conf_flag
, conf_state
;
1470 if (!quality_of_protection
)
1471 conf_flag
= 1; /* confidentiality + integrity */
1472 else if (quality_of_protection
== SECQOP_WRAP_NO_ENCRYPT
)
1473 conf_flag
= 0; /* only integrity */
1476 FIXME( "QOP %08x not supported\n", quality_of_protection
);
1477 return SEC_E_UNSUPPORTED_FUNCTION
;
1480 /* FIXME: multiple data buffers, read-only buffers */
1481 if ((data_idx
= get_buffer_index( message
, SECBUFFER_DATA
)) == -1) return SEC_E_INVALID_TOKEN
;
1482 if ((token_idx
= get_buffer_index( message
, SECBUFFER_TOKEN
)) == -1) return SEC_E_INVALID_TOKEN
;
1484 input
.length
= message
->pBuffers
[data_idx
].cbBuffer
;
1485 input
.value
= message
->pBuffers
[data_idx
].pvBuffer
;
1487 ret
= pgss_wrap( &minor_status
, ctxt_handle
, conf_flag
, GSS_C_QOP_DEFAULT
, &input
, &conf_state
, &output
);
1488 TRACE( "gss_wrap returned %08x minor status %08x\n", ret
, minor_status
);
1489 if (GSS_ERROR(ret
)) trace_gss_status( ret
, minor_status
);
1490 if (ret
== GSS_S_COMPLETE
)
1492 DWORD len_data
= message
->pBuffers
[data_idx
].cbBuffer
, len_token
= message
->pBuffers
[token_idx
].cbBuffer
;
1493 if (len_token
< output
.length
- len_data
)
1495 TRACE( "buffer too small %lu > %u\n", (SIZE_T
)output
.length
- len_data
, len_token
);
1496 pgss_release_buffer( &minor_status
, &output
);
1497 return SEC_E_BUFFER_TOO_SMALL
;
1499 memcpy( message
->pBuffers
[data_idx
].pvBuffer
, output
.value
, len_data
);
1500 memcpy( message
->pBuffers
[token_idx
].pvBuffer
, (char *)output
.value
+ len_data
, output
.length
- len_data
);
1501 message
->pBuffers
[token_idx
].cbBuffer
= output
.length
- len_data
;
1502 pgss_release_buffer( &minor_status
, &output
);
1505 return status_gss_to_sspi( ret
);
1509 static NTSTATUS NTAPI
kerberos_SpSealMessage( LSA_SEC_HANDLE context
, ULONG quality_of_protection
,
1510 SecBufferDesc
*message
, ULONG message_seq_no
)
1512 #ifdef SONAME_LIBGSSAPI_KRB5
1513 gss_ctx_id_t ctxt_handle
;
1515 TRACE( "(%lx 0x%08x %p %u)\n", context
, quality_of_protection
, message
, message_seq_no
);
1516 if (message_seq_no
) FIXME( "ignoring message_seq_no %u\n", message_seq_no
);
1518 if (!context
) return SEC_E_INVALID_HANDLE
;
1519 ctxt_handle
= ctxthandle_sspi_to_gss( context
);
1521 if (is_dce_style_context( ctxt_handle
)) return seal_message_iov( ctxt_handle
, message
, quality_of_protection
);
1522 return seal_message( ctxt_handle
, message
, quality_of_protection
);
1524 FIXME( "(%lx 0x%08x %p %u)\n", context
, quality_of_protection
, message
, message_seq_no
);
1525 return SEC_E_UNSUPPORTED_FUNCTION
;
1529 #ifdef SONAME_LIBGSSAPI_KRB5
1530 static NTSTATUS
unseal_message_iov( gss_ctx_id_t ctxt_handle
, SecBufferDesc
*message
, ULONG
*quality_of_protection
)
1532 gss_iov_buffer_desc iov
[4];
1533 OM_uint32 ret
, minor_status
;
1534 int token_idx
, data_idx
, conf_state
;
1536 if ((data_idx
= get_buffer_index( message
, SECBUFFER_DATA
)) == -1) return SEC_E_INVALID_TOKEN
;
1537 if ((token_idx
= get_buffer_index( message
, SECBUFFER_TOKEN
)) == -1) return SEC_E_INVALID_TOKEN
;
1539 iov
[0].type
= GSS_IOV_BUFFER_TYPE_SIGN_ONLY
;
1540 iov
[0].buffer
.length
= 0;
1541 iov
[0].buffer
.value
= NULL
;
1543 iov
[1].type
= GSS_IOV_BUFFER_TYPE_DATA
;
1544 iov
[1].buffer
.length
= message
->pBuffers
[data_idx
].cbBuffer
;
1545 iov
[1].buffer
.value
= message
->pBuffers
[data_idx
].pvBuffer
;
1547 iov
[2].type
= GSS_IOV_BUFFER_TYPE_SIGN_ONLY
;
1548 iov
[2].buffer
.length
= 0;
1549 iov
[2].buffer
.value
= NULL
;
1551 iov
[3].type
= GSS_IOV_BUFFER_TYPE_HEADER
;
1552 iov
[3].buffer
.length
= message
->pBuffers
[token_idx
].cbBuffer
;
1553 iov
[3].buffer
.value
= message
->pBuffers
[token_idx
].pvBuffer
;
1555 ret
= pgss_unwrap_iov( &minor_status
, ctxt_handle
, &conf_state
, NULL
, iov
, 4 );
1556 TRACE( "gss_unwrap_iov returned %08x minor status %08x\n", ret
, minor_status
);
1557 if (GSS_ERROR(ret
)) trace_gss_status( ret
, minor_status
);
1558 if (ret
== GSS_S_COMPLETE
&& quality_of_protection
)
1560 *quality_of_protection
= (conf_state
? 0 : SECQOP_WRAP_NO_ENCRYPT
);
1562 return status_gss_to_sspi( ret
);
1565 static NTSTATUS
unseal_message( gss_ctx_id_t ctxt_handle
, SecBufferDesc
*message
, ULONG
*quality_of_protection
)
1567 gss_buffer_desc input
, output
;
1568 OM_uint32 ret
, minor_status
;
1569 int token_idx
, data_idx
, conf_state
;
1570 DWORD len_data
, len_token
;
1572 if ((data_idx
= get_buffer_index( message
, SECBUFFER_DATA
)) == -1) return SEC_E_INVALID_TOKEN
;
1573 if ((token_idx
= get_buffer_index( message
, SECBUFFER_TOKEN
)) == -1) return SEC_E_INVALID_TOKEN
;
1575 len_data
= message
->pBuffers
[data_idx
].cbBuffer
;
1576 len_token
= message
->pBuffers
[token_idx
].cbBuffer
;
1578 input
.length
= len_data
+ len_token
;
1579 if (!(input
.value
= heap_alloc( input
.length
))) return SEC_E_INSUFFICIENT_MEMORY
;
1580 memcpy( input
.value
, message
->pBuffers
[data_idx
].pvBuffer
, len_data
);
1581 memcpy( (char *)input
.value
+ len_data
, message
->pBuffers
[token_idx
].pvBuffer
, len_token
);
1583 ret
= pgss_unwrap( &minor_status
, ctxt_handle
, &input
, &output
, &conf_state
, NULL
);
1584 heap_free( input
.value
);
1585 TRACE( "gss_unwrap returned %08x minor status %08x\n", ret
, minor_status
);
1586 if (GSS_ERROR(ret
)) trace_gss_status( ret
, minor_status
);
1587 if (ret
== GSS_S_COMPLETE
)
1589 if (quality_of_protection
) *quality_of_protection
= (conf_state
? 0 : SECQOP_WRAP_NO_ENCRYPT
);
1590 memcpy( message
->pBuffers
[data_idx
].pvBuffer
, output
.value
, len_data
);
1591 pgss_release_buffer( &minor_status
, &output
);
1594 return status_gss_to_sspi( ret
);
1598 static NTSTATUS NTAPI
kerberos_SpUnsealMessage( LSA_SEC_HANDLE context
, SecBufferDesc
*message
,
1599 ULONG message_seq_no
, ULONG
*quality_of_protection
)
1601 #ifdef SONAME_LIBGSSAPI_KRB5
1602 gss_ctx_id_t ctxt_handle
;
1604 TRACE( "(%lx %p %u %p)\n", context
, message
, message_seq_no
, quality_of_protection
);
1605 if (message_seq_no
) FIXME( "ignoring message_seq_no %u\n", message_seq_no
);
1607 if (!context
) return SEC_E_INVALID_HANDLE
;
1608 ctxt_handle
= ctxthandle_sspi_to_gss( context
);
1610 if (is_dce_style_context( ctxt_handle
)) return unseal_message_iov( ctxt_handle
, message
, quality_of_protection
);
1611 return unseal_message( ctxt_handle
, message
, quality_of_protection
);
1613 FIXME( "(%lx %p %u %p)\n", context
, message
, message_seq_no
, quality_of_protection
);
1614 return SEC_E_UNSUPPORTED_FUNCTION
;
1618 static SECPKG_USER_FUNCTION_TABLE kerberos_user_table
=
1620 kerberos_SpInstanceInit
,
1621 NULL
, /* SpInitUserModeContext */
1622 kerberos_SpMakeSignature
,
1623 kerberos_SpVerifySignature
,
1624 kerberos_SpSealMessage
,
1625 kerberos_SpUnsealMessage
,
1626 NULL
, /* SpGetContextToken */
1627 NULL
, /* SpQueryContextAttributes */
1628 NULL
, /* SpCompleteAuthToken */
1629 NULL
, /* SpDeleteContext */
1630 NULL
, /* SpFormatCredentialsFn */
1631 NULL
, /* SpMarshallSupplementalCreds */
1632 NULL
, /* SpExportSecurityContext */
1633 NULL
/* SpImportSecurityContext */
1636 NTSTATUS NTAPI
SpUserModeInitialize(ULONG lsa_version
, PULONG package_version
,
1637 PSECPKG_USER_FUNCTION_TABLE
*table
, PULONG table_count
)
1639 TRACE("%#x,%p,%p,%p\n", lsa_version
, package_version
, table
, table_count
);
1641 *package_version
= SECPKG_INTERFACE_VERSION
;
1642 *table
= &kerberos_user_table
;
1645 return STATUS_SUCCESS
;