s4:smbtorture: Fix samba3.smb.dir on btrfs
[samba4-gss.git] / source4 / kdc / hdb-samba4.c
blob32c6d2f8c2210c3dd6b2122fb450c17bcce3adf8
1 /*
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>
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
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
32 * SUCH DAMAGE.
35 #include "includes.h"
36 #include "kdc/kdc-glue.h"
37 #include "kdc/db-glue.h"
38 #include "kdc/pac-glue.h"
39 #include "auth/auth_sam.h"
40 #include "auth/common_auth.h"
41 #include "auth/authn_policy.h"
42 #include <ldb.h>
43 #include "sdb.h"
44 #include "sdb_hdb.h"
45 #include "dsdb/samdb/samdb.h"
46 #include "param/param.h"
47 #include "../lib/tsocket/tsocket.h"
48 #include "librpc/gen_ndr/ndr_winbind_c.h"
49 #include "lib/messaging/irpc.h"
50 #include "hdb.h"
51 #include <kdc-audit.h>
52 #include <kdc-plugin.h>
54 #undef DBGC_CLASS
55 #define DBGC_CLASS DBGC_KERBEROS
57 static krb5_error_code hdb_samba4_open(krb5_context context, HDB *db, int flags, mode_t mode)
59 if (db->hdb_master_key_set) {
60 krb5_error_code ret = HDB_ERR_NOENTRY;
61 krb5_warnx(context, "hdb_samba4_open: use of a master key incompatible with LDB\n");
62 krb5_set_error_message(context, ret, "hdb_samba4_open: use of a master key incompatible with LDB\n");
63 return ret;
66 return 0;
69 static krb5_error_code hdb_samba4_close(krb5_context context, HDB *db)
71 return 0;
74 static krb5_error_code hdb_samba4_lock(krb5_context context, HDB *db, int operation)
76 return 0;
79 static krb5_error_code hdb_samba4_unlock(krb5_context context, HDB *db)
81 return 0;
84 static krb5_error_code hdb_samba4_rename(krb5_context context, HDB *db, const char *new_name)
86 return HDB_ERR_DB_INUSE;
89 static krb5_error_code hdb_samba4_store(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry)
91 return HDB_ERR_DB_INUSE;
95 * If we ever want kadmin to work fast, we might try and reopen the
96 * ldb with LDB_NOSYNC
98 static krb5_error_code hdb_samba4_set_sync(krb5_context context, struct HDB *db, int set_sync)
100 return 0;
103 static void hdb_samba4_free_entry_context(krb5_context context, struct HDB *db, hdb_entry *entry)
106 * This function is now called for every HDB entry, not just those with
107 * 'context' set, so we have to check that the context is not NULL.
109 if (entry->context != NULL) {
110 struct samba_kdc_entry *skdc_entry =
111 talloc_get_type_abort(entry->context,
112 struct samba_kdc_entry);
114 /* this function is called only from hdb_free_entry().
115 * Make sure we neutralize the destructor or we will
116 * get a double free later when hdb_free_entry() will
117 * try to call free_hdb_entry() */
118 entry->context = NULL;
119 skdc_entry->kdc_entry = NULL;
120 TALLOC_FREE(skdc_entry);
124 static krb5_error_code hdb_samba4_fetch_fast_cookie(krb5_context context,
125 struct samba_kdc_db_context *kdc_db_ctx,
126 hdb_entry *entry)
128 DBG_ERR("Looked up HDB entry for unsupported FX-COOKIE.\n");
129 return HDB_ERR_NOENTRY;
132 static krb5_error_code hdb_samba4_fetch_kvno(krb5_context context, HDB *db,
133 krb5_const_principal principal,
134 unsigned flags,
135 krb5_kvno kvno,
136 hdb_entry *entry)
138 struct samba_kdc_db_context *kdc_db_ctx;
139 struct sdb_entry sentry = {};
140 krb5_error_code code, ret;
141 uint32_t sflags;
143 kdc_db_ctx = talloc_get_type_abort(db->hdb_db,
144 struct samba_kdc_db_context);
146 if (flags & HDB_F_GET_FAST_COOKIE) {
147 return hdb_samba4_fetch_fast_cookie(context,
148 kdc_db_ctx,
149 entry);
152 sflags = (flags & SDB_F_HDB_MASK);
154 ret = samba_kdc_fetch(context,
155 kdc_db_ctx,
156 principal,
157 sflags,
158 kvno,
159 &sentry);
160 switch (ret) {
161 case 0:
162 code = 0;
163 break;
164 case SDB_ERR_WRONG_REALM:
166 * If SDB_ERR_WRONG_REALM is returned we need to process the
167 * sdb_entry to fill the principal in the HDB entry.
169 code = HDB_ERR_WRONG_REALM;
170 break;
171 case SDB_ERR_NOENTRY:
172 return HDB_ERR_NOENTRY;
173 case SDB_ERR_NOT_FOUND_HERE:
174 return HDB_ERR_NOT_FOUND_HERE;
175 default:
176 return ret;
179 ret = sdb_entry_to_hdb_entry(context, &sentry, entry);
180 sdb_entry_free(&sentry);
182 if (code == 0) {
183 code = ret;
186 return code;
189 static krb5_error_code hdb_samba4_kpasswd_fetch_kvno(krb5_context context, HDB *db,
190 krb5_const_principal _principal,
191 unsigned flags,
192 krb5_kvno _kvno,
193 hdb_entry *entry)
195 struct samba_kdc_db_context *kdc_db_ctx = NULL;
196 krb5_error_code ret;
197 krb5_principal kpasswd_principal = NULL;
199 kdc_db_ctx = talloc_get_type_abort(db->hdb_db,
200 struct samba_kdc_db_context);
202 ret = smb_krb5_make_principal(context, &kpasswd_principal,
203 lpcfg_realm(kdc_db_ctx->lp_ctx),
204 "kadmin", "changepw",
205 NULL);
206 if (ret) {
207 return ret;
209 smb_krb5_principal_set_type(context, kpasswd_principal, KRB5_NT_SRV_INST);
212 * For the kpasswd service, always ensure we get the latest kvno. This
213 * also means we (correctly) refuse RODC-issued tickets.
215 flags &= ~HDB_F_KVNO_SPECIFIED;
217 /* Don't bother looking up a client or krbtgt. */
218 flags &= ~(HDB_F_GET_CLIENT|HDB_F_GET_KRBTGT);
220 ret = hdb_samba4_fetch_kvno(context, db,
221 kpasswd_principal,
222 flags,
224 entry);
226 krb5_free_principal(context, kpasswd_principal);
227 return ret;
230 static krb5_error_code hdb_samba4_firstkey(krb5_context context, HDB *db, unsigned flags,
231 hdb_entry *entry)
233 struct samba_kdc_db_context *kdc_db_ctx;
234 struct sdb_entry sentry = {};
235 krb5_error_code ret;
237 kdc_db_ctx = talloc_get_type_abort(db->hdb_db,
238 struct samba_kdc_db_context);
240 ret = samba_kdc_firstkey(context, kdc_db_ctx, SDB_F_ADMIN_DATA, &sentry);
241 switch (ret) {
242 case 0:
243 break;
244 case SDB_ERR_WRONG_REALM:
245 return HDB_ERR_WRONG_REALM;
246 case SDB_ERR_NOENTRY:
247 return HDB_ERR_NOENTRY;
248 case SDB_ERR_NOT_FOUND_HERE:
249 return HDB_ERR_NOT_FOUND_HERE;
250 default:
251 return ret;
254 ret = sdb_entry_to_hdb_entry(context, &sentry, entry);
255 sdb_entry_free(&sentry);
256 return ret;
259 static krb5_error_code hdb_samba4_nextkey(krb5_context context, HDB *db, unsigned flags,
260 hdb_entry *entry)
262 struct samba_kdc_db_context *kdc_db_ctx;
263 struct sdb_entry sentry = {};
264 krb5_error_code ret;
266 kdc_db_ctx = talloc_get_type_abort(db->hdb_db,
267 struct samba_kdc_db_context);
269 ret = samba_kdc_nextkey(context, kdc_db_ctx, SDB_F_ADMIN_DATA, &sentry);
270 switch (ret) {
271 case 0:
272 break;
273 case SDB_ERR_WRONG_REALM:
274 return HDB_ERR_WRONG_REALM;
275 case SDB_ERR_NOENTRY:
276 return HDB_ERR_NOENTRY;
277 case SDB_ERR_NOT_FOUND_HERE:
278 return HDB_ERR_NOT_FOUND_HERE;
279 default:
280 return ret;
283 ret = sdb_entry_to_hdb_entry(context, &sentry, entry);
284 sdb_entry_free(&sentry);
285 return ret;
288 static krb5_error_code hdb_samba4_nextkey_panic(krb5_context context, HDB *db,
289 unsigned flags,
290 hdb_entry *entry)
292 DBG_ERR("Attempt to iterate kpasswd keytab => PANIC\n");
293 smb_panic("hdb_samba4_nextkey_panic: Attempt to iterate kpasswd keytab");
296 static krb5_error_code hdb_samba4_destroy(krb5_context context, HDB *db)
298 talloc_free(db);
299 return 0;
302 static krb5_error_code
303 hdb_samba4_check_constrained_delegation(krb5_context context, HDB *db,
304 hdb_entry *entry,
305 krb5_const_principal target_principal)
307 struct samba_kdc_db_context *kdc_db_ctx = NULL;
308 struct samba_kdc_entry *skdc_entry = NULL;
310 kdc_db_ctx = talloc_get_type_abort(db->hdb_db,
311 struct samba_kdc_db_context);
312 skdc_entry = talloc_get_type_abort(entry->context,
313 struct samba_kdc_entry);
315 return samba_kdc_check_s4u2proxy(context, kdc_db_ctx,
316 skdc_entry,
317 target_principal);
320 static krb5_error_code
321 hdb_samba4_check_rbcd(krb5_context context, HDB *db,
322 const hdb_entry *client_krbtgt,
323 const hdb_entry *client,
324 const hdb_entry *device_krbtgt,
325 const hdb_entry *device,
326 krb5_const_principal server_principal,
327 krb5_const_pac header_pac,
328 krb5_const_pac device_pac,
329 const hdb_entry *proxy)
331 struct samba_kdc_db_context *kdc_db_ctx = NULL;
332 struct samba_kdc_entry *client_skdc_entry = NULL;
333 const struct samba_kdc_entry *client_krbtgt_skdc_entry = NULL;
334 struct samba_kdc_entry *proxy_skdc_entry = NULL;
335 const struct auth_user_info_dc *client_info = NULL;
336 const struct auth_user_info_dc *device_info = NULL;
337 struct samba_kdc_entry_pac client_pac_entry = {};
338 struct auth_claims auth_claims = {};
339 TALLOC_CTX *mem_ctx = NULL;
340 krb5_error_code code;
342 kdc_db_ctx = talloc_get_type_abort(db->hdb_db,
343 struct samba_kdc_db_context);
344 client_skdc_entry = talloc_get_type_abort(client->context,
345 struct samba_kdc_entry);
346 client_krbtgt_skdc_entry = talloc_get_type_abort(client_krbtgt->context,
347 struct samba_kdc_entry);
348 proxy_skdc_entry = talloc_get_type_abort(proxy->context,
349 struct samba_kdc_entry);
351 mem_ctx = talloc_new(kdc_db_ctx);
352 if (mem_ctx == NULL) {
353 return ENOMEM;
356 client_pac_entry = samba_kdc_entry_pac(header_pac,
357 client_skdc_entry,
358 samba_kdc_entry_is_trust(client_krbtgt_skdc_entry));
360 code = samba_kdc_get_user_info_dc(mem_ctx,
361 context,
362 kdc_db_ctx->samdb,
363 client_pac_entry,
364 &client_info,
365 NULL /* resource_groups_out */);
366 if (code != 0) {
367 goto out;
370 code = samba_kdc_get_claims_data(mem_ctx,
371 context,
372 kdc_db_ctx->samdb,
373 client_pac_entry,
374 &auth_claims.user_claims);
375 if (code) {
376 goto out;
379 if (device != NULL) {
380 struct samba_kdc_entry *device_skdc_entry = NULL;
381 const struct samba_kdc_entry *device_krbtgt_skdc_entry = NULL;
382 struct samba_kdc_entry_pac device_pac_entry = {};
384 device_skdc_entry = talloc_get_type_abort(device->context,
385 struct samba_kdc_entry);
387 if (device_krbtgt != NULL) {
388 device_krbtgt_skdc_entry = talloc_get_type_abort(device_krbtgt->context,
389 struct samba_kdc_entry);
392 device_pac_entry = samba_kdc_entry_pac(device_pac,
393 device_skdc_entry,
394 samba_kdc_entry_is_trust(device_krbtgt_skdc_entry));
396 code = samba_kdc_get_user_info_dc(mem_ctx,
397 context,
398 kdc_db_ctx->samdb,
399 device_pac_entry,
400 &device_info,
401 NULL /* resource_groups_out */);
402 if (code) {
403 goto out;
406 code = samba_kdc_get_claims_data(mem_ctx,
407 context,
408 kdc_db_ctx->samdb,
409 device_pac_entry,
410 &auth_claims.device_claims);
411 if (code) {
412 goto out;
416 code = samba_kdc_check_s4u2proxy_rbcd(context,
417 kdc_db_ctx,
418 client->principal,
419 server_principal,
420 client_info,
421 device_info,
422 auth_claims,
423 proxy_skdc_entry);
424 out:
425 talloc_free(mem_ctx);
426 return code;
429 static krb5_error_code
430 hdb_samba4_check_pkinit_ms_upn_match(krb5_context context, HDB *db,
431 hdb_entry *entry,
432 krb5_const_principal certificate_principal)
434 struct samba_kdc_db_context *kdc_db_ctx;
435 struct samba_kdc_entry *skdc_entry;
436 krb5_error_code ret;
438 kdc_db_ctx = talloc_get_type_abort(db->hdb_db,
439 struct samba_kdc_db_context);
440 skdc_entry = talloc_get_type_abort(entry->context,
441 struct samba_kdc_entry);
443 ret = samba_kdc_check_pkinit_ms_upn_match(context, kdc_db_ctx,
444 skdc_entry,
445 certificate_principal);
446 switch (ret) {
447 case 0:
448 break;
449 case SDB_ERR_WRONG_REALM:
450 ret = HDB_ERR_WRONG_REALM;
451 break;
452 case SDB_ERR_NOENTRY:
453 ret = HDB_ERR_NOENTRY;
454 break;
455 case SDB_ERR_NOT_FOUND_HERE:
456 ret = HDB_ERR_NOT_FOUND_HERE;
457 break;
458 default:
459 break;
462 return ret;
465 static krb5_error_code
466 hdb_samba4_check_client_matches_target_service(krb5_context context, HDB *db,
467 hdb_entry *client_entry,
468 hdb_entry *server_target_entry)
470 struct samba_kdc_entry *skdc_client_entry
471 = talloc_get_type_abort(client_entry->context,
472 struct samba_kdc_entry);
473 struct samba_kdc_entry *skdc_server_target_entry
474 = talloc_get_type_abort(server_target_entry->context,
475 struct samba_kdc_entry);
477 return samba_kdc_check_client_matches_target_service(context,
478 skdc_client_entry,
479 skdc_server_target_entry);
482 static void reset_bad_password_netlogon(TALLOC_CTX *mem_ctx,
483 struct samba_kdc_db_context *kdc_db_ctx,
484 struct netr_SendToSamBase *send_to_sam)
486 struct dcerpc_binding_handle *irpc_handle;
487 struct winbind_SendToSam req;
488 struct tevent_req *subreq = NULL;
490 irpc_handle = irpc_binding_handle_by_name(mem_ctx, kdc_db_ctx->msg_ctx,
491 "winbind_server",
492 &ndr_table_winbind);
494 if (irpc_handle == NULL) {
495 DBG_ERR("No winbind_server running!\n");
496 return;
499 req.in.message = *send_to_sam;
502 * This seem to rely on the current IRPC implementation,
503 * which delivers the message in the _send function.
505 * TODO: we need a ONE_WAY IRPC handle and register
506 * a callback and wait for it to be triggered!
508 subreq = dcerpc_winbind_SendToSam_r_send(mem_ctx, kdc_db_ctx->ev_ctx,
509 irpc_handle, &req);
511 /* we aren't interested in a reply */
512 TALLOC_FREE(subreq);
515 #define SAMBA_HDB_AUTHN_AUDIT_INFO_OBJ "samba:authn_audit_info_obj"
516 #define SAMBA_HDB_CLIENT_AUDIT_INFO "samba:client_audit_info"
517 #define SAMBA_HDB_SERVER_AUDIT_INFO "samba:server_audit_info"
519 #define SAMBA_HDB_NT_STATUS_OBJ "samba:nt_status_obj"
520 #define SAMBA_HDB_NT_STATUS "samba:nt_status"
522 struct hdb_audit_info_obj {
523 struct authn_audit_info *audit_info;
526 static void hdb_audit_info_obj_dealloc(void *ptr)
528 struct hdb_audit_info_obj *audit_info_obj = ptr;
530 if (audit_info_obj == NULL) {
531 return;
534 TALLOC_FREE(audit_info_obj->audit_info);
538 * Set talloc-allocated auditing information of the KDC request. On success,
539 * ‘audit_info’ is invalidated and may no longer be used by the caller.
541 static krb5_error_code hdb_samba4_set_steal_audit_info(astgs_request_t r,
542 const char *key,
543 struct authn_audit_info *audit_info)
545 struct hdb_audit_info_obj *audit_info_obj = NULL;
547 audit_info_obj = kdc_object_alloc(sizeof (*audit_info_obj),
548 SAMBA_HDB_AUTHN_AUDIT_INFO_OBJ,
549 hdb_audit_info_obj_dealloc);
550 if (audit_info_obj == NULL) {
551 return ENOMEM;
555 * Steal a handle to the audit information onto the NULL context —
556 * Heimdal will be responsible for the deallocation of the object.
558 audit_info_obj->audit_info = talloc_steal(NULL, audit_info);
560 heim_audit_setkv_object((heim_svc_req_desc)r, key, audit_info_obj);
561 heim_release(audit_info_obj);
563 return 0;
567 * Set talloc-allocated client auditing information of the KDC request. On
568 * success, ‘client_audit_info’ is invalidated and may no longer be used by the
569 * caller.
571 krb5_error_code hdb_samba4_set_steal_client_audit_info(astgs_request_t r,
572 struct authn_audit_info *client_audit_info)
574 return hdb_samba4_set_steal_audit_info(r,
575 SAMBA_HDB_CLIENT_AUDIT_INFO,
576 client_audit_info);
579 static const struct authn_audit_info *hdb_samba4_get_client_audit_info(hdb_request_t r)
581 const struct hdb_audit_info_obj *audit_info_obj = NULL;
583 audit_info_obj = heim_audit_getkv((heim_svc_req_desc)r, SAMBA_HDB_CLIENT_AUDIT_INFO);
584 if (audit_info_obj == NULL) {
585 return NULL;
588 return audit_info_obj->audit_info;
592 * Set talloc-allocated server auditing information of the KDC request. On
593 * success, ‘server_audit_info’ is invalidated and may no longer be used by the
594 * caller.
596 krb5_error_code hdb_samba4_set_steal_server_audit_info(astgs_request_t r,
597 struct authn_audit_info *server_audit_info)
599 return hdb_samba4_set_steal_audit_info(r,
600 SAMBA_HDB_SERVER_AUDIT_INFO,
601 server_audit_info);
604 static const struct authn_audit_info *hdb_samba4_get_server_audit_info(hdb_request_t r)
606 const struct hdb_audit_info_obj *audit_info_obj = NULL;
608 audit_info_obj = heim_audit_getkv((heim_svc_req_desc)r, SAMBA_HDB_SERVER_AUDIT_INFO);
609 if (audit_info_obj == NULL) {
610 return NULL;
613 return audit_info_obj->audit_info;
616 struct hdb_ntstatus_obj {
617 NTSTATUS status;
618 krb5_error_code current_error;
622 * Add an NTSTATUS code to a Kerberos request. ‘error’ is the error value we
623 * want to return to the client. When it comes time to generating the error
624 * request, we shall compare this error value to whatever error we are about to
625 * return; if the two match, we shall replace the ‘e-data’ field in the reply
626 * with the NTSTATUS code.
628 krb5_error_code hdb_samba4_set_ntstatus(astgs_request_t r,
629 const NTSTATUS status,
630 const krb5_error_code error)
632 struct hdb_ntstatus_obj *status_obj = NULL;
634 status_obj = kdc_object_alloc(sizeof (*status_obj),
635 SAMBA_HDB_NT_STATUS_OBJ,
636 NULL);
637 if (status_obj == NULL) {
638 return ENOMEM;
641 *status_obj = (struct hdb_ntstatus_obj) {
642 .status = status,
643 .current_error = error,
646 heim_audit_setkv_object((heim_svc_req_desc)r, SAMBA_HDB_NT_STATUS, status_obj);
647 heim_release(status_obj);
649 return 0;
652 static krb5_error_code hdb_samba4_make_nt_status_edata(const NTSTATUS status,
653 const uint32_t flags,
654 krb5_data *edata_out)
656 const uint32_t status_code = NT_STATUS_V(status);
657 const uint32_t zero = 0;
658 KERB_ERROR_DATA error_data;
659 krb5_data e_data;
661 krb5_error_code ret;
662 size_t size;
664 /* The raw KERB-ERR-TYPE-EXTENDED structure. */
665 uint8_t data[12];
667 PUSH_LE_U32(data, 0, status_code);
668 PUSH_LE_U32(data, 4, zero);
669 PUSH_LE_U32(data, 8, flags);
671 e_data = (krb5_data) {
672 .data = &data,
673 .length = sizeof(data),
676 error_data = (KERB_ERROR_DATA) {
677 .data_type = kERB_ERR_TYPE_EXTENDED,
678 .data_value = &e_data,
681 ASN1_MALLOC_ENCODE(KERB_ERROR_DATA,
682 edata_out->data, edata_out->length,
683 &error_data,
684 &size, ret);
685 if (ret) {
686 return ret;
688 if (size != edata_out->length) {
689 /* Internal ASN.1 encoder error */
690 krb5_data_free(edata_out);
691 return KRB5KRB_ERR_GENERIC;
694 return 0;
697 static krb5_error_code hdb_samba4_set_edata_from_ntstatus(hdb_request_t r, const NTSTATUS status)
699 const KDC_REQ *req = kdc_request_get_req((astgs_request_t)r);
700 krb5_error_code ret = 0;
701 krb5_data e_data;
702 uint32_t flags = 1;
704 if (req->msg_type == krb_tgs_req) {
705 /* This flag is used to indicate a TGS-REQ. */
706 flags |= 2;
709 ret = hdb_samba4_make_nt_status_edata(status, flags, &e_data);
710 if (ret) {
711 return ret;
714 ret = kdc_request_set_e_data((astgs_request_t)r, e_data);
715 if (ret) {
716 krb5_data_free(&e_data);
719 return ret;
722 static NTSTATUS hdb_samba4_get_ntstatus(hdb_request_t r)
724 struct hdb_ntstatus_obj *status_obj = NULL;
726 status_obj = heim_audit_getkv((heim_svc_req_desc)r, SAMBA_HDB_NT_STATUS);
727 if (status_obj == NULL) {
728 return NT_STATUS_OK;
731 if (r->error_code != status_obj->current_error) {
733 * The error code has changed from what we expect. Consider the
734 * NTSTATUS to be invalidated.
736 return NT_STATUS_OK;
739 return status_obj->status;
742 static krb5_error_code hdb_samba4_tgs_audit(const struct samba_kdc_db_context *kdc_db_ctx,
743 const hdb_entry *entry,
744 hdb_request_t r)
746 TALLOC_CTX *frame = talloc_stackframe();
747 const struct authn_audit_info *server_audit_info = NULL;
748 struct tsocket_address *remote_host = NULL;
749 struct samba_kdc_entry *client_entry = NULL;
750 struct dom_sid sid_buf = {};
751 const char *account_name = NULL;
752 const char *domain_name = NULL;
753 const struct dom_sid *sid = NULL;
754 size_t sa_socklen = 0;
755 NTSTATUS auth_status = NT_STATUS_OK;
756 krb5_error_code ret = 0;
757 krb5_error_code final_ret = 0;
759 /* Have we got a status code indicating an error? */
760 auth_status = hdb_samba4_get_ntstatus(r);
761 if (!NT_STATUS_IS_OK(auth_status)) {
763 * Include this status code in the ‘e-data’ field of the reply.
765 ret = hdb_samba4_set_edata_from_ntstatus(r, auth_status);
766 if (ret) {
767 final_ret = ret;
769 } else if (entry == NULL) {
770 auth_status = NT_STATUS_NO_SUCH_USER;
771 } else if (r->error_code) {
773 * Don’t include a status code in the reply. Just log the
774 * request as being unsuccessful.
776 auth_status = NT_STATUS_UNSUCCESSFUL;
779 switch (r->addr->sa_family) {
780 case AF_INET:
781 sa_socklen = sizeof(struct sockaddr_in);
782 break;
783 #ifdef HAVE_IPV6
784 case AF_INET6:
785 sa_socklen = sizeof(struct sockaddr_in6);
786 break;
787 #endif
790 ret = tsocket_address_bsd_from_sockaddr(frame, r->addr,
791 sa_socklen,
792 &remote_host);
793 if (ret != 0) {
794 remote_host = NULL;
795 /* Ignore the error. */
798 server_audit_info = hdb_samba4_get_server_audit_info(r);
800 if (entry != NULL) {
801 client_entry = talloc_get_type_abort(entry->context,
802 struct samba_kdc_entry);
804 ret = samdb_result_dom_sid_buf(client_entry->msg, "objectSid", &sid_buf);
805 if (ret) {
806 /* Ignore the error. */
807 } else {
808 sid = &sid_buf;
811 account_name = ldb_msg_find_attr_as_string(client_entry->msg, "sAMAccountName", NULL);
812 domain_name = lpcfg_sam_name(kdc_db_ctx->lp_ctx);
815 log_authz_event(kdc_db_ctx->msg_ctx,
816 kdc_db_ctx->lp_ctx,
817 remote_host,
818 NULL /* local */,
819 server_audit_info,
820 r->sname,
821 "TGS-REQ with Ticket-Granting Ticket",
822 domain_name,
823 account_name,
824 sid,
825 lpcfg_netbios_name(kdc_db_ctx->lp_ctx),
826 krb5_kdc_get_time(),
827 auth_status);
829 talloc_free(frame);
830 if (final_ret) {
831 r->error_code = final_ret;
833 return final_ret;
836 static krb5_error_code hdb_samba4_audit(krb5_context context,
837 HDB *db,
838 hdb_entry *entry,
839 hdb_request_t r)
841 struct samba_kdc_db_context *kdc_db_ctx = talloc_get_type_abort(db->hdb_db,
842 struct samba_kdc_db_context);
843 struct ldb_dn *domain_dn = ldb_get_default_basedn(kdc_db_ctx->samdb);
844 heim_object_t auth_details_obj = NULL;
845 const char *auth_details = NULL;
846 char *etype_str = NULL;
847 heim_object_t hdb_auth_status_obj = NULL;
848 int hdb_auth_status;
849 heim_object_t pa_type_obj = NULL;
850 const char *pa_type = NULL;
851 struct auth_usersupplied_info ui;
852 size_t sa_socklen = 0;
853 const KDC_REQ *req = kdc_request_get_req((astgs_request_t)r);
854 krb5_error_code final_ret = 0;
855 NTSTATUS edata_status;
857 if (req->msg_type == krb_tgs_req) {
858 return hdb_samba4_tgs_audit(kdc_db_ctx, entry, r);
861 if (r->error_code == KRB5KDC_ERR_PREAUTH_REQUIRED) {
862 /* Let’s not log PREAUTH_REQUIRED errors. */
863 return 0;
866 edata_status = hdb_samba4_get_ntstatus(r);
868 hdb_auth_status_obj = heim_audit_getkv((heim_svc_req_desc)r, KDC_REQUEST_KV_AUTH_EVENT);
869 if (hdb_auth_status_obj == NULL) {
870 /* No status code found, so just return. */
871 return 0;
874 hdb_auth_status = heim_number_get_int(hdb_auth_status_obj);
876 pa_type_obj = heim_audit_getkv((heim_svc_req_desc)r, KDC_REQUEST_KV_PA_NAME);
877 if (pa_type_obj != NULL) {
878 pa_type = heim_string_get_utf8(pa_type_obj);
881 auth_details_obj = heim_audit_getkv((heim_svc_req_desc)r, KDC_REQUEST_KV_PKINIT_CLIENT_CERT);
882 if (auth_details_obj != NULL) {
883 auth_details = heim_string_get_utf8(auth_details_obj);
884 } else {
885 auth_details_obj = heim_audit_getkv((heim_svc_req_desc)r, KDC_REQUEST_KV_GSS_INITIATOR);
886 if (auth_details_obj != NULL) {
887 auth_details = heim_string_get_utf8(auth_details_obj);
888 } else {
889 heim_object_t etype_obj = heim_audit_getkv((heim_svc_req_desc)r, KDC_REQUEST_KV_PA_ETYPE);
890 if (etype_obj != NULL) {
891 int etype = heim_number_get_int(etype_obj);
893 krb5_error_code ret = krb5_enctype_to_string(r->context, etype, &etype_str);
894 if (ret == 0) {
895 auth_details = etype_str;
896 } else {
897 auth_details = "unknown enctype";
904 * Forcing this via the NTLM auth structure is not ideal, but
905 * it is the most practical option right now, and ensures the
906 * logs are consistent, even if some elements are always NULL.
908 ui = (struct auth_usersupplied_info) {
909 .was_mapped = true,
910 .client = {
911 .account_name = r->cname,
912 .domain_name = NULL,
914 .service_description = "Kerberos KDC",
915 .auth_description = "Unknown Auth Description",
916 .password_type = auth_details,
917 .logon_id = generate_random_u64(),
920 switch (r->addr->sa_family) {
921 case AF_INET:
922 sa_socklen = sizeof(struct sockaddr_in);
923 break;
924 #ifdef HAVE_IPV6
925 case AF_INET6:
926 sa_socklen = sizeof(struct sockaddr_in6);
927 break;
928 #endif
931 switch (hdb_auth_status) {
932 default:
934 TALLOC_CTX *frame = talloc_stackframe();
935 struct samba_kdc_entry *p = talloc_get_type_abort(entry->context,
936 struct samba_kdc_entry);
937 struct dom_sid *sid
938 = samdb_result_dom_sid(frame, p->msg, "objectSid");
939 const char *account_name
940 = ldb_msg_find_attr_as_string(p->msg, "sAMAccountName", NULL);
941 const char *domain_name = lpcfg_sam_name(p->kdc_db_ctx->lp_ctx);
942 struct tsocket_address *remote_host;
943 const char *auth_description = NULL;
944 const struct authn_audit_info *client_audit_info = NULL;
945 const struct authn_audit_info *server_audit_info = NULL;
946 NTSTATUS status;
947 int ret;
948 bool rwdc_fallback = false;
950 ret = tsocket_address_bsd_from_sockaddr(frame, r->addr,
951 sa_socklen,
952 &remote_host);
953 if (ret != 0) {
954 ui.remote_host = NULL;
955 } else {
956 ui.remote_host = remote_host;
959 ui.mapped.account_name = account_name;
960 ui.mapped.domain_name = domain_name;
962 if (pa_type != NULL) {
963 auth_description = talloc_asprintf(frame,
964 "%s Pre-authentication",
965 pa_type);
966 if (auth_description == NULL) {
967 auth_description = pa_type;
969 } else {
970 auth_description = "Unknown Pre-authentication";
972 ui.auth_description = auth_description;
974 if (hdb_auth_status == KDC_AUTH_EVENT_CLIENT_AUTHORIZED) {
975 struct netr_SendToSamBase *send_to_sam = NULL;
978 * TODO: We could log the AS-REQ authorization success here as
979 * well. However before we do that, we need to pass
980 * in the PAC here or re-calculate it.
982 status = authsam_logon_success_accounting(kdc_db_ctx->samdb, p->msg,
983 domain_dn, true, frame, &send_to_sam);
984 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCOUNT_LOCKED_OUT)) {
985 edata_status = status;
987 r->error_code = final_ret = KRB5KDC_ERR_CLIENT_REVOKED;
988 rwdc_fallback = kdc_db_ctx->rodc;
989 } else if (!NT_STATUS_IS_OK(status)) {
990 r->error_code = final_ret = KRB5KDC_ERR_CLIENT_REVOKED;
991 rwdc_fallback = kdc_db_ctx->rodc;
992 } else {
993 if (r->error_code == KRB5KDC_ERR_NEVER_VALID) {
994 edata_status = status = NT_STATUS_TIME_DIFFERENCE_AT_DC;
995 } else {
996 status = krb5_to_nt_status(r->error_code);
999 if (kdc_db_ctx->rodc && send_to_sam != NULL) {
1000 reset_bad_password_netlogon(frame, kdc_db_ctx, send_to_sam);
1004 /* This is the final success */
1005 } else if (hdb_auth_status == KDC_AUTH_EVENT_VALIDATED_LONG_TERM_KEY) {
1007 * This was only a pre-authentication success,
1008 * but we didn't reach the final
1009 * KDC_AUTH_EVENT_CLIENT_AUTHORIZED,
1010 * so consult the error code.
1012 if (r->error_code == 0) {
1013 DBG_ERR("ERROR: VALIDATED_LONG_TERM_KEY "
1014 "with error=0 => INTERNAL_ERROR\n");
1015 status = NT_STATUS_INTERNAL_ERROR;
1016 r->error_code = final_ret = KRB5KRB_ERR_GENERIC;
1017 } else if (!NT_STATUS_IS_OK(p->reject_status)) {
1018 status = p->reject_status;
1019 } else {
1020 status = krb5_to_nt_status(r->error_code);
1022 } else if (hdb_auth_status == KDC_AUTH_EVENT_PREAUTH_SUCCEEDED) {
1024 * This was only a pre-authentication success,
1025 * but we didn't reach the final
1026 * KDC_AUTH_EVENT_CLIENT_AUTHORIZED,
1027 * so consult the error code.
1029 if (r->error_code == 0) {
1030 DBG_ERR("ERROR: PREAUTH_SUCCEEDED "
1031 "with error=0 => INTERNAL_ERROR\n");
1032 status = NT_STATUS_INTERNAL_ERROR;
1033 r->error_code = final_ret = KRB5KRB_ERR_GENERIC;
1034 } else if (!NT_STATUS_IS_OK(p->reject_status)) {
1035 status = p->reject_status;
1036 } else {
1037 status = krb5_to_nt_status(r->error_code);
1039 } else if (hdb_auth_status == KDC_AUTH_EVENT_CLIENT_FOUND) {
1041 * We found the client principal,
1042 * but we didn’t reach the final
1043 * KDC_AUTH_EVENT_CLIENT_AUTHORIZED,
1044 * so consult the error code.
1046 if (r->error_code == 0) {
1047 DBG_ERR("ERROR: CLIENT_FOUND "
1048 "with error=0 => INTERNAL_ERROR\n");
1049 status = NT_STATUS_INTERNAL_ERROR;
1050 r->error_code = final_ret = KRB5KRB_ERR_GENERIC;
1051 } else if (!NT_STATUS_IS_OK(p->reject_status)) {
1052 status = p->reject_status;
1053 } else {
1054 status = krb5_to_nt_status(r->error_code);
1056 } else if (hdb_auth_status == KDC_AUTH_EVENT_CLIENT_TIME_SKEW) {
1057 status = NT_STATUS_TIME_DIFFERENCE_AT_DC;
1058 } else if (hdb_auth_status == KDC_AUTH_EVENT_WRONG_LONG_TERM_KEY) {
1059 status = authsam_update_bad_pwd_count(kdc_db_ctx->samdb, p->msg, domain_dn);
1060 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCOUNT_LOCKED_OUT)) {
1061 edata_status = status;
1063 r->error_code = final_ret = KRB5KDC_ERR_CLIENT_REVOKED;
1064 } else {
1065 status = NT_STATUS_WRONG_PASSWORD;
1067 rwdc_fallback = kdc_db_ctx->rodc;
1068 } else if (hdb_auth_status == KDC_AUTH_EVENT_HISTORIC_LONG_TERM_KEY) {
1070 * The pre-authentication succeeds with a password
1071 * from the password history, so we don't
1072 * update the badPwdCount, but still return
1073 * PREAUTH_FAILED and need to forward to
1074 * a RWDC in order to produce an authoritative
1075 * response for the client.
1077 status = NT_STATUS_WRONG_PASSWORD;
1078 rwdc_fallback = kdc_db_ctx->rodc;
1079 } else if (hdb_auth_status == KDC_AUTH_EVENT_CLIENT_LOCKED_OUT) {
1080 edata_status = status = NT_STATUS_ACCOUNT_LOCKED_OUT;
1081 rwdc_fallback = kdc_db_ctx->rodc;
1082 } else if (hdb_auth_status == KDC_AUTH_EVENT_CLIENT_NAME_UNAUTHORIZED) {
1083 if (pa_type != NULL && strncmp(pa_type, "PK-INIT", strlen("PK-INIT")) == 0) {
1084 status = NT_STATUS_PKINIT_NAME_MISMATCH;
1085 } else {
1086 status = NT_STATUS_ACCOUNT_RESTRICTION;
1088 rwdc_fallback = kdc_db_ctx->rodc;
1089 } else if (hdb_auth_status == KDC_AUTH_EVENT_PREAUTH_FAILED) {
1090 if (pa_type != NULL && strncmp(pa_type, "PK-INIT", strlen("PK-INIT")) == 0) {
1091 status = NT_STATUS_PKINIT_FAILURE;
1092 } else {
1093 status = NT_STATUS_GENERIC_COMMAND_FAILED;
1095 rwdc_fallback = kdc_db_ctx->rodc;
1096 } else {
1097 DBG_ERR("Unhandled hdb_auth_status=%d => INTERNAL_ERROR\n",
1098 hdb_auth_status);
1099 status = NT_STATUS_INTERNAL_ERROR;
1100 r->error_code = final_ret = KRB5KRB_ERR_GENERIC;
1103 if (!NT_STATUS_IS_OK(edata_status)) {
1104 krb5_error_code code;
1106 code = hdb_samba4_set_edata_from_ntstatus(r, edata_status);
1107 if (code) {
1108 r->error_code = final_ret = code;
1112 if (rwdc_fallback) {
1114 * Forward the request to an RWDC in order
1115 * to give an authoritative answer to the client.
1117 auth_description = talloc_asprintf(frame,
1118 "%s,Forward-To-RWDC",
1119 ui.auth_description);
1120 if (auth_description != NULL) {
1121 ui.auth_description = auth_description;
1123 final_ret = HDB_ERR_NOT_FOUND_HERE;
1126 client_audit_info = hdb_samba4_get_client_audit_info(r);
1127 server_audit_info = hdb_samba4_get_server_audit_info(r);
1129 log_authentication_event(kdc_db_ctx->msg_ctx,
1130 kdc_db_ctx->lp_ctx,
1131 &r->tv_start,
1132 &ui,
1133 status,
1134 domain_name,
1135 account_name,
1136 sid,
1137 client_audit_info,
1138 server_audit_info);
1139 if (final_ret == KRB5KRB_ERR_GENERIC && socket_wrapper_enabled()) {
1141 * If we're running under make test
1142 * just panic
1144 DBG_ERR("Unexpected situation => PANIC\n");
1145 smb_panic("hdb_samba4_audit: Unexpected situation");
1147 TALLOC_FREE(frame);
1148 break;
1150 case KDC_AUTH_EVENT_CLIENT_UNKNOWN:
1152 struct tsocket_address *remote_host;
1153 int ret;
1154 TALLOC_CTX *frame = talloc_stackframe();
1155 ret = tsocket_address_bsd_from_sockaddr(frame, r->addr,
1156 sa_socklen,
1157 &remote_host);
1158 if (ret != 0) {
1159 ui.remote_host = NULL;
1160 } else {
1161 ui.remote_host = remote_host;
1164 if (pa_type == NULL) {
1165 pa_type = "AS-REQ";
1168 ui.auth_description = pa_type;
1170 /* Note this is not forwarded to an RWDC */
1172 log_authentication_event(kdc_db_ctx->msg_ctx,
1173 kdc_db_ctx->lp_ctx,
1174 &r->tv_start,
1175 &ui,
1176 NT_STATUS_NO_SUCH_USER,
1177 NULL, NULL,
1178 NULL,
1179 NULL /* client_audit_info */,
1180 NULL /* server_audit_info */);
1181 TALLOC_FREE(frame);
1182 break;
1186 free(etype_str);
1188 return final_ret;
1191 /* This interface is to be called by the KDC and libnet_keytab_dump,
1192 * which is expecting Samba calling conventions.
1193 * It is also called by a wrapper (hdb_samba4_create) from the
1194 * kpasswdd -> krb5 -> keytab_hdb -> hdb code */
1196 NTSTATUS hdb_samba4_create_kdc(struct samba_kdc_base_context *base_ctx,
1197 krb5_context context, struct HDB **db,
1198 struct samba_kdc_db_context **kdc_db_ctx)
1200 NTSTATUS nt_status;
1202 if (hdb_interface_version != HDB_INTERFACE_VERSION) {
1203 krb5_set_error_message(context, EINVAL, "Heimdal HDB interface version mismatch between build-time and run-time libraries!");
1204 return NT_STATUS_ERROR_DS_INCOMPATIBLE_VERSION;
1207 *db = talloc_zero(base_ctx, HDB);
1208 if (!*db) {
1209 krb5_set_error_message(context, ENOMEM, "talloc_zero: out of memory");
1210 return NT_STATUS_NO_MEMORY;
1213 (*db)->hdb_master_key_set = 0;
1214 (*db)->hdb_db = NULL;
1215 (*db)->hdb_capability_flags = HDB_CAP_F_HANDLE_ENTERPRISE_PRINCIPAL;
1217 nt_status = samba_kdc_setup_db_ctx(*db, base_ctx, kdc_db_ctx);
1218 if (!NT_STATUS_IS_OK(nt_status)) {
1219 talloc_free(*db);
1220 return nt_status;
1222 (*db)->hdb_db = *kdc_db_ctx;
1224 (*db)->hdb_dbc = NULL;
1225 (*db)->hdb_open = hdb_samba4_open;
1226 (*db)->hdb_close = hdb_samba4_close;
1227 (*db)->hdb_free_entry_context = hdb_samba4_free_entry_context;
1228 (*db)->hdb_fetch_kvno = hdb_samba4_fetch_kvno;
1229 (*db)->hdb_store = hdb_samba4_store;
1230 (*db)->hdb_firstkey = hdb_samba4_firstkey;
1231 (*db)->hdb_nextkey = hdb_samba4_nextkey;
1232 (*db)->hdb_lock = hdb_samba4_lock;
1233 (*db)->hdb_unlock = hdb_samba4_unlock;
1234 (*db)->hdb_set_sync = hdb_samba4_set_sync;
1235 (*db)->hdb_rename = hdb_samba4_rename;
1236 /* we don't implement these, as we are not a lockable database */
1237 (*db)->hdb__get = NULL;
1238 (*db)->hdb__put = NULL;
1239 /* kadmin should not be used for deletes - use other tools instead */
1240 (*db)->hdb__del = NULL;
1241 (*db)->hdb_destroy = hdb_samba4_destroy;
1243 (*db)->hdb_audit = hdb_samba4_audit;
1244 (*db)->hdb_check_constrained_delegation = hdb_samba4_check_constrained_delegation;
1245 (*db)->hdb_check_rbcd = hdb_samba4_check_rbcd;
1246 (*db)->hdb_check_pkinit_ms_upn_match = hdb_samba4_check_pkinit_ms_upn_match;
1247 (*db)->hdb_check_client_matches_target_service = hdb_samba4_check_client_matches_target_service;
1249 return NT_STATUS_OK;
1252 NTSTATUS hdb_samba4_kpasswd_create_kdc(struct samba_kdc_base_context *base_ctx,
1253 krb5_context context, struct HDB **db)
1255 NTSTATUS nt_status;
1257 /* This is only used in other callers */
1258 struct samba_kdc_db_context *kdc_db_ctx = NULL;
1260 nt_status = hdb_samba4_create_kdc(base_ctx, context, db, &kdc_db_ctx);
1261 if (!NT_STATUS_IS_OK(nt_status)) {
1262 return nt_status;
1265 (*db)->hdb_fetch_kvno = hdb_samba4_kpasswd_fetch_kvno;
1266 (*db)->hdb_firstkey = hdb_samba4_nextkey_panic;
1267 (*db)->hdb_nextkey = hdb_samba4_nextkey_panic;
1269 return NT_STATUS_OK;