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
27 #define WIN32_NO_STATUS
37 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(kerberos
);
42 #define KERBEROS_CAPS \
43 ( SECPKG_FLAG_INTEGRITY \
44 | SECPKG_FLAG_PRIVACY \
45 | SECPKG_FLAG_TOKEN_ONLY \
46 | SECPKG_FLAG_DATAGRAM \
47 | SECPKG_FLAG_CONNECTION \
48 | SECPKG_FLAG_MULTI_REQUIRED \
49 | SECPKG_FLAG_EXTENDED_ERROR \
50 | SECPKG_FLAG_IMPERSONATION \
51 | SECPKG_FLAG_ACCEPT_WIN32_NAME \
52 | SECPKG_FLAG_NEGOTIABLE \
53 | SECPKG_FLAG_GSS_COMPATIBLE \
55 | SECPKG_FLAG_MUTUAL_AUTH \
56 | SECPKG_FLAG_DELEGATION \
57 | SECPKG_FLAG_READONLY_WITH_CHECKSUM \
58 | SECPKG_FLAG_RESTRICTED_TOKENS \
59 | SECPKG_FLAG_APPCONTAINER_CHECKS)
61 static WCHAR kerberos_name_W
[] = L
"Kerberos";
62 static WCHAR kerberos_comment_W
[] = L
"Microsoft Kerberos V1.0";
63 static const SecPkgInfoW infoW
=
67 RPC_C_AUTHN_GSS_KERBEROS
,
73 static ULONG kerberos_package_id
;
74 static LSA_DISPATCH_TABLE lsa_dispatch
;
86 static LSA_SEC_HANDLE
create_context_handle( struct context_handle
*ctx
, UINT64 new_context
)
88 UINT64 context
= ctx
? ctx
->handle
: 0;
89 if (new_context
&& new_context
!= context
)
91 struct context_handle
*new_ctx
= malloc(sizeof(*new_ctx
));
92 new_ctx
->handle
= new_context
;
93 return (LSA_SEC_HANDLE
)new_ctx
;
96 return (LSA_SEC_HANDLE
)ctx
;
99 static int get_buffer_index( const SecBufferDesc
*desc
, DWORD type
)
102 if (!desc
) return -1;
103 for (i
= 0; i
< desc
->cBuffers
; i
++)
105 if (desc
->pBuffers
[i
].BufferType
== type
) return i
;
110 static const char *debugstr_us( const UNICODE_STRING
*us
)
112 if (!us
) return "<null>";
113 return debugstr_wn( us
->Buffer
, us
->Length
/ sizeof(WCHAR
) );
116 static void expiry_to_timestamp( ULONG expiry
, TimeStamp
*timestamp
)
120 if (!timestamp
) return;
121 NtQuerySystemTime( &time
);
122 RtlSystemTimeToLocalTime( &time
, &time
);
123 time
.QuadPart
+= expiry
* (ULONGLONG
)10000000;
124 timestamp
->LowPart
= time
.QuadPart
;
125 timestamp
->HighPart
= time
.QuadPart
>> 32;
128 static NTSTATUS NTAPI
kerberos_LsaApInitializePackage(ULONG package_id
, PLSA_DISPATCH_TABLE dispatch
,
129 PLSA_STRING database
, PLSA_STRING confidentiality
, PLSA_STRING
*package_name
)
133 if (!__wine_unixlib_handle
)
135 if (__wine_init_unix_call() || KRB5_CALL( process_attach
, NULL
))
136 ERR( "no Kerberos support, expect problems\n" );
139 kerberos_package_id
= package_id
;
140 lsa_dispatch
= *dispatch
;
142 kerberos_name
= lsa_dispatch
.AllocateLsaHeap(sizeof(MICROSOFT_KERBEROS_NAME_A
));
143 if (!kerberos_name
) return STATUS_NO_MEMORY
;
145 memcpy(kerberos_name
, MICROSOFT_KERBEROS_NAME_A
, sizeof(MICROSOFT_KERBEROS_NAME_A
));
147 *package_name
= lsa_dispatch
.AllocateLsaHeap(sizeof(**package_name
));
150 lsa_dispatch
.FreeLsaHeap(kerberos_name
);
151 return STATUS_NO_MEMORY
;
154 RtlInitString(*package_name
, kerberos_name
);
156 return STATUS_SUCCESS
;
159 static NTSTATUS
copy_to_client( PLSA_CLIENT_REQUEST lsa_req
, KERB_QUERY_TKT_CACHE_EX_RESPONSE
*resp
,
160 void **out
, ULONG size
)
165 KERB_QUERY_TKT_CACHE_RESPONSE
*client_resp
;
167 status
= lsa_dispatch
.AllocateClientBuffer( lsa_req
, size
, out
);
168 if (status
!= STATUS_SUCCESS
) return status
;
171 status
= lsa_dispatch
.CopyToClientBuffer(lsa_req
, offsetof(KERB_QUERY_TKT_CACHE_RESPONSE
, Tickets
),
173 if (status
!= STATUS_SUCCESS
) goto fail
;
175 client_str
= (char *)&client_resp
->Tickets
[resp
->CountOfTickets
];
177 for (i
= 0; i
< resp
->CountOfTickets
; i
++)
179 KERB_TICKET_CACHE_INFO ticket
= {
180 .ServerName
= resp
->Tickets
[i
].ServerName
,
181 .RealmName
= resp
->Tickets
[i
].ServerRealm
,
182 .StartTime
= resp
->Tickets
[i
].StartTime
,
183 .EndTime
= resp
->Tickets
[i
].EndTime
,
184 .RenewTime
= resp
->Tickets
[i
].RenewTime
,
185 .EncryptionType
= resp
->Tickets
[i
].EncryptionType
,
186 .TicketFlags
= resp
->Tickets
[i
].TicketFlags
,
189 RtlSecondsSince1970ToTime( resp
->Tickets
[i
].StartTime
.QuadPart
, &ticket
.StartTime
);
190 RtlSecondsSince1970ToTime( resp
->Tickets
[i
].EndTime
.QuadPart
, &ticket
.EndTime
);
191 RtlSecondsSince1970ToTime( resp
->Tickets
[i
].RenewTime
.QuadPart
, &ticket
.RenewTime
);
193 status
= lsa_dispatch
.CopyToClientBuffer(lsa_req
, ticket
.RealmName
.MaximumLength
,
194 client_str
, ticket
.RealmName
.Buffer
);
195 if (status
!= STATUS_SUCCESS
) goto fail
;
196 ticket
.RealmName
.Buffer
= (WCHAR
*)client_str
;
197 client_str
+= ticket
.RealmName
.MaximumLength
;
199 status
= lsa_dispatch
.CopyToClientBuffer(lsa_req
, ticket
.ServerName
.MaximumLength
,
200 client_str
, ticket
.ServerName
.Buffer
);
201 if (status
!= STATUS_SUCCESS
) goto fail
;
202 ticket
.ServerName
.Buffer
= (WCHAR
*)client_str
;
203 client_str
+= ticket
.ServerName
.MaximumLength
;
205 status
= lsa_dispatch
.CopyToClientBuffer(lsa_req
, sizeof(ticket
), &client_resp
->Tickets
[i
], &ticket
);
206 if (status
!= STATUS_SUCCESS
) goto fail
;
208 return STATUS_SUCCESS
;
211 lsa_dispatch
.FreeClientBuffer(lsa_req
, client_resp
);
215 static NTSTATUS
copy_to_client_ex( PLSA_CLIENT_REQUEST lsa_req
, KERB_QUERY_TKT_CACHE_EX_RESPONSE
*resp
,
216 void **out
, ULONG size
)
221 KERB_QUERY_TKT_CACHE_EX_RESPONSE
*client_resp
;
223 status
= lsa_dispatch
.AllocateClientBuffer( lsa_req
, size
, out
);
224 if (status
!= STATUS_SUCCESS
) return status
;
227 status
= lsa_dispatch
.CopyToClientBuffer(lsa_req
, offsetof(KERB_QUERY_TKT_CACHE_EX_RESPONSE
, Tickets
),
229 if (status
!= STATUS_SUCCESS
) goto fail
;
231 client_str
= (char *)&client_resp
->Tickets
[resp
->CountOfTickets
];
233 for (i
= 0; i
< resp
->CountOfTickets
; i
++)
235 KERB_TICKET_CACHE_INFO_EX ticket
= resp
->Tickets
[i
];
237 RtlSecondsSince1970ToTime( resp
->Tickets
[i
].StartTime
.QuadPart
, &ticket
.StartTime
);
238 RtlSecondsSince1970ToTime( resp
->Tickets
[i
].EndTime
.QuadPart
, &ticket
.EndTime
);
239 RtlSecondsSince1970ToTime( resp
->Tickets
[i
].RenewTime
.QuadPart
, &ticket
.RenewTime
);
241 status
= lsa_dispatch
.CopyToClientBuffer(lsa_req
, ticket
.ClientRealm
.MaximumLength
,
242 client_str
, ticket
.ClientRealm
.Buffer
);
243 if (status
!= STATUS_SUCCESS
) goto fail
;
244 ticket
.ClientRealm
.Buffer
= (WCHAR
*)client_str
;
245 client_str
+= ticket
.ClientRealm
.MaximumLength
;
247 status
= lsa_dispatch
.CopyToClientBuffer(lsa_req
, ticket
.ClientName
.MaximumLength
,
248 client_str
, ticket
.ClientName
.Buffer
);
249 if (status
!= STATUS_SUCCESS
) goto fail
;
250 ticket
.ClientName
.Buffer
= (WCHAR
*)client_str
;
251 client_str
+= ticket
.ClientName
.MaximumLength
;
253 status
= lsa_dispatch
.CopyToClientBuffer(lsa_req
, ticket
.ServerRealm
.MaximumLength
,
254 client_str
, ticket
.ServerRealm
.Buffer
);
255 if (status
!= STATUS_SUCCESS
) goto fail
;
256 ticket
.ServerRealm
.Buffer
= (WCHAR
*)client_str
;
257 client_str
+= ticket
.ServerRealm
.MaximumLength
;
259 status
= lsa_dispatch
.CopyToClientBuffer(lsa_req
, ticket
.ServerName
.MaximumLength
,
260 client_str
, ticket
.ServerName
.Buffer
);
261 if (status
!= STATUS_SUCCESS
) goto fail
;
262 ticket
.ServerName
.Buffer
= (WCHAR
*)client_str
;
263 client_str
+= ticket
.ServerName
.MaximumLength
;
265 status
= lsa_dispatch
.CopyToClientBuffer(lsa_req
, sizeof(ticket
), &client_resp
->Tickets
[i
], &ticket
);
266 if (status
!= STATUS_SUCCESS
) goto fail
;
268 return STATUS_SUCCESS
;
271 lsa_dispatch
.FreeClientBuffer(lsa_req
, client_resp
);
275 static NTSTATUS NTAPI
kerberos_LsaApCallPackageUntrusted(PLSA_CLIENT_REQUEST req
, void *in_buf
,
276 void *client_buf_base
, ULONG in_buf_len
, void **out_buf
, ULONG
*out_buf_len
, NTSTATUS
*ret_status
)
278 KERB_PROTOCOL_MESSAGE_TYPE msg
;
280 TRACE("%p, %p, %p, %lu, %p, %p, %p\n", req
, in_buf
, client_buf_base
, in_buf_len
, out_buf
, out_buf_len
, ret_status
);
282 if (!in_buf
|| in_buf_len
< sizeof(msg
)) return STATUS_INVALID_PARAMETER
;
284 msg
= *(KERB_PROTOCOL_MESSAGE_TYPE
*)in_buf
;
287 case KerbQueryTicketCacheMessage
:
289 KERB_QUERY_TKT_CACHE_REQUEST
*query
= (KERB_QUERY_TKT_CACHE_REQUEST
*)in_buf
;
292 if (!in_buf
|| in_buf_len
!= sizeof(*query
) || !out_buf
|| !out_buf_len
) return STATUS_INVALID_PARAMETER
;
293 if (query
->LogonId
.HighPart
|| query
->LogonId
.LowPart
) return STATUS_ACCESS_DENIED
;
298 KERB_QUERY_TKT_CACHE_EX_RESPONSE
*resp
= malloc( *out_buf_len
);
299 struct query_ticket_cache_params params
= { resp
, out_buf_len
};
302 status
= STATUS_NO_MEMORY
;
305 status
= KRB5_CALL( query_ticket_cache
, ¶ms
);
306 if (status
== STATUS_SUCCESS
) status
= copy_to_client( req
, resp
, out_buf
, *out_buf_len
);
308 if (status
!= STATUS_BUFFER_TOO_SMALL
) break;
310 *ret_status
= status
;
313 case KerbQueryTicketCacheExMessage
:
315 KERB_QUERY_TKT_CACHE_REQUEST
*query
= (KERB_QUERY_TKT_CACHE_REQUEST
*)in_buf
;
318 if (!in_buf
|| in_buf_len
!= sizeof(*query
) || !out_buf
|| !out_buf_len
) return STATUS_INVALID_PARAMETER
;
319 if (query
->LogonId
.HighPart
|| query
->LogonId
.LowPart
) return STATUS_ACCESS_DENIED
;
324 KERB_QUERY_TKT_CACHE_EX_RESPONSE
*resp
= malloc( *out_buf_len
);
325 struct query_ticket_cache_params params
= { resp
, out_buf_len
};
328 status
= STATUS_NO_MEMORY
;
331 status
= KRB5_CALL( query_ticket_cache
, ¶ms
);
332 if (status
== STATUS_SUCCESS
) status
= copy_to_client_ex( req
, resp
, out_buf
, *out_buf_len
);
334 if (status
!= STATUS_BUFFER_TOO_SMALL
) break;
336 *ret_status
= status
;
339 case KerbRetrieveTicketMessage
:
340 FIXME("KerbRetrieveTicketMessage stub\n");
341 *ret_status
= STATUS_NOT_IMPLEMENTED
;
344 case KerbPurgeTicketCacheMessage
:
345 FIXME("KerbPurgeTicketCacheMessage stub\n");
346 *ret_status
= STATUS_NOT_IMPLEMENTED
;
349 default: /* All other requests should call LsaApCallPackage */
350 WARN("%u => access denied\n", msg
);
351 *ret_status
= STATUS_ACCESS_DENIED
;
358 static NTSTATUS NTAPI
kerberos_SpGetInfo(SecPkgInfoW
*info
)
362 /* LSA will make a copy before forwarding the structure, so
363 * it's safe to put pointers to dynamic or constant data there.
367 return STATUS_SUCCESS
;
370 static char *get_str_unixcp( const UNICODE_STRING
*str
)
373 int len
= WideCharToMultiByte( CP_UNIXCP
, 0, str
->Buffer
, str
->Length
/ sizeof(WCHAR
), NULL
, 0, NULL
, NULL
);
374 if (!(ret
= malloc( len
+ 1 ))) return NULL
;
375 WideCharToMultiByte( CP_UNIXCP
, 0, str
->Buffer
, str
->Length
/ sizeof(WCHAR
), ret
, len
, NULL
, NULL
);
380 static char *get_username_unixcp( const WCHAR
*user
, ULONG user_len
, const WCHAR
*domain
, ULONG domain_len
)
382 int len_user
, len_domain
;
385 len_user
= WideCharToMultiByte( CP_UNIXCP
, 0, user
, user_len
, NULL
, 0, NULL
, NULL
);
386 len_domain
= WideCharToMultiByte( CP_UNIXCP
, 0, domain
, domain_len
, NULL
, 0, NULL
, NULL
);
387 if (!(ret
= malloc( len_user
+ len_domain
+ 2 ))) return NULL
;
389 WideCharToMultiByte( CP_UNIXCP
, 0, user
, user_len
, ret
, len_user
, NULL
, NULL
);
391 WideCharToMultiByte( CP_UNIXCP
, 0, domain
, domain_len
, ret
+ len_user
+ 1, len_domain
, NULL
, NULL
);
392 ret
[len_user
+ len_domain
+ 1] = 0;
396 static char *get_password_unixcp( const WCHAR
*passwd
, ULONG passwd_len
)
401 len
= WideCharToMultiByte( CP_UNIXCP
, WC_NO_BEST_FIT_CHARS
, passwd
, passwd_len
, NULL
, 0, NULL
, NULL
);
402 if (!(ret
= malloc( len
+ 1 ))) return NULL
;
403 WideCharToMultiByte( CP_UNIXCP
, 0, passwd
, passwd_len
, ret
, len
, NULL
, NULL
);
408 static NTSTATUS NTAPI
kerberos_SpAcquireCredentialsHandle(
409 UNICODE_STRING
*principal_us
, ULONG credential_use
, LUID
*logon_id
, void *auth_data
,
410 void *get_key_fn
, void *get_key_arg
, LSA_SEC_HANDLE
*credential
, TimeStamp
*expiry
)
412 char *principal
= NULL
, *username
= NULL
, *password
= NULL
;
413 SEC_WINNT_AUTH_IDENTITY_W
*id
= auth_data
;
414 NTSTATUS status
= SEC_E_INSUFFICIENT_MEMORY
;
415 struct cred_handle
*cred_handle
;
418 TRACE( "%s, %#lx, %p, %p, %p, %p, %p, %p\n", debugstr_us(principal_us
), credential_use
,
419 logon_id
, auth_data
, get_key_fn
, get_key_arg
, credential
, expiry
);
421 if (principal_us
&& !(principal
= get_str_unixcp( principal_us
))) return SEC_E_INSUFFICIENT_MEMORY
;
424 if (id
->Flags
& SEC_WINNT_AUTH_IDENTITY_ANSI
)
426 FIXME( "ANSI identity not supported\n" );
427 status
= SEC_E_UNSUPPORTED_FUNCTION
;
430 if (!(username
= get_username_unixcp( id
->User
, id
->UserLength
, id
->Domain
, id
->DomainLength
))) goto done
;
431 if (!(password
= get_password_unixcp( id
->Password
, id
->PasswordLength
))) goto done
;
434 if (!(cred_handle
= calloc( 1, sizeof(*cred_handle
) )))
436 status
= SEC_E_INSUFFICIENT_MEMORY
;
441 struct acquire_credentials_handle_params params
= { principal
, credential_use
, username
, password
,
442 &cred_handle
->handle
, &exptime
};
443 if (!(status
= KRB5_CALL( acquire_credentials_handle
, ¶ms
)))
444 *credential
= (LSA_SEC_HANDLE
)cred_handle
;
447 expiry_to_timestamp( exptime
, expiry
);
457 static NTSTATUS NTAPI
kerberos_SpFreeCredentialsHandle( LSA_SEC_HANDLE credential
)
459 struct cred_handle
*cred_handle
= (void *)credential
;
460 struct free_credentials_handle_params params
;
463 TRACE( "%Ix\n", credential
);
465 if (!cred_handle
) return SEC_E_INVALID_HANDLE
;
467 params
.credential
= cred_handle
->handle
;
468 status
= KRB5_CALL( free_credentials_handle
, ¶ms
);
473 static NTSTATUS NTAPI
kerberos_SpInitLsaModeContext( LSA_SEC_HANDLE credential
, LSA_SEC_HANDLE context
,
474 UNICODE_STRING
*target_name
, ULONG context_req
, ULONG target_data_rep
, SecBufferDesc
*input
,
475 LSA_SEC_HANDLE
*new_context
, SecBufferDesc
*output
, ULONG
*context_attr
, TimeStamp
*expiry
,
476 BOOLEAN
*mapped_context
, SecBuffer
*context_data
)
478 static const ULONG supported
= ISC_REQ_CONFIDENTIALITY
| ISC_REQ_INTEGRITY
| ISC_REQ_SEQUENCE_DETECT
|
479 ISC_REQ_REPLAY_DETECT
| ISC_REQ_MUTUAL_AUTH
| ISC_REQ_USE_DCE_STYLE
|
480 ISC_REQ_IDENTIFY
| ISC_REQ_CONNECTION
| ISC_REQ_DELEGATE
;
485 TRACE( "%Ix, %Ix, %s, %#lx, %lu, %p, %p, %p, %p, %p, %p, %p\n", credential
, context
, debugstr_us(target_name
),
486 context_req
, target_data_rep
, input
, new_context
, output
, context_attr
, expiry
,
487 mapped_context
, context_data
);
488 if (context_req
& ~supported
) FIXME( "flags %#lx not supported\n", context_req
& ~supported
);
490 if (!context
&& !input
&& !credential
) return SEC_E_INVALID_HANDLE
;
491 if (target_name
&& !(target
= get_str_unixcp( target_name
))) return SEC_E_INSUFFICIENT_MEMORY
;
494 struct cred_handle
*cred_handle
= (struct cred_handle
*)credential
;
495 struct context_handle
*context_handle
= (struct context_handle
*)context
;
496 struct initialize_context_params params
= { 0 };
497 UINT64 new_context_handle
= 0;
500 params
.credential
= cred_handle
? cred_handle
->handle
: 0;
501 params
.context
= context_handle
? context_handle
->handle
: 0;
502 params
.target_name
= target
;
503 params
.context_req
= context_req
;
504 params
.new_context
= &new_context_handle
;
505 params
.context_attr
= context_attr
;
506 params
.expiry
= &exptime
;
508 idx
= get_buffer_index( input
, SECBUFFER_TOKEN
);
511 params
.input_token
= input
->pBuffers
[idx
].pvBuffer
;
512 params
.input_token_length
= input
->pBuffers
[idx
].cbBuffer
;
515 if ((idx
= get_buffer_index( output
, SECBUFFER_TOKEN
)) == -1) return SEC_E_INVALID_TOKEN
;
516 params
.output_token
= output
->pBuffers
[idx
].pvBuffer
;
517 params
.output_token_length
= &output
->pBuffers
[idx
].cbBuffer
;
519 status
= KRB5_CALL( initialize_context
, ¶ms
);
520 if (status
== SEC_E_OK
|| status
== SEC_I_CONTINUE_NEEDED
)
521 *new_context
= create_context_handle( context_handle
, new_context_handle
);
524 *mapped_context
= TRUE
;
525 expiry_to_timestamp( exptime
, expiry
);
528 /* FIXME: initialize context_data */
533 static NTSTATUS NTAPI
kerberos_SpAcceptLsaModeContext( LSA_SEC_HANDLE credential
, LSA_SEC_HANDLE context
,
534 SecBufferDesc
*input
, ULONG context_req
, ULONG target_data_rep
, LSA_SEC_HANDLE
*new_context
,
535 SecBufferDesc
*output
, ULONG
*context_attr
, TimeStamp
*expiry
, BOOLEAN
*mapped_context
, SecBuffer
*context_data
)
537 NTSTATUS status
= SEC_E_INVALID_HANDLE
;
541 TRACE( "%Ix, %Ix, %#lx, %lu, %p, %p, %p, %p, %p, %p, %p\n", credential
, context
, context_req
, target_data_rep
,
542 input
, new_context
, output
, context_attr
, expiry
, mapped_context
, context_data
);
543 if (context_req
) FIXME( "ignoring flags %#lx\n", context_req
);
545 if (context
|| input
|| credential
)
547 struct cred_handle
*cred_handle
= (struct cred_handle
*)credential
;
548 struct context_handle
*context_handle
= (struct context_handle
*)context
;
549 struct accept_context_params params
= { 0 };
550 UINT64 new_context_handle
= 0;
552 params
.credential
= cred_handle
? cred_handle
->handle
: 0;
553 params
.context
= context_handle
? context_handle
->handle
: 0;
554 params
.new_context
= &new_context_handle
;
555 params
.context_attr
= context_attr
;
556 params
.expiry
= &exptime
;
560 if ((idx
= get_buffer_index( input
, SECBUFFER_TOKEN
)) == -1) return SEC_E_INVALID_TOKEN
;
561 params
.input_token
= input
->pBuffers
[idx
].pvBuffer
;
562 params
.input_token_length
= input
->pBuffers
[idx
].cbBuffer
;
564 if ((idx
= get_buffer_index( output
, SECBUFFER_TOKEN
)) == -1) return SEC_E_INVALID_TOKEN
;
565 params
.output_token
= output
->pBuffers
[idx
].pvBuffer
;
566 params
.output_token_length
= &output
->pBuffers
[idx
].cbBuffer
;
568 /* FIXME: check if larger output buffer exists */
569 status
= KRB5_CALL( accept_context
, ¶ms
);
570 if (status
== SEC_E_OK
|| status
== SEC_I_CONTINUE_NEEDED
)
571 *new_context
= create_context_handle( context_handle
, new_context_handle
);
574 *mapped_context
= TRUE
;
575 expiry_to_timestamp( exptime
, expiry
);
577 /* FIXME: initialize context_data */
582 static NTSTATUS NTAPI
kerberos_SpDeleteContext( LSA_SEC_HANDLE context
)
584 struct context_handle
*context_handle
= (void *)context
;
585 struct delete_context_params params
;
588 TRACE( "%Ix\n", context
);
590 if (!context
) return SEC_E_INVALID_HANDLE
;
592 params
.context
= context_handle
->handle
;
593 status
= KRB5_CALL( delete_context
, ¶ms
);
594 free( context_handle
);
598 static SecPkgInfoW
*build_package_info( const SecPkgInfoW
*info
)
601 DWORD size_name
= (wcslen(info
->Name
) + 1) * sizeof(WCHAR
);
602 DWORD size_comment
= (wcslen(info
->Comment
) + 1) * sizeof(WCHAR
);
604 if (!(ret
= malloc( sizeof(*ret
) + size_name
+ size_comment
))) return NULL
;
605 ret
->fCapabilities
= info
->fCapabilities
;
606 ret
->wVersion
= info
->wVersion
;
607 ret
->wRPCID
= info
->wRPCID
;
608 ret
->cbMaxToken
= info
->cbMaxToken
;
609 ret
->Name
= (SEC_WCHAR
*)(ret
+ 1);
610 memcpy( ret
->Name
, info
->Name
, size_name
);
611 ret
->Comment
= (SEC_WCHAR
*)((char *)ret
->Name
+ size_name
);
612 memcpy( ret
->Comment
, info
->Comment
, size_comment
);
616 static NTSTATUS NTAPI
kerberos_SpQueryContextAttributes( LSA_SEC_HANDLE context
, ULONG attribute
, void *buffer
)
618 struct context_handle
*context_handle
= (void *)context
;
620 TRACE( "%Ix, %lu, %p\n", context
, attribute
, buffer
);
622 if (!context
) return SEC_E_INVALID_HANDLE
;
626 #define X(x) case (x) : FIXME(#x" stub\n"); break
627 X(SECPKG_ATTR_ACCESS_TOKEN
);
628 X(SECPKG_ATTR_AUTHORITY
);
629 X(SECPKG_ATTR_DCE_INFO
);
630 X(SECPKG_ATTR_KEY_INFO
);
631 X(SECPKG_ATTR_LIFESPAN
);
632 X(SECPKG_ATTR_NAMES
);
633 X(SECPKG_ATTR_NATIVE_NAMES
);
634 X(SECPKG_ATTR_PACKAGE_INFO
);
635 X(SECPKG_ATTR_PASSWORD_EXPIRY
);
636 X(SECPKG_ATTR_STREAM_SIZES
);
637 X(SECPKG_ATTR_TARGET_INFORMATION
);
639 case SECPKG_ATTR_SESSION_KEY
:
641 SecPkgContext_SessionKey key
= { 128 };
642 struct query_context_attributes_params params
= { context_handle
->handle
, attribute
, &key
};
645 if (!(key
.SessionKey
= RtlAllocateHeap( GetProcessHeap(), 0, key
.SessionKeyLength
))) return STATUS_NO_MEMORY
;
647 if ((status
= KRB5_CALL( query_context_attributes
, ¶ms
)))
649 RtlFreeHeap( GetProcessHeap(), 0, key
.SessionKey
);
653 *(SecPkgContext_SessionKey
*)buffer
= key
;
656 case SECPKG_ATTR_SIZES
:
658 struct query_context_attributes_params params
= { context_handle
->handle
, attribute
, buffer
};
659 return KRB5_CALL( query_context_attributes
, ¶ms
);
661 case SECPKG_ATTR_NEGOTIATION_INFO
:
663 SecPkgContext_NegotiationInfoW
*info
= (SecPkgContext_NegotiationInfoW
*)buffer
;
664 if (!(info
->PackageInfo
= build_package_info( &infoW
))) return SEC_E_INSUFFICIENT_MEMORY
;
665 info
->NegotiationState
= SECPKG_NEGOTIATION_COMPLETE
;
669 FIXME( "unknown attribute %lu\n", attribute
);
673 return SEC_E_UNSUPPORTED_FUNCTION
;
676 static NTSTATUS NTAPI
kerberos_SpInitialize(ULONG_PTR package_id
, SECPKG_PARAMETERS
*params
,
677 LSA_SECPKG_FUNCTION_TABLE
*lsa_function_table
)
679 TRACE("%Iu, %p, %p\n", package_id
, params
, lsa_function_table
);
681 if (!__wine_unixlib_handle
)
683 if (__wine_init_unix_call() || KRB5_CALL( process_attach
, NULL
))
684 WARN( "no Kerberos support\n" );
685 return STATUS_UNSUCCESSFUL
;
687 return STATUS_SUCCESS
;
690 static NTSTATUS NTAPI
kerberos_SpShutdown(void)
693 return STATUS_SUCCESS
;
696 static SECPKG_FUNCTION_TABLE kerberos_table
=
698 kerberos_LsaApInitializePackage
, /* InitializePackage */
699 NULL
, /* LsaLogonUser */
700 NULL
, /* CallPackage */
701 NULL
, /* LogonTerminated */
702 kerberos_LsaApCallPackageUntrusted
, /* CallPackageUntrusted */
703 NULL
, /* CallPackagePassthrough */
704 NULL
, /* LogonUserEx */
705 NULL
, /* LogonUserEx2 */
706 kerberos_SpInitialize
,
709 NULL
, /* AcceptCredentials */
710 kerberos_SpAcquireCredentialsHandle
,
711 NULL
, /* SpQueryCredentialsAttributes */
712 kerberos_SpFreeCredentialsHandle
,
713 NULL
, /* SaveCredentials */
714 NULL
, /* GetCredentials */
715 NULL
, /* DeleteCredentials */
716 kerberos_SpInitLsaModeContext
,
717 kerberos_SpAcceptLsaModeContext
,
718 kerberos_SpDeleteContext
,
719 NULL
, /* ApplyControlToken */
720 NULL
, /* GetUserInfo */
721 NULL
, /* GetExtendedInformation */
722 kerberos_SpQueryContextAttributes
,
723 NULL
, /* SpAddCredentials */
724 NULL
, /* SetExtendedInformation */
725 NULL
, /* SetContextAttributes */
726 NULL
, /* SetCredentialsAttributes */
727 NULL
, /* ChangeAccountPassword */
728 NULL
, /* QueryMetaData */
729 NULL
, /* ExchangeMetaData */
730 NULL
, /* GetCredUIContext */
731 NULL
, /* UpdateCredentials */
732 NULL
, /* ValidateTargetInfo */
733 NULL
, /* PostLogonUser */
736 NTSTATUS NTAPI
SpLsaModeInitialize(ULONG lsa_version
, PULONG package_version
,
737 PSECPKG_FUNCTION_TABLE
*table
, PULONG table_count
)
739 TRACE("%#lx, %p, %p, %p\n", lsa_version
, package_version
, table
, table_count
);
741 *package_version
= SECPKG_INTERFACE_VERSION
;
742 *table
= &kerberos_table
;
744 return STATUS_SUCCESS
;
747 static NTSTATUS NTAPI
kerberos_SpInstanceInit(ULONG version
, SECPKG_DLL_FUNCTIONS
*dll_function_table
, void **user_functions
)
749 TRACE("%#lx, %p, %p\n", version
, dll_function_table
, user_functions
);
750 return STATUS_SUCCESS
;
753 static NTSTATUS SEC_ENTRY
kerberos_SpMakeSignature( LSA_SEC_HANDLE context
, ULONG quality_of_protection
,
754 SecBufferDesc
*message
, ULONG message_seq_no
)
756 TRACE( "%Ix, %#lx, %p, %lu\n", context
, quality_of_protection
, message
, message_seq_no
);
757 if (quality_of_protection
) FIXME( "ignoring quality_of_protection %#lx\n", quality_of_protection
);
758 if (message_seq_no
) FIXME( "ignoring message_seq_no %lu\n", message_seq_no
);
762 struct context_handle
*context_handle
= (void *)context
;
763 struct make_signature_params params
;
764 int data_idx
, token_idx
;
766 /* FIXME: multiple data buffers, read-only buffers */
767 if ((data_idx
= get_buffer_index( message
, SECBUFFER_DATA
)) == -1) return SEC_E_INVALID_TOKEN
;
768 if ((token_idx
= get_buffer_index( message
, SECBUFFER_TOKEN
)) == -1) return SEC_E_INVALID_TOKEN
;
770 params
.context
= context_handle
->handle
;
771 params
.data_length
= message
->pBuffers
[data_idx
].cbBuffer
;
772 params
.data
= message
->pBuffers
[data_idx
].pvBuffer
;
773 params
.token_length
= &message
->pBuffers
[token_idx
].cbBuffer
;
774 params
.token
= message
->pBuffers
[token_idx
].pvBuffer
;
776 return KRB5_CALL( make_signature
, ¶ms
);
778 else return SEC_E_INVALID_HANDLE
;
781 static NTSTATUS NTAPI
kerberos_SpVerifySignature( LSA_SEC_HANDLE context
, SecBufferDesc
*message
,
782 ULONG message_seq_no
, ULONG
*quality_of_protection
)
784 TRACE( "%Ix, %p, %lu, %p\n", context
, message
, message_seq_no
, quality_of_protection
);
785 if (message_seq_no
) FIXME( "ignoring message_seq_no %lu\n", message_seq_no
);
789 struct context_handle
*context_handle
= (void *)context
;
790 struct verify_signature_params params
;
791 int data_idx
, token_idx
;
793 if ((data_idx
= get_buffer_index( message
, SECBUFFER_DATA
)) == -1) return SEC_E_INVALID_TOKEN
;
794 if ((token_idx
= get_buffer_index( message
, SECBUFFER_TOKEN
)) == -1) return SEC_E_INVALID_TOKEN
;
796 params
.context
= context_handle
->handle
;
797 params
.data_length
= message
->pBuffers
[data_idx
].cbBuffer
;
798 params
.data
= message
->pBuffers
[data_idx
].pvBuffer
;
799 params
.token_length
= message
->pBuffers
[token_idx
].cbBuffer
;
800 params
.token
= message
->pBuffers
[token_idx
].pvBuffer
;
801 params
.qop
= quality_of_protection
;
803 return KRB5_CALL( verify_signature
, ¶ms
);
805 else return SEC_E_INVALID_HANDLE
;
808 static NTSTATUS NTAPI
kerberos_SpSealMessage( LSA_SEC_HANDLE context
, ULONG quality_of_protection
,
809 SecBufferDesc
*message
, ULONG message_seq_no
)
811 TRACE( "%Ix, %#lx, %p, %lu\n", context
, quality_of_protection
, message
, message_seq_no
);
812 if (message_seq_no
) FIXME( "ignoring message_seq_no %lu\n", message_seq_no
);
816 struct context_handle
*context_handle
= (void *)context
;
817 struct seal_message_params params
;
818 int data_idx
, token_idx
;
820 /* FIXME: multiple data buffers, read-only buffers */
821 if ((data_idx
= get_buffer_index( message
, SECBUFFER_DATA
)) == -1) return SEC_E_INVALID_TOKEN
;
822 if ((token_idx
= get_buffer_index( message
, SECBUFFER_TOKEN
)) == -1) return SEC_E_INVALID_TOKEN
;
824 params
.context
= context_handle
->handle
;
825 params
.data_length
= message
->pBuffers
[data_idx
].cbBuffer
;
826 params
.data
= message
->pBuffers
[data_idx
].pvBuffer
;
827 params
.token_length
= &message
->pBuffers
[token_idx
].cbBuffer
;
828 params
.token
= message
->pBuffers
[token_idx
].pvBuffer
;
829 params
.qop
= quality_of_protection
;
831 return KRB5_CALL( seal_message
, ¶ms
);
833 else return SEC_E_INVALID_HANDLE
;
836 static NTSTATUS NTAPI
kerberos_SpUnsealMessage( LSA_SEC_HANDLE context
, SecBufferDesc
*message
,
837 ULONG message_seq_no
, ULONG
*quality_of_protection
)
839 TRACE( "%Ix, %p, %lu, %p\n", context
, message
, message_seq_no
, quality_of_protection
);
840 if (message_seq_no
) FIXME( "ignoring message_seq_no %lu\n", message_seq_no
);
844 struct context_handle
*context_handle
= (void *)context
;
845 struct unseal_message_params params
;
846 int data_idx
, token_idx
;
848 if ((data_idx
= get_buffer_index( message
, SECBUFFER_DATA
)) == -1) return SEC_E_INVALID_TOKEN
;
849 if ((token_idx
= get_buffer_index( message
, SECBUFFER_TOKEN
)) == -1) return SEC_E_INVALID_TOKEN
;
851 params
.context
= context_handle
->handle
;
852 params
.data_length
= message
->pBuffers
[data_idx
].cbBuffer
;
853 params
.data
= message
->pBuffers
[data_idx
].pvBuffer
;
854 params
.token_length
= message
->pBuffers
[token_idx
].cbBuffer
;
855 params
.token
= message
->pBuffers
[token_idx
].pvBuffer
;
856 params
.qop
= quality_of_protection
;
858 return KRB5_CALL( unseal_message
, ¶ms
);
860 else return SEC_E_INVALID_HANDLE
;
863 static SECPKG_USER_FUNCTION_TABLE kerberos_user_table
=
865 kerberos_SpInstanceInit
,
866 NULL
, /* SpInitUserModeContext */
867 kerberos_SpMakeSignature
,
868 kerberos_SpVerifySignature
,
869 kerberos_SpSealMessage
,
870 kerberos_SpUnsealMessage
,
871 NULL
, /* SpGetContextToken */
872 NULL
, /* SpQueryContextAttributes */
873 NULL
, /* SpCompleteAuthToken */
874 NULL
, /* SpDeleteContext */
875 NULL
, /* SpFormatCredentialsFn */
876 NULL
, /* SpMarshallSupplementalCreds */
877 NULL
, /* SpExportSecurityContext */
878 NULL
/* SpImportSecurityContext */
881 NTSTATUS NTAPI
SpUserModeInitialize(ULONG lsa_version
, PULONG package_version
,
882 PSECPKG_USER_FUNCTION_TABLE
*table
, PULONG table_count
)
884 TRACE("%#lx, %p, %p, %p\n", lsa_version
, package_version
, table
, table_count
);
886 *package_version
= SECPKG_INTERFACE_VERSION
;
887 *table
= &kerberos_user_table
;
889 return STATUS_SUCCESS
;