2 Unix SMB/CIFS implementation.
4 Winbind daemon - pam auth funcions
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 */
460 token
= talloc_zero(talloc_tos(), struct security_token
);
462 DEBUG(0, ("talloc failed\n"));
463 return NT_STATUS_NO_MEMORY
;
466 status
= sid_array_from_info3(talloc_tos(), info3
,
470 if (!NT_STATUS_IS_OK(status
)) {
474 if (!NT_STATUS_IS_OK(status
= add_aliases(get_global_sam_sid(),
476 || !NT_STATUS_IS_OK(status
= add_aliases(&global_sid_Builtin
,
478 DEBUG(3, ("could not add aliases: %s\n",
483 security_token_debug(DBGC_CLASS
, 10, token
);
485 for (i
=0; i
<sid_array
->num_sids
; i
++) {
486 struct dom_sid_buf buf
;
487 DEBUG(10, ("Checking SID %s\n",
488 dom_sid_str_buf(&sid_array
->sids
[i
],
490 if (nt_token_check_sid(&sid_array
->sids
[i
],
492 DEBUG(10, ("Access ok\n"));
497 /* Do not distinguish this error from a wrong username/pw */
499 return NT_STATUS_LOGON_FAILURE
;
502 struct winbindd_domain
*find_auth_domain(uint8_t flags
,
503 const char *domain_name
)
505 struct winbindd_domain
*domain
;
508 domain
= find_domain_from_name_noinit(domain_name
);
509 if (domain
== NULL
) {
510 DEBUG(3, ("Authentication for domain [%s] refused "
511 "as it is not a trusted domain\n",
516 if (domain
->secure_channel_type
!= SEC_CHAN_NULL
) {
520 return domain
->routing_domain
;
523 if (strequal(domain_name
, get_global_sam_name())) {
524 return find_domain_from_name_noinit(domain_name
);
527 if (lp_winbind_use_krb5_enterprise_principals()) {
529 * If we use enterprise principals
530 * we always go trough our primary domain
531 * and follow the WRONG_REALM replies.
533 flags
&= ~WBFLAG_PAM_CONTACT_TRUSTDOM
;
536 /* we can auth against trusted domains */
537 if (flags
& WBFLAG_PAM_CONTACT_TRUSTDOM
) {
538 domain
= find_domain_from_name_noinit(domain_name
);
539 if (domain
== NULL
) {
540 DEBUG(3, ("Authentication for domain [%s] skipped "
541 "as it is not a trusted domain\n",
548 return find_our_domain();
551 static NTSTATUS
get_password_policy(struct winbindd_domain
*domain
,
553 struct samr_DomInfo1
**_policy
)
556 struct samr_DomInfo1
*policy
= NULL
;
558 if ( !winbindd_can_contact_domain( domain
) ) {
559 DBG_INFO("No inbound trust to contact domain %s\n",
561 return NT_STATUS_NOT_SUPPORTED
;
564 policy
= talloc_zero(mem_ctx
, struct samr_DomInfo1
);
565 if (policy
== NULL
) {
566 return NT_STATUS_NO_MEMORY
;
569 status
= wb_cache_password_policy(domain
, mem_ctx
, policy
);
570 if (NT_STATUS_IS_ERR(status
)) {
575 *_policy
= talloc_move(mem_ctx
, &policy
);
580 static NTSTATUS
get_max_bad_attempts_from_lockout_policy(struct winbindd_domain
*domain
,
582 uint16_t *lockout_threshold
)
584 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
585 struct samr_DomInfo12 lockout_policy
;
587 *lockout_threshold
= 0;
589 status
= wb_cache_lockout_policy(domain
, mem_ctx
, &lockout_policy
);
590 if (NT_STATUS_IS_ERR(status
)) {
594 *lockout_threshold
= lockout_policy
.lockout_threshold
;
599 static NTSTATUS
get_pwd_properties(struct winbindd_domain
*domain
,
601 uint32_t *password_properties
)
603 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
604 struct samr_DomInfo1 password_policy
;
606 *password_properties
= 0;
608 status
= wb_cache_password_policy(domain
, mem_ctx
, &password_policy
);
609 if (NT_STATUS_IS_ERR(status
)) {
613 *password_properties
= password_policy
.password_properties
;
620 static const char *generate_krb5_ccache(TALLOC_CTX
*mem_ctx
,
623 const char **user_ccache_file
)
625 /* accept FILE and WRFILE as krb5_cc_type from the client and then
626 * build the full ccname string based on the user's uid here -
629 const char *gen_cc
= NULL
;
632 if (strequal(type
, "FILE")) {
633 gen_cc
= talloc_asprintf(
634 mem_ctx
, "FILE:/tmp/krb5cc_%d", uid
);
636 if (strequal(type
, "WRFILE")) {
637 gen_cc
= talloc_asprintf(
638 mem_ctx
, "WRFILE:/tmp/krb5cc_%d", uid
);
640 if (strequal(type
, "KEYRING")) {
641 gen_cc
= talloc_asprintf(
642 mem_ctx
, "KEYRING:persistent:%d", uid
);
644 if (strequal(type
, "KCM")) {
645 gen_cc
= talloc_asprintf(mem_ctx
,
650 if (strnequal(type
, "FILE:/", 6) ||
651 strnequal(type
, "WRFILE:/", 8) ||
652 strnequal(type
, "DIR:/", 5)) {
654 /* we allow only one "%u" substitution */
658 p
= strchr(type
, '%');
663 if (p
!= NULL
&& *p
== 'u' && strchr(p
, '%') == NULL
) {
664 char uid_str
[sizeof("18446744073709551615")];
666 snprintf(uid_str
, sizeof(uid_str
), "%u", uid
);
668 gen_cc
= talloc_string_sub2(mem_ctx
,
672 /* remove_unsafe_characters */
676 /* allow_trailing_dollar */
683 *user_ccache_file
= gen_cc
;
685 if (gen_cc
== NULL
) {
686 gen_cc
= talloc_strdup(mem_ctx
, "MEMORY:winbindd_pam_ccache");
688 if (gen_cc
== NULL
) {
689 DEBUG(0,("out of memory\n"));
693 DEBUG(10, ("using ccache: %s%s\n", gen_cc
,
694 (*user_ccache_file
== NULL
) ? " (internal)":""));
701 uid_t
get_uid_from_request(struct winbindd_request
*request
)
705 uid
= request
->data
.auth
.uid
;
707 if (uid
== (uid_t
)-1) {
708 DEBUG(1,("invalid uid: '%u'\n", (unsigned int)uid
));
714 /**********************************************************************
715 Authenticate a user with a clear text password using Kerberos and fill up
717 **********************************************************************/
719 static NTSTATUS
winbindd_raw_kerberos_login(TALLOC_CTX
*mem_ctx
,
720 struct winbindd_domain
*domain
,
723 const char *krb5_cc_type
,
725 struct netr_SamInfo6
**info6
,
726 const char **_krb5ccname
)
729 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
730 krb5_error_code krb5_ret
;
731 const char *cc
= NULL
;
732 const char *principal_s
= NULL
;
734 fstring name_namespace
, name_domain
, name_user
;
735 time_t ticket_lifetime
= 0;
736 time_t renewal_until
= 0;
737 time_t time_offset
= 0;
738 const char *user_ccache_file
;
739 struct PAC_LOGON_INFO
*logon_info
= NULL
;
740 struct PAC_UPN_DNS_INFO
*upn_dns_info
= NULL
;
741 struct PAC_DATA
*pac_data
= NULL
;
742 struct PAC_DATA_CTR
*pac_data_ctr
= NULL
;
743 const char *local_service
;
745 struct netr_SamInfo6
*info6_copy
= NULL
;
746 char *canon_principal
= NULL
;
747 char *canon_realm
= NULL
;
752 if (domain
->alt_name
== NULL
) {
753 return NT_STATUS_INVALID_PARAMETER
;
756 if (_krb5ccname
!= NULL
) {
761 * prepare a krb5_cc_cache string for the user */
764 DEBUG(0,("no valid uid\n"));
767 cc
= generate_krb5_ccache(mem_ctx
,
772 return NT_STATUS_NO_MEMORY
;
777 * get kerberos properties */
779 if (domain
->backend_data
.ads_conn
!= NULL
) {
780 time_offset
= domain
->backend_data
.ads_conn
->auth
.time_offset
;
785 * do kerberos auth and setup ccache as the user */
787 ok
= parse_domain_user(user
, name_namespace
, name_domain
, name_user
);
789 return NT_STATUS_INVALID_PARAMETER
;
792 realm
= talloc_strdup(mem_ctx
, domain
->alt_name
);
794 return NT_STATUS_NO_MEMORY
;
797 if (!strupper_m(realm
)) {
798 return NT_STATUS_INVALID_PARAMETER
;
801 if (lp_winbind_use_krb5_enterprise_principals() &&
802 name_namespace
[0] != '\0')
804 principal_s
= talloc_asprintf(mem_ctx
,
810 principal_s
= talloc_asprintf(mem_ctx
,
815 if (principal_s
== NULL
) {
816 return NT_STATUS_NO_MEMORY
;
819 local_service
= talloc_asprintf(mem_ctx
, "%s$@%s",
820 lp_netbios_name(), lp_realm());
821 if (local_service
== NULL
) {
822 return NT_STATUS_NO_MEMORY
;
826 /* if this is a user ccache, we need to act as the user to let the krb5
827 * library handle the chown, etc. */
829 /************************ ENTERING NON-ROOT **********************/
831 if (user_ccache_file
!= NULL
) {
832 set_effective_uid(uid
);
833 DEBUG(10,("winbindd_raw_kerberos_login: uid is %d\n", uid
));
836 result
= kerberos_return_pac(mem_ctx
,
845 WINBINDD_PAM_AUTH_KRB5_RENEW_TIME
,
851 if (user_ccache_file
!= NULL
) {
852 gain_root_privilege();
855 /************************ RETURNED TO ROOT **********************/
857 if (!NT_STATUS_IS_OK(result
)) {
861 if (pac_data_ctr
== NULL
) {
865 pac_data
= pac_data_ctr
->pac_data
;
866 if (pac_data
== NULL
) {
870 for (i
=0; i
< pac_data
->num_buffers
; i
++) {
872 if (pac_data
->buffers
[i
].type
== PAC_TYPE_LOGON_INFO
) {
873 logon_info
= pac_data
->buffers
[i
].info
->logon_info
.info
;
877 if (pac_data
->buffers
[i
].type
== PAC_TYPE_UPN_DNS_INFO
) {
878 upn_dns_info
= &pac_data
->buffers
[i
].info
->upn_dns_info
;
883 if (logon_info
== NULL
) {
884 DEBUG(10,("Missing logon_info in ticket of %s\n",
886 return NT_STATUS_INVALID_PARAMETER
;
889 DEBUG(10,("winbindd_raw_kerberos_login: winbindd validated ticket of %s\n",
892 result
= create_info6_from_pac(mem_ctx
, logon_info
,
893 upn_dns_info
, &info6_copy
);
894 if (!NT_STATUS_IS_OK(result
)) {
898 /* if we had a user's ccache then return that string for the pam
901 if (user_ccache_file
!= NULL
) {
903 if (_krb5ccname
!= NULL
) {
904 *_krb5ccname
= talloc_steal(mem_ctx
, user_ccache_file
);
907 result
= add_ccache_to_list(principal_s
,
920 if (!NT_STATUS_IS_OK(result
)) {
921 DEBUG(10,("winbindd_raw_kerberos_login: failed to add ccache to list: %s\n",
926 /* need to delete the memory cred cache, it is not used anymore */
928 krb5_ret
= ads_kdestroy(cc
);
930 DEBUG(3,("winbindd_raw_kerberos_login: "
931 "could not destroy krb5 credential cache: "
932 "%s\n", error_message(krb5_ret
)));
941 * Do not delete an existing valid credential cache, if the user
942 * e.g. enters a wrong password
944 if ((strequal(krb5_cc_type
, "FILE") || strequal(krb5_cc_type
, "WRFILE"))
945 && user_ccache_file
!= NULL
) {
949 /* we could have created a new credential cache with a valid tgt in it
950 * but we werent able to get or verify the service ticket for this
951 * local host and therefor didn't get the PAC, we need to remove that
952 * cache entirely now */
954 krb5_ret
= ads_kdestroy(cc
);
956 DEBUG(3,("winbindd_raw_kerberos_login: "
957 "could not destroy krb5 credential cache: "
958 "%s\n", error_message(krb5_ret
)));
961 if (!NT_STATUS_IS_OK(remove_ccache(user
))) {
962 DEBUG(3,("winbindd_raw_kerberos_login: "
963 "could not remove ccache for user %s\n",
969 return NT_STATUS_NOT_SUPPORTED
;
970 #endif /* HAVE_KRB5 */
973 /****************************************************************
974 ****************************************************************/
976 bool check_request_flags(uint32_t flags
)
978 uint32_t flags_edata
= WBFLAG_PAM_AFS_TOKEN
|
979 WBFLAG_PAM_INFO3_TEXT
|
980 WBFLAG_PAM_INFO3_NDR
;
982 if ( ( (flags
& flags_edata
) == WBFLAG_PAM_AFS_TOKEN
) ||
983 ( (flags
& flags_edata
) == WBFLAG_PAM_INFO3_NDR
) ||
984 ( (flags
& flags_edata
) == WBFLAG_PAM_INFO3_TEXT
)||
985 !(flags
& flags_edata
) ) {
989 DEBUG(1, ("check_request_flags: invalid request flags[0x%08X]\n",
995 /****************************************************************
996 ****************************************************************/
998 NTSTATUS
append_auth_data(TALLOC_CTX
*mem_ctx
,
999 struct winbindd_response
*resp
,
1000 uint32_t request_flags
,
1001 uint16_t validation_level
,
1002 union netr_Validation
*validation
,
1003 const char *name_domain
,
1004 const char *name_user
)
1006 struct netr_SamInfo3
*info3
= NULL
;
1007 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
1009 result
= map_validation_to_info3(talloc_tos(),
1013 if (!NT_STATUS_IS_OK(result
)) {
1017 if (request_flags
& WBFLAG_PAM_USER_SESSION_KEY
) {
1018 memcpy(resp
->data
.auth
.user_session_key
,
1019 info3
->base
.key
.key
,
1020 sizeof(resp
->data
.auth
.user_session_key
)
1024 if (request_flags
& WBFLAG_PAM_LMKEY
) {
1025 memcpy(resp
->data
.auth
.first_8_lm_hash
,
1026 info3
->base
.LMSessKey
.key
,
1027 sizeof(resp
->data
.auth
.first_8_lm_hash
)
1031 if (request_flags
& WBFLAG_PAM_UNIX_NAME
) {
1032 char *unix_username
= NULL
;
1033 result
= append_unix_username(validation_level
,
1039 if (!NT_STATUS_IS_OK(result
)) {
1040 DEBUG(10,("Failed to append Unix Username: %s\n",
1041 nt_errstr(result
)));
1044 fstrcpy(resp
->data
.auth
.unix_username
, unix_username
);
1045 TALLOC_FREE(unix_username
);
1048 /* currently, anything from here on potentially overwrites extra_data. */
1050 if (request_flags
& WBFLAG_PAM_INFO3_NDR
) {
1051 result
= append_info3_as_ndr(mem_ctx
, resp
, info3
);
1052 if (!NT_STATUS_IS_OK(result
)) {
1053 DEBUG(10,("Failed to append INFO3 (NDR): %s\n",
1054 nt_errstr(result
)));
1059 if (request_flags
& WBFLAG_PAM_INFO3_TEXT
) {
1060 result
= append_info3_as_txt(mem_ctx
, resp
,
1063 if (!NT_STATUS_IS_OK(result
)) {
1064 DEBUG(10,("Failed to append INFO3 (TXT): %s\n",
1065 nt_errstr(result
)));
1070 if (request_flags
& WBFLAG_PAM_AFS_TOKEN
) {
1071 DATA_BLOB blob
= data_blob_null
;
1072 result
= append_afs_token(validation_level
,
1078 if (!NT_STATUS_IS_OK(result
)) {
1079 DEBUG(10,("Failed to append AFS token: %s\n",
1080 nt_errstr(result
)));
1083 resp
->extra_data
.data
= blob
.data
;
1084 resp
->length
+= blob
.length
;
1087 result
= NT_STATUS_OK
;
1093 static NTSTATUS
winbindd_dual_pam_auth_cached(struct winbindd_domain
*domain
,
1097 const char *krb5_cc_type
,
1099 TALLOC_CTX
*mem_ctx
,
1100 uint16_t *_validation_level
,
1101 union netr_Validation
**_validation
,
1102 const char **_krb5ccname
)
1104 TALLOC_CTX
*tmp_ctx
= NULL
;
1105 NTSTATUS result
= NT_STATUS_LOGON_FAILURE
;
1106 uint16_t max_allowed_bad_attempts
;
1107 fstring name_namespace
, name_domain
, name_user
;
1109 enum lsa_SidType type
;
1110 uchar new_nt_pass
[NT_HASH_LEN
];
1111 const uint8_t *cached_nt_pass
;
1112 const uint8_t *cached_salt
;
1113 struct netr_SamInfo3
*my_info3
;
1114 time_t kickoff_time
, must_change_time
;
1115 bool password_good
= false;
1118 struct winbindd_tdc_domain
*tdc_domain
= NULL
;
1121 if (_validation
== NULL
) {
1122 return NT_STATUS_INVALID_PARAMETER
;
1124 *_validation
= NULL
;
1126 if (_krb5ccname
!= NULL
) {
1127 *_krb5ccname
= NULL
;
1130 DEBUG(10,("winbindd_dual_pam_auth_cached\n"));
1132 tmp_ctx
= talloc_new(mem_ctx
);
1133 if (tmp_ctx
== NULL
) {
1134 return NT_STATUS_NO_MEMORY
;
1137 /* Parse domain and username */
1139 ok
= parse_domain_user(user
, name_namespace
, name_domain
, name_user
);
1141 DBG_DEBUG("parse_domain_user failed\n");
1142 result
= NT_STATUS_NO_SUCH_USER
;
1146 if (!lookup_cached_name(name_namespace
,
1151 DEBUG(10,("winbindd_dual_pam_auth_cached: no such user in the cache\n"));
1152 result
= NT_STATUS_NO_SUCH_USER
;
1156 if (type
!= SID_NAME_USER
) {
1157 DEBUG(10,("winbindd_dual_pam_auth_cached: not a user (%s)\n", sid_type_lookup(type
)));
1158 result
= NT_STATUS_LOGON_FAILURE
;
1162 result
= winbindd_get_creds(domain
,
1168 if (!NT_STATUS_IS_OK(result
)) {
1169 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get creds: %s\n", nt_errstr(result
)));
1173 E_md4hash(pass
, new_nt_pass
);
1175 dump_data_pw("new_nt_pass", new_nt_pass
, NT_HASH_LEN
);
1176 dump_data_pw("cached_nt_pass", cached_nt_pass
, NT_HASH_LEN
);
1178 dump_data_pw("cached_salt", cached_salt
, NT_HASH_LEN
);
1182 /* In this case we didn't store the nt_hash itself,
1183 but the MD5 combination of salt + nt_hash. */
1184 uchar salted_hash
[NT_HASH_LEN
];
1185 gnutls_hash_hd_t hash_hnd
= NULL
;
1188 rc
= gnutls_hash_init(&hash_hnd
, GNUTLS_DIG_MD5
);
1190 result
= gnutls_error_to_ntstatus(
1191 rc
, NT_STATUS_HASH_NOT_SUPPORTED
);
1195 rc
= gnutls_hash(hash_hnd
, cached_salt
, 16);
1197 gnutls_hash_deinit(hash_hnd
, NULL
);
1198 result
= gnutls_error_to_ntstatus(
1199 rc
, NT_STATUS_HASH_NOT_SUPPORTED
);
1202 rc
= gnutls_hash(hash_hnd
, new_nt_pass
, 16);
1204 gnutls_hash_deinit(hash_hnd
, NULL
);
1205 result
= gnutls_error_to_ntstatus(
1206 rc
, NT_STATUS_HASH_NOT_SUPPORTED
);
1209 gnutls_hash_deinit(hash_hnd
, salted_hash
);
1211 password_good
= mem_equal_const_time(cached_nt_pass
, salted_hash
,
1214 /* Old cached cred - direct store of nt_hash (bad bad bad !). */
1215 password_good
= mem_equal_const_time(cached_nt_pass
, new_nt_pass
,
1219 if (password_good
) {
1221 /* User *DOES* know the password, update logon_time and reset
1224 my_info3
->base
.user_flags
|= NETLOGON_CACHED_ACCOUNT
;
1226 if (my_info3
->base
.acct_flags
& ACB_AUTOLOCK
) {
1227 result
= NT_STATUS_ACCOUNT_LOCKED_OUT
;
1231 if (my_info3
->base
.acct_flags
& ACB_DISABLED
) {
1232 result
= NT_STATUS_ACCOUNT_DISABLED
;
1236 if (my_info3
->base
.acct_flags
& ACB_WSTRUST
) {
1237 result
= NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT
;
1241 if (my_info3
->base
.acct_flags
& ACB_SVRTRUST
) {
1242 result
= NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT
;
1246 if (my_info3
->base
.acct_flags
& ACB_DOMTRUST
) {
1247 result
= NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT
;
1251 if (!(my_info3
->base
.acct_flags
& ACB_NORMAL
)) {
1252 DEBUG(0,("winbindd_dual_pam_auth_cached: whats wrong with that one?: 0x%08x\n",
1253 my_info3
->base
.acct_flags
));
1254 result
= NT_STATUS_LOGON_FAILURE
;
1258 kickoff_time
= nt_time_to_unix(my_info3
->base
.kickoff_time
);
1259 if (kickoff_time
!= 0 && time(NULL
) > kickoff_time
) {
1260 result
= NT_STATUS_ACCOUNT_EXPIRED
;
1264 must_change_time
= nt_time_to_unix(my_info3
->base
.force_password_change
);
1265 if (must_change_time
!= 0 && must_change_time
< time(NULL
)) {
1266 /* we allow grace logons when the password has expired */
1267 my_info3
->base
.user_flags
|= NETLOGON_GRACE_LOGON
;
1268 /* return NT_STATUS_PASSWORD_EXPIRED; */
1274 ((tdc_domain
= wcache_tdc_fetch_domain(tmp_ctx
, name_domain
)) != NULL
) &&
1275 ((tdc_domain
->trust_type
& LSA_TRUST_TYPE_UPLEVEL
) ||
1276 /* used to cope with the case winbindd starting without network. */
1277 !strequal(tdc_domain
->domain_name
, tdc_domain
->dns_name
))) {
1278 const char *cc
= NULL
;
1280 const char *principal_s
= NULL
;
1281 const char *user_ccache_file
;
1283 if (domain
->alt_name
== NULL
) {
1284 result
= NT_STATUS_INVALID_PARAMETER
;
1289 DEBUG(0,("winbindd_dual_pam_auth_cached: invalid uid\n"));
1290 result
= NT_STATUS_INVALID_PARAMETER
;
1294 cc
= generate_krb5_ccache(tmp_ctx
,
1299 result
= NT_STATUS_NO_MEMORY
;
1303 realm
= talloc_strdup(tmp_ctx
, domain
->alt_name
);
1304 if (realm
== NULL
) {
1305 result
= NT_STATUS_NO_MEMORY
;
1309 if (!strupper_m(realm
)) {
1310 result
= NT_STATUS_INVALID_PARAMETER
;
1314 principal_s
= talloc_asprintf(tmp_ctx
, "%s@%s", name_user
, realm
);
1315 if (principal_s
== NULL
) {
1316 result
= NT_STATUS_NO_MEMORY
;
1320 if (user_ccache_file
!= NULL
) {
1322 if (_krb5ccname
!= NULL
) {
1323 *_krb5ccname
= talloc_move(mem_ctx
,
1327 result
= add_ccache_to_list(principal_s
,
1334 time(NULL
) + lp_winbind_cache_time(),
1335 time(NULL
) + WINBINDD_PAM_AUTH_KRB5_RENEW_TIME
,
1340 if (!NT_STATUS_IS_OK(result
)) {
1341 DEBUG(10,("winbindd_dual_pam_auth_cached: failed "
1342 "to add ccache to list: %s\n",
1343 nt_errstr(result
)));
1347 #endif /* HAVE_KRB5 */
1349 /* FIXME: we possibly should handle logon hours as well (does xp when
1350 * offline?) see auth/auth_sam.c:sam_account_ok for details */
1352 unix_to_nt_time(&my_info3
->base
.logon_time
, time(NULL
));
1353 my_info3
->base
.bad_password_count
= 0;
1355 result
= winbindd_update_creds_by_info3(domain
,
1359 if (!NT_STATUS_IS_OK(result
)) {
1360 DEBUG(1,("winbindd_dual_pam_auth_cached: failed to update creds: %s\n",
1361 nt_errstr(result
)));
1365 result
= map_info3_to_validation(mem_ctx
,
1369 if (!NT_STATUS_IS_OK(result
)) {
1370 DBG_ERR("map_info3_to_validation failed: %s\n",
1375 result
= NT_STATUS_OK
;
1379 /* User does *NOT* know the correct password, modify info3 accordingly, but only if online */
1380 if (domain
->online
== false) {
1384 /* failure of this is not critical */
1385 result
= get_max_bad_attempts_from_lockout_policy(domain
, tmp_ctx
, &max_allowed_bad_attempts
);
1386 if (!NT_STATUS_IS_OK(result
)) {
1387 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get max_allowed_bad_attempts. "
1388 "Won't be able to honour account lockout policies\n"));
1391 /* increase counter */
1392 my_info3
->base
.bad_password_count
++;
1394 if (max_allowed_bad_attempts
== 0) {
1399 if (my_info3
->base
.bad_password_count
>= max_allowed_bad_attempts
) {
1401 uint32_t password_properties
;
1403 result
= get_pwd_properties(domain
, tmp_ctx
, &password_properties
);
1404 if (!NT_STATUS_IS_OK(result
)) {
1405 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get password properties.\n"));
1408 if ((my_info3
->base
.rid
!= DOMAIN_RID_ADMINISTRATOR
) ||
1409 (password_properties
& DOMAIN_PASSWORD_LOCKOUT_ADMINS
)) {
1410 my_info3
->base
.acct_flags
|= ACB_AUTOLOCK
;
1415 result
= winbindd_update_creds_by_info3(domain
, user
, NULL
, my_info3
);
1416 if (!NT_STATUS_IS_OK(result
)) {
1417 DEBUG(0,("winbindd_dual_pam_auth_cached: failed to update creds %s\n",
1418 nt_errstr(result
)));
1421 result
= NT_STATUS_LOGON_FAILURE
;
1424 TALLOC_FREE(tmp_ctx
);
1429 static NTSTATUS
winbindd_dual_pam_auth_kerberos(struct winbindd_domain
*domain
,
1432 const char *krb5_cc_type
,
1434 TALLOC_CTX
*mem_ctx
,
1435 uint16_t *_validation_level
,
1436 union netr_Validation
**_validation
,
1437 const char **_krb5ccname
)
1439 struct netr_SamInfo6
*info6
= NULL
;
1440 struct winbindd_domain
*contact_domain
;
1441 fstring name_namespace
, name_domain
, name_user
;
1445 DEBUG(10,("winbindd_dual_pam_auth_kerberos\n"));
1447 /* Parse domain and username */
1449 ok
= parse_domain_user(user
,
1454 result
= NT_STATUS_INVALID_PARAMETER
;
1458 /* what domain should we contact? */
1460 if (lp_winbind_use_krb5_enterprise_principals()) {
1461 contact_domain
= find_auth_domain(0, name_namespace
);
1463 contact_domain
= find_domain_from_name(name_namespace
);
1465 if (contact_domain
== NULL
) {
1466 DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
1467 user
, name_domain
, name_user
, name_namespace
));
1468 result
= NT_STATUS_NO_SUCH_USER
;
1472 if (contact_domain
->initialized
&&
1473 contact_domain
->active_directory
) {
1477 if (!contact_domain
->initialized
) {
1478 init_dc_connection(contact_domain
, false);
1481 if (!contact_domain
->active_directory
) {
1482 DEBUG(3,("krb5 auth requested but domain (%s) is not Active Directory\n",
1483 contact_domain
->name
));
1484 return NT_STATUS_INVALID_LOGON_TYPE
;
1487 result
= winbindd_raw_kerberos_login(
1496 if (!NT_STATUS_IS_OK(result
)) {
1500 result
= map_info6_to_validation(mem_ctx
,
1505 if (!NT_STATUS_IS_OK(result
)) {
1506 DBG_ERR("map_info6_to_validation failed: %s\n",
1514 static NTSTATUS
winbindd_dual_auth_passdb(TALLOC_CTX
*mem_ctx
,
1515 uint32_t logon_parameters
,
1518 const uint64_t logon_id
,
1519 const char *client_name
,
1520 const int client_pid
,
1521 const DATA_BLOB
*challenge
,
1522 const DATA_BLOB
*lm_resp
,
1523 const DATA_BLOB
*nt_resp
,
1524 const struct tsocket_address
*remote
,
1525 const struct tsocket_address
*local
,
1527 uint8_t *pauthoritative
,
1528 struct netr_SamInfo3
**pinfo3
)
1530 struct auth_context
*auth_context
;
1531 struct auth_serversupplied_info
*server_info
;
1532 struct auth_usersupplied_info
*user_info
= NULL
;
1533 struct netr_SamInfo3
*info3
;
1536 TALLOC_CTX
*frame
= talloc_stackframe();
1539 * We are authoritative by default
1541 *pauthoritative
= 1;
1543 status
= make_user_info(frame
, &user_info
, user
, user
, domain
, domain
,
1544 lp_netbios_name(), remote
, local
,
1546 lm_resp
, nt_resp
, NULL
, NULL
,
1547 NULL
, AUTH_PASSWORD_RESPONSE
);
1548 if (!NT_STATUS_IS_OK(status
)) {
1549 DEBUG(10, ("make_user_info failed: %s\n", nt_errstr(status
)));
1554 user_info
->logon_parameters
= logon_parameters
;
1555 user_info
->logon_id
= logon_id
;
1556 user_info
->auth_description
= talloc_asprintf(
1557 frame
, "PASSDB, %s, %d", client_name
, client_pid
);
1558 if (user_info
->auth_description
== NULL
) {
1560 return NT_STATUS_NO_MEMORY
;
1563 /* We don't want to come back to winbindd or to do PAM account checks */
1564 user_info
->flags
|= USER_INFO_INFO3_AND_NO_AUTHZ
;
1567 user_info
->flags
|= USER_INFO_INTERACTIVE_LOGON
;
1570 status
= make_auth3_context_for_winbind(frame
, &auth_context
);
1571 if (!NT_STATUS_IS_OK(status
)) {
1572 DBG_ERR("make_auth3_context_for_winbind failed: %s\n",
1578 ok
= auth3_context_set_challenge(auth_context
,
1579 challenge
->data
, "fixed");
1582 return NT_STATUS_NO_MEMORY
;
1585 status
= auth_check_ntlm_password(mem_ctx
,
1590 if (!NT_STATUS_IS_OK(status
)) {
1595 info3
= talloc_zero(mem_ctx
, struct netr_SamInfo3
);
1596 if (info3
== NULL
) {
1598 return NT_STATUS_NO_MEMORY
;
1601 status
= serverinfo_to_SamInfo3(server_info
, info3
);
1602 if (!NT_STATUS_IS_OK(status
)) {
1605 DEBUG(0, ("serverinfo_to_SamInfo3 failed: %s\n",
1606 nt_errstr(status
)));
1611 DBG_DEBUG("Authenticating user %s\\%s returned %s\n",
1619 static NTSTATUS
winbind_samlogon_retry_loop(struct winbindd_domain
*domain
,
1620 TALLOC_CTX
*mem_ctx
,
1621 uint32_t logon_parameters
,
1622 const char *username
,
1623 const char *password
,
1624 const char *domainname
,
1625 const char *workstation
,
1626 const uint64_t logon_id
,
1627 bool plaintext_given
,
1629 DATA_BLOB lm_response
,
1630 DATA_BLOB nt_response
,
1632 uint8_t *authoritative
,
1634 uint16_t *_validation_level
,
1635 union netr_Validation
**_validation
)
1638 int netr_attempts
= 0;
1641 enum netr_LogonInfoClass logon_type_i
;
1642 enum netr_LogonInfoClass logon_type_n
;
1643 uint16_t validation_level
= UINT16_MAX
;
1644 union netr_Validation
*validation
= NULL
;
1645 TALLOC_CTX
*base_ctx
= NULL
;
1646 struct netr_SamBaseInfo
*base_info
= NULL
;
1649 struct rpc_pipe_client
*netlogon_pipe
;
1650 struct netlogon_creds_cli_context
*netlogon_creds_ctx
= NULL
;
1654 result
= cm_connect_netlogon_secure(domain
, &netlogon_pipe
,
1655 &netlogon_creds_ctx
);
1657 if (NT_STATUS_EQUAL(result
,
1658 NT_STATUS_CANT_ACCESS_DOMAIN_INFO
)) {
1660 * This means we don't have a trust account.
1663 result
= NT_STATUS_NO_SUCH_USER
;
1667 if (!NT_STATUS_IS_OK(result
)) {
1668 DEBUG(3,("Could not open handle to NETLOGON pipe "
1669 "(error: %s, attempts: %d)\n",
1670 nt_errstr(result
), netr_attempts
));
1672 /* After the first retry always close the connection */
1673 if (netr_attempts
> 0) {
1674 DEBUG(3, ("This is again a problem for this "
1675 "particular call, forcing the close "
1676 "of this connection\n"));
1677 invalidate_cm_connection(domain
);
1680 /* After the second retry failover to the next DC */
1681 if (netr_attempts
> 1) {
1683 * If the netlogon server is not reachable then
1684 * it is possible that the DC is rebuilding
1685 * sysvol and shutdown netlogon for that time.
1686 * We should failover to the next dc.
1688 DEBUG(3, ("This is the third problem for this "
1689 "particular call, adding DC to the "
1690 "negative cache list: %s %s\n", domain
->name
, domain
->dcname
));
1691 add_failed_connection_entry(domain
->name
,
1694 saf_delete(domain
->name
);
1697 /* Only allow 3 retries */
1698 if (netr_attempts
< 3) {
1699 DEBUG(3, ("The connection to netlogon "
1700 "failed, retrying\n"));
1708 logon_type_i
= NetlogonInteractiveInformation
;
1709 logon_type_n
= NetlogonNetworkInformation
;
1710 if (domain
->domain_trust_attribs
& LSA_TRUST_ATTRIBUTE_WITHIN_FOREST
) {
1711 logon_type_i
= NetlogonInteractiveTransitiveInformation
;
1712 logon_type_n
= NetlogonNetworkTransitiveInformation
;
1715 if (domain
->domain_trust_attribs
& LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE
) {
1716 logon_type_i
= NetlogonInteractiveTransitiveInformation
;
1717 logon_type_n
= NetlogonNetworkTransitiveInformation
;
1720 if (domain
->domain_trust_attribs
& LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE
) {
1721 logon_type_i
= NetlogonInteractiveInformation
;
1722 logon_type_n
= NetlogonNetworkInformation
;
1725 if (domain
->domain_trust_attribs
& LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN
) {
1726 logon_type_i
= NetlogonInteractiveInformation
;
1727 logon_type_n
= NetlogonNetworkInformation
;
1731 if (plaintext_given
) {
1732 result
= rpccli_netlogon_password_logon(
1734 netlogon_pipe
->binding_handle
,
1747 } else if (interactive
) {
1748 result
= rpccli_netlogon_interactive_logon(
1750 netlogon_pipe
->binding_handle
,
1765 result
= rpccli_netlogon_network_logon(
1767 netlogon_pipe
->binding_handle
,
1785 * we increment this after the "feature negotiation"
1786 * for can_do_samlogon_ex and can_do_validation6
1790 /* We have to try a second time as cm_connect_netlogon
1791 might not yet have noticed that the DC has killed
1794 if (!rpccli_is_connected(netlogon_pipe
)) {
1799 /* if we get access denied, a possible cause was that we had
1800 an open connection to the DC, but someone changed our
1801 machine account password out from underneath us using 'net
1802 rpc changetrustpw' */
1804 if ( NT_STATUS_EQUAL(result
, NT_STATUS_ACCESS_DENIED
) ) {
1805 DEBUG(1,("winbind_samlogon_retry_loop: sam_logon returned "
1806 "ACCESS_DENIED. Maybe the DC has Restrict "
1807 "NTLM set or the trust account "
1808 "password was changed and we didn't know it. "
1809 "Killing connections to domain %s\n",
1811 invalidate_cm_connection(domain
);
1815 if (NT_STATUS_EQUAL(result
, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
)) {
1817 * Got DCERPC_FAULT_OP_RNG_ERROR for SamLogon
1818 * (no Ex). This happens against old Samba
1819 * DCs, if LogonSamLogonEx() fails with an error
1820 * e.g. NT_STATUS_NO_SUCH_USER or NT_STATUS_WRONG_PASSWORD.
1822 * The server will log something like this:
1823 * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
1825 * This sets the whole connection into a fault_state mode
1826 * and all following request get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
1828 * This also happens to our retry with LogonSamLogonWithFlags()
1829 * and LogonSamLogon().
1831 * In order to recover from this situation, we need to
1832 * drop the connection.
1834 invalidate_cm_connection(domain
);
1835 result
= NT_STATUS_LOGON_FAILURE
;
1839 } while ( (attempts
< 2) && retry
);
1841 if (NT_STATUS_EQUAL(result
, NT_STATUS_IO_TIMEOUT
)) {
1842 DEBUG(3,("winbind_samlogon_retry_loop: sam_network_logon(ex) "
1843 "returned NT_STATUS_IO_TIMEOUT after the retry. "
1844 "Killing connections to domain %s\n",
1846 invalidate_cm_connection(domain
);
1849 if (!NT_STATUS_IS_OK(result
)) {
1853 switch (validation_level
) {
1855 base_ctx
= validation
->sam3
;
1856 base_info
= &validation
->sam3
->base
;
1859 base_ctx
= validation
->sam6
;
1860 base_info
= &validation
->sam6
->base
;
1863 smb_panic(__location__
);
1866 if (base_info
->acct_flags
== 0 || base_info
->account_name
.string
== NULL
) {
1867 struct dom_sid user_sid
;
1868 struct dom_sid_buf sid_buf
;
1869 const char *acct_flags_src
= "server";
1870 const char *acct_name_src
= "server";
1873 * Handle the case where a NT4 DC does not fill in the acct_flags in
1874 * the samlogon reply info3. Yes, in 2021, there are still admins
1875 * arround with real NT4 DCs.
1877 * We used to call dcerpc_samr_QueryUserInfo(level=16) to fetch
1878 * acct_flags, but as NT4 DCs reject authentication with workstation
1879 * accounts with NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT, even if
1880 * MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT is specified, we only ever got
1881 * ACB_NORMAL back (maybe with ACB_PWNOEXP in addition).
1883 * For network logons NT4 DCs also skip the
1884 * account_name, so we have to fallback to the
1885 * one given by the client.
1888 if (base_info
->acct_flags
== 0) {
1889 base_info
->acct_flags
= ACB_NORMAL
;
1890 if (base_info
->force_password_change
== NTTIME_MAX
) {
1891 base_info
->acct_flags
|= ACB_PWNOEXP
;
1893 acct_flags_src
= "calculated";
1896 if (base_info
->account_name
.string
== NULL
) {
1897 base_info
->account_name
.string
= talloc_strdup(base_ctx
,
1899 if (base_info
->account_name
.string
== NULL
) {
1900 TALLOC_FREE(validation
);
1901 return NT_STATUS_NO_MEMORY
;
1903 acct_name_src
= "client";
1906 sid_compose(&user_sid
, base_info
->domain_sid
, base_info
->rid
);
1908 DBG_DEBUG("Fallback to %s_acct_flags[0x%x] %s_acct_name[%s] for %s\n",
1910 base_info
->acct_flags
,
1912 base_info
->account_name
.string
,
1913 dom_sid_str_buf(&user_sid
, &sid_buf
));
1916 *_validation_level
= validation_level
;
1917 *_validation
= validation
;
1918 return NT_STATUS_OK
;
1921 static NTSTATUS
nt_dual_auth_passdb(TALLOC_CTX
*mem_ctx
,
1923 fstring name_domain
,
1926 const char *client_name
,
1927 const int client_pid
,
1928 const struct tsocket_address
*remote
,
1929 const struct tsocket_address
*local
,
1930 uint8_t *authoritative
,
1931 struct netr_SamInfo3
**info3
)
1933 unsigned char local_nt_response
[24];
1935 DATA_BLOB chal_blob
;
1939 /* do password magic */
1941 generate_random_buffer(chal
, sizeof(chal
));
1942 chal_blob
= data_blob_const(chal
, sizeof(chal
));
1944 if (lp_client_ntlmv2_auth()) {
1945 DATA_BLOB server_chal
;
1946 DATA_BLOB names_blob
;
1947 server_chal
= data_blob_const(chal
, 8);
1949 /* note that the 'workgroup' here is for the local
1950 machine. The 'server name' must match the
1951 'workstation' passed to the actual SamLogon call.
1953 names_blob
= NTLMv2_generate_names_blob(mem_ctx
,
1957 if (!SMBNTLMv2encrypt(mem_ctx
, name_user
, name_domain
,
1958 pass
, &server_chal
, &names_blob
,
1959 &lm_resp
, &nt_resp
, NULL
, NULL
)) {
1960 data_blob_free(&names_blob
);
1961 DEBUG(0, ("SMBNTLMv2encrypt() failed!\n"));
1962 return NT_STATUS_NO_MEMORY
;
1964 data_blob_free(&names_blob
);
1967 lm_resp
= data_blob_null
;
1969 rc
= SMBNTencrypt(pass
, chal
, local_nt_response
);
1971 DEBUG(0, ("SMBNTencrypt() failed!\n"));
1972 return gnutls_error_to_ntstatus(rc
,
1973 NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER
);
1976 nt_resp
= data_blob_talloc(mem_ctx
, local_nt_response
,
1977 sizeof(local_nt_response
));
1980 return winbindd_dual_auth_passdb(talloc_tos(), 0, name_domain
,
1981 name_user
, logon_id
, client_name
,
1982 client_pid
, &chal_blob
, &lm_resp
,
1983 &nt_resp
, remote
, local
,
1984 true, /* interactive */
1985 authoritative
, info3
);
1988 static NTSTATUS
winbindd_dual_pam_auth_samlogon(
1989 TALLOC_CTX
*mem_ctx
,
1990 struct winbindd_domain
*domain
,
1994 const char *client_name
,
1995 const int client_pid
,
1996 uint32_t request_flags
,
1997 const struct tsocket_address
*remote
,
1998 const struct tsocket_address
*local
,
1999 uint16_t *_validation_level
,
2000 union netr_Validation
**_validation
)
2002 fstring name_namespace
, name_domain
, name_user
;
2004 uint8_t authoritative
= 1;
2006 uint16_t validation_level
= 0;
2007 union netr_Validation
*validation
= NULL
;
2010 DEBUG(10,("winbindd_dual_pam_auth_samlogon\n"));
2012 /* Parse domain and username */
2014 ok
= parse_domain_user(user
, name_namespace
, name_domain
, name_user
);
2016 return NT_STATUS_INVALID_PARAMETER
;
2020 * We check against domain->name instead of
2021 * name_domain, as find_auth_domain() ->
2022 * find_domain_from_name_noinit() already decided
2023 * that we are in a child for the correct domain.
2025 * name_domain can also be lp_realm()
2026 * we need to check against domain->name.
2028 if (strequal(domain
->name
, get_global_sam_name())) {
2029 struct netr_SamInfo3
*info3
= NULL
;
2031 result
= nt_dual_auth_passdb(mem_ctx
, name_user
, name_domain
,
2032 pass
, logon_id
, client_name
,
2033 client_pid
, remote
, local
,
2034 &authoritative
, &info3
);
2037 * We need to try the remote NETLOGON server if this is
2038 * not authoritative (for example on the RODC).
2040 if (authoritative
!= 0) {
2041 if (!NT_STATUS_IS_OK(result
)) {
2044 result
= map_info3_to_validation(mem_ctx
,
2049 if (!NT_STATUS_IS_OK(result
)) {
2057 /* check authentication loop */
2059 result
= winbind_samlogon_retry_loop(domain
,
2067 true, /* plaintext_given */
2069 data_blob_null
, data_blob_null
,
2070 true, /* interactive */
2075 if (!NT_STATUS_IS_OK(result
)) {
2080 *_validation_level
= validation_level
;
2081 *_validation
= validation
;
2083 return NT_STATUS_OK
;
2087 * @brief generate an authentication message in the logs.
2090 static void log_authentication(
2091 TALLOC_CTX
*mem_ctx
,
2092 const struct winbindd_domain
*domain
,
2093 const char *client_name
,
2095 uint16_t validation_level
,
2096 union netr_Validation
*validation
,
2097 const struct timeval start_time
,
2098 const uint64_t logon_id
,
2099 const char *command
,
2100 const char *user_name
,
2101 const char *domain_name
,
2102 const char *workstation
,
2103 const DATA_BLOB lm_resp
,
2104 const DATA_BLOB nt_resp
,
2105 const struct tsocket_address
*remote
,
2106 const struct tsocket_address
*local
,
2109 struct auth_usersupplied_info
*ui
= NULL
;
2110 struct dom_sid
*sid
= NULL
;
2111 struct loadparm_context
*lp_ctx
= NULL
;
2112 struct imessaging_context
*msg_ctx
= NULL
;
2113 struct netr_SamBaseInfo
*base_info
= NULL
;
2115 if (validation
!= NULL
) {
2116 switch (validation_level
) {
2118 base_info
= &validation
->sam3
->base
;
2121 base_info
= &validation
->sam6
->base
;
2124 DBG_WARNING("Unexpected validation level '%d'\n",
2130 ui
= talloc_zero(mem_ctx
, struct auth_usersupplied_info
);
2131 ui
->logon_id
= logon_id
;
2132 ui
->service_description
= "winbind";
2133 ui
->password
.response
.nt
.length
= nt_resp
.length
;
2134 ui
->password
.response
.nt
.data
= nt_resp
.data
;
2135 ui
->password
.response
.lanman
.length
= lm_resp
.length
;
2136 ui
->password
.response
.lanman
.data
= lm_resp
.data
;
2137 if (nt_resp
.length
== 0 && lm_resp
.length
== 0) {
2138 ui
->password_state
= AUTH_PASSWORD_PLAIN
;
2140 ui
->password_state
= AUTH_PASSWORD_RESPONSE
;
2143 * In the event of a failure ui->auth_description will be null,
2144 * the logging code handles this correctly so it can be ignored.
2146 ui
->auth_description
= talloc_asprintf(
2152 if (ui
->auth_description
== NULL
) {
2153 DBG_ERR("OOM Unable to create auth_description");
2155 ui
->client
.account_name
= user_name
;
2156 ui
->client
.domain_name
= domain_name
;
2157 ui
->workstation_name
= workstation
;
2158 ui
->remote_host
= remote
;
2159 ui
->local_host
= local
;
2161 if (base_info
!= NULL
) {
2162 sid
= dom_sid_dup(ui
, base_info
->domain_sid
);
2164 sid_append_rid(sid
, base_info
->rid
);
2168 if (lp_auth_event_notification()) {
2169 lp_ctx
= loadparm_init_s3(ui
, loadparm_s3_helpers());
2170 msg_ctx
= imessaging_client_init(
2171 ui
, lp_ctx
, global_event_context());
2173 log_authentication_event(
2179 base_info
!= NULL
? base_info
->logon_domain
.string
: "",
2180 base_info
!= NULL
? base_info
->account_name
.string
: "",
2185 NTSTATUS
_wbint_PamAuth(struct pipes_struct
*p
,
2186 struct wbint_PamAuth
*r
)
2188 struct winbindd_domain
*domain
= wb_child_domain();
2189 NTSTATUS result
= NT_STATUS_LOGON_FAILURE
;
2190 NTSTATUS krb5_result
= NT_STATUS_OK
;
2191 fstring name_namespace
, name_domain
, name_user
;
2192 char *mapped_user
= NULL
;
2193 const char *domain_user
= NULL
;
2194 uint16_t validation_level
= UINT16_MAX
;
2195 union netr_Validation
*validation
= NULL
;
2196 struct netr_SamBaseInfo
*base_info
= NULL
;
2197 NTSTATUS name_map_status
= NT_STATUS_UNSUCCESSFUL
;
2199 uint64_t logon_id
= 0;
2200 const struct timeval start_time
= timeval_current();
2201 const struct tsocket_address
*remote
= NULL
;
2202 const struct tsocket_address
*local
= NULL
;
2203 const char *krb5ccname
= NULL
;
2207 if (domain
== NULL
) {
2208 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
2211 /* Cut client_pid to 32bit */
2212 client_pid
= r
->in
.client_pid
;
2213 if ((uint64_t)client_pid
!= r
->in
.client_pid
) {
2214 DBG_DEBUG("pid out of range\n");
2215 return NT_STATUS_INVALID_PARAMETER
;
2218 /* Cut uid to 32bit */
2219 uid
= r
->in
.info
->uid
;
2220 if ((uint64_t)uid
!= r
->in
.info
->uid
) {
2221 DBG_DEBUG("uid out of range\n");
2222 return NT_STATUS_INVALID_PARAMETER
;
2226 * Generate a logon_id for this session.
2228 logon_id
= generate_random_u64();
2229 remote
= dcesrv_connection_get_remote_address(p
->dce_call
->conn
);
2230 local
= dcesrv_connection_get_local_address(p
->dce_call
->conn
);
2231 DEBUG(3, ("[%"PRIu32
"]: dual pam auth %s\n", client_pid
,
2232 r
->in
.info
->username
));
2234 /* Parse domain and username */
2236 name_map_status
= normalize_name_unmap(p
->mem_ctx
,
2237 r
->in
.info
->username
,
2240 /* If the name normalization didn't actually do anything,
2241 just use the original name */
2243 if (!NT_STATUS_IS_OK(name_map_status
) &&
2244 !NT_STATUS_EQUAL(name_map_status
, NT_STATUS_FILE_RENAMED
))
2246 mapped_user
= discard_const(r
->in
.info
->username
);
2249 ok
= parse_domain_user(mapped_user
,
2254 result
= NT_STATUS_INVALID_PARAMETER
;
2258 if (mapped_user
!= r
->in
.info
->username
) {
2259 domain_user
= talloc_asprintf(talloc_tos(),
2262 *lp_winbind_separator(),
2264 if (domain_user
== NULL
) {
2265 result
= NT_STATUS_NO_MEMORY
;
2268 r
->in
.info
->username
= domain_user
;
2271 if (!domain
->online
) {
2272 result
= NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
;
2273 if (domain
->startup
) {
2274 /* Logons are very important to users. If we're offline and
2275 we get a request within the first 30 seconds of startup,
2276 try very hard to find a DC and go online. */
2278 DEBUG(10,("winbindd_dual_pam_auth: domain: %s offline and auth "
2279 "request in startup mode.\n", domain
->name
));
2281 winbindd_flush_negative_conn_cache(domain
);
2282 result
= init_dc_connection(domain
, false);
2286 DEBUG(10,("winbindd_dual_pam_auth: domain: %s last was %s\n", domain
->name
, domain
->online
? "online":"offline"));
2288 /* Check for Kerberos authentication */
2289 if (domain
->online
&& (r
->in
.flags
& WBFLAG_PAM_KRB5
)) {
2290 result
= winbindd_dual_pam_auth_kerberos(
2292 r
->in
.info
->username
,
2293 r
->in
.info
->password
,
2294 r
->in
.info
->krb5_cc_type
,
2301 /* save for later */
2302 krb5_result
= result
;
2304 if (NT_STATUS_IS_OK(result
)) {
2305 DEBUG(10,("winbindd_dual_pam_auth_kerberos succeeded\n"));
2306 goto process_result
;
2309 DBG_DEBUG("winbindd_dual_pam_auth_kerberos failed: %s\n",
2312 if (NT_STATUS_EQUAL(result
, NT_STATUS_NO_LOGON_SERVERS
) ||
2313 NT_STATUS_EQUAL(result
, NT_STATUS_IO_TIMEOUT
) ||
2314 NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2315 DEBUG(10,("winbindd_dual_pam_auth_kerberos setting domain to offline\n"));
2316 set_domain_offline( domain
);
2320 /* there are quite some NT_STATUS errors where there is no
2321 * point in retrying with a samlogon, we explictly have to take
2322 * care not to increase the bad logon counter on the DC */
2324 if (NT_STATUS_EQUAL(result
, NT_STATUS_ACCOUNT_DISABLED
) ||
2325 NT_STATUS_EQUAL(result
, NT_STATUS_ACCOUNT_EXPIRED
) ||
2326 NT_STATUS_EQUAL(result
, NT_STATUS_ACCOUNT_LOCKED_OUT
) ||
2327 NT_STATUS_EQUAL(result
, NT_STATUS_INVALID_LOGON_HOURS
) ||
2328 NT_STATUS_EQUAL(result
, NT_STATUS_INVALID_WORKSTATION
) ||
2329 NT_STATUS_EQUAL(result
, NT_STATUS_LOGON_FAILURE
) ||
2330 NT_STATUS_EQUAL(result
, NT_STATUS_NO_SUCH_USER
) ||
2331 NT_STATUS_EQUAL(result
, NT_STATUS_PASSWORD_EXPIRED
) ||
2332 NT_STATUS_EQUAL(result
, NT_STATUS_PASSWORD_MUST_CHANGE
) ||
2333 NT_STATUS_EQUAL(result
, NT_STATUS_WRONG_PASSWORD
)) {
2337 if (r
->in
.flags
& WBFLAG_PAM_FALLBACK_AFTER_KRB5
) {
2338 DEBUG(3,("falling back to samlogon\n"));
2346 /* Check for Samlogon authentication */
2347 if (domain
->online
) {
2348 result
= winbindd_dual_pam_auth_samlogon(
2351 r
->in
.info
->username
,
2352 r
->in
.info
->password
,
2362 if (NT_STATUS_IS_OK(result
)) {
2363 DEBUG(10,("winbindd_dual_pam_auth_samlogon succeeded\n"));
2365 switch (validation_level
) {
2367 base_info
= &validation
->sam3
->base
;
2370 base_info
= &validation
->sam6
->base
;
2373 DBG_ERR("Bad validation level %d\n",
2375 result
= NT_STATUS_INTERNAL_ERROR
;
2379 /* add the Krb5 err if we have one */
2380 if ( NT_STATUS_EQUAL(krb5_result
, NT_STATUS_TIME_DIFFERENCE_AT_DC
) ) {
2381 base_info
->user_flags
|= LOGON_KRB5_FAIL_CLOCK_SKEW
;
2384 goto process_result
;
2387 DEBUG(10,("winbindd_dual_pam_auth_samlogon failed: %s\n",
2388 nt_errstr(result
)));
2390 if (NT_STATUS_EQUAL(result
, NT_STATUS_NO_LOGON_SERVERS
) ||
2391 NT_STATUS_EQUAL(result
, NT_STATUS_IO_TIMEOUT
) ||
2392 NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
))
2394 DEBUG(10,("winbindd_dual_pam_auth_samlogon setting domain to offline\n"));
2395 set_domain_offline( domain
);
2399 if (domain
->online
) {
2400 /* We're still online - fail. */
2406 /* Check for Cached logons */
2407 if (!domain
->online
&& (r
->in
.flags
& WBFLAG_PAM_CACHED_LOGIN
) &&
2408 lp_winbind_offline_logon()) {
2409 result
= winbindd_dual_pam_auth_cached(domain
,
2410 (r
->in
.flags
& WBFLAG_PAM_KRB5
),
2411 r
->in
.info
->username
,
2412 r
->in
.info
->password
,
2413 r
->in
.info
->krb5_cc_type
,
2420 if (!NT_STATUS_IS_OK(result
)) {
2421 DEBUG(10,("winbindd_dual_pam_auth_cached failed: %s\n", nt_errstr(result
)));
2424 DEBUG(10,("winbindd_dual_pam_auth_cached succeeded\n"));
2429 if (NT_STATUS_IS_OK(result
)) {
2430 struct dom_sid user_sid
;
2431 TALLOC_CTX
*base_ctx
= NULL
;
2432 struct netr_SamInfo3
*info3
= NULL
;
2434 switch (validation_level
) {
2436 base_ctx
= validation
->sam3
;
2437 base_info
= &validation
->sam3
->base
;
2440 base_ctx
= validation
->sam6
;
2441 base_info
= &validation
->sam6
->base
;
2444 DBG_ERR("Bad validation level %d\n", validation_level
);
2445 result
= NT_STATUS_INTERNAL_ERROR
;
2449 sid_compose(&user_sid
, base_info
->domain_sid
, base_info
->rid
);
2451 if (base_info
->full_name
.string
== NULL
) {
2452 struct netr_SamInfo3
*cached_info3
;
2454 cached_info3
= netsamlogon_cache_get(p
->mem_ctx
,
2456 if (cached_info3
!= NULL
&&
2457 cached_info3
->base
.full_name
.string
!= NULL
) {
2458 base_info
->full_name
.string
= talloc_strdup(
2460 cached_info3
->base
.full_name
.string
);
2461 if (base_info
->full_name
.string
== NULL
) {
2462 result
= NT_STATUS_NO_MEMORY
;
2467 /* this might fail so we don't check the return code */
2468 wcache_query_user_fullname(domain
,
2471 &base_info
->full_name
.string
);
2475 result
= map_validation_to_info3(talloc_tos(),
2479 if (!NT_STATUS_IS_OK(result
)) {
2483 wcache_invalidate_samlogon(find_domain_from_name(name_domain
),
2485 netsamlogon_cache_store(name_user
, info3
);
2487 /* save name_to_sid info as early as possible (only if
2488 this is our primary domain so we don't invalidate
2489 the cache entry by storing the seq_num for the wrong
2491 if ( domain
->primary
) {
2492 cache_name2sid(domain
, name_domain
, name_user
,
2493 SID_NAME_USER
, &user_sid
);
2496 /* Check if the user is in the right group */
2498 result
= check_info3_in_group(info3
,
2499 r
->in
.require_membership_of_sid
);
2500 if (!NT_STATUS_IS_OK(result
)) {
2501 char *s
= NDR_PRINT_STRUCT_STRING(p
->mem_ctx
,
2503 r
->in
.require_membership_of_sid
);
2504 DBG_NOTICE("User %s is not in the required groups:\n",
2505 r
->in
.info
->username
);
2506 DEBUGADD(DBGLVL_NOTICE
, ("%s", s
));
2507 DEBUGADD(DBGLVL_NOTICE
,
2508 ("Plaintext authentication is rejected\n"));
2512 if (!is_allowed_domain(info3
->base
.logon_domain
.string
)) {
2513 DBG_NOTICE("Authentication failed for user [%s] "
2514 "from firewalled domain [%s]\n",
2515 info3
->base
.account_name
.string
,
2516 info3
->base
.logon_domain
.string
);
2517 result
= NT_STATUS_AUTHENTICATION_FIREWALL_FAILED
;
2521 r
->out
.validation
= talloc_zero(p
->mem_ctx
,
2522 struct wbint_Validation
);
2523 if (r
->out
.validation
== NULL
) {
2524 result
= NT_STATUS_NO_MEMORY
;
2528 r
->out
.validation
->level
= validation_level
;
2529 r
->out
.validation
->validation
= talloc_steal(r
->out
.validation
,
2531 r
->out
.validation
->krb5ccname
= talloc_steal(r
->out
.validation
,
2533 if ((r
->in
.flags
& WBFLAG_PAM_CACHED_LOGIN
)
2534 && lp_winbind_offline_logon()) {
2536 result
= winbindd_store_creds(domain
,
2537 r
->in
.info
->username
,
2538 r
->in
.info
->password
,
2542 result
= NT_STATUS_OK
;
2546 /* give us a more useful (more correct?) error code */
2547 if ((NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ||
2548 (NT_STATUS_EQUAL(result
, NT_STATUS_UNSUCCESSFUL
)))) {
2549 result
= NT_STATUS_NO_LOGON_SERVERS
;
2552 DBG_PREFIX(NT_STATUS_IS_OK(result
) ? 5 : 2,
2553 ("Plain-text authentication for user %s returned %s"
2555 r
->in
.info
->username
,
2557 nt_status_to_pam(result
)));
2560 * Log the winbind pam authentication, the logon_id will tie this to
2561 * any of the logons invoked from this request.
2583 if (NT_STATUS_IS_OK(result
)) {
2584 gpupdate_user_init(r
->in
.info
->username
);
2590 NTSTATUS
winbind_dual_SamLogon(struct winbindd_domain
*domain
,
2591 TALLOC_CTX
*mem_ctx
,
2593 uint32_t logon_parameters
,
2594 const char *name_user
,
2595 const char *name_domain
,
2596 const char *workstation
,
2597 const uint64_t logon_id
,
2598 const char* client_name
,
2599 const int client_pid
,
2600 DATA_BLOB chal_blob
,
2601 DATA_BLOB lm_response
,
2602 DATA_BLOB nt_response
,
2603 const struct tsocket_address
*remote
,
2604 const struct tsocket_address
*local
,
2605 uint8_t *authoritative
,
2608 uint16_t *_validation_level
,
2609 union netr_Validation
**_validation
)
2611 uint16_t validation_level
= 0;
2612 union netr_Validation
*validation
= NULL
;
2616 * We check against domain->name instead of
2617 * name_domain, as find_auth_domain() ->
2618 * find_domain_from_name_noinit() already decided
2619 * that we are in a child for the correct domain.
2621 * name_domain can also be lp_realm()
2622 * we need to check against domain->name.
2624 if (!skip_sam
&& strequal(domain
->name
, get_global_sam_name())) {
2625 struct netr_SamInfo3
*info3
= NULL
;
2627 result
= winbindd_dual_auth_passdb(
2630 name_domain
, name_user
,
2634 &chal_blob
, &lm_response
, &nt_response
,
2640 if (NT_STATUS_IS_OK(result
)) {
2641 result
= map_info3_to_validation(mem_ctx
,
2646 if (!NT_STATUS_IS_OK(result
)) {
2652 * We need to try the remote NETLOGON server if this is
2653 * not authoritative.
2655 if (*authoritative
!= 0) {
2657 goto process_result
;
2661 result
= winbind_samlogon_retry_loop(domain
,
2665 NULL
, /* password */
2667 /* Bug #3248 - found by Stefan Burkei. */
2668 workstation
, /* We carefully set this above so use it... */
2670 false, /* plaintext_given */
2679 if (!NT_STATUS_IS_OK(result
)) {
2685 if (NT_STATUS_IS_OK(result
)) {
2686 struct dom_sid user_sid
;
2687 TALLOC_CTX
*base_ctx
= NULL
;
2688 struct netr_SamBaseInfo
*base_info
= NULL
;
2689 struct netr_SamInfo3
*info3
= NULL
;
2691 switch (validation_level
) {
2693 base_ctx
= validation
->sam3
;
2694 base_info
= &validation
->sam3
->base
;
2697 base_ctx
= validation
->sam6
;
2698 base_info
= &validation
->sam6
->base
;
2701 result
= NT_STATUS_INTERNAL_ERROR
;
2705 sid_compose(&user_sid
, base_info
->domain_sid
, base_info
->rid
);
2707 if (base_info
->full_name
.string
== NULL
) {
2708 struct netr_SamInfo3
*cached_info3
;
2710 cached_info3
= netsamlogon_cache_get(mem_ctx
,
2712 if (cached_info3
!= NULL
&&
2713 cached_info3
->base
.full_name
.string
!= NULL
)
2715 base_info
->full_name
.string
= talloc_strdup(
2717 cached_info3
->base
.full_name
.string
);
2720 /* this might fail so we don't check the return code */
2721 wcache_query_user_fullname(domain
,
2724 &base_info
->full_name
.string
);
2728 result
= map_validation_to_info3(talloc_tos(),
2732 if (!NT_STATUS_IS_OK(result
)) {
2735 wcache_invalidate_samlogon(find_domain_from_name(name_domain
),
2737 netsamlogon_cache_store(name_user
, info3
);
2743 /* give us a more useful (more correct?) error code */
2744 if ((NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ||
2745 (NT_STATUS_EQUAL(result
, NT_STATUS_UNSUCCESSFUL
)))) {
2746 result
= NT_STATUS_NO_LOGON_SERVERS
;
2749 DEBUG(NT_STATUS_IS_OK(result
) ? 5 : 2,
2750 ("NTLM CRAP authentication for user [%s]\\[%s] returned %s\n",
2753 nt_errstr(result
)));
2755 if (!NT_STATUS_IS_OK(result
)) {
2759 *_validation_level
= validation_level
;
2760 *_validation
= validation
;
2761 return NT_STATUS_OK
;
2764 NTSTATUS
_wbint_PamAuthCrap(struct pipes_struct
*p
, struct wbint_PamAuthCrap
*r
)
2766 struct winbindd_domain
*domain
= wb_child_domain();
2768 uint64_t logon_id
= 0;
2769 uint8_t authoritative
= 1;
2771 uint16_t validation_level
= UINT16_MAX
;
2772 union netr_Validation
*validation
= NULL
;
2773 const struct timeval start_time
= timeval_current();
2774 const struct tsocket_address
*remote
= NULL
;
2775 const struct tsocket_address
*local
= NULL
;
2776 struct netr_SamInfo3
*info3
= NULL
;
2779 if (domain
== NULL
) {
2780 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
2783 /* Cut client_pid to 32bit */
2784 client_pid
= r
->in
.client_pid
;
2785 if ((uint64_t)client_pid
!= r
->in
.client_pid
) {
2786 DBG_DEBUG("pid out of range\n");
2787 return NT_STATUS_INVALID_PARAMETER
;
2790 logon_id
= generate_random_u64();
2791 remote
= dcesrv_connection_get_remote_address(p
->dce_call
->conn
);
2792 local
= dcesrv_connection_get_local_address(p
->dce_call
->conn
);
2794 DBG_NOTICE("[%"PRIu32
"]: pam auth crap domain: %s user: %s\n",
2795 client_pid
, r
->in
.domain
, r
->in
.user
);
2797 result
= winbind_dual_SamLogon(domain
,
2799 false, /* interactive */
2800 r
->in
.logon_parameters
,
2817 if (!NT_STATUS_IS_OK(result
)) {
2821 result
= map_validation_to_info3(p
->mem_ctx
,
2825 if (!NT_STATUS_IS_OK(result
)) {
2829 /* Check if the user is in the right group */
2830 result
= check_info3_in_group(info3
, r
->in
.require_membership_of_sid
);
2831 if (!NT_STATUS_IS_OK(result
)) {
2832 char *s
= NDR_PRINT_STRUCT_STRING(p
->mem_ctx
,
2834 r
->in
.require_membership_of_sid
);
2835 DBG_NOTICE("User %s is not in the required groups:\n",
2837 DEBUGADD(DBGLVL_NOTICE
, ("%s", s
));
2838 DEBUGADD(DBGLVL_NOTICE
,
2839 ("CRAP authentication is rejected\n"));
2843 if (!is_allowed_domain(info3
->base
.logon_domain
.string
)) {
2844 DBG_NOTICE("Authentication failed for user [%s] "
2845 "from firewalled domain [%s]\n",
2846 info3
->base
.account_name
.string
,
2847 info3
->base
.logon_domain
.string
);
2848 result
= NT_STATUS_AUTHENTICATION_FIREWALL_FAILED
;
2852 r
->out
.validation
= talloc_zero(p
->mem_ctx
,
2853 struct wbint_PamAuthCrapValidation
);
2854 if (r
->out
.validation
== NULL
) {
2855 result
= NT_STATUS_NO_MEMORY
;
2859 r
->out
.validation
->level
= validation_level
;
2860 r
->out
.validation
->validation
= talloc_move(r
->out
.validation
,
2864 if (r
->in
.flags
& WBFLAG_PAM_NT_STATUS_SQUASH
) {
2865 result
= nt_status_squash(result
);
2868 *r
->out
.authoritative
= authoritative
;
2871 * Log the winbind pam authentication, the logon_id will tie this to
2872 * any of the logons invoked from this request.
2879 r
->out
.validation
->level
,
2880 r
->out
.validation
->validation
,
2896 NTSTATUS
_wbint_PamAuthChangePassword(struct pipes_struct
*p
,
2897 struct wbint_PamAuthChangePassword
*r
)
2899 struct winbindd_domain
*contact_domain
= wb_child_domain();
2900 struct policy_handle dom_pol
;
2901 struct rpc_pipe_client
*cli
= NULL
;
2902 bool got_info
= false;
2903 struct samr_DomInfo1
*info
= NULL
;
2904 struct userPwdChangeFailureInformation
*reject
= NULL
;
2905 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
2906 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
2907 fstring
namespace, domain
, user
;
2908 struct dcerpc_binding_handle
*b
= NULL
;
2912 ZERO_STRUCT(dom_pol
);
2914 if (contact_domain
== NULL
) {
2915 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
2918 /* Cut client_pid to 32bit */
2919 client_pid
= r
->in
.client_pid
;
2920 if ((uint64_t)client_pid
!= r
->in
.client_pid
) {
2921 DBG_DEBUG("pid out of range\n");
2922 return NT_STATUS_INVALID_PARAMETER
;
2925 DBG_NOTICE("[%"PRIu32
"]: dual pam chauthtok %s\n",
2926 client_pid
, r
->in
.user
);
2928 ok
= parse_domain_user(r
->in
.user
,
2936 if (!is_allowed_domain(domain
)) {
2937 DBG_NOTICE("Authentication failed for user [%s] "
2938 "from firewalled domain [%s]\n",
2940 result
= NT_STATUS_AUTHENTICATION_FIREWALL_FAILED
;
2944 /* Initialize reject reason */
2945 *r
->out
.reject_reason
= Undefined
;
2947 /* Get sam handle */
2949 result
= cm_connect_sam(contact_domain
,
2954 if (!NT_STATUS_IS_OK(result
)) {
2955 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain
));
2959 b
= cli
->binding_handle
;
2961 status
= dcerpc_samr_chgpasswd_user4(cli
->binding_handle
,
2963 cli
->srv_name_slash
,
2968 if (NT_STATUS_IS_OK(status
) && NT_STATUS_IS_OK(result
)) {
2969 /* Password successfully changed. */
2972 if (!NT_STATUS_IS_OK(status
)) {
2973 if (NT_STATUS_EQUAL(status
, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
) ||
2974 NT_STATUS_EQUAL(status
, NT_STATUS_NOT_SUPPORTED
) ||
2975 NT_STATUS_EQUAL(status
, NT_STATUS_NOT_IMPLEMENTED
)) {
2976 /* DO NOT FALLBACK TO RC4 */
2977 if (lp_weak_crypto() == SAMBA_WEAK_CRYPTO_DISALLOWED
) {
2978 result
= NT_STATUS_STRONG_CRYPTO_NOT_SUPPORTED
;
2979 goto process_result
;
2983 /* Password change was unsuccessful. */
2984 if (!NT_STATUS_IS_OK(result
)) {
2989 result
= rpccli_samr_chgpasswd_user3(cli
,
2997 /* Windows 2003 returns NT_STATUS_PASSWORD_RESTRICTION */
2999 if (NT_STATUS_EQUAL(result
, NT_STATUS_PASSWORD_RESTRICTION
) ) {
3001 *r
->out
.dominfo
= talloc_steal(p
->mem_ctx
, info
);
3002 *r
->out
.reject_reason
= reject
->extendedFailureReason
;
3007 /* atm the pidl generated rpccli_samr_ChangePasswordUser3 function will
3008 * return with NT_STATUS_BUFFER_TOO_SMALL for w2k dcs as w2k just
3009 * returns with 4byte error code (NT_STATUS_NOT_SUPPORTED) which is too
3010 * short to comply with the samr_ChangePasswordUser3 idl - gd */
3012 /* only fallback when the chgpasswd_user3 call is not supported */
3013 if (NT_STATUS_EQUAL(result
, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
) ||
3014 NT_STATUS_EQUAL(result
, NT_STATUS_NOT_SUPPORTED
) ||
3015 NT_STATUS_EQUAL(result
, NT_STATUS_BUFFER_TOO_SMALL
) ||
3016 NT_STATUS_EQUAL(result
, NT_STATUS_NOT_IMPLEMENTED
)) {
3018 DEBUG(10,("Password change with chgpasswd_user3 failed with: %s, retrying chgpasswd_user2\n",
3019 nt_errstr(result
)));
3021 result
= rpccli_samr_chgpasswd_user2(cli
,
3025 r
->in
.old_password
);
3027 /* Windows 2000 returns NT_STATUS_ACCOUNT_RESTRICTION.
3028 Map to the same status code as Windows 2003. */
3030 if ( NT_STATUS_EQUAL(NT_STATUS_ACCOUNT_RESTRICTION
, result
) ) {
3031 result
= NT_STATUS_PASSWORD_RESTRICTION
;
3037 if (NT_STATUS_IS_OK(result
)
3038 && (r
->in
.flags
& WBFLAG_PAM_CACHED_LOGIN
)
3039 && lp_winbind_offline_logon()) {
3040 result
= winbindd_update_creds_by_name(contact_domain
, user
,
3041 r
->in
.new_password
);
3042 /* Again, this happens when we login from gdm or xdm
3043 * and the password expires, *BUT* cached crendentials
3044 * doesn't exist. winbindd_update_creds_by_name()
3045 * returns NT_STATUS_NO_SUCH_USER.
3046 * This is not a failure.
3049 if (NT_STATUS_EQUAL(result
, NT_STATUS_NO_SUCH_USER
)) {
3050 result
= NT_STATUS_OK
;
3053 if (!NT_STATUS_IS_OK(result
)) {
3054 DEBUG(10, ("Failed to store creds: %s\n",
3055 nt_errstr(result
)));
3056 goto process_result
;
3060 if (!NT_STATUS_IS_OK(result
) && !got_info
&& contact_domain
) {
3062 NTSTATUS policy_ret
;
3064 policy_ret
= get_password_policy(contact_domain
,
3068 /* failure of this is non critical, it will just provide no
3069 * additional information to the client why the change has
3070 * failed - Guenther */
3072 if (!NT_STATUS_IS_OK(policy_ret
)) {
3073 DEBUG(10,("Failed to get password policies: %s\n", nt_errstr(policy_ret
)));
3074 goto process_result
;
3077 *r
->out
.dominfo
= talloc_steal(p
->mem_ctx
, info
);
3082 if (strequal(contact_domain
->name
, get_global_sam_name())) {
3083 /* FIXME: internal rpc pipe does not cache handles yet */
3085 if (is_valid_policy_hnd(&dom_pol
)) {
3087 dcerpc_samr_Close(b
,
3096 DEBUG(NT_STATUS_IS_OK(result
) ? 5 : 2,
3097 ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
3101 nt_status_to_pam(result
)));
3106 NTSTATUS
_wbint_PamLogOff(struct pipes_struct
*p
, struct wbint_PamLogOff
*r
)
3108 struct winbindd_domain
*domain
= wb_child_domain();
3109 NTSTATUS result
= NT_STATUS_NOT_SUPPORTED
;
3113 if (domain
== NULL
) {
3114 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
3117 /* Cut client_pid to 32bit */
3118 client_pid
= r
->in
.client_pid
;
3119 if ((uint64_t)client_pid
!= r
->in
.client_pid
) {
3120 DBG_DEBUG("pid out of range\n");
3121 return NT_STATUS_INVALID_PARAMETER
;
3124 /* Cut uid to 32bit */
3125 user_uid
= r
->in
.uid
;
3126 if ((uint64_t)user_uid
!= r
->in
.uid
) {
3127 DBG_DEBUG("uid out of range\n");
3128 return NT_STATUS_INVALID_PARAMETER
;
3131 DBG_NOTICE("[%"PRIu32
"]: pam dual logoff %s\n", client_pid
, r
->in
.user
);
3133 if (!(r
->in
.flags
& WBFLAG_PAM_KRB5
)) {
3134 result
= NT_STATUS_OK
;
3135 goto process_result
;
3138 if ((r
->in
.krb5ccname
== NULL
) || (strlen(r
->in
.krb5ccname
) == 0)) {
3139 result
= NT_STATUS_OK
;
3140 goto process_result
;
3145 if (user_uid
== (uid_t
)-1) {
3146 DBG_DEBUG("Invalid uid for user '%s'\n", r
->in
.user
);
3147 goto process_result
;
3150 /* what we need here is to find the corresponding krb5 ccache name *we*
3151 * created for a given username and destroy it */
3153 if (!ccache_entry_exists(r
->in
.user
)) {
3154 result
= NT_STATUS_OK
;
3155 DBG_DEBUG("No entry found for user '%s'.\n", r
->in
.user
);
3156 goto process_result
;
3159 if (!ccache_entry_identical(r
->in
.user
, user_uid
, r
->in
.krb5ccname
)) {
3160 DBG_DEBUG("Cached entry differs for user '%s'\n", r
->in
.user
);
3161 goto process_result
;
3164 result
= remove_ccache(r
->in
.user
);
3165 if (!NT_STATUS_IS_OK(result
)) {
3166 DBG_DEBUG("Failed to remove ccache for user '%s': %s\n",
3167 r
->in
.user
, nt_errstr(result
));
3168 goto process_result
;
3172 * Remove any mlock'ed memory creds in the child
3173 * we might be using for krb5 ticket renewal.
3176 winbindd_delete_memory_creds(r
->in
.user
);
3179 result
= NT_STATUS_NOT_SUPPORTED
;
3187 /* Change user password with auth crap*/
3189 NTSTATUS
_wbint_PamAuthCrapChangePassword(struct pipes_struct
*p
,
3190 struct wbint_PamAuthCrapChangePassword
*r
)
3193 fstring
namespace, domain
, user
;
3194 struct policy_handle dom_pol
;
3195 struct winbindd_domain
*contact_domain
= wb_child_domain();
3196 struct rpc_pipe_client
*cli
= NULL
;
3197 struct dcerpc_binding_handle
*b
= NULL
;
3200 ZERO_STRUCT(dom_pol
);
3202 if (contact_domain
== NULL
) {
3203 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
3206 /* Cut client_pid to 32bit */
3207 client_pid
= r
->in
.client_pid
;
3208 if ((uint64_t)client_pid
!= r
->in
.client_pid
) {
3209 DBG_DEBUG("pid out of range\n");
3210 return NT_STATUS_INVALID_PARAMETER
;
3214 namespace[0] = '\0';
3217 DBG_NOTICE("[%"PRIu32
"]: pam change pswd auth crap domain: %s "
3218 "user: %s\n", client_pid
, r
->in
.domain
, r
->in
.user
);
3220 if (lp_winbind_offline_logon()) {
3221 DEBUG(0,("Refusing password change as winbind offline logons are enabled. "));
3222 DEBUGADD(0,("Changing passwords here would risk inconsistent logons\n"));
3223 result
= NT_STATUS_ACCESS_DENIED
;
3227 if (r
->in
.domain
!= NULL
&& strlen(r
->in
.domain
) > 0) {
3228 fstrcpy(domain
, r
->in
.domain
);
3232 ok
= parse_domain_user(r
->in
.user
,
3237 result
= NT_STATUS_INVALID_PARAMETER
;
3241 if (strlen(domain
) == 0) {
3242 DBG_NOTICE("no domain specified with username (%s) - "
3243 "failing auth\n", r
->in
.user
);
3244 result
= NT_STATUS_NO_SUCH_USER
;
3249 if (!*domain
&& lp_winbind_use_default_domain()) {
3250 fstrcpy(domain
,lp_workgroup());
3253 if (!is_allowed_domain(domain
)) {
3254 DBG_NOTICE("Authentication failed for user [%s] "
3255 "from firewalled domain [%s]\n",
3258 result
= NT_STATUS_AUTHENTICATION_FIREWALL_FAILED
;
3263 fstrcpy(user
, r
->in
.user
);
3266 /* Get sam handle */
3268 result
= cm_connect_sam(contact_domain
,
3273 if (!NT_STATUS_IS_OK(result
)) {
3274 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain
));
3278 b
= cli
->binding_handle
;
3280 result
= rpccli_samr_chng_pswd_auth_crap(cli
,
3284 r
->in
.old_nt_hash_enc
,
3286 r
->in
.old_lm_hash_enc
);
3290 if (strequal(contact_domain
->name
, get_global_sam_name())) {
3291 /* FIXME: internal rpc pipe does not cache handles yet */
3293 if (is_valid_policy_hnd(&dom_pol
)) {
3295 dcerpc_samr_Close(b
,
3304 DEBUG(NT_STATUS_IS_OK(result
) ? 5 : 2,
3305 ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
3308 nt_status_to_pam(result
)));
3314 static NTSTATUS
extract_pac_vrfy_sigs(TALLOC_CTX
*mem_ctx
, DATA_BLOB pac_blob
,
3315 struct PAC_DATA
**p_pac_data
)
3317 krb5_context krbctx
= NULL
;
3318 krb5_error_code k5ret
;
3320 krb5_kt_cursor cursor
;
3321 krb5_keytab_entry entry
;
3322 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
3325 ZERO_STRUCT(cursor
);
3327 k5ret
= smb_krb5_init_context_common(&krbctx
);
3329 DBG_ERR("kerberos init context failed (%s)\n",
3330 error_message(k5ret
));
3331 status
= krb5_to_nt_status(k5ret
);
3335 k5ret
= gse_krb5_get_server_keytab(krbctx
, &keytab
);
3337 DEBUG(1, ("Failed to get keytab: %s\n",
3338 error_message(k5ret
)));
3339 status
= krb5_to_nt_status(k5ret
);
3343 k5ret
= krb5_kt_start_seq_get(krbctx
, keytab
, &cursor
);
3345 DEBUG(1, ("Failed to start seq: %s\n",
3346 error_message(k5ret
)));
3347 status
= krb5_to_nt_status(k5ret
);
3351 k5ret
= krb5_kt_next_entry(krbctx
, keytab
, &entry
, &cursor
);
3352 while (k5ret
== 0) {
3353 status
= kerberos_decode_pac(mem_ctx
,
3356 NULL
, /* krbtgt_keyblock */
3357 KRB5_KT_KEY(&entry
), /* service_keyblock */
3358 NULL
, /* client_principal */
3359 0, /* tgs_authtime */
3361 if (NT_STATUS_IS_OK(status
)) {
3364 k5ret
= smb_krb5_kt_free_entry(krbctx
, &entry
);
3365 k5ret
= krb5_kt_next_entry(krbctx
, keytab
, &entry
, &cursor
);
3368 k5ret
= krb5_kt_end_seq_get(krbctx
, keytab
, &cursor
);
3370 DEBUG(1, ("Failed to end seq: %s\n",
3371 error_message(k5ret
)));
3374 k5ret
= krb5_kt_close(krbctx
, keytab
);
3376 DEBUG(1, ("Failed to close keytab: %s\n",
3377 error_message(k5ret
)));
3380 krb5_free_context(krbctx
);
3385 NTSTATUS
winbindd_pam_auth_pac_verify(struct winbindd_cli_state
*state
,
3386 TALLOC_CTX
*mem_ctx
,
3388 uint16_t *p_validation_level
,
3389 union netr_Validation
**p_validation
)
3391 struct winbindd_request
*req
= state
->request
;
3393 struct PAC_DATA
*pac_data
= NULL
;
3394 struct PAC_LOGON_INFO
*logon_info
= NULL
;
3395 struct PAC_UPN_DNS_INFO
*upn_dns_info
= NULL
;
3396 struct netr_SamInfo6
*info6
= NULL
;
3397 uint16_t validation_level
= 0;
3398 union netr_Validation
*validation
= NULL
;
3399 struct netr_SamInfo3
*info3_copy
= NULL
;
3401 bool is_trusted
= false;
3403 TALLOC_CTX
*tmp_ctx
= NULL
;
3405 tmp_ctx
= talloc_new(mem_ctx
);
3406 if (tmp_ctx
== NULL
) {
3407 return NT_STATUS_NO_MEMORY
;
3410 *p_is_trusted
= false;
3411 *p_validation_level
= 0;
3412 *p_validation
= NULL
;
3414 pac_blob
= data_blob_const(req
->extra_data
.data
, req
->extra_len
);
3415 result
= extract_pac_vrfy_sigs(tmp_ctx
, pac_blob
, &pac_data
);
3416 if (NT_STATUS_IS_OK(result
)) {
3419 if (NT_STATUS_EQUAL(result
, NT_STATUS_ACCESS_DENIED
)) {
3420 /* Try without signature verification */
3421 result
= kerberos_decode_pac(tmp_ctx
,
3423 NULL
, /* krb5_context */
3424 NULL
, /* krbtgt_keyblock */
3425 NULL
, /* service_keyblock */
3426 NULL
, /* client_principal */
3427 0, /* tgs_authtime */
3430 if (!NT_STATUS_IS_OK(result
)) {
3431 DEBUG(1, ("Error during PAC signature verification: %s\n",
3432 nt_errstr(result
)));
3436 for (i
=0; i
< pac_data
->num_buffers
; i
++) {
3437 if (pac_data
->buffers
[i
].type
== PAC_TYPE_LOGON_INFO
) {
3438 logon_info
= pac_data
->buffers
[i
].info
->logon_info
.info
;
3441 if (pac_data
->buffers
[i
].type
== PAC_TYPE_UPN_DNS_INFO
) {
3442 upn_dns_info
= &pac_data
->buffers
[i
].info
->upn_dns_info
;
3447 result
= create_info6_from_pac(tmp_ctx
,
3451 if (!NT_STATUS_IS_OK(result
)) {
3455 if (!is_allowed_domain(info6
->base
.logon_domain
.string
)) {
3456 DBG_NOTICE("Authentication failed for user [%s] "
3457 "from firewalled domain [%s]\n",
3458 info6
->base
.account_name
.string
,
3459 info6
->base
.logon_domain
.string
);
3460 result
= NT_STATUS_AUTHENTICATION_FIREWALL_FAILED
;
3464 result
= map_info6_to_validation(tmp_ctx
,
3468 if (!NT_STATUS_IS_OK(result
)) {
3472 result
= map_validation_to_info3(tmp_ctx
,
3476 if (!NT_STATUS_IS_OK(result
)) {
3482 * Signature verification succeeded, we can
3483 * trust the PAC and prime the netsamlogon
3484 * and name2sid caches. DO NOT DO THIS
3485 * in the signature verification failed
3488 struct winbindd_domain
*domain
= NULL
;
3490 netsamlogon_cache_store(NULL
, info3_copy
);
3493 * We're in the parent here, so find the child
3494 * pointer from the PAC domain name.
3496 domain
= find_lookup_domain_from_name(
3497 info3_copy
->base
.logon_domain
.string
);
3498 if (domain
&& domain
->primary
) {
3499 struct dom_sid user_sid
;
3500 struct dom_sid_buf buf
;
3502 sid_compose(&user_sid
,
3503 info3_copy
->base
.domain_sid
,
3504 info3_copy
->base
.rid
);
3506 cache_name2sid_trusted(domain
,
3507 info3_copy
->base
.logon_domain
.string
,
3508 info3_copy
->base
.account_name
.string
,
3512 DBG_INFO("PAC for user %s\\%s SID %s primed cache\n",
3513 info3_copy
->base
.logon_domain
.string
,
3514 info3_copy
->base
.account_name
.string
,
3515 dom_sid_str_buf(&user_sid
, &buf
));
3519 *p_is_trusted
= is_trusted
;
3520 *p_validation_level
= validation_level
;
3521 *p_validation
= talloc_move(mem_ctx
, &validation
);
3523 result
= NT_STATUS_OK
;
3525 TALLOC_FREE(tmp_ctx
);
3528 #else /* HAVE_KRB5 */
3529 NTSTATUS
winbindd_pam_auth_pac_verify(struct winbindd_cli_state
*state
,
3530 TALLOC_CTX
*mem_ctx
,
3532 uint16_t *p_validation_level
,
3533 union netr_Validation
**p_validation
);
3536 *p_is_trusted
= false;
3537 *p_validation_level
= 0;
3538 *p_validation
= NULL
;
3539 return NT_STATUS_NO_SUCH_USER
;
3541 #endif /* HAVE_KRB5 */