2 * Copyright (c) 1999-2001, 2003, PADL Software Pty Ltd.
3 * Copyright (c) 2004-2009, Andrew Bartlett <abartlet@samba.org>.
4 * Copyright (c) 2004, Stefan Metzmacher <metze@samba.org>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of PADL Software nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 #include "kdc/kdc-glue.h"
37 #include "kdc/db-glue.h"
38 #include "auth/auth_sam.h"
39 #include "auth/common_auth.h"
40 #include "auth/authn_policy.h"
44 #include "dsdb/samdb/samdb.h"
45 #include "param/param.h"
46 #include "../lib/tsocket/tsocket.h"
47 #include "librpc/gen_ndr/ndr_winbind_c.h"
48 #include "lib/messaging/irpc.h"
50 #include <kdc-audit.h>
51 #include <kdc-plugin.h>
54 #define DBGC_CLASS DBGC_KERBEROS
56 static krb5_error_code
hdb_samba4_open(krb5_context context
, HDB
*db
, int flags
, mode_t mode
)
58 if (db
->hdb_master_key_set
) {
59 krb5_error_code ret
= HDB_ERR_NOENTRY
;
60 krb5_warnx(context
, "hdb_samba4_open: use of a master key incompatible with LDB\n");
61 krb5_set_error_message(context
, ret
, "hdb_samba4_open: use of a master key incompatible with LDB\n");
68 static krb5_error_code
hdb_samba4_close(krb5_context context
, HDB
*db
)
73 static krb5_error_code
hdb_samba4_lock(krb5_context context
, HDB
*db
, int operation
)
78 static krb5_error_code
hdb_samba4_unlock(krb5_context context
, HDB
*db
)
83 static krb5_error_code
hdb_samba4_rename(krb5_context context
, HDB
*db
, const char *new_name
)
85 return HDB_ERR_DB_INUSE
;
88 static krb5_error_code
hdb_samba4_store(krb5_context context
, HDB
*db
, unsigned flags
, hdb_entry
*entry
)
90 return HDB_ERR_DB_INUSE
;
94 * If we ever want kadmin to work fast, we might try and reopen the
97 static krb5_error_code
hdb_samba4_set_sync(krb5_context context
, struct HDB
*db
, int set_sync
)
102 static void hdb_samba4_free_entry_context(krb5_context context
, struct HDB
*db
, hdb_entry
*entry
)
105 * This function is now called for every HDB entry, not just those with
106 * 'context' set, so we have to check that the context is not NULL.
108 if (entry
->context
!= NULL
) {
109 struct samba_kdc_entry
*skdc_entry
=
110 talloc_get_type_abort(entry
->context
,
111 struct samba_kdc_entry
);
113 /* this function is called only from hdb_free_entry().
114 * Make sure we neutralize the destructor or we will
115 * get a double free later when hdb_free_entry() will
116 * try to call free_hdb_entry() */
117 entry
->context
= NULL
;
118 skdc_entry
->kdc_entry
= NULL
;
119 TALLOC_FREE(skdc_entry
);
123 static krb5_error_code
hdb_samba4_fetch_fast_cookie(krb5_context context
,
124 struct samba_kdc_db_context
*kdc_db_ctx
,
127 DBG_ERR("Looked up HDB entry for unsupported FX-COOKIE.\n");
128 return HDB_ERR_NOENTRY
;
131 static krb5_error_code
hdb_samba4_fetch_kvno(krb5_context context
, HDB
*db
,
132 krb5_const_principal principal
,
137 struct samba_kdc_db_context
*kdc_db_ctx
;
138 struct sdb_entry sentry
= {};
139 krb5_error_code code
, ret
;
142 kdc_db_ctx
= talloc_get_type_abort(db
->hdb_db
,
143 struct samba_kdc_db_context
);
145 if (flags
& HDB_F_GET_FAST_COOKIE
) {
146 return hdb_samba4_fetch_fast_cookie(context
,
151 sflags
= (flags
& SDB_F_HDB_MASK
);
153 ret
= samba_kdc_fetch(context
,
163 case SDB_ERR_WRONG_REALM
:
165 * If SDB_ERR_WRONG_REALM is returned we need to process the
166 * sdb_entry to fill the principal in the HDB entry.
168 code
= HDB_ERR_WRONG_REALM
;
170 case SDB_ERR_NOENTRY
:
171 return HDB_ERR_NOENTRY
;
172 case SDB_ERR_NOT_FOUND_HERE
:
173 return HDB_ERR_NOT_FOUND_HERE
;
178 ret
= sdb_entry_to_hdb_entry(context
, &sentry
, entry
);
179 sdb_entry_free(&sentry
);
181 if (code
!= 0 && ret
!= 0) {
188 static krb5_error_code
hdb_samba4_kpasswd_fetch_kvno(krb5_context context
, HDB
*db
,
189 krb5_const_principal _principal
,
194 struct samba_kdc_db_context
*kdc_db_ctx
= NULL
;
196 krb5_principal kpasswd_principal
= NULL
;
198 kdc_db_ctx
= talloc_get_type_abort(db
->hdb_db
,
199 struct samba_kdc_db_context
);
201 ret
= smb_krb5_make_principal(context
, &kpasswd_principal
,
202 lpcfg_realm(kdc_db_ctx
->lp_ctx
),
203 "kadmin", "changepw",
208 smb_krb5_principal_set_type(context
, kpasswd_principal
, KRB5_NT_SRV_INST
);
211 * For the kpasswd service, always ensure we get the latest kvno. This
212 * also means we (correctly) refuse RODC-issued tickets.
214 flags
&= ~HDB_F_KVNO_SPECIFIED
;
216 /* Don't bother looking up a client or krbtgt. */
217 flags
&= ~(SDB_F_GET_CLIENT
|SDB_F_GET_KRBTGT
);
219 ret
= hdb_samba4_fetch_kvno(context
, db
,
225 krb5_free_principal(context
, kpasswd_principal
);
229 static krb5_error_code
hdb_samba4_firstkey(krb5_context context
, HDB
*db
, unsigned flags
,
232 struct samba_kdc_db_context
*kdc_db_ctx
;
233 struct sdb_entry sentry
= {};
236 kdc_db_ctx
= talloc_get_type_abort(db
->hdb_db
,
237 struct samba_kdc_db_context
);
239 ret
= samba_kdc_firstkey(context
, kdc_db_ctx
, &sentry
);
243 case SDB_ERR_WRONG_REALM
:
244 return HDB_ERR_WRONG_REALM
;
245 case SDB_ERR_NOENTRY
:
246 return HDB_ERR_NOENTRY
;
247 case SDB_ERR_NOT_FOUND_HERE
:
248 return HDB_ERR_NOT_FOUND_HERE
;
253 ret
= sdb_entry_to_hdb_entry(context
, &sentry
, entry
);
254 sdb_entry_free(&sentry
);
258 static krb5_error_code
hdb_samba4_nextkey(krb5_context context
, HDB
*db
, unsigned flags
,
261 struct samba_kdc_db_context
*kdc_db_ctx
;
262 struct sdb_entry sentry
= {};
265 kdc_db_ctx
= talloc_get_type_abort(db
->hdb_db
,
266 struct samba_kdc_db_context
);
268 ret
= samba_kdc_nextkey(context
, kdc_db_ctx
, &sentry
);
272 case SDB_ERR_WRONG_REALM
:
273 return HDB_ERR_WRONG_REALM
;
274 case SDB_ERR_NOENTRY
:
275 return HDB_ERR_NOENTRY
;
276 case SDB_ERR_NOT_FOUND_HERE
:
277 return HDB_ERR_NOT_FOUND_HERE
;
282 ret
= sdb_entry_to_hdb_entry(context
, &sentry
, entry
);
283 sdb_entry_free(&sentry
);
287 static krb5_error_code
hdb_samba4_nextkey_panic(krb5_context context
, HDB
*db
,
291 DBG_ERR("Attempt to iterate kpasswd keytab => PANIC\n");
292 smb_panic("hdb_samba4_nextkey_panic: Attempt to iterate kpasswd keytab");
295 static krb5_error_code
hdb_samba4_destroy(krb5_context context
, HDB
*db
)
301 static krb5_error_code
302 hdb_samba4_check_constrained_delegation(krb5_context context
, HDB
*db
,
304 krb5_const_principal target_principal
)
306 struct samba_kdc_db_context
*kdc_db_ctx
= NULL
;
307 struct samba_kdc_entry
*skdc_entry
= NULL
;
309 kdc_db_ctx
= talloc_get_type_abort(db
->hdb_db
,
310 struct samba_kdc_db_context
);
311 skdc_entry
= talloc_get_type_abort(entry
->context
,
312 struct samba_kdc_entry
);
314 return samba_kdc_check_s4u2proxy(context
, kdc_db_ctx
,
319 static krb5_error_code
320 hdb_samba4_check_rbcd(krb5_context context
, HDB
*db
,
321 krb5_const_principal client_principal
,
322 krb5_const_principal server_principal
,
323 krb5_const_pac header_pac
,
324 const hdb_entry
*proxy
)
326 struct samba_kdc_db_context
*kdc_db_ctx
= NULL
;
327 struct samba_kdc_entry
*proxy_skdc_entry
= NULL
;
329 kdc_db_ctx
= talloc_get_type_abort(db
->hdb_db
,
330 struct samba_kdc_db_context
);
331 proxy_skdc_entry
= talloc_get_type_abort(proxy
->context
,
332 struct samba_kdc_entry
);
334 return samba_kdc_check_s4u2proxy_rbcd(context
,
342 static krb5_error_code
343 hdb_samba4_check_pkinit_ms_upn_match(krb5_context context
, HDB
*db
,
345 krb5_const_principal certificate_principal
)
347 struct samba_kdc_db_context
*kdc_db_ctx
;
348 struct samba_kdc_entry
*skdc_entry
;
351 kdc_db_ctx
= talloc_get_type_abort(db
->hdb_db
,
352 struct samba_kdc_db_context
);
353 skdc_entry
= talloc_get_type_abort(entry
->context
,
354 struct samba_kdc_entry
);
356 ret
= samba_kdc_check_pkinit_ms_upn_match(context
, kdc_db_ctx
,
358 certificate_principal
);
362 case SDB_ERR_WRONG_REALM
:
363 ret
= HDB_ERR_WRONG_REALM
;
365 case SDB_ERR_NOENTRY
:
366 ret
= HDB_ERR_NOENTRY
;
368 case SDB_ERR_NOT_FOUND_HERE
:
369 ret
= HDB_ERR_NOT_FOUND_HERE
;
378 static krb5_error_code
379 hdb_samba4_check_client_matches_target_service(krb5_context context
, HDB
*db
,
380 hdb_entry
*client_entry
,
381 hdb_entry
*server_target_entry
)
383 struct samba_kdc_entry
*skdc_client_entry
384 = talloc_get_type_abort(client_entry
->context
,
385 struct samba_kdc_entry
);
386 struct samba_kdc_entry
*skdc_server_target_entry
387 = talloc_get_type_abort(server_target_entry
->context
,
388 struct samba_kdc_entry
);
390 return samba_kdc_check_client_matches_target_service(context
,
392 skdc_server_target_entry
);
395 static void reset_bad_password_netlogon(TALLOC_CTX
*mem_ctx
,
396 struct samba_kdc_db_context
*kdc_db_ctx
,
397 struct netr_SendToSamBase
*send_to_sam
)
399 struct dcerpc_binding_handle
*irpc_handle
;
400 struct winbind_SendToSam req
;
401 struct tevent_req
*subreq
= NULL
;
403 irpc_handle
= irpc_binding_handle_by_name(mem_ctx
, kdc_db_ctx
->msg_ctx
,
407 if (irpc_handle
== NULL
) {
408 DEBUG(0, ("No winbind_server running!\n"));
412 req
.in
.message
= *send_to_sam
;
415 * This seem to rely on the current IRPC implementation,
416 * which delivers the message in the _send function.
418 * TODO: we need a ONE_WAY IRPC handle and register
419 * a callback and wait for it to be triggered!
421 subreq
= dcerpc_winbind_SendToSam_r_send(mem_ctx
, kdc_db_ctx
->ev_ctx
,
424 /* we aren't interested in a reply */
428 #define SAMBA_HDB_AUTHN_AUDIT_INFO_OBJ "samba:authn_audit_info_obj"
429 #define SAMBA_HDB_CLIENT_AUDIT_INFO "samba:client_audit_info"
430 #define SAMBA_HDB_SERVER_AUDIT_INFO "samba:server_audit_info"
432 #define SAMBA_HDB_NT_STATUS_OBJ "samba:nt_status_obj"
433 #define SAMBA_HDB_NT_STATUS "samba:nt_status"
435 struct hdb_audit_info_obj
{
436 struct authn_audit_info
*audit_info
;
439 static void hdb_audit_info_obj_dealloc(void *ptr
)
441 struct hdb_audit_info_obj
*audit_info_obj
= ptr
;
443 if (audit_info_obj
== NULL
) {
447 TALLOC_FREE(audit_info_obj
->audit_info
);
451 * Set talloc-allocated auditing information of the KDC request. On success,
452 * ‘audit_info’ is invalidated and may no longer be used by the caller.
454 static krb5_error_code
hdb_samba4_set_steal_audit_info(astgs_request_t r
,
456 struct authn_audit_info
*audit_info
)
458 struct hdb_audit_info_obj
*audit_info_obj
= NULL
;
460 audit_info_obj
= kdc_object_alloc(sizeof (*audit_info_obj
),
461 SAMBA_HDB_AUTHN_AUDIT_INFO_OBJ
,
462 hdb_audit_info_obj_dealloc
);
463 if (audit_info_obj
== NULL
) {
468 * Steal a handle to the audit information onto the NULL context —
469 * Heimdal will be responsible for the deallocation of the object.
471 audit_info_obj
->audit_info
= talloc_steal(NULL
, audit_info
);
473 heim_audit_setkv_object((heim_svc_req_desc
)r
, key
, audit_info_obj
);
474 heim_release(audit_info_obj
);
480 * Set talloc-allocated client auditing information of the KDC request. On
481 * success, ‘client_audit_info’ is invalidated and may no longer be used by the
484 krb5_error_code
hdb_samba4_set_steal_client_audit_info(astgs_request_t r
,
485 struct authn_audit_info
*client_audit_info
)
487 return hdb_samba4_set_steal_audit_info(r
,
488 SAMBA_HDB_CLIENT_AUDIT_INFO
,
492 static const struct authn_audit_info
*hdb_samba4_get_client_audit_info(hdb_request_t r
)
494 const struct hdb_audit_info_obj
*audit_info_obj
= NULL
;
496 audit_info_obj
= heim_audit_getkv((heim_svc_req_desc
)r
, SAMBA_HDB_CLIENT_AUDIT_INFO
);
497 if (audit_info_obj
== NULL
) {
501 return audit_info_obj
->audit_info
;
505 * Set talloc-allocated server auditing information of the KDC request. On
506 * success, ‘server_audit_info’ is invalidated and may no longer be used by the
509 krb5_error_code
hdb_samba4_set_steal_server_audit_info(astgs_request_t r
,
510 struct authn_audit_info
*server_audit_info
)
512 return hdb_samba4_set_steal_audit_info(r
,
513 SAMBA_HDB_SERVER_AUDIT_INFO
,
517 static const struct authn_audit_info
*hdb_samba4_get_server_audit_info(hdb_request_t r
)
519 const struct hdb_audit_info_obj
*audit_info_obj
= NULL
;
521 audit_info_obj
= heim_audit_getkv((heim_svc_req_desc
)r
, SAMBA_HDB_SERVER_AUDIT_INFO
);
522 if (audit_info_obj
== NULL
) {
526 return audit_info_obj
->audit_info
;
529 struct hdb_ntstatus_obj
{
531 krb5_error_code current_error
;
535 * Add an NTSTATUS code to a Kerberos request. ‘error’ is the error value we
536 * want to return to the client. When it comes time to generating the error
537 * request, we shall compare this error value to whatever error we are about to
538 * return; if the two match, we shall replace the ‘e-data’ field in the reply
539 * with the NTSTATUS code.
541 krb5_error_code
hdb_samba4_set_ntstatus(astgs_request_t r
,
542 const NTSTATUS status
,
543 const krb5_error_code error
)
545 struct hdb_ntstatus_obj
*status_obj
= NULL
;
547 status_obj
= kdc_object_alloc(sizeof (*status_obj
),
548 SAMBA_HDB_NT_STATUS_OBJ
,
550 if (status_obj
== NULL
) {
554 *status_obj
= (struct hdb_ntstatus_obj
) {
556 .current_error
= error
,
559 heim_audit_setkv_object((heim_svc_req_desc
)r
, SAMBA_HDB_NT_STATUS
, status_obj
);
560 heim_release(status_obj
);
565 static krb5_error_code
hdb_samba4_make_nt_status_edata(const NTSTATUS status
,
566 const uint32_t flags
,
567 krb5_data
*edata_out
)
569 const uint32_t status_code
= NT_STATUS_V(status
);
570 const uint32_t zero
= 0;
571 KERB_ERROR_DATA error_data
;
577 /* The raw KERB-ERR-TYPE-EXTENDED structure. */
580 PUSH_LE_U32(data
, 0, status_code
);
581 PUSH_LE_U32(data
, 4, zero
);
582 PUSH_LE_U32(data
, 8, flags
);
584 e_data
= (krb5_data
) {
586 .length
= sizeof(data
),
589 error_data
= (KERB_ERROR_DATA
) {
590 .data_type
= kERB_ERR_TYPE_EXTENDED
,
591 .data_value
= &e_data
,
594 ASN1_MALLOC_ENCODE(KERB_ERROR_DATA
,
595 edata_out
->data
, edata_out
->length
,
601 if (size
!= edata_out
->length
) {
602 /* Internal ASN.1 encoder error */
603 krb5_data_free(edata_out
);
604 return KRB5KRB_ERR_GENERIC
;
610 static krb5_error_code
hdb_samba4_set_edata_from_ntstatus(hdb_request_t r
, const NTSTATUS status
)
612 const KDC_REQ
*req
= kdc_request_get_req((astgs_request_t
)r
);
613 krb5_error_code ret
= 0;
617 if (req
->msg_type
== krb_tgs_req
) {
618 /* This flag is used to indicate a TGS-REQ. */
622 ret
= hdb_samba4_make_nt_status_edata(status
, flags
, &e_data
);
627 ret
= kdc_set_e_data((astgs_request_t
)r
, e_data
);
629 krb5_data_free(&e_data
);
635 static NTSTATUS
hdb_samba4_get_ntstatus(hdb_request_t r
)
637 struct hdb_ntstatus_obj
*status_obj
= NULL
;
639 status_obj
= heim_audit_getkv((heim_svc_req_desc
)r
, SAMBA_HDB_NT_STATUS
);
640 if (status_obj
== NULL
) {
644 if (r
->error_code
!= status_obj
->current_error
) {
646 * The error code has changed from what we expect. Consider the
647 * NTSTATUS to be invalidated.
652 return status_obj
->status
;
655 static krb5_error_code
hdb_samba4_tgs_audit(const struct samba_kdc_db_context
*kdc_db_ctx
,
656 const hdb_entry
*entry
,
659 TALLOC_CTX
*frame
= talloc_stackframe();
660 const struct authn_audit_info
*server_audit_info
= NULL
;
661 struct tsocket_address
*remote_host
= NULL
;
662 struct samba_kdc_entry
*client_entry
= NULL
;
663 struct dom_sid sid_buf
= {};
664 const char *account_name
= NULL
;
665 const char *domain_name
= NULL
;
666 const struct dom_sid
*sid
= NULL
;
667 size_t sa_socklen
= 0;
668 NTSTATUS auth_status
= NT_STATUS_OK
;
669 krb5_error_code ret
= 0;
670 krb5_error_code final_ret
= 0;
672 /* Have we got a status code indicating an error? */
673 auth_status
= hdb_samba4_get_ntstatus(r
);
674 if (!NT_STATUS_IS_OK(auth_status
)) {
676 * Include this status code in the ‘e-data’ field of the reply.
678 ret
= hdb_samba4_set_edata_from_ntstatus(r
, auth_status
);
682 } else if (entry
== NULL
) {
683 auth_status
= NT_STATUS_NO_SUCH_USER
;
684 } else if (r
->error_code
) {
686 * Don’t include a status code in the reply. Just log the
687 * request as being unsuccessful.
689 auth_status
= NT_STATUS_UNSUCCESSFUL
;
692 switch (r
->addr
->sa_family
) {
694 sa_socklen
= sizeof(struct sockaddr_in
);
698 sa_socklen
= sizeof(struct sockaddr_in6
);
703 ret
= tsocket_address_bsd_from_sockaddr(frame
, r
->addr
,
708 /* Ignore the error. */
711 server_audit_info
= hdb_samba4_get_server_audit_info(r
);
714 client_entry
= talloc_get_type_abort(entry
->context
,
715 struct samba_kdc_entry
);
717 ret
= samdb_result_dom_sid_buf(client_entry
->msg
, "objectSid", &sid_buf
);
719 /* Ignore the error. */
724 account_name
= ldb_msg_find_attr_as_string(client_entry
->msg
, "sAMAccountName", NULL
);
725 domain_name
= lpcfg_sam_name(kdc_db_ctx
->lp_ctx
);
728 log_authz_event(kdc_db_ctx
->msg_ctx
,
734 "TGS-REQ with Ticket-Granting Ticket",
738 lpcfg_netbios_name(kdc_db_ctx
->lp_ctx
),
744 r
->error_code
= final_ret
;
749 static krb5_error_code
hdb_samba4_audit(krb5_context context
,
754 struct samba_kdc_db_context
*kdc_db_ctx
= talloc_get_type_abort(db
->hdb_db
,
755 struct samba_kdc_db_context
);
756 struct ldb_dn
*domain_dn
= ldb_get_default_basedn(kdc_db_ctx
->samdb
);
757 heim_object_t auth_details_obj
= NULL
;
758 const char *auth_details
= NULL
;
759 char *etype_str
= NULL
;
760 heim_object_t hdb_auth_status_obj
= NULL
;
762 heim_object_t pa_type_obj
= NULL
;
763 const char *pa_type
= NULL
;
764 struct auth_usersupplied_info ui
;
765 size_t sa_socklen
= 0;
766 const KDC_REQ
*req
= kdc_request_get_req((astgs_request_t
)r
);
767 krb5_error_code final_ret
= 0;
768 NTSTATUS edata_status
;
770 if (req
->msg_type
== krb_tgs_req
) {
771 return hdb_samba4_tgs_audit(kdc_db_ctx
, entry
, r
);
774 if (r
->error_code
== KRB5KDC_ERR_PREAUTH_REQUIRED
) {
775 /* Let’s not log PREAUTH_REQUIRED errors. */
779 edata_status
= hdb_samba4_get_ntstatus(r
);
781 hdb_auth_status_obj
= heim_audit_getkv((heim_svc_req_desc
)r
, KDC_REQUEST_KV_AUTH_EVENT
);
782 if (hdb_auth_status_obj
== NULL
) {
783 /* No status code found, so just return. */
787 hdb_auth_status
= heim_number_get_int(hdb_auth_status_obj
);
789 pa_type_obj
= heim_audit_getkv((heim_svc_req_desc
)r
, KDC_REQUEST_KV_PA_NAME
);
790 if (pa_type_obj
!= NULL
) {
791 pa_type
= heim_string_get_utf8(pa_type_obj
);
794 auth_details_obj
= heim_audit_getkv((heim_svc_req_desc
)r
, KDC_REQUEST_KV_PKINIT_CLIENT_CERT
);
795 if (auth_details_obj
!= NULL
) {
796 auth_details
= heim_string_get_utf8(auth_details_obj
);
798 auth_details_obj
= heim_audit_getkv((heim_svc_req_desc
)r
, KDC_REQUEST_KV_GSS_INITIATOR
);
799 if (auth_details_obj
!= NULL
) {
800 auth_details
= heim_string_get_utf8(auth_details_obj
);
802 heim_object_t etype_obj
= heim_audit_getkv((heim_svc_req_desc
)r
, KDC_REQUEST_KV_PA_ETYPE
);
803 if (etype_obj
!= NULL
) {
804 int etype
= heim_number_get_int(etype_obj
);
806 krb5_error_code ret
= krb5_enctype_to_string(r
->context
, etype
, &etype_str
);
808 auth_details
= etype_str
;
810 auth_details
= "unknown enctype";
817 * Forcing this via the NTLM auth structure is not ideal, but
818 * it is the most practical option right now, and ensures the
819 * logs are consistent, even if some elements are always NULL.
821 ui
= (struct auth_usersupplied_info
) {
824 .account_name
= r
->cname
,
827 .service_description
= "Kerberos KDC",
828 .auth_description
= "Unknown Auth Description",
829 .password_type
= auth_details
,
830 .logon_id
= generate_random_u64(),
833 switch (r
->addr
->sa_family
) {
835 sa_socklen
= sizeof(struct sockaddr_in
);
839 sa_socklen
= sizeof(struct sockaddr_in6
);
844 switch (hdb_auth_status
) {
847 TALLOC_CTX
*frame
= talloc_stackframe();
848 struct samba_kdc_entry
*p
= talloc_get_type_abort(entry
->context
,
849 struct samba_kdc_entry
);
851 = samdb_result_dom_sid(frame
, p
->msg
, "objectSid");
852 const char *account_name
853 = ldb_msg_find_attr_as_string(p
->msg
, "sAMAccountName", NULL
);
854 const char *domain_name
= lpcfg_sam_name(p
->kdc_db_ctx
->lp_ctx
);
855 struct tsocket_address
*remote_host
;
856 const char *auth_description
= NULL
;
857 const struct authn_audit_info
*client_audit_info
= NULL
;
858 const struct authn_audit_info
*server_audit_info
= NULL
;
861 bool rwdc_fallback
= false;
863 ret
= tsocket_address_bsd_from_sockaddr(frame
, r
->addr
,
867 ui
.remote_host
= NULL
;
869 ui
.remote_host
= remote_host
;
872 ui
.mapped
.account_name
= account_name
;
873 ui
.mapped
.domain_name
= domain_name
;
875 if (pa_type
!= NULL
) {
876 auth_description
= talloc_asprintf(frame
,
877 "%s Pre-authentication",
879 if (auth_description
== NULL
) {
880 auth_description
= pa_type
;
883 auth_description
= "Unknown Pre-authentication";
885 ui
.auth_description
= auth_description
;
887 if (hdb_auth_status
== KDC_AUTH_EVENT_CLIENT_AUTHORIZED
) {
888 struct netr_SendToSamBase
*send_to_sam
= NULL
;
891 * TODO: We could log the AS-REQ authorization success here as
892 * well. However before we do that, we need to pass
893 * in the PAC here or re-calculate it.
895 status
= authsam_logon_success_accounting(kdc_db_ctx
->samdb
, p
->msg
,
896 domain_dn
, true, frame
, &send_to_sam
);
897 if (NT_STATUS_EQUAL(status
, NT_STATUS_ACCOUNT_LOCKED_OUT
)) {
898 edata_status
= status
;
900 r
->error_code
= final_ret
= KRB5KDC_ERR_CLIENT_REVOKED
;
901 rwdc_fallback
= kdc_db_ctx
->rodc
;
902 } else if (!NT_STATUS_IS_OK(status
)) {
903 r
->error_code
= final_ret
= KRB5KRB_ERR_GENERIC
;
904 rwdc_fallback
= kdc_db_ctx
->rodc
;
906 if (r
->error_code
== KRB5KDC_ERR_NEVER_VALID
) {
907 edata_status
= status
= NT_STATUS_TIME_DIFFERENCE_AT_DC
;
909 status
= krb5_to_nt_status(r
->error_code
);
912 if (kdc_db_ctx
->rodc
&& send_to_sam
!= NULL
) {
913 reset_bad_password_netlogon(frame
, kdc_db_ctx
, send_to_sam
);
917 /* This is the final success */
918 } else if (hdb_auth_status
== KDC_AUTH_EVENT_VALIDATED_LONG_TERM_KEY
) {
920 * This was only a pre-authentication success,
921 * but we didn't reach the final
922 * KDC_AUTH_EVENT_CLIENT_AUTHORIZED,
923 * so consult the error code.
925 if (r
->error_code
== 0) {
926 DBG_ERR("ERROR: VALIDATED_LONG_TERM_KEY "
927 "with error=0 => INTERNAL_ERROR\n");
928 status
= NT_STATUS_INTERNAL_ERROR
;
929 r
->error_code
= final_ret
= KRB5KRB_ERR_GENERIC
;
930 } else if (!NT_STATUS_IS_OK(p
->reject_status
)) {
931 status
= p
->reject_status
;
933 status
= krb5_to_nt_status(r
->error_code
);
935 } else if (hdb_auth_status
== KDC_AUTH_EVENT_PREAUTH_SUCCEEDED
) {
937 * This was only a pre-authentication success,
938 * but we didn't reach the final
939 * KDC_AUTH_EVENT_CLIENT_AUTHORIZED,
940 * so consult the error code.
942 if (r
->error_code
== 0) {
943 DBG_ERR("ERROR: PREAUTH_SUCCEEDED "
944 "with error=0 => INTERNAL_ERROR\n");
945 status
= NT_STATUS_INTERNAL_ERROR
;
946 r
->error_code
= final_ret
= KRB5KRB_ERR_GENERIC
;
947 } else if (!NT_STATUS_IS_OK(p
->reject_status
)) {
948 status
= p
->reject_status
;
950 status
= krb5_to_nt_status(r
->error_code
);
952 } else if (hdb_auth_status
== KDC_AUTH_EVENT_CLIENT_FOUND
) {
954 * We found the client principal,
955 * but we didn’t reach the final
956 * KDC_AUTH_EVENT_CLIENT_AUTHORIZED,
957 * so consult the error code.
959 if (r
->error_code
== 0) {
960 DBG_ERR("ERROR: CLIENT_FOUND "
961 "with error=0 => INTERNAL_ERROR\n");
962 status
= NT_STATUS_INTERNAL_ERROR
;
963 r
->error_code
= final_ret
= KRB5KRB_ERR_GENERIC
;
964 } else if (!NT_STATUS_IS_OK(p
->reject_status
)) {
965 status
= p
->reject_status
;
967 status
= krb5_to_nt_status(r
->error_code
);
969 } else if (hdb_auth_status
== KDC_AUTH_EVENT_CLIENT_TIME_SKEW
) {
970 status
= NT_STATUS_TIME_DIFFERENCE_AT_DC
;
971 } else if (hdb_auth_status
== KDC_AUTH_EVENT_WRONG_LONG_TERM_KEY
) {
972 status
= authsam_update_bad_pwd_count(kdc_db_ctx
->samdb
, p
->msg
, domain_dn
);
973 if (NT_STATUS_EQUAL(status
, NT_STATUS_ACCOUNT_LOCKED_OUT
)) {
974 edata_status
= status
;
976 r
->error_code
= final_ret
= KRB5KDC_ERR_CLIENT_REVOKED
;
978 status
= NT_STATUS_WRONG_PASSWORD
;
980 rwdc_fallback
= kdc_db_ctx
->rodc
;
981 } else if (hdb_auth_status
== KDC_AUTH_EVENT_HISTORIC_LONG_TERM_KEY
) {
983 * The pre-authentication succeeds with a password
984 * from the password history, so we don't
985 * update the badPwdCount, but still return
986 * PREAUTH_FAILED and need to forward to
987 * a RWDC in order to produce an autoritative
988 * response for the client.
990 status
= NT_STATUS_WRONG_PASSWORD
;
991 rwdc_fallback
= kdc_db_ctx
->rodc
;
992 } else if (hdb_auth_status
== KDC_AUTH_EVENT_CLIENT_LOCKED_OUT
) {
993 edata_status
= status
= NT_STATUS_ACCOUNT_LOCKED_OUT
;
994 rwdc_fallback
= kdc_db_ctx
->rodc
;
995 } else if (hdb_auth_status
== KDC_AUTH_EVENT_CLIENT_NAME_UNAUTHORIZED
) {
996 if (pa_type
!= NULL
&& strncmp(pa_type
, "PK-INIT", strlen("PK-INIT")) == 0) {
997 status
= NT_STATUS_PKINIT_NAME_MISMATCH
;
999 status
= NT_STATUS_ACCOUNT_RESTRICTION
;
1001 rwdc_fallback
= kdc_db_ctx
->rodc
;
1002 } else if (hdb_auth_status
== KDC_AUTH_EVENT_PREAUTH_FAILED
) {
1003 if (pa_type
!= NULL
&& strncmp(pa_type
, "PK-INIT", strlen("PK-INIT")) == 0) {
1004 status
= NT_STATUS_PKINIT_FAILURE
;
1006 status
= NT_STATUS_GENERIC_COMMAND_FAILED
;
1008 rwdc_fallback
= kdc_db_ctx
->rodc
;
1010 DBG_ERR("Unhandled hdb_auth_status=%d => INTERNAL_ERROR\n",
1012 status
= NT_STATUS_INTERNAL_ERROR
;
1013 r
->error_code
= final_ret
= KRB5KRB_ERR_GENERIC
;
1016 if (!NT_STATUS_IS_OK(edata_status
)) {
1017 krb5_error_code code
;
1019 code
= hdb_samba4_set_edata_from_ntstatus(r
, edata_status
);
1021 r
->error_code
= final_ret
= code
;
1025 if (rwdc_fallback
) {
1027 * Forward the request to an RWDC in order
1028 * to give an authoritative answer to the client.
1030 auth_description
= talloc_asprintf(frame
,
1031 "%s,Forward-To-RWDC",
1032 ui
.auth_description
);
1033 if (auth_description
!= NULL
) {
1034 ui
.auth_description
= auth_description
;
1036 final_ret
= HDB_ERR_NOT_FOUND_HERE
;
1039 client_audit_info
= hdb_samba4_get_client_audit_info(r
);
1040 server_audit_info
= hdb_samba4_get_server_audit_info(r
);
1042 log_authentication_event(kdc_db_ctx
->msg_ctx
,
1052 if (final_ret
== KRB5KRB_ERR_GENERIC
&& socket_wrapper_enabled()) {
1054 * If we're running under make test
1057 DBG_ERR("Unexpected situation => PANIC\n");
1058 smb_panic("hdb_samba4_audit: Unexpected situation");
1063 case KDC_AUTH_EVENT_CLIENT_UNKNOWN
:
1065 struct tsocket_address
*remote_host
;
1067 TALLOC_CTX
*frame
= talloc_stackframe();
1068 ret
= tsocket_address_bsd_from_sockaddr(frame
, r
->addr
,
1072 ui
.remote_host
= NULL
;
1074 ui
.remote_host
= remote_host
;
1077 if (pa_type
== NULL
) {
1081 ui
.auth_description
= pa_type
;
1083 /* Note this is not forwarded to an RWDC */
1085 log_authentication_event(kdc_db_ctx
->msg_ctx
,
1089 NT_STATUS_NO_SUCH_USER
,
1092 NULL
/* client_audit_info */,
1093 NULL
/* server_audit_info */);
1104 /* This interface is to be called by the KDC and libnet_keytab_dump,
1105 * which is expecting Samba calling conventions.
1106 * It is also called by a wrapper (hdb_samba4_create) from the
1107 * kpasswdd -> krb5 -> keytab_hdb -> hdb code */
1109 NTSTATUS
hdb_samba4_create_kdc(struct samba_kdc_base_context
*base_ctx
,
1110 krb5_context context
, struct HDB
**db
)
1112 struct samba_kdc_db_context
*kdc_db_ctx
;
1115 if (hdb_interface_version
!= HDB_INTERFACE_VERSION
) {
1116 krb5_set_error_message(context
, EINVAL
, "Heimdal HDB interface version mismatch between build-time and run-time libraries!");
1117 return NT_STATUS_ERROR_DS_INCOMPATIBLE_VERSION
;
1120 *db
= talloc_zero(base_ctx
, HDB
);
1122 krb5_set_error_message(context
, ENOMEM
, "malloc: out of memory");
1123 return NT_STATUS_NO_MEMORY
;
1126 (*db
)->hdb_master_key_set
= 0;
1127 (*db
)->hdb_db
= NULL
;
1128 (*db
)->hdb_capability_flags
= HDB_CAP_F_HANDLE_ENTERPRISE_PRINCIPAL
;
1130 nt_status
= samba_kdc_setup_db_ctx(*db
, base_ctx
, &kdc_db_ctx
);
1131 if (!NT_STATUS_IS_OK(nt_status
)) {
1135 (*db
)->hdb_db
= kdc_db_ctx
;
1137 (*db
)->hdb_dbc
= NULL
;
1138 (*db
)->hdb_open
= hdb_samba4_open
;
1139 (*db
)->hdb_close
= hdb_samba4_close
;
1140 (*db
)->hdb_free_entry_context
= hdb_samba4_free_entry_context
;
1141 (*db
)->hdb_fetch_kvno
= hdb_samba4_fetch_kvno
;
1142 (*db
)->hdb_store
= hdb_samba4_store
;
1143 (*db
)->hdb_firstkey
= hdb_samba4_firstkey
;
1144 (*db
)->hdb_nextkey
= hdb_samba4_nextkey
;
1145 (*db
)->hdb_lock
= hdb_samba4_lock
;
1146 (*db
)->hdb_unlock
= hdb_samba4_unlock
;
1147 (*db
)->hdb_set_sync
= hdb_samba4_set_sync
;
1148 (*db
)->hdb_rename
= hdb_samba4_rename
;
1149 /* we don't implement these, as we are not a lockable database */
1150 (*db
)->hdb__get
= NULL
;
1151 (*db
)->hdb__put
= NULL
;
1152 /* kadmin should not be used for deletes - use other tools instead */
1153 (*db
)->hdb__del
= NULL
;
1154 (*db
)->hdb_destroy
= hdb_samba4_destroy
;
1156 (*db
)->hdb_audit
= hdb_samba4_audit
;
1157 (*db
)->hdb_check_constrained_delegation
= hdb_samba4_check_constrained_delegation
;
1158 (*db
)->hdb_check_rbcd
= hdb_samba4_check_rbcd
;
1159 (*db
)->hdb_check_pkinit_ms_upn_match
= hdb_samba4_check_pkinit_ms_upn_match
;
1160 (*db
)->hdb_check_client_matches_target_service
= hdb_samba4_check_client_matches_target_service
;
1162 return NT_STATUS_OK
;
1165 NTSTATUS
hdb_samba4_kpasswd_create_kdc(struct samba_kdc_base_context
*base_ctx
,
1166 krb5_context context
, struct HDB
**db
)
1170 nt_status
= hdb_samba4_create_kdc(base_ctx
, context
, db
);
1171 if (!NT_STATUS_IS_OK(nt_status
)) {
1175 (*db
)->hdb_fetch_kvno
= hdb_samba4_kpasswd_fetch_kvno
;
1176 (*db
)->hdb_firstkey
= hdb_samba4_nextkey_panic
;
1177 (*db
)->hdb_nextkey
= hdb_samba4_nextkey_panic
;
1179 return NT_STATUS_OK
;