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/>.
27 #include "../libcli/auth/libcli_auth.h"
28 #include "../librpc/gen_ndr/ndr_samr_c.h"
29 #include "rpc_client/cli_pipe.h"
30 #include "rpc_client/cli_samr.h"
31 #include "../librpc/gen_ndr/ndr_netlogon.h"
32 #include "rpc_client/cli_netlogon.h"
34 #include "../lib/crypto/arcfour.h"
35 #include "../libcli/security/security.h"
37 #include "../librpc/gen_ndr/krb5pac.h"
38 #include "passdb/machine_sid.h"
40 #include "../lib/tsocket/tsocket.h"
41 #include "auth/kerberos/pac_utils.h"
42 #include "auth/gensec/gensec.h"
43 #include "librpc/crypto/gse_krb5.h"
46 #define DBGC_CLASS DBGC_WINBIND
48 #define LOGON_KRB5_FAIL_CLOCK_SKEW 0x02000000
50 static NTSTATUS
append_info3_as_txt(TALLOC_CTX
*mem_ctx
,
51 struct winbindd_response
*resp
,
52 struct netr_SamInfo3
*info3
)
57 resp
->data
.auth
.info3
.logon_time
=
58 nt_time_to_unix(info3
->base
.logon_time
);
59 resp
->data
.auth
.info3
.logoff_time
=
60 nt_time_to_unix(info3
->base
.logoff_time
);
61 resp
->data
.auth
.info3
.kickoff_time
=
62 nt_time_to_unix(info3
->base
.kickoff_time
);
63 resp
->data
.auth
.info3
.pass_last_set_time
=
64 nt_time_to_unix(info3
->base
.last_password_change
);
65 resp
->data
.auth
.info3
.pass_can_change_time
=
66 nt_time_to_unix(info3
->base
.allow_password_change
);
67 resp
->data
.auth
.info3
.pass_must_change_time
=
68 nt_time_to_unix(info3
->base
.force_password_change
);
70 resp
->data
.auth
.info3
.logon_count
= info3
->base
.logon_count
;
71 resp
->data
.auth
.info3
.bad_pw_count
= info3
->base
.bad_password_count
;
73 resp
->data
.auth
.info3
.user_rid
= info3
->base
.rid
;
74 resp
->data
.auth
.info3
.group_rid
= info3
->base
.primary_gid
;
75 sid_to_fstring(resp
->data
.auth
.info3
.dom_sid
, info3
->base
.domain_sid
);
77 resp
->data
.auth
.info3
.num_groups
= info3
->base
.groups
.count
;
78 resp
->data
.auth
.info3
.user_flgs
= info3
->base
.user_flags
;
80 resp
->data
.auth
.info3
.acct_flags
= info3
->base
.acct_flags
;
81 resp
->data
.auth
.info3
.num_other_sids
= info3
->sidcount
;
83 fstrcpy(resp
->data
.auth
.info3
.user_name
,
84 info3
->base
.account_name
.string
);
85 fstrcpy(resp
->data
.auth
.info3
.full_name
,
86 info3
->base
.full_name
.string
);
87 fstrcpy(resp
->data
.auth
.info3
.logon_script
,
88 info3
->base
.logon_script
.string
);
89 fstrcpy(resp
->data
.auth
.info3
.profile_path
,
90 info3
->base
.profile_path
.string
);
91 fstrcpy(resp
->data
.auth
.info3
.home_dir
,
92 info3
->base
.home_directory
.string
);
93 fstrcpy(resp
->data
.auth
.info3
.dir_drive
,
94 info3
->base
.home_drive
.string
);
96 fstrcpy(resp
->data
.auth
.info3
.logon_srv
,
97 info3
->base
.logon_server
.string
);
98 fstrcpy(resp
->data
.auth
.info3
.logon_dom
,
99 info3
->base
.logon_domain
.string
);
101 ex
= talloc_strdup(mem_ctx
, "");
102 NT_STATUS_HAVE_NO_MEMORY(ex
);
104 for (i
=0; i
< info3
->base
.groups
.count
; i
++) {
105 ex
= talloc_asprintf_append_buffer(ex
, "0x%08X:0x%08X\n",
106 info3
->base
.groups
.rids
[i
].rid
,
107 info3
->base
.groups
.rids
[i
].attributes
);
108 NT_STATUS_HAVE_NO_MEMORY(ex
);
111 for (i
=0; i
< info3
->sidcount
; i
++) {
114 sid
= dom_sid_string(mem_ctx
, info3
->sids
[i
].sid
);
115 NT_STATUS_HAVE_NO_MEMORY(sid
);
117 ex
= talloc_asprintf_append_buffer(ex
, "%s:0x%08X\n",
119 info3
->sids
[i
].attributes
);
120 NT_STATUS_HAVE_NO_MEMORY(ex
);
125 resp
->extra_data
.data
= ex
;
126 resp
->length
+= talloc_get_size(ex
);
131 static NTSTATUS
append_info3_as_ndr(TALLOC_CTX
*mem_ctx
,
132 struct winbindd_response
*resp
,
133 struct netr_SamInfo3
*info3
)
136 enum ndr_err_code ndr_err
;
138 ndr_err
= ndr_push_struct_blob(&blob
, mem_ctx
, info3
,
139 (ndr_push_flags_fn_t
)ndr_push_netr_SamInfo3
);
140 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
141 DEBUG(0,("append_info3_as_ndr: failed to append\n"));
142 return ndr_map_error2ntstatus(ndr_err
);
145 resp
->extra_data
.data
= blob
.data
;
146 resp
->length
+= blob
.length
;
151 static NTSTATUS
append_unix_username(TALLOC_CTX
*mem_ctx
,
152 struct winbindd_response
*resp
,
153 const struct netr_SamInfo3
*info3
,
154 const char *name_domain
,
155 const char *name_user
)
157 /* We've been asked to return the unix username, per
158 'winbind use default domain' settings and the like */
160 const char *nt_username
, *nt_domain
;
162 nt_domain
= talloc_strdup(mem_ctx
, info3
->base
.logon_domain
.string
);
164 /* If the server didn't give us one, just use the one
166 nt_domain
= name_domain
;
169 nt_username
= talloc_strdup(mem_ctx
, info3
->base
.account_name
.string
);
171 /* If the server didn't give us one, just use the one
173 nt_username
= name_user
;
176 fill_domain_username(resp
->data
.auth
.unix_username
,
177 nt_domain
, nt_username
, true);
179 DEBUG(5, ("Setting unix username to [%s]\n",
180 resp
->data
.auth
.unix_username
));
185 static NTSTATUS
append_afs_token(TALLOC_CTX
*mem_ctx
,
186 struct winbindd_response
*resp
,
187 const struct netr_SamInfo3
*info3
,
188 const char *name_domain
,
189 const char *name_user
)
191 char *afsname
= NULL
;
195 afsname
= talloc_strdup(mem_ctx
, lp_afs_username_map());
196 if (afsname
== NULL
) {
197 return NT_STATUS_NO_MEMORY
;
200 afsname
= talloc_string_sub(mem_ctx
,
201 lp_afs_username_map(),
203 afsname
= talloc_string_sub(mem_ctx
, afsname
,
205 afsname
= talloc_string_sub(mem_ctx
, afsname
,
209 struct dom_sid user_sid
;
212 sid_compose(&user_sid
, info3
->base
.domain_sid
,
214 sid_to_fstring(sidstr
, &user_sid
);
215 afsname
= talloc_string_sub(mem_ctx
, afsname
,
219 if (afsname
== NULL
) {
220 return NT_STATUS_NO_MEMORY
;
223 if (!strlower_m(afsname
)) {
224 return NT_STATUS_INVALID_PARAMETER
;
227 DEBUG(10, ("Generating token for user %s\n", afsname
));
229 cell
= strchr(afsname
, '@');
232 return NT_STATUS_NO_MEMORY
;
238 token
= afs_createtoken_str(afsname
, cell
);
242 resp
->extra_data
.data
= talloc_strdup(mem_ctx
, token
);
243 if (resp
->extra_data
.data
== NULL
) {
244 return NT_STATUS_NO_MEMORY
;
246 resp
->length
+= strlen((const char *)resp
->extra_data
.data
)+1;
251 static NTSTATUS
check_info3_in_group(struct netr_SamInfo3
*info3
,
252 const char *group_sid
)
254 * Check whether a user belongs to a group or list of groups.
256 * @param mem_ctx talloc memory context.
257 * @param info3 user information, including group membership info.
258 * @param group_sid One or more groups , separated by commas.
260 * @return NT_STATUS_OK on success,
261 * NT_STATUS_LOGON_FAILURE if the user does not belong,
262 * or other NT_STATUS_IS_ERR(status) for other kinds of failure.
265 struct dom_sid
*require_membership_of_sid
;
266 uint32_t num_require_membership_of_sid
;
271 struct security_token
*token
;
272 TALLOC_CTX
*frame
= talloc_stackframe();
275 /* Parse the 'required group' SID */
277 if (!group_sid
|| !group_sid
[0]) {
278 /* NO sid supplied, all users may access */
283 token
= talloc_zero(talloc_tos(), struct security_token
);
285 DEBUG(0, ("talloc failed\n"));
287 return NT_STATUS_NO_MEMORY
;
290 num_require_membership_of_sid
= 0;
291 require_membership_of_sid
= NULL
;
295 while (next_token_talloc(talloc_tos(), &p
, &req_sid
, ",")) {
296 if (!string_to_sid(&sid
, req_sid
)) {
297 DEBUG(0, ("check_info3_in_group: could not parse %s "
298 "as a SID!", req_sid
));
300 return NT_STATUS_INVALID_PARAMETER
;
303 status
= add_sid_to_array(talloc_tos(), &sid
,
304 &require_membership_of_sid
,
305 &num_require_membership_of_sid
);
306 if (!NT_STATUS_IS_OK(status
)) {
307 DEBUG(0, ("add_sid_to_array failed\n"));
313 status
= sid_array_from_info3(talloc_tos(), info3
,
317 if (!NT_STATUS_IS_OK(status
)) {
322 if (!NT_STATUS_IS_OK(status
= add_aliases(get_global_sam_sid(),
324 || !NT_STATUS_IS_OK(status
= add_aliases(&global_sid_Builtin
,
326 DEBUG(3, ("could not add aliases: %s\n",
332 security_token_debug(DBGC_CLASS
, 10, token
);
334 for (i
=0; i
<num_require_membership_of_sid
; i
++) {
335 DEBUG(10, ("Checking SID %s\n", sid_string_dbg(
336 &require_membership_of_sid
[i
])));
337 if (nt_token_check_sid(&require_membership_of_sid
[i
],
339 DEBUG(10, ("Access ok\n"));
345 /* Do not distinguish this error from a wrong username/pw */
348 return NT_STATUS_LOGON_FAILURE
;
351 struct winbindd_domain
*find_auth_domain(uint8_t flags
,
352 const char *domain_name
)
354 struct winbindd_domain
*domain
;
357 domain
= find_domain_from_name_noinit(domain_name
);
358 if (domain
== NULL
) {
359 DEBUG(3, ("Authentication for domain [%s] refused "
360 "as it is not a trusted domain\n",
366 if (strequal(domain_name
, get_global_sam_name())) {
367 return find_domain_from_name_noinit(domain_name
);
370 /* we can auth against trusted domains */
371 if (flags
& WBFLAG_PAM_CONTACT_TRUSTDOM
) {
372 domain
= find_domain_from_name_noinit(domain_name
);
373 if (domain
== NULL
) {
374 DEBUG(3, ("Authentication for domain [%s] skipped "
375 "as it is not a trusted domain\n",
382 return find_our_domain();
385 static void fill_in_password_policy(struct winbindd_response
*r
,
386 const struct samr_DomInfo1
*p
)
388 r
->data
.auth
.policy
.min_length_password
=
389 p
->min_password_length
;
390 r
->data
.auth
.policy
.password_history
=
391 p
->password_history_length
;
392 r
->data
.auth
.policy
.password_properties
=
393 p
->password_properties
;
394 r
->data
.auth
.policy
.expire
=
395 nt_time_to_unix_abs((const NTTIME
*)&(p
->max_password_age
));
396 r
->data
.auth
.policy
.min_passwordage
=
397 nt_time_to_unix_abs((const NTTIME
*)&(p
->min_password_age
));
400 static NTSTATUS
fillup_password_policy(struct winbindd_domain
*domain
,
401 struct winbindd_response
*response
)
403 TALLOC_CTX
*frame
= talloc_stackframe();
404 struct winbindd_methods
*methods
;
406 struct samr_DomInfo1 password_policy
;
408 if ( !winbindd_can_contact_domain( domain
) ) {
409 DEBUG(5,("fillup_password_policy: No inbound trust to "
410 "contact domain %s\n", domain
->name
));
411 status
= NT_STATUS_NOT_SUPPORTED
;
415 methods
= domain
->methods
;
417 status
= methods
->password_policy(domain
, talloc_tos(), &password_policy
);
418 if (NT_STATUS_IS_ERR(status
)) {
422 fill_in_password_policy(response
, &password_policy
);
429 static NTSTATUS
get_max_bad_attempts_from_lockout_policy(struct winbindd_domain
*domain
,
431 uint16
*lockout_threshold
)
433 struct winbindd_methods
*methods
;
434 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
435 struct samr_DomInfo12 lockout_policy
;
437 *lockout_threshold
= 0;
439 methods
= domain
->methods
;
441 status
= methods
->lockout_policy(domain
, mem_ctx
, &lockout_policy
);
442 if (NT_STATUS_IS_ERR(status
)) {
446 *lockout_threshold
= lockout_policy
.lockout_threshold
;
451 static NTSTATUS
get_pwd_properties(struct winbindd_domain
*domain
,
453 uint32
*password_properties
)
455 struct winbindd_methods
*methods
;
456 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
457 struct samr_DomInfo1 password_policy
;
459 *password_properties
= 0;
461 methods
= domain
->methods
;
463 status
= methods
->password_policy(domain
, mem_ctx
, &password_policy
);
464 if (NT_STATUS_IS_ERR(status
)) {
468 *password_properties
= password_policy
.password_properties
;
475 static const char *generate_krb5_ccache(TALLOC_CTX
*mem_ctx
,
478 const char **user_ccache_file
)
480 /* accept FILE and WRFILE as krb5_cc_type from the client and then
481 * build the full ccname string based on the user's uid here -
484 const char *gen_cc
= NULL
;
487 if (strequal(type
, "FILE")) {
488 gen_cc
= talloc_asprintf(
489 mem_ctx
, "FILE:/tmp/krb5cc_%d", uid
);
491 if (strequal(type
, "WRFILE")) {
492 gen_cc
= talloc_asprintf(
493 mem_ctx
, "WRFILE:/tmp/krb5cc_%d", uid
);
497 *user_ccache_file
= gen_cc
;
499 if (gen_cc
== NULL
) {
500 gen_cc
= talloc_strdup(mem_ctx
, "MEMORY:winbindd_pam_ccache");
502 if (gen_cc
== NULL
) {
503 DEBUG(0,("out of memory\n"));
507 DEBUG(10, ("using ccache: %s%s\n", gen_cc
,
508 (*user_ccache_file
== NULL
) ? " (internal)":""));
515 uid_t
get_uid_from_request(struct winbindd_request
*request
)
519 uid
= request
->data
.auth
.uid
;
522 DEBUG(1,("invalid uid: '%u'\n", (unsigned int)uid
));
528 /**********************************************************************
529 Authenticate a user with a clear text password using Kerberos and fill up
531 **********************************************************************/
533 static NTSTATUS
winbindd_raw_kerberos_login(TALLOC_CTX
*mem_ctx
,
534 struct winbindd_domain
*domain
,
537 const char *krb5_cc_type
,
539 struct netr_SamInfo3
**info3
,
543 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
544 krb5_error_code krb5_ret
;
545 const char *cc
= NULL
;
546 const char *principal_s
= NULL
;
547 const char *service
= NULL
;
549 fstring name_domain
, name_user
;
550 time_t ticket_lifetime
= 0;
551 time_t renewal_until
= 0;
553 time_t time_offset
= 0;
554 const char *user_ccache_file
;
555 struct PAC_LOGON_INFO
*logon_info
= NULL
;
559 if (domain
->alt_name
== NULL
) {
560 return NT_STATUS_INVALID_PARAMETER
;
564 * prepare a krb5_cc_cache string for the user */
567 DEBUG(0,("no valid uid\n"));
570 cc
= generate_krb5_ccache(mem_ctx
,
575 return NT_STATUS_NO_MEMORY
;
580 * get kerberos properties */
582 if (domain
->private_data
) {
583 ads
= (ADS_STRUCT
*)domain
->private_data
;
584 time_offset
= ads
->auth
.time_offset
;
589 * do kerberos auth and setup ccache as the user */
591 parse_domain_user(user
, name_domain
, name_user
);
593 realm
= talloc_strdup(mem_ctx
, domain
->alt_name
);
595 return NT_STATUS_NO_MEMORY
;
598 if (!strupper_m(realm
)) {
599 return NT_STATUS_INVALID_PARAMETER
;
602 principal_s
= talloc_asprintf(mem_ctx
, "%s@%s", name_user
, realm
);
603 if (principal_s
== NULL
) {
604 return NT_STATUS_NO_MEMORY
;
607 service
= talloc_asprintf(mem_ctx
, "%s/%s@%s", KRB5_TGS_NAME
, realm
, realm
);
608 if (service
== NULL
) {
609 return NT_STATUS_NO_MEMORY
;
612 /* if this is a user ccache, we need to act as the user to let the krb5
613 * library handle the chown, etc. */
615 /************************ ENTERING NON-ROOT **********************/
617 if (user_ccache_file
!= NULL
) {
618 set_effective_uid(uid
);
619 DEBUG(10,("winbindd_raw_kerberos_login: uid is %d\n", uid
));
622 result
= kerberos_return_pac(mem_ctx
,
631 WINBINDD_PAM_AUTH_KRB5_RENEW_TIME
,
634 if (user_ccache_file
!= NULL
) {
635 gain_root_privilege();
638 /************************ RETURNED TO ROOT **********************/
640 if (!NT_STATUS_IS_OK(result
)) {
644 *info3
= &logon_info
->info3
;
646 DEBUG(10,("winbindd_raw_kerberos_login: winbindd validated ticket of %s\n",
649 /* if we had a user's ccache then return that string for the pam
652 if (user_ccache_file
!= NULL
) {
654 fstrcpy(krb5ccname
, user_ccache_file
);
656 result
= add_ccache_to_list(principal_s
,
668 if (!NT_STATUS_IS_OK(result
)) {
669 DEBUG(10,("winbindd_raw_kerberos_login: failed to add ccache to list: %s\n",
674 /* need to delete the memory cred cache, it is not used anymore */
676 krb5_ret
= ads_kdestroy(cc
);
678 DEBUG(3,("winbindd_raw_kerberos_login: "
679 "could not destroy krb5 credential cache: "
680 "%s\n", error_message(krb5_ret
)));
689 /* we could have created a new credential cache with a valid tgt in it
690 * but we werent able to get or verify the service ticket for this
691 * local host and therefor didn't get the PAC, we need to remove that
692 * cache entirely now */
694 krb5_ret
= ads_kdestroy(cc
);
696 DEBUG(3,("winbindd_raw_kerberos_login: "
697 "could not destroy krb5 credential cache: "
698 "%s\n", error_message(krb5_ret
)));
701 if (!NT_STATUS_IS_OK(remove_ccache(user
))) {
702 DEBUG(3,("winbindd_raw_kerberos_login: "
703 "could not remove ccache for user %s\n",
709 return NT_STATUS_NOT_SUPPORTED
;
710 #endif /* HAVE_KRB5 */
713 /****************************************************************
714 ****************************************************************/
716 bool check_request_flags(uint32_t flags
)
718 uint32_t flags_edata
= WBFLAG_PAM_AFS_TOKEN
|
719 WBFLAG_PAM_INFO3_TEXT
|
720 WBFLAG_PAM_INFO3_NDR
;
722 if ( ( (flags
& flags_edata
) == WBFLAG_PAM_AFS_TOKEN
) ||
723 ( (flags
& flags_edata
) == WBFLAG_PAM_INFO3_NDR
) ||
724 ( (flags
& flags_edata
) == WBFLAG_PAM_INFO3_TEXT
)||
725 !(flags
& flags_edata
) ) {
729 DEBUG(1, ("check_request_flags: invalid request flags[0x%08X]\n",
735 /****************************************************************
736 ****************************************************************/
738 NTSTATUS
append_auth_data(TALLOC_CTX
*mem_ctx
,
739 struct winbindd_response
*resp
,
740 uint32_t request_flags
,
741 struct netr_SamInfo3
*info3
,
742 const char *name_domain
,
743 const char *name_user
)
747 if (request_flags
& WBFLAG_PAM_USER_SESSION_KEY
) {
748 memcpy(resp
->data
.auth
.user_session_key
,
750 sizeof(resp
->data
.auth
.user_session_key
)
754 if (request_flags
& WBFLAG_PAM_LMKEY
) {
755 memcpy(resp
->data
.auth
.first_8_lm_hash
,
756 info3
->base
.LMSessKey
.key
,
757 sizeof(resp
->data
.auth
.first_8_lm_hash
)
761 if (request_flags
& WBFLAG_PAM_UNIX_NAME
) {
762 result
= append_unix_username(mem_ctx
, resp
,
763 info3
, name_domain
, name_user
);
764 if (!NT_STATUS_IS_OK(result
)) {
765 DEBUG(10,("Failed to append Unix Username: %s\n",
771 /* currently, anything from here on potentially overwrites extra_data. */
773 if (request_flags
& WBFLAG_PAM_INFO3_NDR
) {
774 result
= append_info3_as_ndr(mem_ctx
, resp
, info3
);
775 if (!NT_STATUS_IS_OK(result
)) {
776 DEBUG(10,("Failed to append INFO3 (NDR): %s\n",
782 if (request_flags
& WBFLAG_PAM_INFO3_TEXT
) {
783 result
= append_info3_as_txt(mem_ctx
, resp
, info3
);
784 if (!NT_STATUS_IS_OK(result
)) {
785 DEBUG(10,("Failed to append INFO3 (TXT): %s\n",
791 if (request_flags
& WBFLAG_PAM_AFS_TOKEN
) {
792 result
= append_afs_token(mem_ctx
, resp
,
793 info3
, name_domain
, name_user
);
794 if (!NT_STATUS_IS_OK(result
)) {
795 DEBUG(10,("Failed to append AFS token: %s\n",
804 static NTSTATUS
winbindd_dual_pam_auth_cached(struct winbindd_domain
*domain
,
805 struct winbindd_cli_state
*state
,
806 struct netr_SamInfo3
**info3
)
808 NTSTATUS result
= NT_STATUS_LOGON_FAILURE
;
809 uint16 max_allowed_bad_attempts
;
810 fstring name_domain
, name_user
;
812 enum lsa_SidType type
;
813 uchar new_nt_pass
[NT_HASH_LEN
];
814 const uint8
*cached_nt_pass
;
815 const uint8
*cached_salt
;
816 struct netr_SamInfo3
*my_info3
;
817 time_t kickoff_time
, must_change_time
;
818 bool password_good
= false;
820 struct winbindd_tdc_domain
*tdc_domain
= NULL
;
827 DEBUG(10,("winbindd_dual_pam_auth_cached\n"));
829 /* Parse domain and username */
831 parse_domain_user(state
->request
->data
.auth
.user
, name_domain
, name_user
);
834 if (!lookup_cached_name(name_domain
,
838 DEBUG(10,("winbindd_dual_pam_auth_cached: no such user in the cache\n"));
839 return NT_STATUS_NO_SUCH_USER
;
842 if (type
!= SID_NAME_USER
) {
843 DEBUG(10,("winbindd_dual_pam_auth_cached: not a user (%s)\n", sid_type_lookup(type
)));
844 return NT_STATUS_LOGON_FAILURE
;
847 result
= winbindd_get_creds(domain
,
853 if (!NT_STATUS_IS_OK(result
)) {
854 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get creds: %s\n", nt_errstr(result
)));
860 E_md4hash(state
->request
->data
.auth
.pass
, new_nt_pass
);
862 dump_data_pw("new_nt_pass", new_nt_pass
, NT_HASH_LEN
);
863 dump_data_pw("cached_nt_pass", cached_nt_pass
, NT_HASH_LEN
);
865 dump_data_pw("cached_salt", cached_salt
, NT_HASH_LEN
);
869 /* In this case we didn't store the nt_hash itself,
870 but the MD5 combination of salt + nt_hash. */
871 uchar salted_hash
[NT_HASH_LEN
];
872 E_md5hash(cached_salt
, new_nt_pass
, salted_hash
);
874 password_good
= (memcmp(cached_nt_pass
, salted_hash
,
877 /* Old cached cred - direct store of nt_hash (bad bad bad !). */
878 password_good
= (memcmp(cached_nt_pass
, new_nt_pass
,
884 /* User *DOES* know the password, update logon_time and reset
887 my_info3
->base
.user_flags
|= NETLOGON_CACHED_ACCOUNT
;
889 if (my_info3
->base
.acct_flags
& ACB_AUTOLOCK
) {
890 return NT_STATUS_ACCOUNT_LOCKED_OUT
;
893 if (my_info3
->base
.acct_flags
& ACB_DISABLED
) {
894 return NT_STATUS_ACCOUNT_DISABLED
;
897 if (my_info3
->base
.acct_flags
& ACB_WSTRUST
) {
898 return NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT
;
901 if (my_info3
->base
.acct_flags
& ACB_SVRTRUST
) {
902 return NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT
;
905 if (my_info3
->base
.acct_flags
& ACB_DOMTRUST
) {
906 return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT
;
909 if (!(my_info3
->base
.acct_flags
& ACB_NORMAL
)) {
910 DEBUG(0,("winbindd_dual_pam_auth_cached: whats wrong with that one?: 0x%08x\n",
911 my_info3
->base
.acct_flags
));
912 return NT_STATUS_LOGON_FAILURE
;
915 kickoff_time
= nt_time_to_unix(my_info3
->base
.kickoff_time
);
916 if (kickoff_time
!= 0 && time(NULL
) > kickoff_time
) {
917 return NT_STATUS_ACCOUNT_EXPIRED
;
920 must_change_time
= nt_time_to_unix(my_info3
->base
.force_password_change
);
921 if (must_change_time
!= 0 && must_change_time
< time(NULL
)) {
922 /* we allow grace logons when the password has expired */
923 my_info3
->base
.user_flags
|= NETLOGON_GRACE_LOGON
;
924 /* return NT_STATUS_PASSWORD_EXPIRED; */
929 if ((state
->request
->flags
& WBFLAG_PAM_KRB5
) &&
930 ((tdc_domain
= wcache_tdc_fetch_domain(state
->mem_ctx
, name_domain
)) != NULL
) &&
931 ((tdc_domain
->trust_type
& NETR_TRUST_TYPE_UPLEVEL
) ||
932 /* used to cope with the case winbindd starting without network. */
933 !strequal(tdc_domain
->domain_name
, tdc_domain
->dns_name
))) {
936 const char *cc
= NULL
;
938 const char *principal_s
= NULL
;
939 const char *service
= NULL
;
940 const char *user_ccache_file
;
942 if (domain
->alt_name
== NULL
) {
943 return NT_STATUS_INVALID_PARAMETER
;
946 uid
= get_uid_from_request(state
->request
);
948 DEBUG(0,("winbindd_dual_pam_auth_cached: invalid uid\n"));
949 return NT_STATUS_INVALID_PARAMETER
;
952 cc
= generate_krb5_ccache(state
->mem_ctx
,
953 state
->request
->data
.auth
.krb5_cc_type
,
954 state
->request
->data
.auth
.uid
,
957 return NT_STATUS_NO_MEMORY
;
960 realm
= talloc_strdup(state
->mem_ctx
, domain
->alt_name
);
962 return NT_STATUS_NO_MEMORY
;
965 if (!strupper_m(realm
)) {
966 return NT_STATUS_INVALID_PARAMETER
;
969 principal_s
= talloc_asprintf(state
->mem_ctx
, "%s@%s", name_user
, realm
);
970 if (principal_s
== NULL
) {
971 return NT_STATUS_NO_MEMORY
;
974 service
= talloc_asprintf(state
->mem_ctx
, "%s/%s@%s", KRB5_TGS_NAME
, realm
, realm
);
975 if (service
== NULL
) {
976 return NT_STATUS_NO_MEMORY
;
979 if (user_ccache_file
!= NULL
) {
981 fstrcpy(state
->response
->data
.auth
.krb5ccname
,
984 result
= add_ccache_to_list(principal_s
,
987 state
->request
->data
.auth
.user
,
988 state
->request
->data
.auth
.pass
,
992 time(NULL
) + lp_winbind_cache_time(),
993 time(NULL
) + WINBINDD_PAM_AUTH_KRB5_RENEW_TIME
,
996 if (!NT_STATUS_IS_OK(result
)) {
997 DEBUG(10,("winbindd_dual_pam_auth_cached: failed "
998 "to add ccache to list: %s\n",
1003 #endif /* HAVE_KRB5 */
1005 /* FIXME: we possibly should handle logon hours as well (does xp when
1006 * offline?) see auth/auth_sam.c:sam_account_ok for details */
1008 unix_to_nt_time(&my_info3
->base
.logon_time
, time(NULL
));
1009 my_info3
->base
.bad_password_count
= 0;
1011 result
= winbindd_update_creds_by_info3(domain
,
1012 state
->request
->data
.auth
.user
,
1013 state
->request
->data
.auth
.pass
,
1015 if (!NT_STATUS_IS_OK(result
)) {
1016 DEBUG(1,("winbindd_dual_pam_auth_cached: failed to update creds: %s\n",
1017 nt_errstr(result
)));
1021 return NT_STATUS_OK
;
1025 /* User does *NOT* know the correct password, modify info3 accordingly, but only if online */
1026 if (domain
->online
== false) {
1030 /* failure of this is not critical */
1031 result
= get_max_bad_attempts_from_lockout_policy(domain
, state
->mem_ctx
, &max_allowed_bad_attempts
);
1032 if (!NT_STATUS_IS_OK(result
)) {
1033 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get max_allowed_bad_attempts. "
1034 "Won't be able to honour account lockout policies\n"));
1037 /* increase counter */
1038 my_info3
->base
.bad_password_count
++;
1040 if (max_allowed_bad_attempts
== 0) {
1045 if (my_info3
->base
.bad_password_count
>= max_allowed_bad_attempts
) {
1047 uint32 password_properties
;
1049 result
= get_pwd_properties(domain
, state
->mem_ctx
, &password_properties
);
1050 if (!NT_STATUS_IS_OK(result
)) {
1051 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get password properties.\n"));
1054 if ((my_info3
->base
.rid
!= DOMAIN_RID_ADMINISTRATOR
) ||
1055 (password_properties
& DOMAIN_PASSWORD_LOCKOUT_ADMINS
)) {
1056 my_info3
->base
.acct_flags
|= ACB_AUTOLOCK
;
1061 result
= winbindd_update_creds_by_info3(domain
,
1062 state
->request
->data
.auth
.user
,
1066 if (!NT_STATUS_IS_OK(result
)) {
1067 DEBUG(0,("winbindd_dual_pam_auth_cached: failed to update creds %s\n",
1068 nt_errstr(result
)));
1071 return NT_STATUS_LOGON_FAILURE
;
1074 static NTSTATUS
winbindd_dual_pam_auth_kerberos(struct winbindd_domain
*domain
,
1075 struct winbindd_cli_state
*state
,
1076 struct netr_SamInfo3
**info3
)
1078 struct winbindd_domain
*contact_domain
;
1079 fstring name_domain
, name_user
;
1082 DEBUG(10,("winbindd_dual_pam_auth_kerberos\n"));
1084 /* Parse domain and username */
1086 parse_domain_user(state
->request
->data
.auth
.user
, name_domain
, name_user
);
1088 /* what domain should we contact? */
1091 if (!(contact_domain
= find_domain_from_name(name_domain
))) {
1092 DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
1093 state
->request
->data
.auth
.user
, name_domain
, name_user
, name_domain
));
1094 result
= NT_STATUS_NO_SUCH_USER
;
1099 if (is_myname(name_domain
)) {
1100 DEBUG(3, ("Authentication for domain %s (local domain to this server) not supported at this stage\n", name_domain
));
1101 result
= NT_STATUS_NO_SUCH_USER
;
1105 contact_domain
= find_domain_from_name(name_domain
);
1106 if (contact_domain
== NULL
) {
1107 DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
1108 state
->request
->data
.auth
.user
, name_domain
, name_user
, name_domain
));
1110 result
= NT_STATUS_NO_SUCH_USER
;
1115 if (contact_domain
->initialized
&&
1116 contact_domain
->active_directory
) {
1120 if (!contact_domain
->initialized
) {
1121 init_dc_connection(contact_domain
);
1124 if (!contact_domain
->active_directory
) {
1125 DEBUG(3,("krb5 auth requested but domain is not Active Directory\n"));
1126 return NT_STATUS_INVALID_LOGON_TYPE
;
1129 result
= winbindd_raw_kerberos_login(
1130 state
->mem_ctx
, contact_domain
,
1131 state
->request
->data
.auth
.user
,
1132 state
->request
->data
.auth
.pass
,
1133 state
->request
->data
.auth
.krb5_cc_type
,
1134 get_uid_from_request(state
->request
),
1135 info3
, state
->response
->data
.auth
.krb5ccname
);
1140 static NTSTATUS
winbindd_dual_auth_passdb(TALLOC_CTX
*mem_ctx
,
1141 uint32_t logon_parameters
,
1142 const char *domain
, const char *user
,
1143 const DATA_BLOB
*challenge
,
1144 const DATA_BLOB
*lm_resp
,
1145 const DATA_BLOB
*nt_resp
,
1146 struct netr_SamInfo3
**pinfo3
)
1148 struct auth_usersupplied_info
*user_info
= NULL
;
1149 struct tsocket_address
*local
;
1153 rc
= tsocket_address_inet_from_strings(mem_ctx
,
1159 return NT_STATUS_NO_MEMORY
;
1161 status
= make_user_info(&user_info
, user
, user
, domain
, domain
,
1162 lp_netbios_name(), local
, lm_resp
, nt_resp
, NULL
, NULL
,
1163 NULL
, AUTH_PASSWORD_RESPONSE
);
1164 if (!NT_STATUS_IS_OK(status
)) {
1165 DEBUG(10, ("make_user_info failed: %s\n", nt_errstr(status
)));
1168 user_info
->logon_parameters
= logon_parameters
;
1170 /* We don't want any more mapping of the username */
1171 user_info
->mapped_state
= True
;
1173 status
= check_sam_security_info3(challenge
, talloc_tos(), user_info
,
1175 free_user_info(&user_info
);
1176 DEBUG(10, ("Authenticaticating user %s\\%s returned %s\n", domain
,
1177 user
, nt_errstr(status
)));
1181 static NTSTATUS
winbind_samlogon_retry_loop(struct winbindd_domain
*domain
,
1182 TALLOC_CTX
*mem_ctx
,
1183 uint32_t logon_parameters
,
1185 const char *username
,
1186 const char *domainname
,
1187 const char *workstation
,
1188 const uint8_t chal
[8],
1189 DATA_BLOB lm_response
,
1190 DATA_BLOB nt_response
,
1191 struct netr_SamInfo3
**info3
)
1194 int netr_attempts
= 0;
1199 struct rpc_pipe_client
*netlogon_pipe
;
1200 const struct pipe_auth_data
*auth
;
1201 uint32_t neg_flags
= 0;
1203 ZERO_STRUCTP(info3
);
1206 result
= cm_connect_netlogon(domain
, &netlogon_pipe
);
1208 if (!NT_STATUS_IS_OK(result
)) {
1209 DEBUG(3,("Could not open handle to NETLOGON pipe "
1210 "(error: %s, attempts: %d)\n",
1211 nt_errstr(result
), netr_attempts
));
1213 /* After the first retry always close the connection */
1214 if (netr_attempts
> 0) {
1215 DEBUG(3, ("This is again a problem for this "
1216 "particular call, forcing the close "
1217 "of this connection\n"));
1218 invalidate_cm_connection(&domain
->conn
);
1221 /* After the second retry failover to the next DC */
1222 if (netr_attempts
> 1) {
1224 * If the netlogon server is not reachable then
1225 * it is possible that the DC is rebuilding
1226 * sysvol and shutdown netlogon for that time.
1227 * We should failover to the next dc.
1229 DEBUG(3, ("This is the third problem for this "
1230 "particular call, adding DC to the "
1231 "negative cache list\n"));
1232 add_failed_connection_entry(domain
->name
,
1235 saf_delete(domain
->name
);
1238 /* Only allow 3 retries */
1239 if (netr_attempts
< 3) {
1240 DEBUG(3, ("The connection to netlogon "
1241 "failed, retrying\n"));
1250 auth
= netlogon_pipe
->auth
;
1251 if (netlogon_pipe
->dc
) {
1252 neg_flags
= netlogon_pipe
->dc
->negotiate_flags
;
1255 /* It is really important to try SamLogonEx here,
1256 * because in a clustered environment, we want to use
1257 * one machine account from multiple physical
1260 * With a normal SamLogon call, we must keep the
1261 * credentials chain updated and intact between all
1262 * users of the machine account (which would imply
1263 * cross-node communication for every NTLM logon).
1265 * (The credentials chain is not per NETLOGON pipe
1266 * connection, but globally on the server/client pair
1269 * When using SamLogonEx, the credentials are not
1270 * supplied, but the session key is implied by the
1271 * wrapping SamLogon context.
1273 * -- abartlet 21 April 2008
1275 * It's also important to use NetlogonValidationSamInfo4 (6),
1276 * because it relies on the rpc transport encryption
1277 * and avoids using the global netlogon schannel
1278 * session key to en/decrypt secret information
1279 * like the user_session_key for network logons.
1281 * [MS-APDS] 3.1.5.2 NTLM Network Logon
1282 * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
1283 * NETLOGON_NEG_AUTHENTICATED_RPC set together
1284 * are the indication that the server supports
1285 * NetlogonValidationSamInfo4 (6). And it must only
1286 * be used if "SealSecureChannel" is used.
1288 * -- metze 4 February 2011
1292 domain
->can_do_validation6
= false;
1293 } else if (auth
->auth_type
!= DCERPC_AUTH_TYPE_SCHANNEL
) {
1294 domain
->can_do_validation6
= false;
1295 } else if (auth
->auth_level
!= DCERPC_AUTH_LEVEL_PRIVACY
) {
1296 domain
->can_do_validation6
= false;
1297 } else if (!(neg_flags
& NETLOGON_NEG_CROSS_FOREST_TRUSTS
)) {
1298 domain
->can_do_validation6
= false;
1299 } else if (!(neg_flags
& NETLOGON_NEG_AUTHENTICATED_RPC
)) {
1300 domain
->can_do_validation6
= false;
1303 if (domain
->can_do_samlogon_ex
&& domain
->can_do_validation6
) {
1304 result
= rpccli_netlogon_sam_network_logon_ex(
1308 server
, /* server name */
1309 username
, /* user name */
1310 domainname
, /* target domain */
1311 workstation
, /* workstation */
1318 result
= rpccli_netlogon_sam_network_logon(
1322 server
, /* server name */
1323 username
, /* user name */
1324 domainname
, /* target domain */
1325 workstation
, /* workstation */
1327 domain
->can_do_validation6
? 6 : 3,
1333 if (NT_STATUS_EQUAL(result
, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
)) {
1336 * It's likely that the server also does not support
1337 * validation level 6
1339 domain
->can_do_validation6
= false;
1341 if (domain
->can_do_samlogon_ex
) {
1342 DEBUG(3, ("Got a DC that can not do NetSamLogonEx, "
1343 "retrying with NetSamLogon\n"));
1344 domain
->can_do_samlogon_ex
= false;
1350 /* Got DCERPC_FAULT_OP_RNG_ERROR for SamLogon
1351 * (no Ex). This happens against old Samba
1352 * DCs. Drop the connection.
1354 invalidate_cm_connection(&domain
->conn
);
1355 result
= NT_STATUS_LOGON_FAILURE
;
1359 if (domain
->can_do_validation6
&&
1360 (NT_STATUS_EQUAL(result
, NT_STATUS_INVALID_INFO_CLASS
) ||
1361 NT_STATUS_EQUAL(result
, NT_STATUS_INVALID_PARAMETER
) ||
1362 NT_STATUS_EQUAL(result
, NT_STATUS_BUFFER_TOO_SMALL
))) {
1363 DEBUG(3,("Got a DC that can not do validation level 6, "
1364 "retrying with level 3\n"));
1365 domain
->can_do_validation6
= false;
1371 * we increment this after the "feature negotiation"
1372 * for can_do_samlogon_ex and can_do_validation6
1376 /* We have to try a second time as cm_connect_netlogon
1377 might not yet have noticed that the DC has killed
1380 if (!rpccli_is_connected(netlogon_pipe
)) {
1385 /* if we get access denied, a possible cause was that we had
1386 and open connection to the DC, but someone changed our
1387 machine account password out from underneath us using 'net
1388 rpc changetrustpw' */
1390 if ( NT_STATUS_EQUAL(result
, NT_STATUS_ACCESS_DENIED
) ) {
1391 DEBUG(3,("winbind_samlogon_retry_loop: sam_logon returned "
1392 "ACCESS_DENIED. Maybe the trust account "
1393 "password was changed and we didn't know it. "
1394 "Killing connections to domain %s\n",
1396 invalidate_cm_connection(&domain
->conn
);
1400 } while ( (attempts
< 2) && retry
);
1402 if (NT_STATUS_EQUAL(result
, NT_STATUS_IO_TIMEOUT
)) {
1403 DEBUG(3,("winbind_samlogon_retry_loop: sam_network_logon(ex) "
1404 "returned NT_STATUS_IO_TIMEOUT after the retry."
1405 "Killing connections to domain %s\n",
1407 invalidate_cm_connection(&domain
->conn
);
1412 static NTSTATUS
winbindd_dual_pam_auth_samlogon(TALLOC_CTX
*mem_ctx
,
1413 struct winbindd_domain
*domain
,
1416 uint32_t request_flags
,
1417 struct netr_SamInfo3
**info3
)
1423 unsigned char local_nt_response
[24];
1424 fstring name_domain
, name_user
;
1426 struct netr_SamInfo3
*my_info3
= NULL
;
1430 DEBUG(10,("winbindd_dual_pam_auth_samlogon\n"));
1432 /* Parse domain and username */
1434 parse_domain_user(user
, name_domain
, name_user
);
1436 /* do password magic */
1438 generate_random_buffer(chal
, sizeof(chal
));
1440 if (lp_client_ntlmv2_auth()) {
1441 DATA_BLOB server_chal
;
1442 DATA_BLOB names_blob
;
1443 server_chal
= data_blob_const(chal
, 8);
1445 /* note that the 'workgroup' here is for the local
1446 machine. The 'server name' must match the
1447 'workstation' passed to the actual SamLogon call.
1449 names_blob
= NTLMv2_generate_names_blob(
1450 mem_ctx
, lp_netbios_name(), lp_workgroup());
1452 if (!SMBNTLMv2encrypt(mem_ctx
, name_user
, name_domain
,
1456 &lm_resp
, &nt_resp
, NULL
, NULL
)) {
1457 data_blob_free(&names_blob
);
1458 DEBUG(0, ("winbindd_pam_auth: SMBNTLMv2encrypt() failed!\n"));
1459 result
= NT_STATUS_NO_MEMORY
;
1462 data_blob_free(&names_blob
);
1464 lm_resp
= data_blob_null
;
1465 SMBNTencrypt(pass
, chal
, local_nt_response
);
1467 nt_resp
= data_blob_talloc(mem_ctx
, local_nt_response
,
1468 sizeof(local_nt_response
));
1471 if (strequal(name_domain
, get_global_sam_name())) {
1472 DATA_BLOB chal_blob
= data_blob_const(chal
, sizeof(chal
));
1474 result
= winbindd_dual_auth_passdb(
1475 mem_ctx
, 0, name_domain
, name_user
,
1476 &chal_blob
, &lm_resp
, &nt_resp
, info3
);
1480 /* check authentication loop */
1482 result
= winbind_samlogon_retry_loop(domain
,
1493 if (!NT_STATUS_IS_OK(result
)) {
1497 /* handle the case where a NT4 DC does not fill in the acct_flags in
1498 * the samlogon reply info3. When accurate info3 is required by the
1499 * caller, we look up the account flags ourselve - gd */
1501 if ((request_flags
& WBFLAG_PAM_INFO3_TEXT
) &&
1502 NT_STATUS_IS_OK(result
) && (my_info3
->base
.acct_flags
== 0)) {
1504 struct rpc_pipe_client
*samr_pipe
;
1505 struct policy_handle samr_domain_handle
, user_pol
;
1506 union samr_UserInfo
*info
= NULL
;
1507 NTSTATUS status_tmp
, result_tmp
;
1509 struct dcerpc_binding_handle
*b
;
1511 status_tmp
= cm_connect_sam(domain
, mem_ctx
,
1512 &samr_pipe
, &samr_domain_handle
);
1514 if (!NT_STATUS_IS_OK(status_tmp
)) {
1515 DEBUG(3, ("could not open handle to SAMR pipe: %s\n",
1516 nt_errstr(status_tmp
)));
1520 b
= samr_pipe
->binding_handle
;
1522 status_tmp
= dcerpc_samr_OpenUser(b
, mem_ctx
,
1523 &samr_domain_handle
,
1524 MAXIMUM_ALLOWED_ACCESS
,
1529 if (!NT_STATUS_IS_OK(status_tmp
)) {
1530 DEBUG(3, ("could not open user handle on SAMR pipe: %s\n",
1531 nt_errstr(status_tmp
)));
1534 if (!NT_STATUS_IS_OK(result_tmp
)) {
1535 DEBUG(3, ("could not open user handle on SAMR pipe: %s\n",
1536 nt_errstr(result_tmp
)));
1540 status_tmp
= dcerpc_samr_QueryUserInfo(b
, mem_ctx
,
1546 if (!NT_STATUS_IS_OK(status_tmp
)) {
1547 DEBUG(3, ("could not query user info on SAMR pipe: %s\n",
1548 nt_errstr(status_tmp
)));
1549 dcerpc_samr_Close(b
, mem_ctx
, &user_pol
, &result_tmp
);
1552 if (!NT_STATUS_IS_OK(result_tmp
)) {
1553 DEBUG(3, ("could not query user info on SAMR pipe: %s\n",
1554 nt_errstr(result_tmp
)));
1555 dcerpc_samr_Close(b
, mem_ctx
, &user_pol
, &result_tmp
);
1559 acct_flags
= info
->info16
.acct_flags
;
1561 if (acct_flags
== 0) {
1562 dcerpc_samr_Close(b
, mem_ctx
, &user_pol
, &result_tmp
);
1566 my_info3
->base
.acct_flags
= acct_flags
;
1568 DEBUG(10,("successfully retrieved acct_flags 0x%x\n", acct_flags
));
1570 dcerpc_samr_Close(b
, mem_ctx
, &user_pol
, &result_tmp
);
1578 enum winbindd_result
winbindd_dual_pam_auth(struct winbindd_domain
*domain
,
1579 struct winbindd_cli_state
*state
)
1581 NTSTATUS result
= NT_STATUS_LOGON_FAILURE
;
1582 NTSTATUS krb5_result
= NT_STATUS_OK
;
1583 fstring name_domain
, name_user
;
1585 fstring domain_user
;
1586 struct netr_SamInfo3
*info3
= NULL
;
1587 NTSTATUS name_map_status
= NT_STATUS_UNSUCCESSFUL
;
1589 /* Ensure null termination */
1590 state
->request
->data
.auth
.user
[sizeof(state
->request
->data
.auth
.user
)-1]='\0';
1592 /* Ensure null termination */
1593 state
->request
->data
.auth
.pass
[sizeof(state
->request
->data
.auth
.pass
)-1]='\0';
1595 DEBUG(3, ("[%5lu]: dual pam auth %s\n", (unsigned long)state
->pid
,
1596 state
->request
->data
.auth
.user
));
1598 /* Parse domain and username */
1600 name_map_status
= normalize_name_unmap(state
->mem_ctx
,
1601 state
->request
->data
.auth
.user
,
1604 /* If the name normalization didnt' actually do anything,
1605 just use the original name */
1607 if (!NT_STATUS_IS_OK(name_map_status
) &&
1608 !NT_STATUS_EQUAL(name_map_status
, NT_STATUS_FILE_RENAMED
))
1610 mapped_user
= state
->request
->data
.auth
.user
;
1613 parse_domain_user(mapped_user
, name_domain
, name_user
);
1615 if ( mapped_user
!= state
->request
->data
.auth
.user
) {
1616 fstr_sprintf( domain_user
, "%s%c%s", name_domain
,
1617 *lp_winbind_separator(),
1619 strlcpy( state
->request
->data
.auth
.user
, domain_user
,
1620 sizeof(state
->request
->data
.auth
.user
));
1623 if (!domain
->online
) {
1624 result
= NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
;
1625 if (domain
->startup
) {
1626 /* Logons are very important to users. If we're offline and
1627 we get a request within the first 30 seconds of startup,
1628 try very hard to find a DC and go online. */
1630 DEBUG(10,("winbindd_dual_pam_auth: domain: %s offline and auth "
1631 "request in startup mode.\n", domain
->name
));
1633 winbindd_flush_negative_conn_cache(domain
);
1634 result
= init_dc_connection(domain
);
1638 DEBUG(10,("winbindd_dual_pam_auth: domain: %s last was %s\n", domain
->name
, domain
->online
? "online":"offline"));
1640 /* Check for Kerberos authentication */
1641 if (domain
->online
&& (state
->request
->flags
& WBFLAG_PAM_KRB5
)) {
1643 result
= winbindd_dual_pam_auth_kerberos(domain
, state
, &info3
);
1644 /* save for later */
1645 krb5_result
= result
;
1648 if (NT_STATUS_IS_OK(result
)) {
1649 DEBUG(10,("winbindd_dual_pam_auth_kerberos succeeded\n"));
1650 goto process_result
;
1652 DEBUG(10,("winbindd_dual_pam_auth_kerberos failed: %s\n", nt_errstr(result
)));
1655 if (NT_STATUS_EQUAL(result
, NT_STATUS_NO_LOGON_SERVERS
) ||
1656 NT_STATUS_EQUAL(result
, NT_STATUS_IO_TIMEOUT
) ||
1657 NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1658 DEBUG(10,("winbindd_dual_pam_auth_kerberos setting domain to offline\n"));
1659 set_domain_offline( domain
);
1663 /* there are quite some NT_STATUS errors where there is no
1664 * point in retrying with a samlogon, we explictly have to take
1665 * care not to increase the bad logon counter on the DC */
1667 if (NT_STATUS_EQUAL(result
, NT_STATUS_ACCOUNT_DISABLED
) ||
1668 NT_STATUS_EQUAL(result
, NT_STATUS_ACCOUNT_EXPIRED
) ||
1669 NT_STATUS_EQUAL(result
, NT_STATUS_ACCOUNT_LOCKED_OUT
) ||
1670 NT_STATUS_EQUAL(result
, NT_STATUS_INVALID_LOGON_HOURS
) ||
1671 NT_STATUS_EQUAL(result
, NT_STATUS_INVALID_WORKSTATION
) ||
1672 NT_STATUS_EQUAL(result
, NT_STATUS_LOGON_FAILURE
) ||
1673 NT_STATUS_EQUAL(result
, NT_STATUS_NO_SUCH_USER
) ||
1674 NT_STATUS_EQUAL(result
, NT_STATUS_PASSWORD_EXPIRED
) ||
1675 NT_STATUS_EQUAL(result
, NT_STATUS_PASSWORD_MUST_CHANGE
) ||
1676 NT_STATUS_EQUAL(result
, NT_STATUS_WRONG_PASSWORD
)) {
1680 if (state
->request
->flags
& WBFLAG_PAM_FALLBACK_AFTER_KRB5
) {
1681 DEBUG(3,("falling back to samlogon\n"));
1689 /* Check for Samlogon authentication */
1690 if (domain
->online
) {
1691 result
= winbindd_dual_pam_auth_samlogon(
1692 state
->mem_ctx
, domain
,
1693 state
->request
->data
.auth
.user
,
1694 state
->request
->data
.auth
.pass
,
1695 state
->request
->flags
,
1698 if (NT_STATUS_IS_OK(result
)) {
1699 DEBUG(10,("winbindd_dual_pam_auth_samlogon succeeded\n"));
1700 /* add the Krb5 err if we have one */
1701 if ( NT_STATUS_EQUAL(krb5_result
, NT_STATUS_TIME_DIFFERENCE_AT_DC
) ) {
1702 info3
->base
.user_flags
|= LOGON_KRB5_FAIL_CLOCK_SKEW
;
1704 goto process_result
;
1707 DEBUG(10,("winbindd_dual_pam_auth_samlogon failed: %s\n",
1708 nt_errstr(result
)));
1710 if (NT_STATUS_EQUAL(result
, NT_STATUS_NO_LOGON_SERVERS
) ||
1711 NT_STATUS_EQUAL(result
, NT_STATUS_IO_TIMEOUT
) ||
1712 NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
))
1714 DEBUG(10,("winbindd_dual_pam_auth_samlogon setting domain to offline\n"));
1715 set_domain_offline( domain
);
1719 if (domain
->online
) {
1720 /* We're still online - fail. */
1726 /* Check for Cached logons */
1727 if (!domain
->online
&& (state
->request
->flags
& WBFLAG_PAM_CACHED_LOGIN
) &&
1728 lp_winbind_offline_logon()) {
1730 result
= winbindd_dual_pam_auth_cached(domain
, state
, &info3
);
1732 if (NT_STATUS_IS_OK(result
)) {
1733 DEBUG(10,("winbindd_dual_pam_auth_cached succeeded\n"));
1734 goto process_result
;
1736 DEBUG(10,("winbindd_dual_pam_auth_cached failed: %s\n", nt_errstr(result
)));
1743 if (NT_STATUS_IS_OK(result
)) {
1745 struct dom_sid user_sid
;
1747 /* In all codepaths where result == NT_STATUS_OK info3 must have
1748 been initialized. */
1750 result
= NT_STATUS_INTERNAL_ERROR
;
1754 sid_compose(&user_sid
, info3
->base
.domain_sid
,
1757 wcache_invalidate_samlogon(find_domain_from_name(name_domain
),
1759 netsamlogon_cache_store(name_user
, info3
);
1761 /* save name_to_sid info as early as possible (only if
1762 this is our primary domain so we don't invalidate
1763 the cache entry by storing the seq_num for the wrong
1765 if ( domain
->primary
) {
1766 cache_name2sid(domain
, name_domain
, name_user
,
1767 SID_NAME_USER
, &user_sid
);
1770 /* Check if the user is in the right group */
1772 result
= check_info3_in_group(
1774 state
->request
->data
.auth
.require_membership_of_sid
);
1775 if (!NT_STATUS_IS_OK(result
)) {
1776 DEBUG(3, ("User %s is not in the required group (%s), so plaintext authentication is rejected\n",
1777 state
->request
->data
.auth
.user
,
1778 state
->request
->data
.auth
.require_membership_of_sid
));
1782 result
= append_auth_data(state
->mem_ctx
, state
->response
,
1783 state
->request
->flags
, info3
,
1784 name_domain
, name_user
);
1785 if (!NT_STATUS_IS_OK(result
)) {
1789 if ((state
->request
->flags
& WBFLAG_PAM_CACHED_LOGIN
)
1790 && lp_winbind_offline_logon()) {
1792 result
= winbindd_store_creds(domain
,
1793 state
->request
->data
.auth
.user
,
1794 state
->request
->data
.auth
.pass
,
1798 if (state
->request
->flags
& WBFLAG_PAM_GET_PWD_POLICY
) {
1799 struct winbindd_domain
*our_domain
= find_our_domain();
1801 /* This is not entirely correct I believe, but it is
1802 consistent. Only apply the password policy settings
1803 too warn users for our own domain. Cannot obtain these
1804 from trusted DCs all the time so don't do it at all.
1807 result
= NT_STATUS_NOT_SUPPORTED
;
1808 if (our_domain
== domain
) {
1809 result
= fillup_password_policy(
1810 our_domain
, state
->response
);
1813 if (!NT_STATUS_IS_OK(result
)
1814 && !NT_STATUS_EQUAL(result
, NT_STATUS_NOT_SUPPORTED
) )
1816 DEBUG(10,("Failed to get password policies for domain %s: %s\n",
1817 domain
->name
, nt_errstr(result
)));
1822 result
= NT_STATUS_OK
;
1826 /* give us a more useful (more correct?) error code */
1827 if ((NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ||
1828 (NT_STATUS_EQUAL(result
, NT_STATUS_UNSUCCESSFUL
)))) {
1829 result
= NT_STATUS_NO_LOGON_SERVERS
;
1832 set_auth_errors(state
->response
, result
);
1834 DEBUG(NT_STATUS_IS_OK(result
) ? 5 : 2, ("Plain-text authentication for user %s returned %s (PAM: %d)\n",
1835 state
->request
->data
.auth
.user
,
1836 state
->response
->data
.auth
.nt_status_string
,
1837 state
->response
->data
.auth
.pam_error
));
1839 return NT_STATUS_IS_OK(result
) ? WINBINDD_OK
: WINBINDD_ERROR
;
1842 enum winbindd_result
winbindd_dual_pam_auth_crap(struct winbindd_domain
*domain
,
1843 struct winbindd_cli_state
*state
)
1846 struct netr_SamInfo3
*info3
= NULL
;
1847 const char *name_user
= NULL
;
1848 const char *name_domain
= NULL
;
1849 const char *workstation
;
1851 DATA_BLOB lm_resp
, nt_resp
;
1853 /* This is child-only, so no check for privileged access is needed
1856 /* Ensure null termination */
1857 state
->request
->data
.auth_crap
.user
[sizeof(state
->request
->data
.auth_crap
.user
)-1]=0;
1858 state
->request
->data
.auth_crap
.domain
[sizeof(state
->request
->data
.auth_crap
.domain
)-1]=0;
1860 name_user
= state
->request
->data
.auth_crap
.user
;
1861 name_domain
= state
->request
->data
.auth_crap
.domain
;
1862 workstation
= state
->request
->data
.auth_crap
.workstation
;
1864 DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n", (unsigned long)state
->pid
,
1865 name_domain
, name_user
));
1867 if (state
->request
->data
.auth_crap
.lm_resp_len
> sizeof(state
->request
->data
.auth_crap
.lm_resp
)
1868 || state
->request
->data
.auth_crap
.nt_resp_len
> sizeof(state
->request
->data
.auth_crap
.nt_resp
)) {
1869 if (!(state
->request
->flags
& WBFLAG_BIG_NTLMV2_BLOB
) ||
1870 state
->request
->extra_len
!= state
->request
->data
.auth_crap
.nt_resp_len
) {
1871 DEBUG(0, ("winbindd_pam_auth_crap: invalid password length %u/%u\n",
1872 state
->request
->data
.auth_crap
.lm_resp_len
,
1873 state
->request
->data
.auth_crap
.nt_resp_len
));
1874 result
= NT_STATUS_INVALID_PARAMETER
;
1879 lm_resp
= data_blob_talloc(state
->mem_ctx
, state
->request
->data
.auth_crap
.lm_resp
,
1880 state
->request
->data
.auth_crap
.lm_resp_len
);
1882 if (state
->request
->flags
& WBFLAG_BIG_NTLMV2_BLOB
) {
1883 nt_resp
= data_blob_talloc(state
->mem_ctx
,
1884 state
->request
->extra_data
.data
,
1885 state
->request
->data
.auth_crap
.nt_resp_len
);
1887 nt_resp
= data_blob_talloc(state
->mem_ctx
,
1888 state
->request
->data
.auth_crap
.nt_resp
,
1889 state
->request
->data
.auth_crap
.nt_resp_len
);
1892 if (strequal(name_domain
, get_global_sam_name())) {
1893 DATA_BLOB chal_blob
= data_blob_const(
1894 state
->request
->data
.auth_crap
.chal
,
1895 sizeof(state
->request
->data
.auth_crap
.chal
));
1897 result
= winbindd_dual_auth_passdb(
1899 state
->request
->data
.auth_crap
.logon_parameters
,
1900 name_domain
, name_user
,
1901 &chal_blob
, &lm_resp
, &nt_resp
, &info3
);
1902 goto process_result
;
1905 result
= winbind_samlogon_retry_loop(domain
,
1907 state
->request
->data
.auth_crap
.logon_parameters
,
1911 /* Bug #3248 - found by Stefan Burkei. */
1912 workstation
, /* We carefully set this above so use it... */
1913 state
->request
->data
.auth_crap
.chal
,
1917 if (!NT_STATUS_IS_OK(result
)) {
1923 if (NT_STATUS_IS_OK(result
)) {
1924 struct dom_sid user_sid
;
1926 sid_compose(&user_sid
, info3
->base
.domain_sid
,
1928 wcache_invalidate_samlogon(find_domain_from_name(name_domain
),
1930 netsamlogon_cache_store(name_user
, info3
);
1932 /* Check if the user is in the right group */
1934 result
= check_info3_in_group(
1936 state
->request
->data
.auth_crap
.require_membership_of_sid
);
1937 if (!NT_STATUS_IS_OK(result
)) {
1938 DEBUG(3, ("User %s is not in the required group (%s), so "
1939 "crap authentication is rejected\n",
1940 state
->request
->data
.auth_crap
.user
,
1941 state
->request
->data
.auth_crap
.require_membership_of_sid
));
1945 result
= append_auth_data(state
->mem_ctx
, state
->response
,
1946 state
->request
->flags
, info3
,
1947 name_domain
, name_user
);
1948 if (!NT_STATUS_IS_OK(result
)) {
1955 /* give us a more useful (more correct?) error code */
1956 if ((NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ||
1957 (NT_STATUS_EQUAL(result
, NT_STATUS_UNSUCCESSFUL
)))) {
1958 result
= NT_STATUS_NO_LOGON_SERVERS
;
1961 if (state
->request
->flags
& WBFLAG_PAM_NT_STATUS_SQUASH
) {
1962 result
= nt_status_squash(result
);
1965 set_auth_errors(state
->response
, result
);
1967 DEBUG(NT_STATUS_IS_OK(result
) ? 5 : 2,
1968 ("NTLM CRAP authentication for user [%s]\\[%s] returned %s (PAM: %d)\n",
1971 state
->response
->data
.auth
.nt_status_string
,
1972 state
->response
->data
.auth
.pam_error
));
1974 return NT_STATUS_IS_OK(result
) ? WINBINDD_OK
: WINBINDD_ERROR
;
1977 enum winbindd_result
winbindd_dual_pam_chauthtok(struct winbindd_domain
*contact_domain
,
1978 struct winbindd_cli_state
*state
)
1981 char *newpass
= NULL
;
1982 struct policy_handle dom_pol
;
1983 struct rpc_pipe_client
*cli
= NULL
;
1984 bool got_info
= false;
1985 struct samr_DomInfo1
*info
= NULL
;
1986 struct userPwdChangeFailureInformation
*reject
= NULL
;
1987 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
1988 fstring domain
, user
;
1989 struct dcerpc_binding_handle
*b
= NULL
;
1991 ZERO_STRUCT(dom_pol
);
1993 DEBUG(3, ("[%5lu]: dual pam chauthtok %s\n", (unsigned long)state
->pid
,
1994 state
->request
->data
.auth
.user
));
1996 if (!parse_domain_user(state
->request
->data
.chauthtok
.user
, domain
, user
)) {
2000 /* Change password */
2002 oldpass
= state
->request
->data
.chauthtok
.oldpass
;
2003 newpass
= state
->request
->data
.chauthtok
.newpass
;
2005 /* Initialize reject reason */
2006 state
->response
->data
.auth
.reject_reason
= Undefined
;
2008 /* Get sam handle */
2010 result
= cm_connect_sam(contact_domain
, state
->mem_ctx
, &cli
,
2012 if (!NT_STATUS_IS_OK(result
)) {
2013 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain
));
2017 b
= cli
->binding_handle
;
2019 result
= rpccli_samr_chgpasswd_user3(cli
, state
->mem_ctx
,
2026 /* Windows 2003 returns NT_STATUS_PASSWORD_RESTRICTION */
2028 if (NT_STATUS_EQUAL(result
, NT_STATUS_PASSWORD_RESTRICTION
) ) {
2030 fill_in_password_policy(state
->response
, info
);
2032 state
->response
->data
.auth
.reject_reason
=
2033 reject
->extendedFailureReason
;
2038 /* atm the pidl generated rpccli_samr_ChangePasswordUser3 function will
2039 * return with NT_STATUS_BUFFER_TOO_SMALL for w2k dcs as w2k just
2040 * returns with 4byte error code (NT_STATUS_NOT_SUPPORTED) which is too
2041 * short to comply with the samr_ChangePasswordUser3 idl - gd */
2043 /* only fallback when the chgpasswd_user3 call is not supported */
2044 if (NT_STATUS_EQUAL(result
, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
) ||
2045 NT_STATUS_EQUAL(result
, NT_STATUS_NOT_SUPPORTED
) ||
2046 NT_STATUS_EQUAL(result
, NT_STATUS_BUFFER_TOO_SMALL
) ||
2047 NT_STATUS_EQUAL(result
, NT_STATUS_NOT_IMPLEMENTED
)) {
2049 DEBUG(10,("Password change with chgpasswd_user3 failed with: %s, retrying chgpasswd_user2\n",
2050 nt_errstr(result
)));
2052 result
= rpccli_samr_chgpasswd_user2(cli
, state
->mem_ctx
, user
, newpass
, oldpass
);
2054 /* Windows 2000 returns NT_STATUS_ACCOUNT_RESTRICTION.
2055 Map to the same status code as Windows 2003. */
2057 if ( NT_STATUS_EQUAL(NT_STATUS_ACCOUNT_RESTRICTION
, result
) ) {
2058 result
= NT_STATUS_PASSWORD_RESTRICTION
;
2064 if (NT_STATUS_IS_OK(result
)
2065 && (state
->request
->flags
& WBFLAG_PAM_CACHED_LOGIN
)
2066 && lp_winbind_offline_logon()) {
2067 result
= winbindd_update_creds_by_name(contact_domain
, user
,
2069 /* Again, this happens when we login from gdm or xdm
2070 * and the password expires, *BUT* cached crendentials
2071 * doesn't exist. winbindd_update_creds_by_name()
2072 * returns NT_STATUS_NO_SUCH_USER.
2073 * This is not a failure.
2076 if (NT_STATUS_EQUAL(result
, NT_STATUS_NO_SUCH_USER
)) {
2077 result
= NT_STATUS_OK
;
2080 if (!NT_STATUS_IS_OK(result
)) {
2081 DEBUG(10, ("Failed to store creds: %s\n",
2082 nt_errstr(result
)));
2083 goto process_result
;
2087 if (!NT_STATUS_IS_OK(result
) && !got_info
&& contact_domain
) {
2089 NTSTATUS policy_ret
;
2091 policy_ret
= fillup_password_policy(
2092 contact_domain
, state
->response
);
2094 /* failure of this is non critical, it will just provide no
2095 * additional information to the client why the change has
2096 * failed - Guenther */
2098 if (!NT_STATUS_IS_OK(policy_ret
)) {
2099 DEBUG(10,("Failed to get password policies: %s\n", nt_errstr(policy_ret
)));
2100 goto process_result
;
2106 if (strequal(contact_domain
->name
, get_global_sam_name())) {
2107 /* FIXME: internal rpc pipe does not cache handles yet */
2109 if (is_valid_policy_hnd(&dom_pol
)) {
2111 dcerpc_samr_Close(b
, state
->mem_ctx
, &dom_pol
, &_result
);
2117 set_auth_errors(state
->response
, result
);
2119 DEBUG(NT_STATUS_IS_OK(result
) ? 5 : 2,
2120 ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
2123 state
->response
->data
.auth
.nt_status_string
,
2124 state
->response
->data
.auth
.pam_error
));
2126 return NT_STATUS_IS_OK(result
) ? WINBINDD_OK
: WINBINDD_ERROR
;
2129 enum winbindd_result
winbindd_dual_pam_logoff(struct winbindd_domain
*domain
,
2130 struct winbindd_cli_state
*state
)
2132 NTSTATUS result
= NT_STATUS_NOT_SUPPORTED
;
2134 DEBUG(3, ("[%5lu]: pam dual logoff %s\n", (unsigned long)state
->pid
,
2135 state
->request
->data
.logoff
.user
));
2137 if (!(state
->request
->flags
& WBFLAG_PAM_KRB5
)) {
2138 result
= NT_STATUS_OK
;
2139 goto process_result
;
2142 if (state
->request
->data
.logoff
.krb5ccname
[0] == '\0') {
2143 result
= NT_STATUS_OK
;
2144 goto process_result
;
2149 if (state
->request
->data
.logoff
.uid
< 0) {
2150 DEBUG(0,("winbindd_pam_logoff: invalid uid\n"));
2151 goto process_result
;
2154 /* what we need here is to find the corresponding krb5 ccache name *we*
2155 * created for a given username and destroy it */
2157 if (!ccache_entry_exists(state
->request
->data
.logoff
.user
)) {
2158 result
= NT_STATUS_OK
;
2159 DEBUG(10,("winbindd_pam_logoff: no entry found.\n"));
2160 goto process_result
;
2163 if (!ccache_entry_identical(state
->request
->data
.logoff
.user
,
2164 state
->request
->data
.logoff
.uid
,
2165 state
->request
->data
.logoff
.krb5ccname
)) {
2166 DEBUG(0,("winbindd_pam_logoff: cached entry differs.\n"));
2167 goto process_result
;
2170 result
= remove_ccache(state
->request
->data
.logoff
.user
);
2171 if (!NT_STATUS_IS_OK(result
)) {
2172 DEBUG(0,("winbindd_pam_logoff: failed to remove ccache: %s\n",
2173 nt_errstr(result
)));
2174 goto process_result
;
2178 * Remove any mlock'ed memory creds in the child
2179 * we might be using for krb5 ticket renewal.
2182 winbindd_delete_memory_creds(state
->request
->data
.logoff
.user
);
2185 result
= NT_STATUS_NOT_SUPPORTED
;
2191 set_auth_errors(state
->response
, result
);
2193 return NT_STATUS_IS_OK(result
) ? WINBINDD_OK
: WINBINDD_ERROR
;
2196 /* Change user password with auth crap*/
2198 enum winbindd_result
winbindd_dual_pam_chng_pswd_auth_crap(struct winbindd_domain
*domainSt
, struct winbindd_cli_state
*state
)
2201 DATA_BLOB new_nt_password
;
2202 DATA_BLOB old_nt_hash_enc
;
2203 DATA_BLOB new_lm_password
;
2204 DATA_BLOB old_lm_hash_enc
;
2205 fstring domain
,user
;
2206 struct policy_handle dom_pol
;
2207 struct winbindd_domain
*contact_domain
= domainSt
;
2208 struct rpc_pipe_client
*cli
= NULL
;
2209 struct dcerpc_binding_handle
*b
= NULL
;
2211 ZERO_STRUCT(dom_pol
);
2213 /* Ensure null termination */
2214 state
->request
->data
.chng_pswd_auth_crap
.user
[
2215 sizeof(state
->request
->data
.chng_pswd_auth_crap
.user
)-1]=0;
2216 state
->request
->data
.chng_pswd_auth_crap
.domain
[
2217 sizeof(state
->request
->data
.chng_pswd_auth_crap
.domain
)-1]=0;
2221 DEBUG(3, ("[%5lu]: pam change pswd auth crap domain: %s user: %s\n",
2222 (unsigned long)state
->pid
,
2223 state
->request
->data
.chng_pswd_auth_crap
.domain
,
2224 state
->request
->data
.chng_pswd_auth_crap
.user
));
2226 if (lp_winbind_offline_logon()) {
2227 DEBUG(0,("Refusing password change as winbind offline logons are enabled. "));
2228 DEBUGADD(0,("Changing passwords here would risk inconsistent logons\n"));
2229 result
= NT_STATUS_ACCESS_DENIED
;
2233 if (*state
->request
->data
.chng_pswd_auth_crap
.domain
) {
2234 fstrcpy(domain
,state
->request
->data
.chng_pswd_auth_crap
.domain
);
2236 parse_domain_user(state
->request
->data
.chng_pswd_auth_crap
.user
,
2240 DEBUG(3,("no domain specified with username (%s) - "
2242 state
->request
->data
.chng_pswd_auth_crap
.user
));
2243 result
= NT_STATUS_NO_SUCH_USER
;
2248 if (!*domain
&& lp_winbind_use_default_domain()) {
2249 fstrcpy(domain
,lp_workgroup());
2253 fstrcpy(user
, state
->request
->data
.chng_pswd_auth_crap
.user
);
2256 DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n",
2257 (unsigned long)state
->pid
, domain
, user
));
2259 /* Change password */
2260 new_nt_password
= data_blob_const(
2261 state
->request
->data
.chng_pswd_auth_crap
.new_nt_pswd
,
2262 state
->request
->data
.chng_pswd_auth_crap
.new_nt_pswd_len
);
2264 old_nt_hash_enc
= data_blob_const(
2265 state
->request
->data
.chng_pswd_auth_crap
.old_nt_hash_enc
,
2266 state
->request
->data
.chng_pswd_auth_crap
.old_nt_hash_enc_len
);
2268 if(state
->request
->data
.chng_pswd_auth_crap
.new_lm_pswd_len
> 0) {
2269 new_lm_password
= data_blob_const(
2270 state
->request
->data
.chng_pswd_auth_crap
.new_lm_pswd
,
2271 state
->request
->data
.chng_pswd_auth_crap
.new_lm_pswd_len
);
2273 old_lm_hash_enc
= data_blob_const(
2274 state
->request
->data
.chng_pswd_auth_crap
.old_lm_hash_enc
,
2275 state
->request
->data
.chng_pswd_auth_crap
.old_lm_hash_enc_len
);
2277 new_lm_password
= data_blob_null
;
2278 old_lm_hash_enc
= data_blob_null
;
2281 /* Get sam handle */
2283 result
= cm_connect_sam(contact_domain
, state
->mem_ctx
, &cli
, &dom_pol
);
2284 if (!NT_STATUS_IS_OK(result
)) {
2285 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain
));
2289 b
= cli
->binding_handle
;
2291 result
= rpccli_samr_chng_pswd_auth_crap(
2292 cli
, state
->mem_ctx
, user
, new_nt_password
, old_nt_hash_enc
,
2293 new_lm_password
, old_lm_hash_enc
);
2297 if (strequal(contact_domain
->name
, get_global_sam_name())) {
2298 /* FIXME: internal rpc pipe does not cache handles yet */
2300 if (is_valid_policy_hnd(&dom_pol
)) {
2302 dcerpc_samr_Close(b
, state
->mem_ctx
, &dom_pol
, &_result
);
2308 set_auth_errors(state
->response
, result
);
2310 DEBUG(NT_STATUS_IS_OK(result
) ? 5 : 2,
2311 ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
2313 state
->response
->data
.auth
.nt_status_string
,
2314 state
->response
->data
.auth
.pam_error
));
2316 return NT_STATUS_IS_OK(result
) ? WINBINDD_OK
: WINBINDD_ERROR
;
2320 static NTSTATUS
extract_pac_vrfy_sigs(TALLOC_CTX
*mem_ctx
, DATA_BLOB pac_blob
,
2321 struct PAC_LOGON_INFO
**logon_info
)
2323 krb5_context krbctx
= NULL
;
2324 krb5_error_code k5ret
;
2326 krb5_kt_cursor cursor
;
2327 krb5_keytab_entry entry
;
2328 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
2331 ZERO_STRUCT(cursor
);
2333 k5ret
= krb5_init_context(&krbctx
);
2335 DEBUG(1, ("Failed to initialize kerberos context: %s\n",
2336 error_message(k5ret
)));
2337 status
= krb5_to_nt_status(k5ret
);
2341 k5ret
= gse_krb5_get_server_keytab(krbctx
, &keytab
);
2343 DEBUG(1, ("Failed to get keytab: %s\n",
2344 error_message(k5ret
)));
2345 status
= krb5_to_nt_status(k5ret
);
2349 k5ret
= krb5_kt_start_seq_get(krbctx
, keytab
, &cursor
);
2351 DEBUG(1, ("Failed to start seq: %s\n",
2352 error_message(k5ret
)));
2353 status
= krb5_to_nt_status(k5ret
);
2357 k5ret
= krb5_kt_next_entry(krbctx
, keytab
, &entry
, &cursor
);
2358 while (k5ret
== 0) {
2359 status
= kerberos_pac_logon_info(mem_ctx
, pac_blob
,
2361 KRB5_KT_KEY(&entry
), NULL
, 0,
2363 if (NT_STATUS_IS_OK(status
)) {
2366 k5ret
= smb_krb5_kt_free_entry(krbctx
, &entry
);
2367 k5ret
= krb5_kt_next_entry(krbctx
, keytab
, &entry
, &cursor
);
2370 k5ret
= krb5_kt_end_seq_get(krbctx
, keytab
, &cursor
);
2372 DEBUG(1, ("Failed to end seq: %s\n",
2373 error_message(k5ret
)));
2376 k5ret
= krb5_kt_close(krbctx
, keytab
);
2378 DEBUG(1, ("Failed to close keytab: %s\n",
2379 error_message(k5ret
)));
2382 krb5_free_context(krbctx
);
2387 NTSTATUS
winbindd_pam_auth_pac_send(struct winbindd_cli_state
*state
,
2388 struct netr_SamInfo3
**info3
)
2390 struct winbindd_request
*req
= state
->request
;
2392 struct PAC_LOGON_INFO
*logon_info
= NULL
;
2395 pac_blob
= data_blob_const(req
->extra_data
.data
, req
->extra_len
);
2396 result
= extract_pac_vrfy_sigs(state
->mem_ctx
, pac_blob
, &logon_info
);
2397 if (!NT_STATUS_IS_OK(result
) &&
2398 !NT_STATUS_EQUAL(result
, NT_STATUS_ACCESS_DENIED
)) {
2399 DEBUG(1, ("Error during PAC signature verification: %s\n",
2400 nt_errstr(result
)));
2405 /* Signature verification succeeded, trust the PAC */
2406 netsamlogon_cache_store(NULL
, &logon_info
->info3
);
2409 /* Try without signature verification */
2410 result
= kerberos_pac_logon_info(state
->mem_ctx
, pac_blob
, NULL
,
2411 NULL
, NULL
, NULL
, 0,
2413 if (!NT_STATUS_IS_OK(result
)) {
2414 DEBUG(10, ("Could not extract PAC: %s\n",
2415 nt_errstr(result
)));
2420 *info3
= &logon_info
->info3
;
2422 return NT_STATUS_OK
;
2424 #else /* HAVE_KRB5 */
2425 NTSTATUS
winbindd_pam_auth_pac_send(struct winbindd_cli_state
*state
,
2426 struct netr_SamInfo3
**info3
)
2428 return NT_STATUS_NO_SUCH_USER
;
2430 #endif /* HAVE_KRB5 */