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
= user_info
->logon_id
;
365 identity_info
->account_name
.string
= user_info
->mapped
.account_name
;
366 identity_info
->workstation
.string
367 = talloc_asprintf(identity_info
, "krb5-bad-pw on RODC from %s",
368 tsocket_address_string(user_info
->remote_host
,
370 if (identity_info
->workstation
.string
== NULL
) {
371 DEBUG(0, ("Winbind forwarding failed: No memory allocating workstation string\n"));
375 req
.in
.validation_level
= 3;
378 * The memory in identity_info and user_info only needs to be
379 * valid until the end of this function call, as it will be
380 * pushed to NDR during this call
383 dcerpc_winbind_SamLogon_r_send(mem_ctx
, kdc_db_ctx
->ev_ctx
,
387 static krb5_error_code
hdb_samba4_auth_status(krb5_context context
, HDB
*db
,
389 struct sockaddr
*from_addr
,
390 struct timeval
*start_time
,
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
);
399 uint64_t logon_id
= generate_random_u64();
402 * Forcing this via the NTLM auth structure is not ideal, but
403 * it is the most practical option right now, and ensures the
404 * logs are consistent, even if some elements are always NULL.
406 struct auth_usersupplied_info ui
= {
407 .mapped_state
= true,
410 .account_name
= original_client_name
,
413 .service_description
= "Kerberos KDC",
414 .auth_description
= "ENC-TS Pre-authentication",
415 .password_type
= auth_type
,
419 size_t sa_socklen
= 0;
421 switch (from_addr
->sa_family
) {
423 sa_socklen
= sizeof(struct sockaddr_in
);
427 sa_socklen
= sizeof(struct sockaddr_in6
);
432 switch (hdb_auth_status
) {
433 case HDB_AUTHZ_SUCCESS
:
435 TALLOC_CTX
*frame
= talloc_stackframe();
436 struct samba_kdc_entry
*p
= talloc_get_type(entry
->ctx
,
437 struct samba_kdc_entry
);
438 struct netr_SendToSamBase
*send_to_sam
= NULL
;
441 * TODO: We could log the AS-REQ authorization success here as
442 * well. However before we do that, we need to pass
443 * in the PAC here or re-calculate it.
445 authsam_logon_success_accounting(kdc_db_ctx
->samdb
, p
->msg
,
446 domain_dn
, true, &send_to_sam
);
447 if (kdc_db_ctx
->rodc
&& send_to_sam
!= NULL
) {
448 reset_bad_password_netlogon(frame
, kdc_db_ctx
, send_to_sam
);
453 case HDB_AUTH_INVALID_SIGNATURE
:
455 case HDB_AUTH_CORRECT_PASSWORD
:
456 case HDB_AUTH_WRONG_PASSWORD
:
458 TALLOC_CTX
*frame
= talloc_stackframe();
459 struct samba_kdc_entry
*p
= talloc_get_type(entry
->ctx
,
460 struct samba_kdc_entry
);
462 = samdb_result_dom_sid(frame
, p
->msg
, "objectSid");
463 const char *account_name
464 = ldb_msg_find_attr_as_string(p
->msg
, "sAMAccountName", NULL
);
465 const char *domain_name
= lpcfg_sam_name(p
->kdc_db_ctx
->lp_ctx
);
466 struct tsocket_address
*remote_host
;
470 ret
= tsocket_address_bsd_from_sockaddr(frame
, from_addr
,
474 ui
.remote_host
= NULL
;
476 ui
.remote_host
= remote_host
;
479 ui
.mapped
.account_name
= account_name
;
480 ui
.mapped
.domain_name
= domain_name
;
482 if (hdb_auth_status
== HDB_AUTH_WRONG_PASSWORD
) {
483 authsam_update_bad_pwd_count(kdc_db_ctx
->samdb
, p
->msg
, domain_dn
);
484 status
= NT_STATUS_WRONG_PASSWORD
;
486 * TODO We currently send a bad password via NETLOGON,
487 * however, it should probably forward the ticket to
488 * another KDC to allow login after password changes.
490 if (kdc_db_ctx
->rodc
) {
491 send_bad_password_netlogon(frame
, kdc_db_ctx
, &ui
);
494 status
= NT_STATUS_OK
;
497 log_authentication_event(kdc_db_ctx
->msg_ctx
,
509 case HDB_AUTH_CLIENT_UNKNOWN
:
511 struct tsocket_address
*remote_host
;
513 TALLOC_CTX
*frame
= talloc_stackframe();
514 ret
= tsocket_address_bsd_from_sockaddr(frame
, from_addr
,
518 ui
.remote_host
= NULL
;
520 ui
.remote_host
= remote_host
;
523 log_authentication_event(kdc_db_ctx
->msg_ctx
,
527 NT_STATUS_NO_SUCH_USER
,
537 /* This interface is to be called by the KDC and libnet_keytab_dump,
538 * which is expecting Samba calling conventions.
539 * It is also called by a wrapper (hdb_samba4_create) from the
540 * kpasswdd -> krb5 -> keytab_hdb -> hdb code */
542 NTSTATUS
hdb_samba4_create_kdc(struct samba_kdc_base_context
*base_ctx
,
543 krb5_context context
, struct HDB
**db
)
545 struct samba_kdc_db_context
*kdc_db_ctx
;
548 if (hdb_interface_version
!= HDB_INTERFACE_VERSION
) {
549 krb5_set_error_message(context
, EINVAL
, "Heimdal HDB interface version mismatch between build-time and run-time libraries!");
550 return NT_STATUS_ERROR_DS_INCOMPATIBLE_VERSION
;
553 *db
= talloc(base_ctx
, HDB
);
555 krb5_set_error_message(context
, ENOMEM
, "malloc: out of memory");
556 return NT_STATUS_NO_MEMORY
;
559 (*db
)->hdb_master_key_set
= 0;
560 (*db
)->hdb_db
= NULL
;
561 (*db
)->hdb_capability_flags
= HDB_CAP_F_HANDLE_ENTERPRISE_PRINCIPAL
;
563 nt_status
= samba_kdc_setup_db_ctx(*db
, base_ctx
, &kdc_db_ctx
);
564 if (!NT_STATUS_IS_OK(nt_status
)) {
568 (*db
)->hdb_db
= kdc_db_ctx
;
570 (*db
)->hdb_dbc
= NULL
;
571 (*db
)->hdb_open
= hdb_samba4_open
;
572 (*db
)->hdb_close
= hdb_samba4_close
;
573 (*db
)->hdb_fetch_kvno
= hdb_samba4_fetch_kvno
;
574 (*db
)->hdb_store
= hdb_samba4_store
;
575 (*db
)->hdb_remove
= hdb_samba4_remove
;
576 (*db
)->hdb_firstkey
= hdb_samba4_firstkey
;
577 (*db
)->hdb_nextkey
= hdb_samba4_nextkey
;
578 (*db
)->hdb_lock
= hdb_samba4_lock
;
579 (*db
)->hdb_unlock
= hdb_samba4_unlock
;
580 (*db
)->hdb_rename
= hdb_samba4_rename
;
581 /* we don't implement these, as we are not a lockable database */
582 (*db
)->hdb__get
= NULL
;
583 (*db
)->hdb__put
= NULL
;
584 /* kadmin should not be used for deletes - use other tools instead */
585 (*db
)->hdb__del
= NULL
;
586 (*db
)->hdb_destroy
= hdb_samba4_destroy
;
588 (*db
)->hdb_auth_status
= hdb_samba4_auth_status
;
589 (*db
)->hdb_check_constrained_delegation
= hdb_samba4_check_constrained_delegation
;
590 (*db
)->hdb_check_pkinit_ms_upn_match
= hdb_samba4_check_pkinit_ms_upn_match
;
591 (*db
)->hdb_check_s4u2self
= hdb_samba4_check_s4u2self
;