4 Copyright (c) 2010, Simo Sorce <idra@samba.org>
5 Copyright (c) 2014-2015 Guenther Deschner <gd@samba.org>
6 Copyright (c) 2014-2016 Andreas Schneider <asn@samba.org>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #define TEVENT_DEPRECATED 1
25 #include "param/param.h"
26 #include "dsdb/samdb/samdb.h"
27 #include "system/kerberos.h"
28 #include "lib/replace/system/filesys.h"
31 #include <kadm5/kadm_err.h>
33 #include "kdc/sdb_kdb.h"
34 #include "auth/kerberos/kerberos.h"
35 #include "auth/kerberos/pac_utils.h"
36 #include "kdc/samba_kdc.h"
37 #include "kdc/pac-glue.h"
38 #include "kdc/db-glue.h"
39 #include "auth/auth.h"
40 #include "kdc/kpasswd_glue.h"
41 #include "auth/auth_sam.h"
43 #include "mit_samba.h"
46 #define DBGC_CLASS DBGC_KERBEROS
48 void mit_samba_context_free(struct mit_samba_context
*ctx
)
50 /* free MIT's krb5_context */
52 krb5_free_context(ctx
->context
);
55 /* then free everything else */
60 * Implement a callback to log to the MIT KDC log facility
62 * http://web.mit.edu/kerberos/krb5-devel/doc/plugindev/general.html#logging-from-kdc-and-kadmind-plugin-modules
64 static void mit_samba_debug(void *private_ptr
, int msg_level
, const char *msg
)
72 com_err("mitkdc", is_error
, "%s", msg
);
75 krb5_error_code
mit_samba_context_init(struct mit_samba_context
**_ctx
)
78 struct mit_samba_context
*ctx
;
79 const char *s4_conf_file
;
81 struct samba_kdc_base_context base_ctx
= {};
83 ctx
= talloc_zero(NULL
, struct mit_samba_context
);
89 base_ctx
.ev_ctx
= tevent_context_init(ctx
);
90 if (!base_ctx
.ev_ctx
) {
94 tevent_loop_allow_nesting(base_ctx
.ev_ctx
);
95 base_ctx
.lp_ctx
= loadparm_init_global(false);
96 if (!base_ctx
.lp_ctx
) {
101 debug_set_callback(NULL
, mit_samba_debug
);
103 /* init s4 configuration */
104 s4_conf_file
= lpcfg_configfile(base_ctx
.lp_ctx
);
105 if (s4_conf_file
!= NULL
) {
106 char *p
= talloc_strdup(ctx
, s4_conf_file
);
111 lpcfg_load(base_ctx
.lp_ctx
, p
);
114 lpcfg_load_default(base_ctx
.lp_ctx
);
117 base_ctx
.current_nttime_ull
= talloc_zero(ctx
, unsigned long long);
118 if (base_ctx
.current_nttime_ull
== NULL
) {
123 status
= samba_kdc_setup_db_ctx(ctx
, &base_ctx
, &ctx
->db_ctx
);
124 if (!NT_STATUS_IS_OK(status
)) {
129 /* init MIT's krb_context and log facilities */
130 ret
= smb_krb5_init_context_basic(ctx
,
141 mit_samba_context_free(ctx
);
148 int mit_samba_generate_salt(krb5_data
*salt
)
155 salt
->data
= malloc(salt
->length
);
156 if (salt
->data
== NULL
) {
160 generate_random_buffer((uint8_t *)salt
->data
, salt
->length
);
165 int mit_samba_generate_random_password(krb5_data
*pwd
)
170 const unsigned length
= 24;
176 tmp_ctx
= talloc_named(NULL
,
178 "mit_samba_generate_random_password context");
179 if (tmp_ctx
== NULL
) {
183 password
= generate_random_password(tmp_ctx
, length
, length
);
184 if (password
== NULL
) {
185 talloc_free(tmp_ctx
);
189 data
= strdup(password
);
190 talloc_free(tmp_ctx
);
195 *pwd
= smb_krb5_make_data(data
, length
);
200 krb5_error_code
mit_samba_get_principal(struct mit_samba_context
*ctx
,
201 krb5_const_principal principal
,
203 krb5_db_entry
**_kentry
)
205 struct sdb_entry sentry
= {};
206 krb5_db_entry
*kentry
;
209 krb5_principal referral_principal
= NULL
;
213 time_ok
= gmsa_current_time(&now
);
218 *ctx
->db_ctx
->current_nttime_ull
= now
;
220 kentry
= calloc(1, sizeof(krb5_db_entry
));
221 if (kentry
== NULL
) {
226 * The MIT KDC code that wants the canonical name in all lookups, and
227 * takes care to canonicalize only when appropriate.
229 sflags
|= SDB_F_FORCE_CANON
;
231 if (kflags
& KRB5_KDB_FLAG_REFERRAL_OK
) {
232 sflags
|= SDB_F_CANON
;
235 if (kflags
& KRB5_KDB_FLAG_CLIENT
) {
236 sflags
|= SDB_F_GET_CLIENT
;
237 sflags
|= SDB_F_FOR_AS_REQ
;
239 int equal
= smb_krb5_principal_is_tgs(ctx
->context
, principal
);
245 sflags
|= SDB_F_GET_KRBTGT
;
247 sflags
|= SDB_F_GET_SERVER
;
248 sflags
|= SDB_F_FOR_TGS_REQ
;
252 /* always set this or the created_by data will not be populated by samba's
253 * backend and we will fail to parse the entry later */
254 sflags
|= SDB_F_ADMIN_DATA
;
257 fetch_referral_principal
:
258 ret
= samba_kdc_fetch(ctx
->context
, ctx
->db_ctx
,
259 principal
, sflags
, 0, &sentry
);
263 case SDB_ERR_NOENTRY
:
264 ret
= KRB5_KDB_NOENTRY
;
266 case SDB_ERR_WRONG_REALM
: {
267 char *dest_realm
= NULL
;
268 const char *our_realm
= lpcfg_realm(ctx
->db_ctx
->lp_ctx
);
270 if (sflags
& SDB_F_FOR_AS_REQ
) {
272 * If this is a request for a TGT, we are done. The KDC
273 * will return the correct error to the client.
279 if (referral_principal
!= NULL
) {
280 sdb_entry_free(&sentry
);
281 ret
= KRB5_KDB_NOENTRY
;
286 * We get a TGS request
288 * cifs/dc7.SAMBA2008R2.EXAMPLE.COM@ADDOM.SAMBA.EXAMPLE.COM
290 * to our DC for the realm
292 * ADDOM.SAMBA.EXAMPLE.COM
294 * We look up if we have an entry in the database and get an
295 * entry with the principal:
297 * cifs/dc7.SAMBA2008R2.EXAMPLE.COM@SAMBA2008R2.EXAMPLE.COM
299 * and the error: SDB_ERR_WRONG_REALM.
301 * In the case of a TGS-REQ we need to return a referral ticket
302 * for the next trust hop to the client. This ticket will have
303 * the following principal:
305 * krbtgt/SAMBA2008R2.EXAMPLE.COM@ADDOM.SAMBA.EXAMPLE.COM
307 * We just redo the lookup in the database with the referral
308 * principal and return success.
310 dest_realm
= smb_krb5_principal_get_realm(
311 ctx
, ctx
->context
, sentry
.principal
);
312 sdb_entry_free(&sentry
);
313 if (dest_realm
== NULL
) {
314 ret
= KRB5_KDB_NOENTRY
;
318 ret
= smb_krb5_make_principal(ctx
->context
,
324 TALLOC_FREE(dest_realm
);
329 principal
= referral_principal
;
330 goto fetch_referral_principal
;
332 case SDB_ERR_NOT_FOUND_HERE
:
333 /* FIXME: RODC support */
338 ret
= sdb_entry_to_krb5_db_entry(ctx
->context
, &sentry
, kentry
);
340 sdb_entry_free(&sentry
);
343 krb5_free_principal(ctx
->context
, referral_principal
);
344 referral_principal
= NULL
;
354 krb5_error_code
mit_samba_get_firstkey(struct mit_samba_context
*ctx
,
355 krb5_db_entry
**_kentry
)
357 struct sdb_entry sentry
= {};
358 krb5_db_entry
*kentry
;
364 time_ok
= gmsa_current_time(&now
);
369 *ctx
->db_ctx
->current_nttime_ull
= now
;
371 kentry
= malloc(sizeof(krb5_db_entry
));
372 if (kentry
== NULL
) {
376 ret
= samba_kdc_firstkey(ctx
->context
, ctx
->db_ctx
, SDB_F_ADMIN_DATA
, &sentry
);
380 case SDB_ERR_NOENTRY
:
382 return KRB5_KDB_NOENTRY
;
383 case SDB_ERR_NOT_FOUND_HERE
:
384 /* FIXME: RODC support */
390 ret
= sdb_entry_to_krb5_db_entry(ctx
->context
, &sentry
, kentry
);
392 sdb_entry_free(&sentry
);
402 krb5_error_code
mit_samba_get_nextkey(struct mit_samba_context
*ctx
,
403 krb5_db_entry
**_kentry
)
405 struct sdb_entry sentry
= {};
406 krb5_db_entry
*kentry
;
409 /* Not updating time, keep the same for the whole operation */
411 kentry
= malloc(sizeof(krb5_db_entry
));
412 if (kentry
== NULL
) {
416 ret
= samba_kdc_nextkey(ctx
->context
, ctx
->db_ctx
, SDB_F_ADMIN_DATA
, &sentry
);
420 case SDB_ERR_NOENTRY
:
422 return KRB5_KDB_NOENTRY
;
423 case SDB_ERR_NOT_FOUND_HERE
:
424 /* FIXME: RODC support */
430 ret
= sdb_entry_to_krb5_db_entry(ctx
->context
, &sentry
, kentry
);
432 sdb_entry_free(&sentry
);
442 krb5_error_code
mit_samba_get_pac(struct mit_samba_context
*smb_ctx
,
443 krb5_context context
,
445 krb5_db_entry
*client
,
446 krb5_db_entry
*server
,
447 krb5_keyblock
*replaced_reply_key
,
451 const struct auth_user_info_dc
*user_info_dc
= NULL
;
452 struct auth_user_info_dc
*user_info_dc_shallow_copy
= NULL
;
453 DATA_BLOB
*logon_info_blob
= NULL
;
454 DATA_BLOB
*upn_dns_info_blob
= NULL
;
455 DATA_BLOB
*cred_ndr
= NULL
;
456 DATA_BLOB
**cred_ndr_ptr
= NULL
;
457 DATA_BLOB cred_blob
= data_blob_null
;
458 DATA_BLOB
*pcred_blob
= NULL
;
459 DATA_BLOB
*pac_attrs_blob
= NULL
;
460 DATA_BLOB
*requester_sid_blob
= NULL
;
461 const DATA_BLOB
*client_claims_blob
= NULL
;
463 krb5_error_code code
;
464 struct samba_kdc_entry
*skdc_entry
;
465 struct samba_kdc_entry
*server_entry
= NULL
;
467 /* Only include resource groups in a service ticket. */
468 enum auth_group_inclusion group_inclusion
;
469 enum samba_asserted_identity asserted_identity
=
470 (flags
& KRB5_KDB_FLAG_PROTOCOL_TRANSITION
) ?
471 SAMBA_ASSERTED_IDENTITY_SERVICE
:
472 SAMBA_ASSERTED_IDENTITY_AUTHENTICATION_AUTHORITY
;
474 if (client
== NULL
) {
477 skdc_entry
= talloc_get_type_abort(client
->e_data
,
478 struct samba_kdc_entry
);
480 /* This sets the time into the DSDB opaque */
481 *smb_ctx
->db_ctx
->current_nttime_ull
= skdc_entry
->current_nttime
;
483 if (server
== NULL
) {
487 int result
= smb_krb5_principal_is_tgs(smb_ctx
->context
, server
->princ
);
494 server_entry
= talloc_get_type_abort(server
->e_data
,
495 struct samba_kdc_entry
);
497 /* Only include resource groups in a service ticket. */
499 group_inclusion
= AUTH_EXCLUDE_RESOURCE_GROUPS
;
500 } else if (server_entry
->supported_enctypes
& KERB_ENCTYPE_RESOURCE_SID_COMPRESSION_DISABLED
) {
501 group_inclusion
= AUTH_INCLUDE_RESOURCE_GROUPS
;
503 group_inclusion
= AUTH_INCLUDE_RESOURCE_GROUPS_COMPRESSED
;
506 tmp_ctx
= talloc_named(smb_ctx
,
508 "mit_samba_get_pac context");
509 if (tmp_ctx
== NULL
) {
513 /* Check if we have a PREAUTH key */
514 if (replaced_reply_key
!= NULL
) {
515 cred_ndr_ptr
= &cred_ndr
;
518 code
= samba_kdc_get_user_info_from_db(tmp_ctx
,
519 server_entry
->kdc_db_ctx
->samdb
,
524 talloc_free(tmp_ctx
);
528 /* Make a shallow copy of the user_info_dc structure. */
529 nt_status
= authsam_shallow_copy_user_info_dc(tmp_ctx
,
531 &user_info_dc_shallow_copy
);
534 if (!NT_STATUS_IS_OK(nt_status
)) {
535 DBG_ERR("Failed to allocate shallow copy of user_info_dc: %s\n",
536 nt_errstr(nt_status
));
537 talloc_free(tmp_ctx
);
538 return map_errno_from_nt_status(nt_status
);
542 nt_status
= samba_kdc_add_asserted_identity(asserted_identity
,
543 user_info_dc_shallow_copy
);
544 if (!NT_STATUS_IS_OK(nt_status
)) {
545 DBG_ERR("Failed to add asserted identity: %s\n",
546 nt_errstr(nt_status
));
547 talloc_free(tmp_ctx
);
551 nt_status
= samba_kdc_add_claims_valid(user_info_dc_shallow_copy
);
552 if (!NT_STATUS_IS_OK(nt_status
)) {
553 DBG_ERR("Failed to add Claims Valid: %s\n",
554 nt_errstr(nt_status
));
555 talloc_free(tmp_ctx
);
559 /* We no longer need to modify this, so assign to const variable */
560 user_info_dc
= user_info_dc_shallow_copy
;
562 nt_status
= samba_kdc_get_logon_info_blob(tmp_ctx
,
566 if (!NT_STATUS_IS_OK(nt_status
)) {
567 talloc_free(tmp_ctx
);
571 if (cred_ndr_ptr
!= NULL
) {
572 nt_status
= samba_kdc_get_cred_ndr_blob(tmp_ctx
,
575 if (!NT_STATUS_IS_OK(nt_status
)) {
576 talloc_free(tmp_ctx
);
581 nt_status
= samba_kdc_get_upn_info_blob(tmp_ctx
,
584 if (!NT_STATUS_IS_OK(nt_status
)) {
585 talloc_free(tmp_ctx
);
590 nt_status
= samba_kdc_get_pac_attrs_blob(tmp_ctx
,
591 PAC_ATTRIBUTE_FLAG_PAC_WAS_GIVEN_IMPLICITLY
,
593 if (!NT_STATUS_IS_OK(nt_status
)) {
594 talloc_free(tmp_ctx
);
598 nt_status
= samba_kdc_get_requester_sid_blob(tmp_ctx
,
600 &requester_sid_blob
);
601 if (!NT_STATUS_IS_OK(nt_status
)) {
602 talloc_free(tmp_ctx
);
607 nt_status
= samba_kdc_get_claims_blob(tmp_ctx
,
609 &client_claims_blob
);
610 if (!NT_STATUS_IS_OK(nt_status
)) {
611 talloc_free(tmp_ctx
);
615 if (replaced_reply_key
!= NULL
&& cred_ndr
!= NULL
) {
616 code
= samba_kdc_encrypt_pac_credentials(context
,
622 talloc_free(tmp_ctx
);
625 pcred_blob
= &cred_blob
;
628 code
= samba_make_krb5_pac(context
,
634 NULL
/* deleg_blob */,
636 NULL
/* device_info_blob */,
637 NULL
/* device_claims_blob */,
640 talloc_free(tmp_ctx
);
644 krb5_error_code
mit_samba_update_pac(struct mit_samba_context
*ctx
,
645 krb5_context context
,
647 krb5_db_entry
*client
,
648 krb5_db_entry
*server
,
649 krb5_db_entry
*krbtgt
,
653 TALLOC_CTX
*tmp_ctx
= NULL
;
654 krb5_error_code code
;
655 struct samba_kdc_entry
*client_skdc_entry
= NULL
;
656 struct samba_kdc_entry
*server_skdc_entry
= NULL
;
657 struct samba_kdc_entry
*krbtgt_skdc_entry
= NULL
;
658 struct samba_kdc_entry_pac client_pac_entry
= {};
659 bool is_in_db
= false;
660 bool is_trusted
= false;
663 /* Create a memory context early so code can use talloc_stackframe() */
664 tmp_ctx
= talloc_named(ctx
, 0, "mit_samba_update_pac context");
665 if (tmp_ctx
== NULL
) {
669 if (client
!= NULL
) {
671 talloc_get_type_abort(client
->e_data
,
672 struct samba_kdc_entry
);
675 if (krbtgt
== NULL
) {
680 talloc_get_type_abort(krbtgt
->e_data
,
681 struct samba_kdc_entry
);
683 /* This sets the time into the DSDB opaque */
684 *ctx
->db_ctx
->current_nttime_ull
= krbtgt_skdc_entry
->current_nttime
;
686 if (server
== NULL
) {
691 talloc_get_type_abort(server
->e_data
,
692 struct samba_kdc_entry
);
695 * If the krbtgt was generated by an RODC, and we are not that
696 * RODC, then we need to regenerate the PAC - we can't trust
697 * it, and confirm that the RODC was permitted to print this ticket
699 * Because of the samba_kdc_validate_pac_blob() step we can be
700 * sure that the record in 'client' or 'server' matches the SID in the
703 code
= samba_krbtgt_is_in_db(krbtgt_skdc_entry
,
710 if (kdc_flags
& KRB5_KDB_FLAG_PROTOCOL_TRANSITION
) {
711 flags
|= SAMBA_KDC_FLAG_PROTOCOL_TRANSITION
;
714 if (kdc_flags
& KRB5_KDB_FLAG_CONSTRAINED_DELEGATION
) {
715 flags
|= SAMBA_KDC_FLAG_CONSTRAINED_DELEGATION
;
718 client_pac_entry
= samba_kdc_entry_pac_from_trusted(old_pac
,
720 samba_kdc_entry_is_trust(krbtgt_skdc_entry
),
723 code
= samba_kdc_verify_pac(tmp_ctx
,
725 krbtgt_skdc_entry
->kdc_db_ctx
->samdb
,
733 code
= samba_kdc_update_pac(tmp_ctx
,
735 krbtgt_skdc_entry
->kdc_db_ctx
->samdb
,
736 krbtgt_skdc_entry
->kdc_db_ctx
->lp_ctx
,
741 NULL
/* delegated_proxy_principal */,
742 (struct samba_kdc_entry_pac
) {} /* delegated_proxy */,
743 (struct samba_kdc_entry_pac
) {} /* device */,
745 NULL
/* server_audit_info_out */,
746 NULL
/* status_out */);
748 if (code
== ENOATTR
) {
750 * We can't tell the KDC to not issue a PAC. It will
751 * just return the newly allocated empty PAC.
758 talloc_free(tmp_ctx
);
762 /* provide header, function is exported but there are no public headers */
764 krb5_error_code
encode_krb5_padata_sequence(krb5_pa_data
*const *rep
, krb5_data
**code
);
766 /* this function allocates 'data' using malloc.
767 * The caller is responsible for freeing it */
768 static void samba_kdc_build_edata_reply(NTSTATUS nt_status
, DATA_BLOB
*e_data
)
770 krb5_error_code ret
= 0;
771 krb5_pa_data pa
, *ppa
[2];
780 pa
.magic
= KV5M_PA_DATA
;
781 pa
.pa_type
= KRB5_PADATA_PW_SALT
/* KERB_ERR_TYPE_EXTENDED */;
783 pa
.contents
= malloc(pa
.length
);
788 SIVAL(pa
.contents
, 0, NT_STATUS_V(nt_status
));
789 SIVAL(pa
.contents
, 4, 0);
790 SIVAL(pa
.contents
, 8, 1);
795 ret
= encode_krb5_padata_sequence(ppa
, &d
);
801 e_data
->data
= (uint8_t *)d
->data
;
802 e_data
->length
= d
->length
;
804 /* free d, not d->data - gd */
810 krb5_error_code
mit_samba_check_client_access(struct mit_samba_context
*ctx
,
811 krb5_db_entry
*client
,
812 const char *client_name
,
813 krb5_db_entry
*server
,
814 const char *server_name
,
815 const char *netbios_name
,
816 bool password_change
,
819 struct samba_kdc_entry
*skdc_entry
;
822 skdc_entry
= talloc_get_type(client
->e_data
, struct samba_kdc_entry
);
824 /* This sets the time into the DSDB opaque */
825 *ctx
->db_ctx
->current_nttime_ull
= skdc_entry
->current_nttime
;
827 nt_status
= samba_kdc_check_client_access(skdc_entry
,
832 if (!NT_STATUS_IS_OK(nt_status
)) {
833 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_NO_MEMORY
)) {
837 samba_kdc_build_edata_reply(nt_status
, e_data
);
839 return samba_kdc_map_policy_err(nt_status
);
845 krb5_error_code
mit_samba_check_s4u2proxy(struct mit_samba_context
*ctx
,
846 const krb5_db_entry
*server
,
847 krb5_const_principal target_principal
)
849 struct samba_kdc_entry
*server_skdc_entry
=
850 talloc_get_type_abort(server
->e_data
, struct samba_kdc_entry
);
851 krb5_error_code code
;
853 /* This sets the time into the DSDB opaque */
854 *ctx
->db_ctx
->current_nttime_ull
= server_skdc_entry
->current_nttime
;
856 code
= samba_kdc_check_s4u2proxy(ctx
->context
,
864 krb5_error_code
mit_samba_check_allowed_to_delegate_from(
865 struct mit_samba_context
*ctx
,
866 krb5_const_principal client_principal
,
867 krb5_const_principal server_principal
,
869 const krb5_db_entry
*proxy
)
871 struct samba_kdc_entry
*proxy_skdc_entry
=
872 talloc_get_type_abort(proxy
->e_data
, struct samba_kdc_entry
);
873 struct auth_user_info_dc
*user_info_dc
= NULL
;
874 TALLOC_CTX
*mem_ctx
= NULL
;
875 krb5_error_code code
;
877 /* This sets the time into the DSDB opaque */
878 *ctx
->db_ctx
->current_nttime_ull
= proxy_skdc_entry
->current_nttime
;
880 mem_ctx
= talloc_new(NULL
);
881 if (mem_ctx
== NULL
) {
886 * FIXME: If ever we support RODCs, we must check that the PAC has not
887 * been issued by an RODC (other than ourselves) — otherwise the PAC
888 * cannot be trusted. Because the plugin interface does not give us the
889 * client entry, we cannot look up its groups in the database.
891 code
= kerberos_pac_to_user_info_dc(mem_ctx
,
895 AUTH_INCLUDE_RESOURCE_GROUPS
,
903 code
= samba_kdc_check_s4u2proxy_rbcd(ctx
->context
,
908 NULL
/* device_info_dc */,
909 (struct auth_claims
) {},
912 talloc_free(mem_ctx
);
916 static krb5_error_code
mit_samba_change_pwd_error(krb5_context context
,
918 enum samPwdChangeReason reject_reason
,
919 struct samr_DomInfo1
*dominfo
)
921 krb5_error_code code
= KADM5_PASS_Q_GENERIC
;
923 if (NT_STATUS_EQUAL(result
, NT_STATUS_NO_SUCH_USER
)) {
924 code
= KADM5_BAD_PRINCIPAL
;
925 krb5_set_error_message(context
,
927 "No such user when changing password");
929 if (NT_STATUS_EQUAL(result
, NT_STATUS_ACCESS_DENIED
)) {
930 code
= KADM5_PASS_Q_GENERIC
;
931 krb5_set_error_message(context
,
933 "Not permitted to change password");
935 if (NT_STATUS_EQUAL(result
, NT_STATUS_PASSWORD_RESTRICTION
) &&
937 switch (reject_reason
) {
938 case SAM_PWD_CHANGE_PASSWORD_TOO_SHORT
:
939 code
= KADM5_PASS_Q_TOOSHORT
;
940 krb5_set_error_message(context
,
942 "Password too short, password "
943 "must be at least %d characters "
945 dominfo
->min_password_length
);
947 case SAM_PWD_CHANGE_NOT_COMPLEX
:
948 code
= KADM5_PASS_Q_DICT
;
949 krb5_set_error_message(context
,
951 "Password does not meet "
952 "complexity requirements");
954 case SAM_PWD_CHANGE_PWD_IN_HISTORY
:
955 code
= KADM5_PASS_TOOSOON
;
956 krb5_set_error_message(context
,
958 "Password is already in password "
959 "history. New password must not "
960 "match any of your %d previous "
962 dominfo
->password_history_length
);
965 code
= KADM5_PASS_Q_GENERIC
;
966 krb5_set_error_message(context
,
968 "Password change rejected, "
969 "password changes may not be "
970 "permitted on this account, or "
971 "the minimum password age may "
972 "not have elapsed.");
980 krb5_error_code
mit_samba_kpasswd_change_password(struct mit_samba_context
*ctx
,
982 krb5_db_entry
*db_entry
)
985 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
988 enum samPwdChangeReason reject_reason
;
989 struct samr_DomInfo1
*dominfo
;
990 const char *error_string
= NULL
;
991 const struct auth_user_info_dc
*user_info_dc
= NULL
;
992 struct samba_kdc_entry
*p
=
993 talloc_get_type_abort(db_entry
->e_data
, struct samba_kdc_entry
);
994 krb5_error_code code
= 0;
996 /* This sets the time into the DSDB opaque */
997 *ctx
->db_ctx
->current_nttime_ull
= p
->current_nttime
;
999 #ifdef DEBUG_PASSWORD
1000 DBG_WARNING("mit_samba_kpasswd_change_password called with: %s\n", pwd
);
1003 tmp_ctx
= talloc_named(ctx
, 0, "mit_samba_kpasswd_change_password");
1004 if (tmp_ctx
== NULL
) {
1008 code
= samba_kdc_get_user_info_from_db(tmp_ctx
,
1014 const char *krb5err
= krb5_get_error_message(ctx
->context
, code
);
1015 DBG_WARNING("samba_kdc_get_user_info_from_db failed: %s\n",
1016 krb5err
!= NULL
? krb5err
: "<unknown>");
1017 krb5_free_error_message(ctx
->context
, krb5err
);
1022 status
= auth_generate_session_info(tmp_ctx
,
1023 ctx
->db_ctx
->lp_ctx
,
1026 0, /* session_info_flags */
1027 &ctx
->session_info
);
1029 if (!NT_STATUS_IS_OK(status
)) {
1030 DBG_WARNING("auth_generate_session_info failed: %s\n",
1036 /* password is expected as UTF16 */
1038 if (!convert_string_talloc(tmp_ctx
, CH_UTF8
, CH_UTF16
,
1040 &password
.data
, &password
.length
)) {
1041 DBG_WARNING("convert_string_talloc failed\n");
1046 status
= samdb_kpasswd_change_password(tmp_ctx
,
1047 ctx
->db_ctx
->lp_ctx
,
1048 ctx
->db_ctx
->ev_ctx
,
1055 if (!NT_STATUS_IS_OK(status
)) {
1056 DBG_WARNING("samdb_kpasswd_change_password failed: %s\n",
1058 code
= KADM5_PASS_Q_GENERIC
;
1059 krb5_set_error_message(ctx
->context
, code
, "%s", error_string
);
1063 if (!NT_STATUS_IS_OK(result
)) {
1064 code
= mit_samba_change_pwd_error(ctx
->context
,
1071 talloc_free(tmp_ctx
);
1076 void mit_samba_zero_bad_password_count(krb5_db_entry
*db_entry
)
1078 /* struct netr_SendToSamBase *send_to_sam = NULL; */
1079 struct samba_kdc_entry
*p
=
1080 talloc_get_type_abort(db_entry
->e_data
, struct samba_kdc_entry
);
1081 struct ldb_dn
*domain_dn
;
1083 /* This sets the time into the DSDB opaque */
1084 *p
->kdc_db_ctx
->current_nttime_ull
= p
->current_nttime
;
1086 domain_dn
= ldb_get_default_basedn(p
->kdc_db_ctx
->samdb
);
1088 authsam_logon_success_accounting(p
->kdc_db_ctx
->samdb
,
1093 /* TODO: RODC support */
1097 void mit_samba_update_bad_password_count(krb5_db_entry
*db_entry
)
1099 struct samba_kdc_entry
*p
=
1100 talloc_get_type_abort(db_entry
->e_data
, struct samba_kdc_entry
);
1102 /* This sets the time into the DSDB opaque */
1103 *p
->kdc_db_ctx
->current_nttime_ull
= p
->current_nttime
;
1105 authsam_update_bad_pwd_count(p
->kdc_db_ctx
->samdb
,
1107 ldb_get_default_basedn(p
->kdc_db_ctx
->samdb
));
1110 bool mit_samba_princ_needs_pac(krb5_db_entry
*db_entry
)
1112 struct samba_kdc_entry
*skdc_entry
=
1113 talloc_get_type_abort(db_entry
->e_data
, struct samba_kdc_entry
);
1115 /* This sets the time into the DSDB opaque */
1116 *skdc_entry
->kdc_db_ctx
->current_nttime_ull
= skdc_entry
->current_nttime
;
1118 return samba_princ_needs_pac(skdc_entry
);