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"
43 #include "dsdb/samdb/samdb.h"
44 #include "param/param.h"
45 #include "../lib/tsocket/tsocket.h"
46 #include "librpc/gen_ndr/ndr_winbind_c.h"
47 #include "lib/messaging/irpc.h"
49 static krb5_error_code
hdb_samba4_open(krb5_context context
, HDB
*db
, int flags
, mode_t mode
)
51 if (db
->hdb_master_key_set
) {
52 krb5_error_code ret
= HDB_ERR_NOENTRY
;
53 krb5_warnx(context
, "hdb_samba4_open: use of a master key incompatible with LDB\n");
54 krb5_set_error_message(context
, ret
, "hdb_samba4_open: use of a master key incompatible with LDB\n");
61 static krb5_error_code
hdb_samba4_close(krb5_context context
, HDB
*db
)
66 static krb5_error_code
hdb_samba4_lock(krb5_context context
, HDB
*db
, int operation
)
71 static krb5_error_code
hdb_samba4_unlock(krb5_context context
, HDB
*db
)
76 static krb5_error_code
hdb_samba4_rename(krb5_context context
, HDB
*db
, const char *new_name
)
78 return HDB_ERR_DB_INUSE
;
81 static krb5_error_code
hdb_samba4_store(krb5_context context
, HDB
*db
, unsigned flags
, hdb_entry_ex
*entry
)
83 return HDB_ERR_DB_INUSE
;
86 static krb5_error_code
hdb_samba4_remove(krb5_context context
, HDB
*db
, krb5_const_principal principal
)
88 return HDB_ERR_DB_INUSE
;
91 static krb5_error_code
hdb_samba4_fetch_kvno(krb5_context context
, HDB
*db
,
92 krb5_const_principal principal
,
95 hdb_entry_ex
*entry_ex
)
97 struct samba_kdc_db_context
*kdc_db_ctx
;
98 struct sdb_entry_ex sdb_entry_ex
= {};
99 krb5_error_code code
, ret
;
101 kdc_db_ctx
= talloc_get_type_abort(db
->hdb_db
,
102 struct samba_kdc_db_context
);
104 ret
= samba_kdc_fetch(context
,
114 case SDB_ERR_WRONG_REALM
:
116 * If SDB_ERR_WRONG_REALM is returned we need to process the
117 * sdb_entry to fill the principal in the HDB entry.
119 code
= HDB_ERR_WRONG_REALM
;
121 case SDB_ERR_NOENTRY
:
122 return HDB_ERR_NOENTRY
;
123 case SDB_ERR_NOT_FOUND_HERE
:
124 return HDB_ERR_NOT_FOUND_HERE
;
129 ret
= sdb_entry_ex_to_hdb_entry_ex(context
, &sdb_entry_ex
, entry_ex
);
130 sdb_free_entry(&sdb_entry_ex
);
132 if (code
!= 0 && ret
!= 0) {
139 static krb5_error_code
hdb_samba4_firstkey(krb5_context context
, HDB
*db
, unsigned flags
,
142 struct samba_kdc_db_context
*kdc_db_ctx
;
143 struct sdb_entry_ex sdb_entry_ex
= {};
146 kdc_db_ctx
= talloc_get_type_abort(db
->hdb_db
,
147 struct samba_kdc_db_context
);
149 ret
= samba_kdc_firstkey(context
, kdc_db_ctx
, &sdb_entry_ex
);
153 case SDB_ERR_WRONG_REALM
:
154 return HDB_ERR_WRONG_REALM
;
155 case SDB_ERR_NOENTRY
:
156 return HDB_ERR_NOENTRY
;
157 case SDB_ERR_NOT_FOUND_HERE
:
158 return HDB_ERR_NOT_FOUND_HERE
;
163 ret
= sdb_entry_ex_to_hdb_entry_ex(context
, &sdb_entry_ex
, entry
);
164 sdb_free_entry(&sdb_entry_ex
);
168 static krb5_error_code
hdb_samba4_nextkey(krb5_context context
, HDB
*db
, unsigned flags
,
171 struct samba_kdc_db_context
*kdc_db_ctx
;
172 struct sdb_entry_ex sdb_entry_ex
= {};
175 kdc_db_ctx
= talloc_get_type_abort(db
->hdb_db
,
176 struct samba_kdc_db_context
);
178 ret
= samba_kdc_nextkey(context
, kdc_db_ctx
, &sdb_entry_ex
);
182 case SDB_ERR_WRONG_REALM
:
183 return HDB_ERR_WRONG_REALM
;
184 case SDB_ERR_NOENTRY
:
185 return HDB_ERR_NOENTRY
;
186 case SDB_ERR_NOT_FOUND_HERE
:
187 return HDB_ERR_NOT_FOUND_HERE
;
192 ret
= sdb_entry_ex_to_hdb_entry_ex(context
, &sdb_entry_ex
, entry
);
193 sdb_free_entry(&sdb_entry_ex
);
197 static krb5_error_code
hdb_samba4_destroy(krb5_context context
, HDB
*db
)
203 static krb5_error_code
204 hdb_samba4_check_constrained_delegation(krb5_context context
, HDB
*db
,
206 krb5_const_principal target_principal
)
208 struct samba_kdc_db_context
*kdc_db_ctx
;
209 struct samba_kdc_entry
*skdc_entry
;
212 kdc_db_ctx
= talloc_get_type_abort(db
->hdb_db
,
213 struct samba_kdc_db_context
);
214 skdc_entry
= talloc_get_type_abort(entry
->ctx
,
215 struct samba_kdc_entry
);
217 ret
= samba_kdc_check_s4u2proxy(context
, kdc_db_ctx
,
223 case SDB_ERR_WRONG_REALM
:
224 ret
= HDB_ERR_WRONG_REALM
;
226 case SDB_ERR_NOENTRY
:
227 ret
= HDB_ERR_NOENTRY
;
229 case SDB_ERR_NOT_FOUND_HERE
:
230 ret
= HDB_ERR_NOT_FOUND_HERE
;
239 static krb5_error_code
240 hdb_samba4_check_pkinit_ms_upn_match(krb5_context context
, HDB
*db
,
242 krb5_const_principal certificate_principal
)
244 struct samba_kdc_db_context
*kdc_db_ctx
;
245 struct samba_kdc_entry
*skdc_entry
;
248 kdc_db_ctx
= talloc_get_type_abort(db
->hdb_db
,
249 struct samba_kdc_db_context
);
250 skdc_entry
= talloc_get_type_abort(entry
->ctx
,
251 struct samba_kdc_entry
);
253 ret
= samba_kdc_check_pkinit_ms_upn_match(context
, kdc_db_ctx
,
255 certificate_principal
);
259 case SDB_ERR_WRONG_REALM
:
260 ret
= HDB_ERR_WRONG_REALM
;
262 case SDB_ERR_NOENTRY
:
263 ret
= HDB_ERR_NOENTRY
;
265 case SDB_ERR_NOT_FOUND_HERE
:
266 ret
= HDB_ERR_NOT_FOUND_HERE
;
275 static krb5_error_code
276 hdb_samba4_check_s4u2self(krb5_context context
, HDB
*db
,
278 krb5_const_principal target_principal
)
280 struct samba_kdc_db_context
*kdc_db_ctx
;
281 struct samba_kdc_entry
*skdc_entry
;
284 kdc_db_ctx
= talloc_get_type_abort(db
->hdb_db
,
285 struct samba_kdc_db_context
);
286 skdc_entry
= talloc_get_type_abort(entry
->ctx
,
287 struct samba_kdc_entry
);
289 ret
= samba_kdc_check_s4u2self(context
, kdc_db_ctx
,
295 case SDB_ERR_WRONG_REALM
:
296 ret
= HDB_ERR_WRONG_REALM
;
298 case SDB_ERR_NOENTRY
:
299 ret
= HDB_ERR_NOENTRY
;
301 case SDB_ERR_NOT_FOUND_HERE
:
302 ret
= HDB_ERR_NOT_FOUND_HERE
;
311 static void reset_bad_password_netlogon(TALLOC_CTX
*mem_ctx
,
312 struct samba_kdc_db_context
*kdc_db_ctx
,
313 struct netr_SendToSamBase
*send_to_sam
)
315 struct dcerpc_binding_handle
*irpc_handle
;
316 struct winbind_SendToSam req
;
318 irpc_handle
= irpc_binding_handle_by_name(mem_ctx
, kdc_db_ctx
->msg_ctx
,
322 if (irpc_handle
== NULL
) {
323 DEBUG(0, ("No winbind_server running!\n"));
327 req
.in
.message
= *send_to_sam
;
329 dcerpc_winbind_SendToSam_r_send(mem_ctx
, kdc_db_ctx
->ev_ctx
,
333 static void send_bad_password_netlogon(TALLOC_CTX
*mem_ctx
,
334 struct samba_kdc_db_context
*kdc_db_ctx
,
335 struct auth_usersupplied_info
*user_info
)
337 struct dcerpc_binding_handle
*irpc_handle
;
338 struct winbind_SamLogon req
;
339 struct netr_IdentityInfo
*identity_info
;
340 struct netr_NetworkInfo
*network_info
;
342 irpc_handle
= irpc_binding_handle_by_name(mem_ctx
, kdc_db_ctx
->msg_ctx
,
345 if (irpc_handle
== NULL
) {
346 DEBUG(0, ("Winbind forwarding for [%s]\\[%s] failed, "
347 "no winbind_server running!\n",
348 user_info
->mapped
.domain_name
, user_info
->mapped
.account_name
));
352 network_info
= talloc_zero(mem_ctx
, struct netr_NetworkInfo
);
353 if (network_info
== NULL
) {
354 DEBUG(0, ("Winbind forwarding failed: No memory\n"));
358 identity_info
= &network_info
->identity_info
;
359 req
.in
.logon_level
= 2;
360 req
.in
.logon
.network
= network_info
;
362 identity_info
->domain_name
.string
= user_info
->mapped
.domain_name
;
363 identity_info
->parameter_control
= user_info
->logon_parameters
; /* TODO */
364 identity_info
->logon_id_low
= 0;
365 identity_info
->logon_id_high
= 0;
366 identity_info
->account_name
.string
= user_info
->mapped
.account_name
;
367 identity_info
->workstation
.string
368 = talloc_asprintf(identity_info
, "krb5-bad-pw on RODC from %s",
369 tsocket_address_string(user_info
->remote_host
,
371 if (identity_info
->workstation
.string
== NULL
) {
372 DEBUG(0, ("Winbind forwarding failed: No memory allocating workstation string\n"));
376 req
.in
.validation_level
= 3;
379 * The memory in identity_info and user_info only needs to be
380 * valid until the end of this function call, as it will be
381 * pushed to NDR during this call
384 dcerpc_winbind_SamLogon_r_send(mem_ctx
, kdc_db_ctx
->ev_ctx
,
388 static krb5_error_code
hdb_samba4_auth_status(krb5_context context
, HDB
*db
,
390 struct sockaddr
*from_addr
,
391 const char *original_client_name
,
392 const char *auth_type
,
395 struct samba_kdc_db_context
*kdc_db_ctx
= talloc_get_type_abort(db
->hdb_db
,
396 struct samba_kdc_db_context
);
398 struct ldb_dn
*domain_dn
= ldb_get_default_basedn(kdc_db_ctx
->samdb
);
401 * Forcing this via the NTLM auth structure is not ideal, but
402 * it is the most practical option right now, and ensures the
403 * logs are consistent, even if some elements are always NULL.
405 struct auth_usersupplied_info ui
= {
406 .mapped_state
= true,
409 .account_name
= original_client_name
,
412 .service_description
= "Kerberos KDC",
413 .auth_description
= "ENC-TS Pre-authentication",
414 .password_type
= auth_type
417 size_t sa_socklen
= 0;
419 switch (from_addr
->sa_family
) {
421 sa_socklen
= sizeof(struct sockaddr_in
);
425 sa_socklen
= sizeof(struct sockaddr_in6
);
430 switch (hdb_auth_status
) {
431 case HDB_AUTHZ_SUCCESS
:
433 TALLOC_CTX
*frame
= talloc_stackframe();
434 struct samba_kdc_entry
*p
= talloc_get_type(entry
->ctx
,
435 struct samba_kdc_entry
);
436 struct netr_SendToSamBase
*send_to_sam
= NULL
;
439 * TODO: We could log the AS-REQ authorization success here as
440 * well. However before we do that, we need to pass
441 * in the PAC here or re-calculate it.
443 authsam_logon_success_accounting(kdc_db_ctx
->samdb
, p
->msg
,
444 domain_dn
, true, &send_to_sam
);
445 if (kdc_db_ctx
->rodc
&& send_to_sam
!= NULL
) {
446 reset_bad_password_netlogon(frame
, kdc_db_ctx
, send_to_sam
);
451 case HDB_AUTH_INVALID_SIGNATURE
:
453 case HDB_AUTH_CORRECT_PASSWORD
:
454 case HDB_AUTH_WRONG_PASSWORD
:
456 TALLOC_CTX
*frame
= talloc_stackframe();
457 struct samba_kdc_entry
*p
= talloc_get_type(entry
->ctx
,
458 struct samba_kdc_entry
);
460 = samdb_result_dom_sid(frame
, p
->msg
, "objectSid");
461 const char *account_name
462 = ldb_msg_find_attr_as_string(p
->msg
, "sAMAccountName", NULL
);
463 const char *domain_name
= lpcfg_sam_name(p
->kdc_db_ctx
->lp_ctx
);
464 struct tsocket_address
*remote_host
;
468 ret
= tsocket_address_bsd_from_sockaddr(frame
, from_addr
,
472 ui
.remote_host
= NULL
;
474 ui
.remote_host
= remote_host
;
477 ui
.mapped
.account_name
= account_name
;
478 ui
.mapped
.domain_name
= domain_name
;
480 if (hdb_auth_status
== HDB_AUTH_WRONG_PASSWORD
) {
481 authsam_update_bad_pwd_count(kdc_db_ctx
->samdb
, p
->msg
, domain_dn
);
482 status
= NT_STATUS_WRONG_PASSWORD
;
484 * TODO We currently send a bad password via NETLOGON,
485 * however, it should probably forward the ticket to
486 * another KDC to allow login after password changes.
488 if (kdc_db_ctx
->rodc
) {
489 send_bad_password_netlogon(frame
, kdc_db_ctx
, &ui
);
492 status
= NT_STATUS_OK
;
495 log_authentication_event(kdc_db_ctx
->msg_ctx
,
506 case HDB_AUTH_CLIENT_UNKNOWN
:
508 struct tsocket_address
*remote_host
;
510 TALLOC_CTX
*frame
= talloc_stackframe();
511 ret
= tsocket_address_bsd_from_sockaddr(frame
, from_addr
,
515 ui
.remote_host
= NULL
;
517 ui
.remote_host
= remote_host
;
520 log_authentication_event(kdc_db_ctx
->msg_ctx
,
523 NT_STATUS_NO_SUCH_USER
,
533 /* This interface is to be called by the KDC and libnet_keytab_dump,
534 * which is expecting Samba calling conventions.
535 * It is also called by a wrapper (hdb_samba4_create) from the
536 * kpasswdd -> krb5 -> keytab_hdb -> hdb code */
538 NTSTATUS
hdb_samba4_create_kdc(struct samba_kdc_base_context
*base_ctx
,
539 krb5_context context
, struct HDB
**db
)
541 struct samba_kdc_db_context
*kdc_db_ctx
;
544 if (hdb_interface_version
!= HDB_INTERFACE_VERSION
) {
545 krb5_set_error_message(context
, EINVAL
, "Heimdal HDB interface version mismatch between build-time and run-time libraries!");
546 return NT_STATUS_ERROR_DS_INCOMPATIBLE_VERSION
;
549 *db
= talloc(base_ctx
, HDB
);
551 krb5_set_error_message(context
, ENOMEM
, "malloc: out of memory");
552 return NT_STATUS_NO_MEMORY
;
555 (*db
)->hdb_master_key_set
= 0;
556 (*db
)->hdb_db
= NULL
;
557 (*db
)->hdb_capability_flags
= HDB_CAP_F_HANDLE_ENTERPRISE_PRINCIPAL
;
559 nt_status
= samba_kdc_setup_db_ctx(*db
, base_ctx
, &kdc_db_ctx
);
560 if (!NT_STATUS_IS_OK(nt_status
)) {
564 (*db
)->hdb_db
= kdc_db_ctx
;
566 (*db
)->hdb_dbc
= NULL
;
567 (*db
)->hdb_open
= hdb_samba4_open
;
568 (*db
)->hdb_close
= hdb_samba4_close
;
569 (*db
)->hdb_fetch_kvno
= hdb_samba4_fetch_kvno
;
570 (*db
)->hdb_store
= hdb_samba4_store
;
571 (*db
)->hdb_remove
= hdb_samba4_remove
;
572 (*db
)->hdb_firstkey
= hdb_samba4_firstkey
;
573 (*db
)->hdb_nextkey
= hdb_samba4_nextkey
;
574 (*db
)->hdb_lock
= hdb_samba4_lock
;
575 (*db
)->hdb_unlock
= hdb_samba4_unlock
;
576 (*db
)->hdb_rename
= hdb_samba4_rename
;
577 /* we don't implement these, as we are not a lockable database */
578 (*db
)->hdb__get
= NULL
;
579 (*db
)->hdb__put
= NULL
;
580 /* kadmin should not be used for deletes - use other tools instead */
581 (*db
)->hdb__del
= NULL
;
582 (*db
)->hdb_destroy
= hdb_samba4_destroy
;
584 (*db
)->hdb_auth_status
= hdb_samba4_auth_status
;
585 (*db
)->hdb_check_constrained_delegation
= hdb_samba4_check_constrained_delegation
;
586 (*db
)->hdb_check_pkinit_ms_upn_match
= hdb_samba4_check_pkinit_ms_upn_match
;
587 (*db
)->hdb_check_s4u2self
= hdb_samba4_check_s4u2self
;