2 Unix SMB/CIFS implementation.
4 Winbind daemon - pam auth functions
6 Copyright (C) Andrew Tridgell 2000
7 Copyright (C) Tim Potter 2001
8 Copyright (C) Andrew Bartlett 2001-2002
9 Copyright (C) Guenther Deschner 2005
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
28 #include "libsmb/namequery.h"
29 #include "../libcli/auth/libcli_auth.h"
30 #include "libcli/auth/pam_errors.h"
31 #include "../librpc/gen_ndr/ndr_samr_c.h"
32 #include "librpc/rpc/dcesrv_core.h"
33 #include "librpc/gen_ndr/ndr_winbind.h"
34 #include "rpc_client/cli_pipe.h"
35 #include "rpc_client/cli_samr.h"
36 #include "../librpc/gen_ndr/ndr_netlogon.h"
37 #include "rpc_client/cli_netlogon.h"
39 #include "../libcli/security/security.h"
41 #include "../librpc/gen_ndr/krb5pac.h"
42 #include "passdb/machine_sid.h"
44 #include "../lib/tsocket/tsocket.h"
45 #include "auth/kerberos/pac_utils.h"
46 #include "auth/gensec/gensec.h"
47 #include "librpc/crypto/gse_krb5.h"
48 #include "lib/afs/afs_funcs.h"
49 #include "libsmb/samlogon_cache.h"
50 #include "rpc_client/util_netlogon.h"
51 #include "param/param.h"
52 #include "messaging/messaging.h"
53 #include "lib/util/string_wrappers.h"
54 #include "lib/crypto/gnutls_helpers.h"
56 #include "lib/crypto/gnutls_helpers.h"
57 #include <gnutls/crypto.h>
58 #include "lib/global_contexts.h"
61 #define DBGC_CLASS DBGC_WINBIND
63 #define LOGON_KRB5_FAIL_CLOCK_SKEW 0x02000000
65 static NTSTATUS
append_info3_as_txt(TALLOC_CTX
*mem_ctx
,
66 struct winbindd_response
*resp
,
67 uint16_t validation_level
,
68 union netr_Validation
*validation
)
70 struct netr_SamInfo3
*info3
= NULL
;
73 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
74 TALLOC_CTX
*frame
= talloc_stackframe();
76 status
= map_validation_to_info3(frame
,
80 if (!NT_STATUS_IS_OK(status
)) {
84 resp
->data
.auth
.info3
.logon_time
=
85 nt_time_to_unix(info3
->base
.logon_time
);
86 resp
->data
.auth
.info3
.logoff_time
=
87 nt_time_to_unix(info3
->base
.logoff_time
);
88 resp
->data
.auth
.info3
.kickoff_time
=
89 nt_time_to_unix(info3
->base
.kickoff_time
);
90 resp
->data
.auth
.info3
.pass_last_set_time
=
91 nt_time_to_unix(info3
->base
.last_password_change
);
92 resp
->data
.auth
.info3
.pass_can_change_time
=
93 nt_time_to_unix(info3
->base
.allow_password_change
);
94 resp
->data
.auth
.info3
.pass_must_change_time
=
95 nt_time_to_unix(info3
->base
.force_password_change
);
97 resp
->data
.auth
.info3
.logon_count
= info3
->base
.logon_count
;
98 resp
->data
.auth
.info3
.bad_pw_count
= info3
->base
.bad_password_count
;
100 resp
->data
.auth
.info3
.user_rid
= info3
->base
.rid
;
101 resp
->data
.auth
.info3
.group_rid
= info3
->base
.primary_gid
;
102 sid_to_fstring(resp
->data
.auth
.info3
.dom_sid
, info3
->base
.domain_sid
);
104 resp
->data
.auth
.info3
.num_groups
= info3
->base
.groups
.count
;
105 resp
->data
.auth
.info3
.user_flgs
= info3
->base
.user_flags
;
107 resp
->data
.auth
.info3
.acct_flags
= info3
->base
.acct_flags
;
108 resp
->data
.auth
.info3
.num_other_sids
= info3
->sidcount
;
110 fstrcpy(resp
->data
.auth
.info3
.user_name
,
111 info3
->base
.account_name
.string
);
112 fstrcpy(resp
->data
.auth
.info3
.full_name
,
113 info3
->base
.full_name
.string
);
114 fstrcpy(resp
->data
.auth
.info3
.logon_script
,
115 info3
->base
.logon_script
.string
);
116 fstrcpy(resp
->data
.auth
.info3
.profile_path
,
117 info3
->base
.profile_path
.string
);
118 fstrcpy(resp
->data
.auth
.info3
.home_dir
,
119 info3
->base
.home_directory
.string
);
120 fstrcpy(resp
->data
.auth
.info3
.dir_drive
,
121 info3
->base
.home_drive
.string
);
123 fstrcpy(resp
->data
.auth
.info3
.logon_srv
,
124 info3
->base
.logon_server
.string
);
125 fstrcpy(resp
->data
.auth
.info3
.logon_dom
,
126 info3
->base
.logon_domain
.string
);
128 resp
->data
.auth
.validation_level
= validation_level
;
129 if (validation_level
== 6) {
130 fstrcpy(resp
->data
.auth
.info6
.dns_domainname
,
131 validation
->sam6
->dns_domainname
.string
);
132 fstrcpy(resp
->data
.auth
.info6
.principal_name
,
133 validation
->sam6
->principal_name
.string
);
136 ex
= talloc_strdup(frame
, "");
138 status
= NT_STATUS_NO_MEMORY
;
142 for (i
=0; i
< info3
->base
.groups
.count
; i
++) {
143 ex
= talloc_asprintf_append_buffer(ex
, "0x%08X:0x%08X\n",
144 info3
->base
.groups
.rids
[i
].rid
,
145 info3
->base
.groups
.rids
[i
].attributes
);
147 status
= NT_STATUS_NO_MEMORY
;
152 for (i
=0; i
< info3
->sidcount
; i
++) {
153 struct dom_sid_buf sidbuf
;
155 ex
= talloc_asprintf_append_buffer(
158 dom_sid_str_buf(info3
->sids
[i
].sid
, &sidbuf
),
159 info3
->sids
[i
].attributes
);
161 status
= NT_STATUS_NO_MEMORY
;
166 resp
->length
+= talloc_get_size(ex
);
167 resp
->extra_data
.data
= talloc_move(mem_ctx
, &ex
);
169 status
= NT_STATUS_OK
;
175 static NTSTATUS
append_info3_as_ndr(TALLOC_CTX
*mem_ctx
,
176 struct winbindd_response
*resp
,
177 struct netr_SamInfo3
*info3
)
180 enum ndr_err_code ndr_err
;
182 ndr_err
= ndr_push_struct_blob(&blob
, mem_ctx
, info3
,
183 (ndr_push_flags_fn_t
)ndr_push_netr_SamInfo3
);
184 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
185 DEBUG(0,("append_info3_as_ndr: failed to append\n"));
186 return ndr_map_error2ntstatus(ndr_err
);
189 resp
->extra_data
.data
= blob
.data
;
190 resp
->length
+= blob
.length
;
195 static NTSTATUS
append_unix_username(uint16_t validation_level
,
196 union netr_Validation
*validation
,
197 const char *name_domain
,
198 const char *name_user
,
200 char **_unix_username
)
202 TALLOC_CTX
*tmp_ctx
= NULL
;
203 const char *nt_username
= NULL
;
204 const char *nt_domain
= NULL
;
205 char *unix_username
= NULL
;
206 struct netr_SamBaseInfo
*base_info
= NULL
;
209 tmp_ctx
= talloc_new(mem_ctx
);
210 if (tmp_ctx
== NULL
) {
211 return NT_STATUS_NO_MEMORY
;
214 /* We've been asked to return the unix username, per
215 'winbind use default domain' settings and the like */
217 switch (validation_level
) {
219 base_info
= &validation
->sam3
->base
;
222 base_info
= &validation
->sam6
->base
;
225 DBG_ERR("Invalid validation level %d\n", validation_level
);
226 status
= NT_STATUS_INTERNAL_ERROR
;
230 nt_domain
= talloc_strdup(tmp_ctx
, base_info
->logon_domain
.string
);
232 /* If the server didn't give us one, just use the one
234 nt_domain
= name_domain
;
237 nt_username
= talloc_strdup(tmp_ctx
, base_info
->account_name
.string
);
239 /* If the server didn't give us one, just use the one
241 nt_username
= name_user
;
244 unix_username
= fill_domain_username_talloc(tmp_ctx
,
248 if (unix_username
== NULL
) {
249 status
= NT_STATUS_NO_MEMORY
;
253 DBG_INFO("Setting unix username to [%s]\n", unix_username
);
255 *_unix_username
= talloc_move(mem_ctx
, &unix_username
);
257 status
= NT_STATUS_OK
;
259 TALLOC_FREE(tmp_ctx
);
264 static NTSTATUS
append_afs_token(uint16_t validation_level
,
265 union netr_Validation
*validation
,
266 const char *name_domain
,
267 const char *name_user
,
271 TALLOC_CTX
*tmp_ctx
= NULL
;
272 char *afsname
= NULL
;
275 struct netr_SamBaseInfo
*base_info
= NULL
;
278 tmp_ctx
= talloc_new(mem_ctx
);
279 if (tmp_ctx
== NULL
) {
280 return NT_STATUS_NO_MEMORY
;
283 switch (validation_level
) {
285 base_info
= &validation
->sam3
->base
;
288 base_info
= &validation
->sam6
->base
;
291 DBG_ERR("Invalid validation level %d\n", validation_level
);
292 status
= NT_STATUS_INTERNAL_ERROR
;
296 afsname
= talloc_strdup(tmp_ctx
, lp_afs_username_map());
297 if (afsname
== NULL
) {
298 status
= NT_STATUS_NO_MEMORY
;
302 afsname
= talloc_string_sub(tmp_ctx
,
303 lp_afs_username_map(),
305 afsname
= talloc_string_sub(tmp_ctx
, afsname
,
307 afsname
= talloc_string_sub(tmp_ctx
, afsname
,
311 struct dom_sid user_sid
;
312 struct dom_sid_buf sidstr
;
314 sid_compose(&user_sid
, base_info
->domain_sid
, base_info
->rid
);
315 afsname
= talloc_string_sub(
319 dom_sid_str_buf(&user_sid
, &sidstr
));
322 if (afsname
== NULL
) {
323 status
= NT_STATUS_NO_MEMORY
;
327 if (!strlower_m(afsname
)) {
328 status
= NT_STATUS_INVALID_PARAMETER
;
332 DEBUG(10, ("Generating token for user %s\n", afsname
));
334 cell
= strchr(afsname
, '@');
337 status
= NT_STATUS_NO_MEMORY
;
344 token
= afs_createtoken_str(afsname
, cell
);
346 status
= NT_STATUS_OK
;
350 talloc_steal(mem_ctx
, token
);
351 *_blob
= data_blob_string_const_null(token
);
353 status
= NT_STATUS_OK
;
355 TALLOC_FREE(tmp_ctx
);
360 NTSTATUS
extra_data_to_sid_array(const char *group_sid
,
362 struct wbint_SidArray
**_sid_array
)
364 TALLOC_CTX
*tmp_ctx
= NULL
;
365 struct wbint_SidArray
*sid_array
= NULL
;
366 struct dom_sid
*require_membership_of_sid
= NULL
;
367 uint32_t num_require_membership_of_sid
= 0;
368 char *req_sid
= NULL
;
369 const char *p
= NULL
;
372 if (_sid_array
== NULL
) {
373 return NT_STATUS_INVALID_PARAMETER
;
378 tmp_ctx
= talloc_new(mem_ctx
);
379 if (tmp_ctx
== NULL
) {
380 return NT_STATUS_NO_MEMORY
;
383 sid_array
= talloc_zero(tmp_ctx
, struct wbint_SidArray
);
384 if (sid_array
== NULL
) {
385 status
= NT_STATUS_NO_MEMORY
;
389 if (!group_sid
|| !group_sid
[0]) {
390 /* NO sid supplied, all users may access */
391 status
= NT_STATUS_OK
;
393 * Always return an allocated wbint_SidArray,
394 * even if the array is empty.
399 num_require_membership_of_sid
= 0;
400 require_membership_of_sid
= NULL
;
403 while (next_token_talloc(tmp_ctx
, &p
, &req_sid
, ",")) {
406 if (!string_to_sid(&sid
, req_sid
)) {
407 DBG_ERR("check_info3_in_group: could not parse %s "
408 "as a SID!\n", req_sid
);
409 status
= NT_STATUS_INVALID_PARAMETER
;
413 status
= add_sid_to_array(tmp_ctx
, &sid
,
414 &require_membership_of_sid
,
415 &num_require_membership_of_sid
);
416 if (!NT_STATUS_IS_OK(status
)) {
417 DBG_ERR("add_sid_to_array failed\n");
422 sid_array
->num_sids
= num_require_membership_of_sid
;
423 sid_array
->sids
= talloc_move(sid_array
, &require_membership_of_sid
);
425 status
= NT_STATUS_OK
;
427 *_sid_array
= talloc_move(mem_ctx
, &sid_array
);
430 TALLOC_FREE(tmp_ctx
);
435 static NTSTATUS
check_info3_in_group(struct netr_SamInfo3
*info3
,
436 struct wbint_SidArray
*sid_array
)
438 * Check whether a user belongs to a group or list of groups.
440 * @param mem_ctx talloc memory context.
441 * @param info3 user information, including group membership info.
442 * @param group_sid One or more groups , separated by commas.
444 * @return NT_STATUS_OK on success,
445 * NT_STATUS_LOGON_FAILURE if the user does not belong,
446 * or other NT_STATUS_IS_ERR(status) for other kinds of failure.
450 struct security_token
*token
;
453 /* Parse the 'required group' SID */
455 if (sid_array
== NULL
|| sid_array
->num_sids
== 0) {
456 /* NO sid supplied, all users may access */
461 * This is a limited-use security_token for the purpose of
462 * checking the SID list below, so no claims need to be added
463 * and se_access_check() will never run.
465 token
= security_token_initialise(talloc_tos(),
466 CLAIMS_EVALUATION_INVALID_STATE
);
468 DEBUG(0, ("talloc failed\n"));
469 return NT_STATUS_NO_MEMORY
;
472 status
= sid_array_from_info3(token
, info3
,
476 if (!NT_STATUS_IS_OK(status
)) {
480 if (!NT_STATUS_IS_OK(status
= add_aliases(get_global_sam_sid(),
482 || !NT_STATUS_IS_OK(status
= add_aliases(&global_sid_Builtin
,
484 DEBUG(3, ("could not add aliases: %s\n",
489 security_token_debug(DBGC_CLASS
, 10, token
);
491 for (i
=0; i
<sid_array
->num_sids
; i
++) {
492 struct dom_sid_buf buf
;
493 DEBUG(10, ("Checking SID %s\n",
494 dom_sid_str_buf(&sid_array
->sids
[i
],
496 if (nt_token_check_sid(&sid_array
->sids
[i
],
498 DEBUG(10, ("Access ok\n"));
503 /* Do not distinguish this error from a wrong username/pw */
505 return NT_STATUS_LOGON_FAILURE
;
508 struct winbindd_domain
*find_auth_domain(uint8_t flags
,
509 const char *domain_name
)
511 struct winbindd_domain
*domain
;
514 domain
= find_domain_from_name_noinit(domain_name
);
515 if (domain
== NULL
) {
516 DEBUG(3, ("Authentication for domain [%s] refused "
517 "as it is not a trusted domain\n",
522 if (domain
->secure_channel_type
!= SEC_CHAN_NULL
) {
526 return domain
->routing_domain
;
529 if (strequal(domain_name
, get_global_sam_name())) {
530 return find_domain_from_name_noinit(domain_name
);
533 if (lp_winbind_use_krb5_enterprise_principals()) {
535 * If we use enterprise principals
536 * we always go through our primary domain
537 * and follow the WRONG_REALM replies.
539 flags
&= ~WBFLAG_PAM_CONTACT_TRUSTDOM
;
542 /* we can auth against trusted domains */
543 if (flags
& WBFLAG_PAM_CONTACT_TRUSTDOM
) {
544 domain
= find_domain_from_name_noinit(domain_name
);
545 if (domain
== NULL
) {
546 DEBUG(3, ("Authentication for domain [%s] skipped "
547 "as it is not a trusted domain\n",
554 return find_our_domain();
557 static NTSTATUS
get_password_policy(struct winbindd_domain
*domain
,
559 struct samr_DomInfo1
**_policy
)
562 struct samr_DomInfo1
*policy
= NULL
;
564 if ( !winbindd_can_contact_domain( domain
) ) {
565 DBG_INFO("No inbound trust to contact domain %s\n",
567 return NT_STATUS_NOT_SUPPORTED
;
570 policy
= talloc_zero(mem_ctx
, struct samr_DomInfo1
);
571 if (policy
== NULL
) {
572 return NT_STATUS_NO_MEMORY
;
575 status
= wb_cache_password_policy(domain
, mem_ctx
, policy
);
576 if (NT_STATUS_IS_ERR(status
)) {
581 *_policy
= talloc_move(mem_ctx
, &policy
);
586 static NTSTATUS
get_max_bad_attempts_from_lockout_policy(struct winbindd_domain
*domain
,
588 uint16_t *lockout_threshold
)
590 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
591 struct samr_DomInfo12 lockout_policy
;
593 *lockout_threshold
= 0;
595 status
= wb_cache_lockout_policy(domain
, mem_ctx
, &lockout_policy
);
596 if (NT_STATUS_IS_ERR(status
)) {
600 *lockout_threshold
= lockout_policy
.lockout_threshold
;
605 static NTSTATUS
get_pwd_properties(struct winbindd_domain
*domain
,
607 uint32_t *password_properties
)
609 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
610 struct samr_DomInfo1 password_policy
;
612 *password_properties
= 0;
614 status
= wb_cache_password_policy(domain
, mem_ctx
, &password_policy
);
615 if (NT_STATUS_IS_ERR(status
)) {
619 *password_properties
= password_policy
.password_properties
;
626 static bool generate_krb5_ccache(TALLOC_CTX
*mem_ctx
,
629 const char **user_ccache_file
)
631 /* accept FILE and WRFILE as krb5_cc_type from the client and then
632 * build the full ccname string based on the user's uid here -
635 const char *gen_cc
= NULL
;
638 if (strequal(type
, "FILE")) {
639 gen_cc
= talloc_asprintf(
640 mem_ctx
, "FILE:/tmp/krb5cc_%d", uid
);
641 if (gen_cc
== NULL
) {
645 if (strequal(type
, "WRFILE")) {
646 gen_cc
= talloc_asprintf(
647 mem_ctx
, "WRFILE:/tmp/krb5cc_%d", uid
);
648 if (gen_cc
== NULL
) {
652 if (strequal(type
, "KEYRING")) {
653 gen_cc
= talloc_asprintf(
654 mem_ctx
, "KEYRING:persistent:%d", uid
);
655 if (gen_cc
== NULL
) {
659 if (strequal(type
, "KCM")) {
660 gen_cc
= talloc_asprintf(mem_ctx
,
663 if (gen_cc
== NULL
) {
668 if (strnequal(type
, "FILE:/", 6) ||
669 strnequal(type
, "WRFILE:/", 8) ||
670 strnequal(type
, "DIR:/", 5)) {
672 /* we allow only one "%u" substitution */
676 p
= strchr(type
, '%');
681 if (p
!= NULL
&& *p
== 'u' && strchr(p
, '%') == NULL
) {
682 char uid_str
[sizeof("18446744073709551615")];
684 snprintf(uid_str
, sizeof(uid_str
), "%u", uid
);
686 gen_cc
= talloc_string_sub2(mem_ctx
,
690 /* remove_unsafe_characters */
694 /* allow_trailing_dollar */
696 if (gen_cc
== NULL
) {
704 *user_ccache_file
= gen_cc
;
706 DBG_DEBUG("using ccache: %s\n", gen_cc
!= NULL
? gen_cc
: "(internal)");
713 uid_t
get_uid_from_request(struct winbindd_request
*request
)
717 uid
= request
->data
.auth
.uid
;
719 if (uid
== (uid_t
)-1) {
720 DEBUG(1,("invalid uid: '%u'\n", (unsigned int)uid
));
726 /**********************************************************************
727 Authenticate a user with a clear text password using Kerberos and fill up
729 **********************************************************************/
731 static NTSTATUS
winbindd_raw_kerberos_login(TALLOC_CTX
*mem_ctx
,
732 struct winbindd_domain
*domain
,
735 const char *krb5_cc_type
,
737 struct netr_SamInfo6
**info6
,
738 const char **_krb5ccname
)
741 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
742 const char *cc
= NULL
;
743 const char *principal_s
= NULL
;
745 char *name_namespace
= NULL
;
746 char *name_domain
= NULL
;
747 char *name_user
= NULL
;
748 time_t ticket_lifetime
= 0;
749 time_t renewal_until
= 0;
750 const char *user_ccache_file
;
751 struct PAC_LOGON_INFO
*logon_info
= NULL
;
752 struct PAC_UPN_DNS_INFO
*upn_dns_info
= NULL
;
753 struct PAC_DATA
*pac_data
= NULL
;
754 struct PAC_DATA_CTR
*pac_data_ctr
= NULL
;
755 const char *local_service
;
757 struct netr_SamInfo6
*info6_copy
= NULL
;
758 char *canon_principal
= NULL
;
759 char *canon_realm
= NULL
;
764 if (domain
->alt_name
== NULL
) {
765 return NT_STATUS_INVALID_PARAMETER
;
768 if (_krb5ccname
!= NULL
) {
773 * prepare a krb5_cc_cache string for the user */
776 DEBUG(0,("no valid uid\n"));
779 ok
= generate_krb5_ccache(mem_ctx
,
784 return NT_STATUS_NO_MEMORY
;
786 cc
= user_ccache_file
;
789 * get kerberos properties */
793 * do kerberos auth and setup ccache as the user */
795 ok
= parse_domain_user(mem_ctx
,
801 return NT_STATUS_INVALID_PARAMETER
;
804 realm
= talloc_strdup(mem_ctx
, domain
->alt_name
);
806 return NT_STATUS_NO_MEMORY
;
809 if (!strupper_m(realm
)) {
810 return NT_STATUS_INVALID_PARAMETER
;
813 if (lp_winbind_use_krb5_enterprise_principals() &&
814 name_namespace
[0] != '\0')
816 principal_s
= talloc_asprintf(mem_ctx
,
822 principal_s
= talloc_asprintf(mem_ctx
,
827 if (principal_s
== NULL
) {
828 return NT_STATUS_NO_MEMORY
;
831 local_service
= talloc_asprintf(mem_ctx
, "%s$@%s",
832 lp_netbios_name(), lp_realm());
833 if (local_service
== NULL
) {
834 return NT_STATUS_NO_MEMORY
;
838 /* if this is a user ccache, we need to act as the user to let the krb5
839 * library handle the chown, etc. */
841 /************************ ENTERING NON-ROOT **********************/
843 if (user_ccache_file
!= NULL
) {
844 set_effective_uid(uid
);
845 DEBUG(10,("winbindd_raw_kerberos_login: uid is %d\n", uid
));
849 * Note cc can be NULL, it means
850 * kerberos_return_pac() will use
851 * a temporary krb5 ccache internally.
853 result
= kerberos_return_pac(mem_ctx
,
862 WINBINDD_PAM_AUTH_KRB5_RENEW_TIME
,
868 if (user_ccache_file
!= NULL
) {
869 gain_root_privilege();
872 /************************ RETURNED TO ROOT **********************/
874 if (!NT_STATUS_IS_OK(result
)) {
878 if (pac_data_ctr
== NULL
) {
882 pac_data
= pac_data_ctr
->pac_data
;
883 if (pac_data
== NULL
) {
887 for (i
=0; i
< pac_data
->num_buffers
; i
++) {
889 if (pac_data
->buffers
[i
].type
== PAC_TYPE_LOGON_INFO
) {
890 logon_info
= pac_data
->buffers
[i
].info
->logon_info
.info
;
894 if (pac_data
->buffers
[i
].type
== PAC_TYPE_UPN_DNS_INFO
) {
895 upn_dns_info
= &pac_data
->buffers
[i
].info
->upn_dns_info
;
900 if (logon_info
== NULL
) {
901 DBG_DEBUG("Missing logon_info in ticket of %s\n", principal_s
);
902 return NT_STATUS_INVALID_PARAMETER
;
905 DBG_DEBUG("winbindd validated ticket of %s\n", principal_s
);
907 result
= create_info6_from_pac(mem_ctx
, logon_info
,
908 upn_dns_info
, &info6_copy
);
909 if (!NT_STATUS_IS_OK(result
)) {
913 /* if we had a user's ccache then return that string for the pam
916 if (user_ccache_file
!= NULL
) {
918 if (_krb5ccname
!= NULL
) {
919 *_krb5ccname
= talloc_steal(mem_ctx
, user_ccache_file
);
922 result
= add_ccache_to_list(principal_s
,
935 if (!NT_STATUS_IS_OK(result
)) {
936 DBG_DEBUG("failed to add ccache to list: %s\n",
946 * Do not delete an existing valid credential cache, if the user
947 * e.g. enters a wrong password
949 if ((strequal(krb5_cc_type
, "FILE") || strequal(krb5_cc_type
, "WRFILE"))
950 && user_ccache_file
!= NULL
) {
954 /* we could have created a new credential cache with a valid tgt in it
955 * but we weren't able to get or verify the service ticket for this
956 * local host and therefore didn't get the PAC, we need to remove that
957 * cache entirely now */
959 if (!NT_STATUS_IS_OK(remove_ccache(user
))) {
960 DBG_NOTICE("could not remove ccache for user %s\n", user
);
965 return NT_STATUS_NOT_SUPPORTED
;
966 #endif /* HAVE_KRB5 */
969 /****************************************************************
970 ****************************************************************/
972 bool check_request_flags(uint32_t flags
)
974 uint32_t flags_edata
= WBFLAG_PAM_AFS_TOKEN
|
975 WBFLAG_PAM_INFO3_TEXT
|
976 WBFLAG_PAM_INFO3_NDR
;
978 if ( ( (flags
& flags_edata
) == WBFLAG_PAM_AFS_TOKEN
) ||
979 ( (flags
& flags_edata
) == WBFLAG_PAM_INFO3_NDR
) ||
980 ( (flags
& flags_edata
) == WBFLAG_PAM_INFO3_TEXT
)||
981 !(flags
& flags_edata
) ) {
985 DBG_WARNING("invalid request flags[0x%08X]\n", flags
);
990 /****************************************************************
991 ****************************************************************/
993 NTSTATUS
append_auth_data(TALLOC_CTX
*mem_ctx
,
994 struct winbindd_response
*resp
,
995 uint32_t request_flags
,
996 uint16_t validation_level
,
997 union netr_Validation
*validation
,
998 const char *name_domain
,
999 const char *name_user
)
1001 struct netr_SamInfo3
*info3
= NULL
;
1002 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
1004 result
= map_validation_to_info3(talloc_tos(),
1008 if (!NT_STATUS_IS_OK(result
)) {
1012 if (request_flags
& WBFLAG_PAM_USER_SESSION_KEY
) {
1013 memcpy(resp
->data
.auth
.user_session_key
,
1014 info3
->base
.key
.key
,
1015 sizeof(resp
->data
.auth
.user_session_key
)
1019 if (request_flags
& WBFLAG_PAM_LMKEY
) {
1020 memcpy(resp
->data
.auth
.first_8_lm_hash
,
1021 info3
->base
.LMSessKey
.key
,
1022 sizeof(resp
->data
.auth
.first_8_lm_hash
)
1026 if (request_flags
& WBFLAG_PAM_UNIX_NAME
) {
1027 char *unix_username
= NULL
;
1028 result
= append_unix_username(validation_level
,
1034 if (!NT_STATUS_IS_OK(result
)) {
1035 DEBUG(10,("Failed to append Unix Username: %s\n",
1036 nt_errstr(result
)));
1039 fstrcpy(resp
->data
.auth
.unix_username
, unix_username
);
1040 TALLOC_FREE(unix_username
);
1043 /* currently, anything from here on potentially overwrites extra_data. */
1045 if (request_flags
& WBFLAG_PAM_INFO3_NDR
) {
1046 result
= append_info3_as_ndr(mem_ctx
, resp
, info3
);
1047 if (!NT_STATUS_IS_OK(result
)) {
1048 DEBUG(10,("Failed to append INFO3 (NDR): %s\n",
1049 nt_errstr(result
)));
1054 if (request_flags
& WBFLAG_PAM_INFO3_TEXT
) {
1055 result
= append_info3_as_txt(mem_ctx
, resp
,
1058 if (!NT_STATUS_IS_OK(result
)) {
1059 DEBUG(10,("Failed to append INFO3 (TXT): %s\n",
1060 nt_errstr(result
)));
1065 if (request_flags
& WBFLAG_PAM_AFS_TOKEN
) {
1066 DATA_BLOB blob
= data_blob_null
;
1067 result
= append_afs_token(validation_level
,
1073 if (!NT_STATUS_IS_OK(result
)) {
1074 DEBUG(10,("Failed to append AFS token: %s\n",
1075 nt_errstr(result
)));
1078 resp
->extra_data
.data
= blob
.data
;
1079 resp
->length
+= blob
.length
;
1082 result
= NT_STATUS_OK
;
1088 static NTSTATUS
winbindd_dual_pam_auth_cached(struct winbindd_domain
*domain
,
1092 const char *krb5_cc_type
,
1094 TALLOC_CTX
*mem_ctx
,
1095 uint16_t *_validation_level
,
1096 union netr_Validation
**_validation
,
1097 const char **_krb5ccname
)
1099 TALLOC_CTX
*tmp_ctx
= NULL
;
1100 NTSTATUS result
= NT_STATUS_LOGON_FAILURE
;
1101 uint16_t max_allowed_bad_attempts
;
1102 char *name_namespace
= NULL
;
1103 char *name_domain
= NULL
;
1104 char *name_user
= NULL
;
1106 enum lsa_SidType type
;
1107 uchar new_nt_pass
[NT_HASH_LEN
];
1108 const uint8_t *cached_nt_pass
;
1109 const uint8_t *cached_salt
;
1110 struct netr_SamInfo3
*my_info3
;
1111 time_t kickoff_time
, must_change_time
;
1112 bool password_good
= false;
1115 struct winbindd_tdc_domain
*tdc_domain
= NULL
;
1118 if (_validation
== NULL
) {
1119 return NT_STATUS_INVALID_PARAMETER
;
1121 *_validation
= NULL
;
1123 if (_krb5ccname
!= NULL
) {
1124 *_krb5ccname
= NULL
;
1127 DEBUG(10,("winbindd_dual_pam_auth_cached\n"));
1129 tmp_ctx
= talloc_new(mem_ctx
);
1130 if (tmp_ctx
== NULL
) {
1131 return NT_STATUS_NO_MEMORY
;
1134 /* Parse domain and username */
1136 ok
= parse_domain_user(tmp_ctx
,
1142 DBG_DEBUG("parse_domain_user failed\n");
1143 result
= NT_STATUS_NO_SUCH_USER
;
1147 if (!lookup_cached_name(name_namespace
,
1152 DEBUG(10,("winbindd_dual_pam_auth_cached: no such user in the cache\n"));
1153 result
= NT_STATUS_NO_SUCH_USER
;
1157 if (type
!= SID_NAME_USER
) {
1158 DEBUG(10,("winbindd_dual_pam_auth_cached: not a user (%s)\n", sid_type_lookup(type
)));
1159 result
= NT_STATUS_LOGON_FAILURE
;
1163 result
= winbindd_get_creds(domain
,
1169 if (!NT_STATUS_IS_OK(result
)) {
1170 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get creds: %s\n", nt_errstr(result
)));
1174 E_md4hash(pass
, new_nt_pass
);
1176 dump_data_pw("new_nt_pass", new_nt_pass
, NT_HASH_LEN
);
1177 dump_data_pw("cached_nt_pass", cached_nt_pass
, NT_HASH_LEN
);
1179 dump_data_pw("cached_salt", cached_salt
, NT_HASH_LEN
);
1183 /* In this case we didn't store the nt_hash itself,
1184 but the MD5 combination of salt + nt_hash. */
1185 uchar salted_hash
[NT_HASH_LEN
];
1186 gnutls_hash_hd_t hash_hnd
= NULL
;
1189 rc
= gnutls_hash_init(&hash_hnd
, GNUTLS_DIG_MD5
);
1191 result
= gnutls_error_to_ntstatus(
1192 rc
, NT_STATUS_HASH_NOT_SUPPORTED
);
1196 rc
= gnutls_hash(hash_hnd
, cached_salt
, 16);
1198 gnutls_hash_deinit(hash_hnd
, NULL
);
1199 result
= gnutls_error_to_ntstatus(
1200 rc
, NT_STATUS_HASH_NOT_SUPPORTED
);
1203 rc
= gnutls_hash(hash_hnd
, new_nt_pass
, 16);
1205 gnutls_hash_deinit(hash_hnd
, NULL
);
1206 result
= gnutls_error_to_ntstatus(
1207 rc
, NT_STATUS_HASH_NOT_SUPPORTED
);
1210 gnutls_hash_deinit(hash_hnd
, salted_hash
);
1212 password_good
= mem_equal_const_time(cached_nt_pass
, salted_hash
,
1215 /* Old cached cred - direct store of nt_hash (bad bad bad !). */
1216 password_good
= mem_equal_const_time(cached_nt_pass
, new_nt_pass
,
1220 if (password_good
) {
1222 /* User *DOES* know the password, update logon_time and reset
1225 my_info3
->base
.user_flags
|= NETLOGON_CACHED_ACCOUNT
;
1227 if (my_info3
->base
.acct_flags
& ACB_AUTOLOCK
) {
1228 result
= NT_STATUS_ACCOUNT_LOCKED_OUT
;
1232 if (my_info3
->base
.acct_flags
& ACB_DISABLED
) {
1233 result
= NT_STATUS_ACCOUNT_DISABLED
;
1237 if (my_info3
->base
.acct_flags
& ACB_WSTRUST
) {
1238 result
= NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT
;
1242 if (my_info3
->base
.acct_flags
& ACB_SVRTRUST
) {
1243 result
= NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT
;
1247 if (my_info3
->base
.acct_flags
& ACB_DOMTRUST
) {
1248 result
= NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT
;
1252 if (!(my_info3
->base
.acct_flags
& ACB_NORMAL
)) {
1253 DEBUG(0,("winbindd_dual_pam_auth_cached: what's wrong with that one?: 0x%08x\n",
1254 my_info3
->base
.acct_flags
));
1255 result
= NT_STATUS_LOGON_FAILURE
;
1259 kickoff_time
= nt_time_to_unix(my_info3
->base
.kickoff_time
);
1260 if (kickoff_time
!= 0 && time(NULL
) > kickoff_time
) {
1261 result
= NT_STATUS_ACCOUNT_EXPIRED
;
1265 must_change_time
= nt_time_to_unix(my_info3
->base
.force_password_change
);
1266 if (must_change_time
!= 0 && must_change_time
< time(NULL
)) {
1267 /* we allow grace logons when the password has expired */
1268 my_info3
->base
.user_flags
|= NETLOGON_GRACE_LOGON
;
1269 /* return NT_STATUS_PASSWORD_EXPIRED; */
1275 ((tdc_domain
= wcache_tdc_fetch_domain(tmp_ctx
, name_domain
)) != NULL
) &&
1276 ((tdc_domain
->trust_type
& LSA_TRUST_TYPE_UPLEVEL
) ||
1277 /* used to cope with the case winbindd starting without network. */
1278 !strequal(tdc_domain
->domain_name
, tdc_domain
->dns_name
))) {
1279 const char *cc
= NULL
;
1281 const char *principal_s
= NULL
;
1282 const char *user_ccache_file
;
1284 if (domain
->alt_name
== NULL
) {
1285 result
= NT_STATUS_INVALID_PARAMETER
;
1290 DEBUG(0,("winbindd_dual_pam_auth_cached: invalid uid\n"));
1291 result
= NT_STATUS_INVALID_PARAMETER
;
1295 ok
= generate_krb5_ccache(tmp_ctx
,
1300 result
= NT_STATUS_NO_MEMORY
;
1303 cc
= user_ccache_file
;
1305 realm
= talloc_strdup(tmp_ctx
, domain
->alt_name
);
1306 if (realm
== NULL
) {
1307 result
= NT_STATUS_NO_MEMORY
;
1311 if (!strupper_m(realm
)) {
1312 result
= NT_STATUS_INVALID_PARAMETER
;
1316 principal_s
= talloc_asprintf(tmp_ctx
, "%s@%s", name_user
, realm
);
1317 if (principal_s
== NULL
) {
1318 result
= NT_STATUS_NO_MEMORY
;
1322 if (user_ccache_file
!= NULL
) {
1324 if (_krb5ccname
!= NULL
) {
1325 *_krb5ccname
= talloc_move(mem_ctx
,
1329 result
= add_ccache_to_list(principal_s
,
1336 time(NULL
) + lp_winbind_cache_time(),
1337 time(NULL
) + WINBINDD_PAM_AUTH_KRB5_RENEW_TIME
,
1342 if (!NT_STATUS_IS_OK(result
)) {
1343 DEBUG(10,("winbindd_dual_pam_auth_cached: failed "
1344 "to add ccache to list: %s\n",
1345 nt_errstr(result
)));
1349 #endif /* HAVE_KRB5 */
1351 /* FIXME: we possibly should handle logon hours as well (does xp when
1352 * offline?) see auth/auth_sam.c:sam_account_ok for details */
1354 unix_to_nt_time(&my_info3
->base
.logon_time
, time(NULL
));
1355 my_info3
->base
.bad_password_count
= 0;
1357 result
= winbindd_update_creds_by_info3(domain
,
1361 if (!NT_STATUS_IS_OK(result
)) {
1362 DEBUG(1,("winbindd_dual_pam_auth_cached: failed to update creds: %s\n",
1363 nt_errstr(result
)));
1367 result
= map_info3_to_validation(mem_ctx
,
1371 if (!NT_STATUS_IS_OK(result
)) {
1372 DBG_ERR("map_info3_to_validation failed: %s\n",
1377 result
= NT_STATUS_OK
;
1381 /* User does *NOT* know the correct password, modify info3 accordingly, but only if online */
1382 if (domain
->online
== false) {
1386 /* failure of this is not critical */
1387 result
= get_max_bad_attempts_from_lockout_policy(domain
, tmp_ctx
, &max_allowed_bad_attempts
);
1388 if (!NT_STATUS_IS_OK(result
)) {
1389 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get max_allowed_bad_attempts. "
1390 "Won't be able to honour account lockout policies\n"));
1393 /* increase counter */
1394 my_info3
->base
.bad_password_count
++;
1396 if (max_allowed_bad_attempts
== 0) {
1401 if (my_info3
->base
.bad_password_count
>= max_allowed_bad_attempts
) {
1403 uint32_t password_properties
;
1405 result
= get_pwd_properties(domain
, tmp_ctx
, &password_properties
);
1406 if (!NT_STATUS_IS_OK(result
)) {
1407 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get password properties.\n"));
1410 if ((my_info3
->base
.rid
!= DOMAIN_RID_ADMINISTRATOR
) ||
1411 (password_properties
& DOMAIN_PASSWORD_LOCKOUT_ADMINS
)) {
1412 my_info3
->base
.acct_flags
|= ACB_AUTOLOCK
;
1417 result
= winbindd_update_creds_by_info3(domain
, user
, NULL
, my_info3
);
1418 if (!NT_STATUS_IS_OK(result
)) {
1419 DEBUG(0,("winbindd_dual_pam_auth_cached: failed to update creds %s\n",
1420 nt_errstr(result
)));
1423 result
= NT_STATUS_LOGON_FAILURE
;
1426 TALLOC_FREE(tmp_ctx
);
1431 static NTSTATUS
winbindd_dual_pam_auth_kerberos(struct winbindd_domain
*domain
,
1434 const char *krb5_cc_type
,
1436 TALLOC_CTX
*mem_ctx
,
1437 uint16_t *_validation_level
,
1438 union netr_Validation
**_validation
,
1439 const char **_krb5ccname
)
1441 struct netr_SamInfo6
*info6
= NULL
;
1442 struct winbindd_domain
*contact_domain
;
1443 char *name_namespace
= NULL
;
1444 char *name_domain
= NULL
;
1445 char *name_user
= NULL
;
1449 DEBUG(10,("winbindd_dual_pam_auth_kerberos\n"));
1451 /* Parse domain and username */
1453 ok
= parse_domain_user(mem_ctx
,
1459 result
= NT_STATUS_INVALID_PARAMETER
;
1463 /* what domain should we contact? */
1465 if (lp_winbind_use_krb5_enterprise_principals()) {
1466 contact_domain
= find_auth_domain(0, name_namespace
);
1468 contact_domain
= find_domain_from_name(name_namespace
);
1470 if (contact_domain
== NULL
) {
1471 DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
1472 user
, name_domain
, name_user
, name_namespace
));
1473 result
= NT_STATUS_NO_SUCH_USER
;
1477 if (contact_domain
->initialized
&&
1478 contact_domain
->active_directory
) {
1482 if (!contact_domain
->initialized
) {
1483 init_dc_connection(contact_domain
, false);
1486 if (!contact_domain
->active_directory
) {
1487 DEBUG(3,("krb5 auth requested but domain (%s) is not Active Directory\n",
1488 contact_domain
->name
));
1489 return NT_STATUS_INVALID_LOGON_TYPE
;
1492 result
= winbindd_raw_kerberos_login(
1501 if (!NT_STATUS_IS_OK(result
)) {
1505 result
= map_info6_to_validation(mem_ctx
,
1510 if (!NT_STATUS_IS_OK(result
)) {
1511 DBG_ERR("map_info6_to_validation failed: %s\n",
1519 static NTSTATUS
winbindd_dual_auth_passdb(TALLOC_CTX
*mem_ctx
,
1520 uint32_t logon_parameters
,
1523 const uint64_t logon_id
,
1524 const char *client_name
,
1525 const int client_pid
,
1526 const DATA_BLOB
*challenge
,
1527 const DATA_BLOB
*lm_resp
,
1528 const DATA_BLOB
*nt_resp
,
1529 const struct tsocket_address
*remote
,
1530 const struct tsocket_address
*local
,
1532 uint8_t *pauthoritative
,
1533 struct netr_SamInfo3
**pinfo3
)
1535 struct auth_context
*auth_context
;
1536 struct auth_serversupplied_info
*server_info
;
1537 struct auth_usersupplied_info
*user_info
= NULL
;
1538 struct netr_SamInfo3
*info3
;
1541 TALLOC_CTX
*frame
= talloc_stackframe();
1544 * We are authoritative by default
1546 *pauthoritative
= 1;
1548 status
= make_user_info(frame
, &user_info
, user
, user
, domain
, domain
,
1549 lp_netbios_name(), remote
, local
,
1551 lm_resp
, nt_resp
, NULL
, NULL
,
1552 NULL
, AUTH_PASSWORD_RESPONSE
);
1553 if (!NT_STATUS_IS_OK(status
)) {
1554 DEBUG(10, ("make_user_info failed: %s\n", nt_errstr(status
)));
1559 user_info
->logon_parameters
= logon_parameters
;
1560 user_info
->logon_id
= logon_id
;
1561 user_info
->auth_description
= talloc_asprintf(
1562 frame
, "PASSDB, %s, %d", client_name
, client_pid
);
1563 if (user_info
->auth_description
== NULL
) {
1565 return NT_STATUS_NO_MEMORY
;
1568 /* We don't want to come back to winbindd or to do PAM account checks */
1569 user_info
->flags
|= USER_INFO_INFO3_AND_NO_AUTHZ
;
1572 user_info
->flags
|= USER_INFO_INTERACTIVE_LOGON
;
1575 status
= make_auth3_context_for_winbind(frame
, &auth_context
);
1576 if (!NT_STATUS_IS_OK(status
)) {
1577 DBG_ERR("make_auth3_context_for_winbind failed: %s\n",
1583 ok
= auth3_context_set_challenge(auth_context
,
1584 challenge
->data
, "fixed");
1587 return NT_STATUS_NO_MEMORY
;
1590 status
= auth_check_ntlm_password(mem_ctx
,
1595 if (!NT_STATUS_IS_OK(status
)) {
1600 info3
= talloc_zero(mem_ctx
, struct netr_SamInfo3
);
1601 if (info3
== NULL
) {
1603 return NT_STATUS_NO_MEMORY
;
1606 status
= serverinfo_to_SamInfo3(server_info
, info3
);
1607 if (!NT_STATUS_IS_OK(status
)) {
1610 DEBUG(0, ("serverinfo_to_SamInfo3 failed: %s\n",
1611 nt_errstr(status
)));
1616 DBG_DEBUG("Authenticating user %s\\%s returned %s\n",
1624 static NTSTATUS
winbind_samlogon_retry_loop(struct winbindd_domain
*domain
,
1625 TALLOC_CTX
*mem_ctx
,
1626 uint32_t logon_parameters
,
1627 const char *username
,
1628 const char *password
,
1629 const char *domainname
,
1630 const char *workstation
,
1631 const uint64_t logon_id
,
1632 bool plaintext_given
,
1634 DATA_BLOB lm_response
,
1635 DATA_BLOB nt_response
,
1637 uint8_t *authoritative
,
1639 uint16_t *_validation_level
,
1640 union netr_Validation
**_validation
)
1643 int netr_attempts
= 0;
1645 bool valid_result
= false;
1647 enum netr_LogonInfoClass logon_type_i
;
1648 enum netr_LogonInfoClass logon_type_n
;
1649 uint16_t validation_level
= UINT16_MAX
;
1650 union netr_Validation
*validation
= NULL
;
1651 TALLOC_CTX
*base_ctx
= NULL
;
1652 struct netr_SamBaseInfo
*base_info
= NULL
;
1655 struct rpc_pipe_client
*netlogon_pipe
;
1656 struct netlogon_creds_cli_context
*netlogon_creds_ctx
= NULL
;
1659 * We should always reset authoritative to 1
1660 * before calling a server again.
1662 * Otherwise we could treat a local problem as
1663 * non-authoritative.
1669 D_DEBUG("Creating a DCERPC netlogon connection for SAM logon. "
1670 "netlogon attempt: %d, samlogon attempt: %d.\n",
1673 result
= cm_connect_netlogon_secure(domain
, &netlogon_pipe
,
1674 &netlogon_creds_ctx
);
1676 if (NT_STATUS_EQUAL(result
,
1677 NT_STATUS_CANT_ACCESS_DOMAIN_INFO
)) {
1679 * This means we don't have a trust account.
1682 result
= NT_STATUS_NO_SUCH_USER
;
1686 if (!NT_STATUS_IS_OK(result
)) {
1687 DEBUG(3,("Could not open handle to NETLOGON pipe "
1688 "(error: %s, attempts: %d)\n",
1689 nt_errstr(result
), netr_attempts
));
1691 reset_cm_connection_on_error(domain
, NULL
, result
);
1693 /* After the first retry always close the connection */
1694 if (netr_attempts
> 0) {
1695 DEBUG(3, ("This is again a problem for this "
1696 "particular call, forcing the close "
1697 "of this connection\n"));
1698 invalidate_cm_connection(domain
);
1701 /* After the second retry failover to the next DC */
1702 if (netr_attempts
> 1) {
1704 * If the netlogon server is not reachable then
1705 * it is possible that the DC is rebuilding
1706 * sysvol and shutdown netlogon for that time.
1707 * We should failover to the next dc.
1709 DEBUG(3, ("This is the third problem for this "
1710 "particular call, adding DC to the "
1711 "negative cache list: %s %s\n", domain
->name
, domain
->dcname
));
1712 add_failed_connection_entry(domain
->name
,
1715 saf_delete(domain
->name
);
1718 /* Only allow 3 retries */
1719 if (netr_attempts
< 3) {
1720 DEBUG(3, ("The connection to netlogon "
1721 "failed, retrying\n"));
1729 logon_type_i
= NetlogonInteractiveInformation
;
1730 logon_type_n
= NetlogonNetworkInformation
;
1731 if (domain
->domain_trust_attribs
& LSA_TRUST_ATTRIBUTE_WITHIN_FOREST
) {
1732 logon_type_i
= NetlogonInteractiveTransitiveInformation
;
1733 logon_type_n
= NetlogonNetworkTransitiveInformation
;
1736 if (domain
->domain_trust_attribs
& LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE
) {
1737 logon_type_i
= NetlogonInteractiveTransitiveInformation
;
1738 logon_type_n
= NetlogonNetworkTransitiveInformation
;
1741 if (domain
->domain_trust_attribs
& LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE
) {
1742 logon_type_i
= NetlogonInteractiveInformation
;
1743 logon_type_n
= NetlogonNetworkInformation
;
1746 if (domain
->domain_trust_attribs
& LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN
) {
1747 logon_type_i
= NetlogonInteractiveInformation
;
1748 logon_type_n
= NetlogonNetworkInformation
;
1752 if (plaintext_given
) {
1753 result
= rpccli_netlogon_password_logon(
1755 netlogon_pipe
->binding_handle
,
1768 } else if (interactive
) {
1769 result
= rpccli_netlogon_interactive_logon(
1771 netlogon_pipe
->binding_handle
,
1786 result
= rpccli_netlogon_network_logon(
1788 netlogon_pipe
->binding_handle
,
1806 * we increment this after the "feature negotiation"
1807 * for can_do_samlogon_ex and can_do_validation6
1811 /* We have to try a second time as cm_connect_netlogon
1812 might not yet have noticed that the DC has killed
1815 retry
= reset_cm_connection_on_error(domain
,
1816 netlogon_pipe
->binding_handle
,
1819 DBG_PREFIX(attempts
> 1 ? DBGLVL_NOTICE
: DBGLVL_INFO
, (
1820 "This is problem %d for this "
1822 "DOMAIN[%s] DC[%s] - %s\n",
1826 nt_errstr(result
)));
1830 valid_result
= true;
1832 if (NT_STATUS_EQUAL(result
, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
)) {
1834 * Got DCERPC_FAULT_OP_RNG_ERROR for SamLogon
1835 * (no Ex). This happens against old Samba
1836 * DCs, if LogonSamLogonEx() fails with an error
1837 * e.g. NT_STATUS_NO_SUCH_USER or NT_STATUS_WRONG_PASSWORD.
1839 * The server will log something like this:
1840 * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
1842 * This sets the whole connection into a fault_state mode
1843 * and all following request get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
1845 * This also happens to our retry with LogonSamLogonWithFlags()
1846 * and LogonSamLogon().
1848 * In order to recover from this situation, we need to
1849 * drop the connection.
1851 invalidate_cm_connection(domain
);
1852 result
= NT_STATUS_LOGON_FAILURE
;
1856 } while ( (attempts
< 3) && retry
);
1858 if (!valid_result
) {
1860 * This matches what windows does. In a chain of transitive
1861 * trusts the ACCESS_DENIED/authoritative=0 is not propagated
1862 * instead of NT_STATUS_NO_LOGON_SERVERS/authoritative=1 is
1863 * passed along the chain if there's no other DC is available.
1865 DBG_WARNING("Mapping %s/authoritative=%u to "
1866 "NT_STATUS_NO_LOGON_SERVERS/authoritative=1 for"
1867 "USERNAME[%s] USERDOMAIN[%s] REMOTE-DOMAIN[%s] \n",
1874 return NT_STATUS_NO_LOGON_SERVERS
;
1877 if (!NT_STATUS_IS_OK(result
)) {
1881 switch (validation_level
) {
1883 base_ctx
= validation
->sam3
;
1884 base_info
= &validation
->sam3
->base
;
1887 base_ctx
= validation
->sam6
;
1888 base_info
= &validation
->sam6
->base
;
1891 smb_panic(__location__
);
1894 if (base_info
->acct_flags
== 0 || base_info
->account_name
.string
== NULL
) {
1895 struct dom_sid user_sid
;
1896 struct dom_sid_buf sid_buf
;
1897 const char *acct_flags_src
= "server";
1898 const char *acct_name_src
= "server";
1901 * Handle the case where a NT4 DC does not fill in the acct_flags in
1902 * the samlogon reply info3. Yes, in 2021, there are still admins
1903 * around with real NT4 DCs.
1905 * We used to call dcerpc_samr_QueryUserInfo(level=16) to fetch
1906 * acct_flags, but as NT4 DCs reject authentication with workstation
1907 * accounts with NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT, even if
1908 * MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT is specified, we only ever got
1909 * ACB_NORMAL back (maybe with ACB_PWNOEXP in addition).
1911 * For network logons NT4 DCs also skip the
1912 * account_name, so we have to fallback to the
1913 * one given by the client.
1916 if (base_info
->acct_flags
== 0) {
1917 base_info
->acct_flags
= ACB_NORMAL
;
1918 if (base_info
->force_password_change
== NTTIME_MAX
) {
1919 base_info
->acct_flags
|= ACB_PWNOEXP
;
1921 acct_flags_src
= "calculated";
1924 if (base_info
->account_name
.string
== NULL
) {
1925 base_info
->account_name
.string
= talloc_strdup(base_ctx
,
1927 if (base_info
->account_name
.string
== NULL
) {
1928 TALLOC_FREE(validation
);
1929 return NT_STATUS_NO_MEMORY
;
1931 acct_name_src
= "client";
1934 sid_compose(&user_sid
, base_info
->domain_sid
, base_info
->rid
);
1936 DBG_DEBUG("Fallback to %s_acct_flags[0x%x] %s_acct_name[%s] for %s\n",
1938 base_info
->acct_flags
,
1940 base_info
->account_name
.string
,
1941 dom_sid_str_buf(&user_sid
, &sid_buf
));
1944 *_validation_level
= validation_level
;
1945 *_validation
= validation
;
1946 return NT_STATUS_OK
;
1949 static NTSTATUS
nt_dual_auth_passdb(TALLOC_CTX
*mem_ctx
,
1951 fstring name_domain
,
1954 const char *client_name
,
1955 const int client_pid
,
1956 const struct tsocket_address
*remote
,
1957 const struct tsocket_address
*local
,
1958 uint8_t *authoritative
,
1959 struct netr_SamInfo3
**info3
)
1961 unsigned char local_nt_response
[24];
1963 DATA_BLOB chal_blob
;
1967 /* do password magic */
1969 generate_random_buffer(chal
, sizeof(chal
));
1970 chal_blob
= data_blob_const(chal
, sizeof(chal
));
1972 if (lp_client_ntlmv2_auth()) {
1973 DATA_BLOB server_chal
;
1974 DATA_BLOB names_blob
;
1975 server_chal
= data_blob_const(chal
, 8);
1977 /* note that the 'workgroup' here is for the local
1978 machine. The 'server name' must match the
1979 'workstation' passed to the actual SamLogon call.
1981 names_blob
= NTLMv2_generate_names_blob(mem_ctx
,
1985 if (!SMBNTLMv2encrypt(mem_ctx
, name_user
, name_domain
,
1986 pass
, &server_chal
, &names_blob
,
1987 &lm_resp
, &nt_resp
, NULL
, NULL
)) {
1988 data_blob_free(&names_blob
);
1989 DEBUG(0, ("SMBNTLMv2encrypt() failed!\n"));
1990 return NT_STATUS_NO_MEMORY
;
1992 data_blob_free(&names_blob
);
1995 lm_resp
= data_blob_null
;
1997 rc
= SMBNTencrypt(pass
, chal
, local_nt_response
);
1999 DEBUG(0, ("SMBNTencrypt() failed!\n"));
2000 return gnutls_error_to_ntstatus(rc
,
2001 NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER
);
2004 nt_resp
= data_blob_talloc(mem_ctx
, local_nt_response
,
2005 sizeof(local_nt_response
));
2008 return winbindd_dual_auth_passdb(talloc_tos(), 0, name_domain
,
2009 name_user
, logon_id
, client_name
,
2010 client_pid
, &chal_blob
, &lm_resp
,
2011 &nt_resp
, remote
, local
,
2012 true, /* interactive */
2013 authoritative
, info3
);
2016 static NTSTATUS
winbindd_dual_pam_auth_samlogon(
2017 TALLOC_CTX
*mem_ctx
,
2018 struct winbindd_domain
*domain
,
2022 const char *client_name
,
2023 const int client_pid
,
2024 uint32_t request_flags
,
2025 const struct tsocket_address
*remote
,
2026 const struct tsocket_address
*local
,
2027 uint16_t *_validation_level
,
2028 union netr_Validation
**_validation
)
2030 char *name_namespace
= NULL
;
2031 char *name_domain
= NULL
;
2032 char *name_user
= NULL
;
2034 uint8_t authoritative
= 1;
2036 uint16_t validation_level
= 0;
2037 union netr_Validation
*validation
= NULL
;
2040 DEBUG(10,("winbindd_dual_pam_auth_samlogon\n"));
2042 /* Parse domain and username */
2044 ok
= parse_domain_user(mem_ctx
,
2050 return NT_STATUS_INVALID_PARAMETER
;
2054 * We check against domain->name instead of
2055 * name_domain, as find_auth_domain() ->
2056 * find_domain_from_name_noinit() already decided
2057 * that we are in a child for the correct domain.
2059 * name_domain can also be lp_realm()
2060 * we need to check against domain->name.
2062 if (strequal(domain
->name
, get_global_sam_name())) {
2063 struct netr_SamInfo3
*info3
= NULL
;
2065 result
= nt_dual_auth_passdb(mem_ctx
, name_user
, name_domain
,
2066 pass
, logon_id
, client_name
,
2067 client_pid
, remote
, local
,
2068 &authoritative
, &info3
);
2071 * We need to try the remote NETLOGON server if this is
2072 * not authoritative (for example on the RODC).
2074 if (authoritative
!= 0) {
2075 if (!NT_STATUS_IS_OK(result
)) {
2078 result
= map_info3_to_validation(mem_ctx
,
2083 if (!NT_STATUS_IS_OK(result
)) {
2091 /* check authentication loop */
2093 result
= winbind_samlogon_retry_loop(domain
,
2101 true, /* plaintext_given */
2103 data_blob_null
, data_blob_null
,
2104 true, /* interactive */
2109 if (!NT_STATUS_IS_OK(result
)) {
2114 *_validation_level
= validation_level
;
2115 *_validation
= validation
;
2117 return NT_STATUS_OK
;
2121 * @brief generate an authentication message in the logs.
2124 static void log_authentication(
2125 TALLOC_CTX
*mem_ctx
,
2126 const struct winbindd_domain
*domain
,
2127 const char *client_name
,
2129 uint16_t validation_level
,
2130 union netr_Validation
*validation
,
2131 const struct timeval start_time
,
2132 const uint64_t logon_id
,
2133 const char *command
,
2134 const char *user_name
,
2135 const char *domain_name
,
2136 const char *workstation
,
2137 const DATA_BLOB lm_resp
,
2138 const DATA_BLOB nt_resp
,
2139 const struct tsocket_address
*remote
,
2140 const struct tsocket_address
*local
,
2143 struct auth_usersupplied_info
*ui
= NULL
;
2144 struct dom_sid
*sid
= NULL
;
2145 struct loadparm_context
*lp_ctx
= NULL
;
2146 struct imessaging_context
*msg_ctx
= NULL
;
2147 struct netr_SamBaseInfo
*base_info
= NULL
;
2149 if (validation
!= NULL
) {
2150 switch (validation_level
) {
2152 base_info
= &validation
->sam3
->base
;
2155 base_info
= &validation
->sam6
->base
;
2158 DBG_WARNING("Unexpected validation level '%d'\n",
2164 ui
= talloc_zero(mem_ctx
, struct auth_usersupplied_info
);
2165 ui
->logon_id
= logon_id
;
2166 ui
->service_description
= "winbind";
2167 ui
->password
.response
.nt
.length
= nt_resp
.length
;
2168 ui
->password
.response
.nt
.data
= nt_resp
.data
;
2169 ui
->password
.response
.lanman
.length
= lm_resp
.length
;
2170 ui
->password
.response
.lanman
.data
= lm_resp
.data
;
2171 if (nt_resp
.length
== 0 && lm_resp
.length
== 0) {
2172 ui
->password_state
= AUTH_PASSWORD_PLAIN
;
2174 ui
->password_state
= AUTH_PASSWORD_RESPONSE
;
2177 * In the event of a failure ui->auth_description will be null,
2178 * the logging code handles this correctly so it can be ignored.
2180 ui
->auth_description
= talloc_asprintf(
2186 if (ui
->auth_description
== NULL
) {
2187 DBG_ERR("OOM Unable to create auth_description\n");
2189 ui
->client
.account_name
= user_name
;
2190 ui
->client
.domain_name
= domain_name
;
2191 ui
->workstation_name
= workstation
;
2192 ui
->remote_host
= remote
;
2193 ui
->local_host
= local
;
2195 if (base_info
!= NULL
) {
2196 sid
= dom_sid_dup(ui
, base_info
->domain_sid
);
2198 sid_append_rid(sid
, base_info
->rid
);
2202 if (lp_auth_event_notification()) {
2203 lp_ctx
= loadparm_init_s3(ui
, loadparm_s3_helpers());
2204 msg_ctx
= imessaging_client_init(
2205 ui
, lp_ctx
, global_event_context());
2207 log_authentication_event(
2213 base_info
!= NULL
? base_info
->logon_domain
.string
: "",
2214 base_info
!= NULL
? base_info
->account_name
.string
: "",
2216 NULL
/* client_audit_info */,
2217 NULL
/* server_audit_info */);
2221 NTSTATUS
_wbint_PamAuth(struct pipes_struct
*p
,
2222 struct wbint_PamAuth
*r
)
2224 struct winbindd_domain
*domain
= wb_child_domain();
2225 NTSTATUS result
= NT_STATUS_LOGON_FAILURE
;
2226 NTSTATUS krb5_result
= NT_STATUS_OK
;
2227 char *name_namespace
= NULL
;
2228 char *name_domain
= NULL
;
2229 char *name_user
= NULL
;
2230 char *mapped_user
= NULL
;
2231 const char *domain_user
= NULL
;
2232 uint16_t validation_level
= UINT16_MAX
;
2233 union netr_Validation
*validation
= NULL
;
2234 struct netr_SamBaseInfo
*base_info
= NULL
;
2235 NTSTATUS name_map_status
= NT_STATUS_UNSUCCESSFUL
;
2237 uint64_t logon_id
= 0;
2238 const struct timeval start_time
= timeval_current();
2239 const struct tsocket_address
*remote
= NULL
;
2240 const struct tsocket_address
*local
= NULL
;
2241 const char *krb5ccname
= NULL
;
2245 if (domain
== NULL
) {
2246 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
2249 /* Cut client_pid to 32bit */
2250 client_pid
= r
->in
.client_pid
;
2251 if ((uint64_t)client_pid
!= r
->in
.client_pid
) {
2252 DBG_DEBUG("pid out of range\n");
2253 return NT_STATUS_INVALID_PARAMETER
;
2256 /* Cut uid to 32bit */
2257 uid
= r
->in
.info
->uid
;
2258 if ((uint64_t)uid
!= r
->in
.info
->uid
) {
2259 DBG_DEBUG("uid out of range\n");
2260 return NT_STATUS_INVALID_PARAMETER
;
2264 * Generate a logon_id for this session.
2266 logon_id
= generate_random_u64();
2267 remote
= dcesrv_connection_get_remote_address(p
->dce_call
->conn
);
2268 local
= dcesrv_connection_get_local_address(p
->dce_call
->conn
);
2269 DEBUG(3, ("[%"PRIu32
"]: dual pam auth %s\n", client_pid
,
2270 r
->in
.info
->username
));
2272 /* Parse domain and username */
2274 name_map_status
= normalize_name_unmap(p
->mem_ctx
,
2275 r
->in
.info
->username
,
2278 /* If the name normalization didn't actually do anything,
2279 just use the original name */
2281 if (!NT_STATUS_IS_OK(name_map_status
) &&
2282 !NT_STATUS_EQUAL(name_map_status
, NT_STATUS_FILE_RENAMED
))
2284 mapped_user
= discard_const(r
->in
.info
->username
);
2287 ok
= parse_domain_user(p
->mem_ctx
,
2293 result
= NT_STATUS_INVALID_PARAMETER
;
2297 if (mapped_user
!= r
->in
.info
->username
) {
2298 domain_user
= talloc_asprintf(talloc_tos(),
2301 *lp_winbind_separator(),
2303 if (domain_user
== NULL
) {
2304 result
= NT_STATUS_NO_MEMORY
;
2307 r
->in
.info
->username
= domain_user
;
2310 if (!domain
->online
) {
2311 result
= NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
;
2312 if (domain
->startup
) {
2313 /* Logons are very important to users. If we're offline and
2314 we get a request within the first 30 seconds of startup,
2315 try very hard to find a DC and go online. */
2317 DEBUG(10,("winbindd_dual_pam_auth: domain: %s offline and auth "
2318 "request in startup mode.\n", domain
->name
));
2320 winbindd_flush_negative_conn_cache(domain
);
2321 result
= init_dc_connection(domain
, false);
2325 DEBUG(10,("winbindd_dual_pam_auth: domain: %s last was %s\n", domain
->name
, domain
->online
? "online":"offline"));
2327 /* Check for Kerberos authentication */
2328 if (domain
->online
&& (r
->in
.flags
& WBFLAG_PAM_KRB5
)) {
2329 result
= winbindd_dual_pam_auth_kerberos(
2331 r
->in
.info
->username
,
2332 r
->in
.info
->password
,
2333 r
->in
.info
->krb5_cc_type
,
2340 /* save for later */
2341 krb5_result
= result
;
2343 if (NT_STATUS_IS_OK(result
)) {
2344 DEBUG(10,("winbindd_dual_pam_auth_kerberos succeeded\n"));
2345 goto process_result
;
2348 DBG_DEBUG("winbindd_dual_pam_auth_kerberos failed: %s\n",
2351 if (NT_STATUS_EQUAL(result
, NT_STATUS_NO_LOGON_SERVERS
) ||
2352 NT_STATUS_EQUAL(result
, NT_STATUS_IO_TIMEOUT
) ||
2353 NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2354 DEBUG(10,("winbindd_dual_pam_auth_kerberos setting domain to offline\n"));
2355 set_domain_offline( domain
);
2359 /* there are quite some NT_STATUS errors where there is no
2360 * point in retrying with a samlogon, we explicitly have to take
2361 * care not to increase the bad logon counter on the DC */
2363 if (NT_STATUS_EQUAL(result
, NT_STATUS_ACCOUNT_DISABLED
) ||
2364 NT_STATUS_EQUAL(result
, NT_STATUS_ACCOUNT_EXPIRED
) ||
2365 NT_STATUS_EQUAL(result
, NT_STATUS_ACCOUNT_LOCKED_OUT
) ||
2366 NT_STATUS_EQUAL(result
, NT_STATUS_INVALID_LOGON_HOURS
) ||
2367 NT_STATUS_EQUAL(result
, NT_STATUS_INVALID_WORKSTATION
) ||
2368 NT_STATUS_EQUAL(result
, NT_STATUS_LOGON_FAILURE
) ||
2369 NT_STATUS_EQUAL(result
, NT_STATUS_NO_SUCH_USER
) ||
2370 NT_STATUS_EQUAL(result
, NT_STATUS_PASSWORD_EXPIRED
) ||
2371 NT_STATUS_EQUAL(result
, NT_STATUS_PASSWORD_MUST_CHANGE
) ||
2372 NT_STATUS_EQUAL(result
, NT_STATUS_WRONG_PASSWORD
)) {
2376 if (r
->in
.flags
& WBFLAG_PAM_FALLBACK_AFTER_KRB5
) {
2377 DEBUG(3,("falling back to samlogon\n"));
2385 /* Check for Samlogon authentication */
2386 if (domain
->online
) {
2387 result
= winbindd_dual_pam_auth_samlogon(
2390 r
->in
.info
->username
,
2391 r
->in
.info
->password
,
2401 if (NT_STATUS_IS_OK(result
)) {
2402 DEBUG(10,("winbindd_dual_pam_auth_samlogon succeeded\n"));
2404 switch (validation_level
) {
2406 base_info
= &validation
->sam3
->base
;
2409 base_info
= &validation
->sam6
->base
;
2412 DBG_ERR("Bad validation level %d\n",
2414 result
= NT_STATUS_INTERNAL_ERROR
;
2418 /* add the Krb5 err if we have one */
2419 if ( NT_STATUS_EQUAL(krb5_result
, NT_STATUS_TIME_DIFFERENCE_AT_DC
) ) {
2420 base_info
->user_flags
|= LOGON_KRB5_FAIL_CLOCK_SKEW
;
2423 goto process_result
;
2426 DEBUG(10,("winbindd_dual_pam_auth_samlogon failed: %s\n",
2427 nt_errstr(result
)));
2429 if (NT_STATUS_EQUAL(result
, NT_STATUS_NO_LOGON_SERVERS
) ||
2430 NT_STATUS_EQUAL(result
, NT_STATUS_IO_TIMEOUT
) ||
2431 NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
))
2433 DEBUG(10,("winbindd_dual_pam_auth_samlogon setting domain to offline\n"));
2434 set_domain_offline( domain
);
2438 if (domain
->online
) {
2439 /* We're still online - fail. */
2445 /* Check for Cached logons */
2446 if (!domain
->online
&& (r
->in
.flags
& WBFLAG_PAM_CACHED_LOGIN
) &&
2447 lp_winbind_offline_logon()) {
2448 result
= winbindd_dual_pam_auth_cached(domain
,
2449 (r
->in
.flags
& WBFLAG_PAM_KRB5
),
2450 r
->in
.info
->username
,
2451 r
->in
.info
->password
,
2452 r
->in
.info
->krb5_cc_type
,
2459 if (!NT_STATUS_IS_OK(result
)) {
2460 DEBUG(10,("winbindd_dual_pam_auth_cached failed: %s\n", nt_errstr(result
)));
2463 DEBUG(10,("winbindd_dual_pam_auth_cached succeeded\n"));
2468 if (NT_STATUS_IS_OK(result
)) {
2469 struct dom_sid user_sid
;
2470 TALLOC_CTX
*base_ctx
= NULL
;
2471 struct netr_SamInfo3
*info3
= NULL
;
2473 switch (validation_level
) {
2475 base_ctx
= validation
->sam3
;
2476 base_info
= &validation
->sam3
->base
;
2479 base_ctx
= validation
->sam6
;
2480 base_info
= &validation
->sam6
->base
;
2483 DBG_ERR("Bad validation level %d\n", validation_level
);
2484 result
= NT_STATUS_INTERNAL_ERROR
;
2488 sid_compose(&user_sid
, base_info
->domain_sid
, base_info
->rid
);
2490 if (base_info
->full_name
.string
== NULL
) {
2491 struct netr_SamInfo3
*cached_info3
;
2493 cached_info3
= netsamlogon_cache_get(p
->mem_ctx
,
2495 if (cached_info3
!= NULL
&&
2496 cached_info3
->base
.full_name
.string
!= NULL
) {
2497 base_info
->full_name
.string
= talloc_strdup(
2499 cached_info3
->base
.full_name
.string
);
2500 if (base_info
->full_name
.string
== NULL
) {
2501 result
= NT_STATUS_NO_MEMORY
;
2506 /* this might fail so we don't check the return code */
2507 wcache_query_user_fullname(domain
,
2510 &base_info
->full_name
.string
);
2514 result
= map_validation_to_info3(talloc_tos(),
2518 if (!NT_STATUS_IS_OK(result
)) {
2522 wcache_invalidate_samlogon(find_domain_from_name(name_domain
),
2524 netsamlogon_cache_store(name_user
, info3
);
2526 /* save name_to_sid info as early as possible (only if
2527 this is our primary domain so we don't invalidate
2528 the cache entry by storing the seq_num for the wrong
2530 if ( domain
->primary
) {
2531 cache_name2sid(domain
, name_domain
, name_user
,
2532 SID_NAME_USER
, &user_sid
);
2535 /* Check if the user is in the right group */
2537 result
= check_info3_in_group(info3
,
2538 r
->in
.require_membership_of_sid
);
2539 if (!NT_STATUS_IS_OK(result
)) {
2540 char *s
= NDR_PRINT_STRUCT_STRING(p
->mem_ctx
,
2542 r
->in
.require_membership_of_sid
);
2543 DBG_NOTICE("User %s is not in the required groups:\n",
2544 r
->in
.info
->username
);
2545 DEBUGADD(DBGLVL_NOTICE
, ("%s", s
));
2546 DEBUGADD(DBGLVL_NOTICE
,
2547 ("Plaintext authentication is rejected\n"));
2551 if (!is_allowed_domain(info3
->base
.logon_domain
.string
)) {
2552 DBG_NOTICE("Authentication failed for user [%s] "
2553 "from firewalled domain [%s]\n",
2554 info3
->base
.account_name
.string
,
2555 info3
->base
.logon_domain
.string
);
2556 result
= NT_STATUS_AUTHENTICATION_FIREWALL_FAILED
;
2560 r
->out
.validation
= talloc_zero(p
->mem_ctx
,
2561 struct wbint_Validation
);
2562 if (r
->out
.validation
== NULL
) {
2563 result
= NT_STATUS_NO_MEMORY
;
2567 r
->out
.validation
->level
= validation_level
;
2568 r
->out
.validation
->validation
= talloc_steal(r
->out
.validation
,
2570 r
->out
.validation
->krb5ccname
= talloc_steal(r
->out
.validation
,
2572 if ((r
->in
.flags
& WBFLAG_PAM_CACHED_LOGIN
)
2573 && lp_winbind_offline_logon()) {
2575 result
= winbindd_store_creds(domain
,
2576 r
->in
.info
->username
,
2577 r
->in
.info
->password
,
2581 result
= NT_STATUS_OK
;
2585 /* give us a more useful (more correct?) error code */
2586 if ((NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ||
2587 (NT_STATUS_EQUAL(result
, NT_STATUS_UNSUCCESSFUL
)))) {
2588 result
= NT_STATUS_NO_LOGON_SERVERS
;
2591 DBG_PREFIX(NT_STATUS_IS_OK(result
) ? 5 : 2,
2592 ("Plain-text authentication for user %s returned %s"
2594 r
->in
.info
->username
,
2596 nt_status_to_pam(result
)));
2599 * Log the winbind pam authentication, the logon_id will tie this to
2600 * any of the logons invoked from this request.
2622 if (NT_STATUS_IS_OK(result
)) {
2623 gpupdate_user_init(r
->in
.info
->username
);
2629 NTSTATUS
winbind_dual_SamLogon(struct winbindd_domain
*domain
,
2630 TALLOC_CTX
*mem_ctx
,
2632 uint32_t logon_parameters
,
2633 const char *name_user
,
2634 const char *name_domain
,
2635 const char *workstation
,
2636 const uint64_t logon_id
,
2637 const char* client_name
,
2638 const int client_pid
,
2639 DATA_BLOB chal_blob
,
2640 DATA_BLOB lm_response
,
2641 DATA_BLOB nt_response
,
2642 const struct tsocket_address
*remote
,
2643 const struct tsocket_address
*local
,
2644 uint8_t *authoritative
,
2647 uint16_t *_validation_level
,
2648 union netr_Validation
**_validation
)
2650 uint16_t validation_level
= 0;
2651 union netr_Validation
*validation
= NULL
;
2655 * We check against domain->name instead of
2656 * name_domain, as find_auth_domain() ->
2657 * find_domain_from_name_noinit() already decided
2658 * that we are in a child for the correct domain.
2660 * name_domain can also be lp_realm()
2661 * we need to check against domain->name.
2663 if (!skip_sam
&& strequal(domain
->name
, get_global_sam_name())) {
2664 struct netr_SamInfo3
*info3
= NULL
;
2666 result
= winbindd_dual_auth_passdb(
2669 name_domain
, name_user
,
2673 &chal_blob
, &lm_response
, &nt_response
,
2679 if (NT_STATUS_IS_OK(result
)) {
2680 result
= map_info3_to_validation(mem_ctx
,
2685 if (!NT_STATUS_IS_OK(result
)) {
2691 * We need to try the remote NETLOGON server if this is
2692 * not authoritative.
2694 if (*authoritative
!= 0) {
2696 goto process_result
;
2700 result
= winbind_samlogon_retry_loop(domain
,
2704 NULL
, /* password */
2706 /* Bug #3248 - found by Stefan Burkei. */
2707 workstation
, /* We carefully set this above so use it... */
2709 false, /* plaintext_given */
2718 if (!NT_STATUS_IS_OK(result
)) {
2724 if (NT_STATUS_IS_OK(result
)) {
2725 struct dom_sid user_sid
;
2726 TALLOC_CTX
*base_ctx
= NULL
;
2727 struct netr_SamBaseInfo
*base_info
= NULL
;
2728 struct netr_SamInfo3
*info3
= NULL
;
2730 switch (validation_level
) {
2732 base_ctx
= validation
->sam3
;
2733 base_info
= &validation
->sam3
->base
;
2736 base_ctx
= validation
->sam6
;
2737 base_info
= &validation
->sam6
->base
;
2740 result
= NT_STATUS_INTERNAL_ERROR
;
2744 sid_compose(&user_sid
, base_info
->domain_sid
, base_info
->rid
);
2746 if (base_info
->full_name
.string
== NULL
) {
2747 struct netr_SamInfo3
*cached_info3
;
2749 cached_info3
= netsamlogon_cache_get(mem_ctx
,
2751 if (cached_info3
!= NULL
&&
2752 cached_info3
->base
.full_name
.string
!= NULL
)
2754 base_info
->full_name
.string
= talloc_strdup(
2756 cached_info3
->base
.full_name
.string
);
2759 /* this might fail so we don't check the return code */
2760 wcache_query_user_fullname(domain
,
2763 &base_info
->full_name
.string
);
2767 result
= map_validation_to_info3(talloc_tos(),
2771 if (!NT_STATUS_IS_OK(result
)) {
2774 wcache_invalidate_samlogon(find_domain_from_name(name_domain
),
2776 netsamlogon_cache_store(name_user
, info3
);
2782 /* give us a more useful (more correct?) error code */
2783 if ((NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ||
2784 (NT_STATUS_EQUAL(result
, NT_STATUS_UNSUCCESSFUL
)))) {
2785 result
= NT_STATUS_NO_LOGON_SERVERS
;
2788 DEBUG(NT_STATUS_IS_OK(result
) ? 5 : 2,
2789 ("NTLM CRAP authentication for user [%s]\\[%s] returned %s\n",
2792 nt_errstr(result
)));
2794 if (!NT_STATUS_IS_OK(result
)) {
2798 *_validation_level
= validation_level
;
2799 *_validation
= validation
;
2800 return NT_STATUS_OK
;
2803 NTSTATUS
_wbint_PamAuthCrap(struct pipes_struct
*p
, struct wbint_PamAuthCrap
*r
)
2805 struct winbindd_domain
*domain
= wb_child_domain();
2807 uint64_t logon_id
= 0;
2808 uint8_t authoritative
= 1;
2810 uint16_t validation_level
= UINT16_MAX
;
2811 union netr_Validation
*validation
= NULL
;
2812 const struct timeval start_time
= timeval_current();
2813 const struct tsocket_address
*remote
= NULL
;
2814 const struct tsocket_address
*local
= NULL
;
2815 struct netr_SamInfo3
*info3
= NULL
;
2818 if (domain
== NULL
) {
2819 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
2822 /* Cut client_pid to 32bit */
2823 client_pid
= r
->in
.client_pid
;
2824 if ((uint64_t)client_pid
!= r
->in
.client_pid
) {
2825 DBG_DEBUG("pid out of range\n");
2826 return NT_STATUS_INVALID_PARAMETER
;
2829 logon_id
= generate_random_u64();
2830 remote
= dcesrv_connection_get_remote_address(p
->dce_call
->conn
);
2831 local
= dcesrv_connection_get_local_address(p
->dce_call
->conn
);
2833 DBG_NOTICE("[%"PRIu32
"]: pam auth crap domain: %s user: %s\n",
2834 client_pid
, r
->in
.domain
, r
->in
.user
);
2836 result
= winbind_dual_SamLogon(domain
,
2838 false, /* interactive */
2839 r
->in
.logon_parameters
,
2856 if (!NT_STATUS_IS_OK(result
)) {
2860 result
= map_validation_to_info3(p
->mem_ctx
,
2864 if (!NT_STATUS_IS_OK(result
)) {
2868 /* Check if the user is in the right group */
2869 result
= check_info3_in_group(info3
, r
->in
.require_membership_of_sid
);
2870 if (!NT_STATUS_IS_OK(result
)) {
2871 char *s
= NDR_PRINT_STRUCT_STRING(p
->mem_ctx
,
2873 r
->in
.require_membership_of_sid
);
2874 DBG_NOTICE("User %s is not in the required groups:\n",
2876 DEBUGADD(DBGLVL_NOTICE
, ("%s", s
));
2877 DEBUGADD(DBGLVL_NOTICE
,
2878 ("CRAP authentication is rejected\n"));
2882 if (!is_allowed_domain(info3
->base
.logon_domain
.string
)) {
2883 DBG_NOTICE("Authentication failed for user [%s] "
2884 "from firewalled domain [%s]\n",
2885 info3
->base
.account_name
.string
,
2886 info3
->base
.logon_domain
.string
);
2887 result
= NT_STATUS_AUTHENTICATION_FIREWALL_FAILED
;
2891 r
->out
.validation
= talloc_zero(p
->mem_ctx
,
2892 struct wbint_PamAuthCrapValidation
);
2893 if (r
->out
.validation
== NULL
) {
2894 result
= NT_STATUS_NO_MEMORY
;
2898 r
->out
.validation
->level
= validation_level
;
2899 r
->out
.validation
->validation
= talloc_move(r
->out
.validation
,
2903 if (r
->in
.flags
& WBFLAG_PAM_NT_STATUS_SQUASH
) {
2904 result
= nt_status_squash(result
);
2907 *r
->out
.authoritative
= authoritative
;
2910 * Log the winbind pam authentication, the logon_id will tie this to
2911 * any of the logons invoked from this request.
2918 r
->out
.validation
->level
,
2919 r
->out
.validation
->validation
,
2935 NTSTATUS
_wbint_PamAuthChangePassword(struct pipes_struct
*p
,
2936 struct wbint_PamAuthChangePassword
*r
)
2938 struct winbindd_domain
*contact_domain
= wb_child_domain();
2939 struct policy_handle dom_pol
;
2940 struct rpc_pipe_client
*cli
= NULL
;
2941 bool got_info
= false;
2942 struct samr_DomInfo1
*info
= NULL
;
2943 struct userPwdChangeFailureInformation
*reject
= NULL
;
2944 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
2945 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
2946 char *namespace = NULL
;
2947 char *domain
= NULL
;
2949 struct dcerpc_binding_handle
*b
= NULL
;
2953 ZERO_STRUCT(dom_pol
);
2955 if (contact_domain
== NULL
) {
2956 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
2959 /* Cut client_pid to 32bit */
2960 client_pid
= r
->in
.client_pid
;
2961 if ((uint64_t)client_pid
!= r
->in
.client_pid
) {
2962 DBG_DEBUG("pid out of range\n");
2963 return NT_STATUS_INVALID_PARAMETER
;
2966 DBG_NOTICE("[%"PRIu32
"]: dual pam chauthtok %s\n",
2967 client_pid
, r
->in
.user
);
2969 ok
= parse_domain_user(p
->mem_ctx
,
2978 if (!is_allowed_domain(domain
)) {
2979 DBG_NOTICE("Authentication failed for user [%s] "
2980 "from firewalled domain [%s]\n",
2982 result
= NT_STATUS_AUTHENTICATION_FIREWALL_FAILED
;
2986 /* Initialize reject reason */
2987 *r
->out
.reject_reason
= Undefined
;
2989 /* Get sam handle */
2991 result
= cm_connect_sam(contact_domain
,
2996 if (!NT_STATUS_IS_OK(result
)) {
2997 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain
));
3001 b
= cli
->binding_handle
;
3003 status
= dcerpc_samr_chgpasswd_user4(cli
->binding_handle
,
3005 cli
->srv_name_slash
,
3010 if (NT_STATUS_IS_OK(status
) && NT_STATUS_IS_OK(result
)) {
3011 /* Password successfully changed. */
3014 if (!NT_STATUS_IS_OK(status
)) {
3015 if (NT_STATUS_EQUAL(status
, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
) ||
3016 NT_STATUS_EQUAL(status
, NT_STATUS_NOT_SUPPORTED
) ||
3017 NT_STATUS_EQUAL(status
, NT_STATUS_NOT_IMPLEMENTED
)) {
3018 /* DO NOT FALLBACK TO RC4 */
3019 if (lp_weak_crypto() == SAMBA_WEAK_CRYPTO_DISALLOWED
) {
3020 result
= NT_STATUS_STRONG_CRYPTO_NOT_SUPPORTED
;
3021 goto process_result
;
3025 /* Password change was unsuccessful. */
3026 if (!NT_STATUS_IS_OK(result
)) {
3031 result
= rpccli_samr_chgpasswd_user3(cli
,
3039 /* Windows 2003 returns NT_STATUS_PASSWORD_RESTRICTION */
3041 if (NT_STATUS_EQUAL(result
, NT_STATUS_PASSWORD_RESTRICTION
) ) {
3043 *r
->out
.dominfo
= talloc_steal(p
->mem_ctx
, info
);
3044 *r
->out
.reject_reason
= reject
->extendedFailureReason
;
3049 /* atm the pidl generated rpccli_samr_ChangePasswordUser3 function will
3050 * return with NT_STATUS_BUFFER_TOO_SMALL for w2k dcs as w2k just
3051 * returns with 4byte error code (NT_STATUS_NOT_SUPPORTED) which is too
3052 * short to comply with the samr_ChangePasswordUser3 idl - gd */
3054 /* only fallback when the chgpasswd_user3 call is not supported */
3055 if (NT_STATUS_EQUAL(result
, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
) ||
3056 NT_STATUS_EQUAL(result
, NT_STATUS_NOT_SUPPORTED
) ||
3057 NT_STATUS_EQUAL(result
, NT_STATUS_BUFFER_TOO_SMALL
) ||
3058 NT_STATUS_EQUAL(result
, NT_STATUS_NOT_IMPLEMENTED
)) {
3060 DEBUG(10,("Password change with chgpasswd_user3 failed with: %s, retrying chgpasswd_user2\n",
3061 nt_errstr(result
)));
3063 result
= rpccli_samr_chgpasswd_user2(cli
,
3067 r
->in
.old_password
);
3069 /* Windows 2000 returns NT_STATUS_ACCOUNT_RESTRICTION.
3070 Map to the same status code as Windows 2003. */
3072 if ( NT_STATUS_EQUAL(NT_STATUS_ACCOUNT_RESTRICTION
, result
) ) {
3073 result
= NT_STATUS_PASSWORD_RESTRICTION
;
3079 if (NT_STATUS_IS_OK(result
)
3080 && (r
->in
.flags
& WBFLAG_PAM_CACHED_LOGIN
)
3081 && lp_winbind_offline_logon()) {
3082 result
= winbindd_update_creds_by_name(contact_domain
, user
,
3083 r
->in
.new_password
);
3084 /* Again, this happens when we login from gdm or xdm
3085 * and the password expires, *BUT* cached credentials
3086 * don't exist. winbindd_update_creds_by_name()
3087 * returns NT_STATUS_NO_SUCH_USER.
3088 * This is not a failure.
3091 if (NT_STATUS_EQUAL(result
, NT_STATUS_NO_SUCH_USER
)) {
3092 result
= NT_STATUS_OK
;
3095 if (!NT_STATUS_IS_OK(result
)) {
3096 DEBUG(10, ("Failed to store creds: %s\n",
3097 nt_errstr(result
)));
3098 goto process_result
;
3102 if (!NT_STATUS_IS_OK(result
) && !got_info
&& contact_domain
) {
3104 NTSTATUS policy_ret
;
3106 policy_ret
= get_password_policy(contact_domain
,
3110 /* failure of this is non critical, it will just provide no
3111 * additional information to the client why the change has
3112 * failed - Guenther */
3114 if (!NT_STATUS_IS_OK(policy_ret
)) {
3115 DEBUG(10,("Failed to get password policies: %s\n", nt_errstr(policy_ret
)));
3116 goto process_result
;
3119 *r
->out
.dominfo
= talloc_steal(p
->mem_ctx
, info
);
3124 if (strequal(contact_domain
->name
, get_global_sam_name())) {
3125 /* FIXME: internal rpc pipe does not cache handles yet */
3127 if (is_valid_policy_hnd(&dom_pol
)) {
3129 dcerpc_samr_Close(b
,
3138 DEBUG(NT_STATUS_IS_OK(result
) ? 5 : 2,
3139 ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
3143 nt_status_to_pam(result
)));
3148 NTSTATUS
_wbint_PamLogOff(struct pipes_struct
*p
, struct wbint_PamLogOff
*r
)
3150 struct winbindd_domain
*domain
= wb_child_domain();
3151 NTSTATUS result
= NT_STATUS_NOT_SUPPORTED
;
3155 if (domain
== NULL
) {
3156 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
3159 /* Cut client_pid to 32bit */
3160 client_pid
= r
->in
.client_pid
;
3161 if ((uint64_t)client_pid
!= r
->in
.client_pid
) {
3162 DBG_DEBUG("pid out of range\n");
3163 return NT_STATUS_INVALID_PARAMETER
;
3166 /* Cut uid to 32bit */
3167 user_uid
= r
->in
.uid
;
3168 if ((uint64_t)user_uid
!= r
->in
.uid
) {
3169 DBG_DEBUG("uid out of range\n");
3170 return NT_STATUS_INVALID_PARAMETER
;
3173 DBG_NOTICE("[%"PRIu32
"]: pam dual logoff %s\n", client_pid
, r
->in
.user
);
3175 if (!(r
->in
.flags
& WBFLAG_PAM_KRB5
)) {
3176 result
= NT_STATUS_OK
;
3177 goto process_result
;
3180 if ((r
->in
.krb5ccname
== NULL
) || (strlen(r
->in
.krb5ccname
) == 0)) {
3181 result
= NT_STATUS_OK
;
3182 goto process_result
;
3187 if (user_uid
== (uid_t
)-1) {
3188 DBG_DEBUG("Invalid uid for user '%s'\n", r
->in
.user
);
3189 goto process_result
;
3192 /* what we need here is to find the corresponding krb5 ccache name *we*
3193 * created for a given username and destroy it */
3195 if (!ccache_entry_exists(r
->in
.user
)) {
3196 result
= NT_STATUS_OK
;
3197 DBG_DEBUG("No entry found for user '%s'.\n", r
->in
.user
);
3198 goto process_result
;
3201 if (!ccache_entry_identical(r
->in
.user
, user_uid
, r
->in
.krb5ccname
)) {
3202 DBG_DEBUG("Cached entry differs for user '%s'\n", r
->in
.user
);
3203 goto process_result
;
3206 result
= remove_ccache(r
->in
.user
);
3207 if (!NT_STATUS_IS_OK(result
)) {
3208 DBG_DEBUG("Failed to remove ccache for user '%s': %s\n",
3209 r
->in
.user
, nt_errstr(result
));
3210 goto process_result
;
3214 * Remove any mlock'ed memory creds in the child
3215 * we might be using for krb5 ticket renewal.
3218 winbindd_delete_memory_creds(r
->in
.user
);
3221 result
= NT_STATUS_NOT_SUPPORTED
;
3229 /* Change user password with auth crap*/
3231 NTSTATUS
_wbint_PamAuthCrapChangePassword(struct pipes_struct
*p
,
3232 struct wbint_PamAuthCrapChangePassword
*r
)
3235 char *namespace = NULL
;
3236 char *domain
= NULL
;
3238 struct policy_handle dom_pol
;
3239 struct winbindd_domain
*contact_domain
= wb_child_domain();
3240 struct rpc_pipe_client
*cli
= NULL
;
3241 struct dcerpc_binding_handle
*b
= NULL
;
3242 TALLOC_CTX
*frame
= talloc_stackframe();
3245 ZERO_STRUCT(dom_pol
);
3247 if (contact_domain
== NULL
) {
3248 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
3251 /* Cut client_pid to 32bit */
3252 client_pid
= r
->in
.client_pid
;
3253 if ((uint64_t)client_pid
!= r
->in
.client_pid
) {
3254 DBG_DEBUG("pid out of range\n");
3255 return NT_STATUS_INVALID_PARAMETER
;
3258 DBG_NOTICE("[%"PRIu32
"]: pam change pswd auth crap domain: %s "
3259 "user: %s\n", client_pid
, r
->in
.domain
, r
->in
.user
);
3261 if (lp_winbind_offline_logon()) {
3262 DEBUG(0,("Refusing password change as winbind offline logons are enabled. "));
3263 DEBUGADD(0,("Changing passwords here would risk inconsistent logons\n"));
3264 result
= NT_STATUS_ACCESS_DENIED
;
3268 if (r
->in
.domain
!= NULL
&& strlen(r
->in
.domain
) > 0) {
3269 user
= talloc_strdup(frame
, "");
3270 namespace = talloc_strdup(frame
, "");
3271 domain
= talloc_strdup(frame
, r
->in
.domain
);
3272 if (domain
== NULL
|| user
== NULL
|| namespace == NULL
) {
3273 result
= NT_STATUS_NO_MEMORY
;
3280 ok
= parse_domain_user(frame
,
3286 result
= NT_STATUS_INVALID_PARAMETER
;
3290 if (strlen(domain
) == 0) {
3291 DBG_NOTICE("no domain specified with username (%s) - "
3292 "failing auth\n", r
->in
.user
);
3293 result
= NT_STATUS_NO_SUCH_USER
;
3298 if (!*domain
&& lp_winbind_use_default_domain()) {
3299 TALLOC_FREE(domain
);
3300 domain
= talloc_strdup(frame
, lp_workgroup());
3301 if (domain
== NULL
) {
3302 result
= NT_STATUS_NO_MEMORY
;
3307 if (!is_allowed_domain(domain
)) {
3308 DBG_NOTICE("Authentication failed for user [%s] "
3309 "from firewalled domain [%s]\n",
3312 result
= NT_STATUS_AUTHENTICATION_FIREWALL_FAILED
;
3318 user
= talloc_strdup(frame
, r
->in
.user
);
3320 result
= NT_STATUS_NO_SUCH_USER
;
3325 /* Get sam handle */
3327 result
= cm_connect_sam(contact_domain
,
3332 if (!NT_STATUS_IS_OK(result
)) {
3333 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain
));
3337 b
= cli
->binding_handle
;
3339 result
= rpccli_samr_chng_pswd_auth_crap(cli
,
3343 r
->in
.old_nt_hash_enc
,
3345 r
->in
.old_lm_hash_enc
);
3349 if (strequal(contact_domain
->name
, get_global_sam_name())) {
3350 /* FIXME: internal rpc pipe does not cache handles yet */
3352 if (is_valid_policy_hnd(&dom_pol
)) {
3354 dcerpc_samr_Close(b
,
3363 DEBUG(NT_STATUS_IS_OK(result
) ? 5 : 2,
3364 ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
3367 nt_status_to_pam(result
)));
3373 static NTSTATUS
extract_pac_vrfy_sigs(TALLOC_CTX
*mem_ctx
, DATA_BLOB pac_blob
,
3374 struct PAC_DATA
**p_pac_data
)
3376 krb5_context krbctx
= NULL
;
3377 krb5_error_code k5ret
;
3379 krb5_kt_cursor cursor
;
3380 krb5_keytab_entry entry
;
3381 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
3384 ZERO_STRUCT(cursor
);
3386 k5ret
= smb_krb5_init_context_common(&krbctx
);
3388 DBG_ERR("kerberos init context failed (%s)\n",
3389 error_message(k5ret
));
3390 status
= krb5_to_nt_status(k5ret
);
3394 k5ret
= gse_krb5_get_server_keytab(krbctx
, &keytab
);
3396 DEBUG(1, ("Failed to get keytab: %s\n",
3397 error_message(k5ret
)));
3398 status
= krb5_to_nt_status(k5ret
);
3402 k5ret
= krb5_kt_start_seq_get(krbctx
, keytab
, &cursor
);
3404 DEBUG(1, ("Failed to start seq: %s\n",
3405 error_message(k5ret
)));
3406 status
= krb5_to_nt_status(k5ret
);
3410 k5ret
= krb5_kt_next_entry(krbctx
, keytab
, &entry
, &cursor
);
3411 while (k5ret
== 0) {
3412 status
= kerberos_decode_pac(mem_ctx
,
3415 NULL
, /* krbtgt_keyblock */
3416 KRB5_KT_KEY(&entry
), /* service_keyblock */
3417 NULL
, /* client_principal */
3418 0, /* tgs_authtime */
3420 (void)smb_krb5_kt_free_entry(krbctx
, &entry
);
3421 if (NT_STATUS_IS_OK(status
)) {
3424 k5ret
= krb5_kt_next_entry(krbctx
, keytab
, &entry
, &cursor
);
3426 if (k5ret
!= 0 && k5ret
!= KRB5_KT_END
) {
3427 DEBUG(1, ("Failed to get next entry: %s\n",
3428 error_message(k5ret
)));
3429 (void)smb_krb5_kt_free_entry(krbctx
, &entry
);
3432 k5ret
= krb5_kt_end_seq_get(krbctx
, keytab
, &cursor
);
3434 DEBUG(1, ("Failed to end seq: %s\n",
3435 error_message(k5ret
)));
3438 k5ret
= krb5_kt_close(krbctx
, keytab
);
3440 DEBUG(1, ("Failed to close keytab: %s\n",
3441 error_message(k5ret
)));
3444 krb5_free_context(krbctx
);
3449 NTSTATUS
winbindd_pam_auth_pac_verify(struct winbindd_cli_state
*state
,
3450 TALLOC_CTX
*mem_ctx
,
3452 uint16_t *p_validation_level
,
3453 union netr_Validation
**p_validation
)
3455 struct winbindd_request
*req
= state
->request
;
3457 struct PAC_DATA
*pac_data
= NULL
;
3458 struct PAC_LOGON_INFO
*logon_info
= NULL
;
3459 struct PAC_UPN_DNS_INFO
*upn_dns_info
= NULL
;
3460 struct netr_SamInfo6
*info6
= NULL
;
3461 uint16_t validation_level
= 0;
3462 union netr_Validation
*validation
= NULL
;
3463 struct netr_SamInfo3
*info3_copy
= NULL
;
3465 bool is_trusted
= false;
3467 TALLOC_CTX
*tmp_ctx
= NULL
;
3469 tmp_ctx
= talloc_new(mem_ctx
);
3470 if (tmp_ctx
== NULL
) {
3471 return NT_STATUS_NO_MEMORY
;
3474 *p_is_trusted
= false;
3475 *p_validation_level
= 0;
3476 *p_validation
= NULL
;
3478 pac_blob
= data_blob_const(req
->extra_data
.data
, req
->extra_len
);
3479 result
= extract_pac_vrfy_sigs(tmp_ctx
, pac_blob
, &pac_data
);
3480 if (NT_STATUS_IS_OK(result
)) {
3483 if (NT_STATUS_EQUAL(result
, NT_STATUS_ACCESS_DENIED
)) {
3484 /* Try without signature verification */
3485 result
= kerberos_decode_pac(tmp_ctx
,
3487 NULL
, /* krb5_context */
3488 NULL
, /* krbtgt_keyblock */
3489 NULL
, /* service_keyblock */
3490 NULL
, /* client_principal */
3491 0, /* tgs_authtime */
3494 if (!NT_STATUS_IS_OK(result
)) {
3495 DEBUG(1, ("Error during PAC signature verification: %s\n",
3496 nt_errstr(result
)));
3500 for (i
=0; i
< pac_data
->num_buffers
; i
++) {
3501 if (pac_data
->buffers
[i
].type
== PAC_TYPE_LOGON_INFO
) {
3502 logon_info
= pac_data
->buffers
[i
].info
->logon_info
.info
;
3505 if (pac_data
->buffers
[i
].type
== PAC_TYPE_UPN_DNS_INFO
) {
3506 upn_dns_info
= &pac_data
->buffers
[i
].info
->upn_dns_info
;
3511 result
= create_info6_from_pac(tmp_ctx
,
3515 if (!NT_STATUS_IS_OK(result
)) {
3519 if (!is_allowed_domain(info6
->base
.logon_domain
.string
)) {
3520 DBG_NOTICE("Authentication failed for user [%s] "
3521 "from firewalled domain [%s]\n",
3522 info6
->base
.account_name
.string
,
3523 info6
->base
.logon_domain
.string
);
3524 result
= NT_STATUS_AUTHENTICATION_FIREWALL_FAILED
;
3528 result
= map_info6_to_validation(tmp_ctx
,
3532 if (!NT_STATUS_IS_OK(result
)) {
3536 result
= map_validation_to_info3(tmp_ctx
,
3540 if (!NT_STATUS_IS_OK(result
)) {
3546 * Signature verification succeeded, we can
3547 * trust the PAC and prime the netsamlogon
3548 * and name2sid caches. DO NOT DO THIS
3549 * in the signature verification failed
3552 struct winbindd_domain
*domain
= NULL
;
3554 netsamlogon_cache_store(NULL
, info3_copy
);
3557 * We're in the parent here, so find the child
3558 * pointer from the PAC domain name.
3560 domain
= find_lookup_domain_from_name(
3561 info3_copy
->base
.logon_domain
.string
);
3562 if (domain
&& domain
->primary
) {
3563 struct dom_sid user_sid
;
3564 struct dom_sid_buf buf
;
3566 sid_compose(&user_sid
,
3567 info3_copy
->base
.domain_sid
,
3568 info3_copy
->base
.rid
);
3570 cache_name2sid_trusted(domain
,
3571 info3_copy
->base
.logon_domain
.string
,
3572 info3_copy
->base
.account_name
.string
,
3576 DBG_INFO("PAC for user %s\\%s SID %s primed cache\n",
3577 info3_copy
->base
.logon_domain
.string
,
3578 info3_copy
->base
.account_name
.string
,
3579 dom_sid_str_buf(&user_sid
, &buf
));
3583 *p_is_trusted
= is_trusted
;
3584 *p_validation_level
= validation_level
;
3585 *p_validation
= talloc_move(mem_ctx
, &validation
);
3587 result
= NT_STATUS_OK
;
3589 TALLOC_FREE(tmp_ctx
);
3592 #else /* HAVE_KRB5 */
3593 NTSTATUS
winbindd_pam_auth_pac_verify(struct winbindd_cli_state
*state
,
3594 TALLOC_CTX
*mem_ctx
,
3596 uint16_t *p_validation_level
,
3597 union netr_Validation
**p_validation
);
3600 *p_is_trusted
= false;
3601 *p_validation_level
= 0;
3602 *p_validation
= NULL
;
3603 return NT_STATUS_NO_SUCH_USER
;
3605 #endif /* HAVE_KRB5 */