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"
43 #define DBGC_CLASS DBGC_WINBIND
45 #define LOGON_KRB5_FAIL_CLOCK_SKEW 0x02000000
47 static NTSTATUS
append_info3_as_txt(TALLOC_CTX
*mem_ctx
,
48 struct winbindd_response
*resp
,
49 struct netr_SamInfo3
*info3
)
54 resp
->data
.auth
.info3
.logon_time
=
55 nt_time_to_unix(info3
->base
.logon_time
);
56 resp
->data
.auth
.info3
.logoff_time
=
57 nt_time_to_unix(info3
->base
.logoff_time
);
58 resp
->data
.auth
.info3
.kickoff_time
=
59 nt_time_to_unix(info3
->base
.kickoff_time
);
60 resp
->data
.auth
.info3
.pass_last_set_time
=
61 nt_time_to_unix(info3
->base
.last_password_change
);
62 resp
->data
.auth
.info3
.pass_can_change_time
=
63 nt_time_to_unix(info3
->base
.allow_password_change
);
64 resp
->data
.auth
.info3
.pass_must_change_time
=
65 nt_time_to_unix(info3
->base
.force_password_change
);
67 resp
->data
.auth
.info3
.logon_count
= info3
->base
.logon_count
;
68 resp
->data
.auth
.info3
.bad_pw_count
= info3
->base
.bad_password_count
;
70 resp
->data
.auth
.info3
.user_rid
= info3
->base
.rid
;
71 resp
->data
.auth
.info3
.group_rid
= info3
->base
.primary_gid
;
72 sid_to_fstring(resp
->data
.auth
.info3
.dom_sid
, info3
->base
.domain_sid
);
74 resp
->data
.auth
.info3
.num_groups
= info3
->base
.groups
.count
;
75 resp
->data
.auth
.info3
.user_flgs
= info3
->base
.user_flags
;
77 resp
->data
.auth
.info3
.acct_flags
= info3
->base
.acct_flags
;
78 resp
->data
.auth
.info3
.num_other_sids
= info3
->sidcount
;
80 fstrcpy(resp
->data
.auth
.info3
.user_name
,
81 info3
->base
.account_name
.string
);
82 fstrcpy(resp
->data
.auth
.info3
.full_name
,
83 info3
->base
.full_name
.string
);
84 fstrcpy(resp
->data
.auth
.info3
.logon_script
,
85 info3
->base
.logon_script
.string
);
86 fstrcpy(resp
->data
.auth
.info3
.profile_path
,
87 info3
->base
.profile_path
.string
);
88 fstrcpy(resp
->data
.auth
.info3
.home_dir
,
89 info3
->base
.home_directory
.string
);
90 fstrcpy(resp
->data
.auth
.info3
.dir_drive
,
91 info3
->base
.home_drive
.string
);
93 fstrcpy(resp
->data
.auth
.info3
.logon_srv
,
94 info3
->base
.logon_server
.string
);
95 fstrcpy(resp
->data
.auth
.info3
.logon_dom
,
96 info3
->base
.logon_domain
.string
);
98 ex
= talloc_strdup(mem_ctx
, "");
99 NT_STATUS_HAVE_NO_MEMORY(ex
);
101 for (i
=0; i
< info3
->base
.groups
.count
; i
++) {
102 ex
= talloc_asprintf_append_buffer(ex
, "0x%08X:0x%08X\n",
103 info3
->base
.groups
.rids
[i
].rid
,
104 info3
->base
.groups
.rids
[i
].attributes
);
105 NT_STATUS_HAVE_NO_MEMORY(ex
);
108 for (i
=0; i
< info3
->sidcount
; i
++) {
111 sid
= dom_sid_string(mem_ctx
, info3
->sids
[i
].sid
);
112 NT_STATUS_HAVE_NO_MEMORY(sid
);
114 ex
= talloc_asprintf_append_buffer(ex
, "%s:0x%08X\n",
116 info3
->sids
[i
].attributes
);
117 NT_STATUS_HAVE_NO_MEMORY(ex
);
122 resp
->extra_data
.data
= ex
;
123 resp
->length
+= talloc_get_size(ex
);
128 static NTSTATUS
append_info3_as_ndr(TALLOC_CTX
*mem_ctx
,
129 struct winbindd_response
*resp
,
130 struct netr_SamInfo3
*info3
)
133 enum ndr_err_code ndr_err
;
135 ndr_err
= ndr_push_struct_blob(&blob
, mem_ctx
, info3
,
136 (ndr_push_flags_fn_t
)ndr_push_netr_SamInfo3
);
137 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
138 DEBUG(0,("append_info3_as_ndr: failed to append\n"));
139 return ndr_map_error2ntstatus(ndr_err
);
142 resp
->extra_data
.data
= blob
.data
;
143 resp
->length
+= blob
.length
;
148 static NTSTATUS
append_unix_username(TALLOC_CTX
*mem_ctx
,
149 struct winbindd_response
*resp
,
150 const struct netr_SamInfo3
*info3
,
151 const char *name_domain
,
152 const char *name_user
)
154 /* We've been asked to return the unix username, per
155 'winbind use default domain' settings and the like */
157 const char *nt_username
, *nt_domain
;
159 nt_domain
= talloc_strdup(mem_ctx
, info3
->base
.logon_domain
.string
);
161 /* If the server didn't give us one, just use the one
163 nt_domain
= name_domain
;
166 nt_username
= talloc_strdup(mem_ctx
, info3
->base
.account_name
.string
);
168 /* If the server didn't give us one, just use the one
170 nt_username
= name_user
;
173 fill_domain_username(resp
->data
.auth
.unix_username
,
174 nt_domain
, nt_username
, true);
176 DEBUG(5, ("Setting unix username to [%s]\n",
177 resp
->data
.auth
.unix_username
));
182 static NTSTATUS
append_afs_token(TALLOC_CTX
*mem_ctx
,
183 struct winbindd_response
*resp
,
184 const struct netr_SamInfo3
*info3
,
185 const char *name_domain
,
186 const char *name_user
)
188 char *afsname
= NULL
;
192 afsname
= talloc_strdup(mem_ctx
, lp_afs_username_map());
193 if (afsname
== NULL
) {
194 return NT_STATUS_NO_MEMORY
;
197 afsname
= talloc_string_sub(mem_ctx
,
198 lp_afs_username_map(),
200 afsname
= talloc_string_sub(mem_ctx
, afsname
,
202 afsname
= talloc_string_sub(mem_ctx
, afsname
,
206 struct dom_sid user_sid
;
209 sid_compose(&user_sid
, info3
->base
.domain_sid
,
211 sid_to_fstring(sidstr
, &user_sid
);
212 afsname
= talloc_string_sub(mem_ctx
, afsname
,
216 if (afsname
== NULL
) {
217 return NT_STATUS_NO_MEMORY
;
222 DEBUG(10, ("Generating token for user %s\n", afsname
));
224 cell
= strchr(afsname
, '@');
227 return NT_STATUS_NO_MEMORY
;
233 token
= afs_createtoken_str(afsname
, cell
);
237 resp
->extra_data
.data
= talloc_strdup(mem_ctx
, token
);
238 if (resp
->extra_data
.data
== NULL
) {
239 return NT_STATUS_NO_MEMORY
;
241 resp
->length
+= strlen((const char *)resp
->extra_data
.data
)+1;
246 static NTSTATUS
check_info3_in_group(struct netr_SamInfo3
*info3
,
247 const char *group_sid
)
249 * Check whether a user belongs to a group or list of groups.
251 * @param mem_ctx talloc memory context.
252 * @param info3 user information, including group membership info.
253 * @param group_sid One or more groups , separated by commas.
255 * @return NT_STATUS_OK on success,
256 * NT_STATUS_LOGON_FAILURE if the user does not belong,
257 * or other NT_STATUS_IS_ERR(status) for other kinds of failure.
260 struct dom_sid
*require_membership_of_sid
;
261 uint32_t num_require_membership_of_sid
;
266 struct security_token
*token
;
267 TALLOC_CTX
*frame
= talloc_stackframe();
270 /* Parse the 'required group' SID */
272 if (!group_sid
|| !group_sid
[0]) {
273 /* NO sid supplied, all users may access */
277 token
= talloc_zero(talloc_tos(), struct security_token
);
279 DEBUG(0, ("talloc failed\n"));
281 return NT_STATUS_NO_MEMORY
;
284 num_require_membership_of_sid
= 0;
285 require_membership_of_sid
= NULL
;
289 while (next_token_talloc(talloc_tos(), &p
, &req_sid
, ",")) {
290 if (!string_to_sid(&sid
, req_sid
)) {
291 DEBUG(0, ("check_info3_in_group: could not parse %s "
292 "as a SID!", req_sid
));
294 return NT_STATUS_INVALID_PARAMETER
;
297 status
= add_sid_to_array(talloc_tos(), &sid
,
298 &require_membership_of_sid
,
299 &num_require_membership_of_sid
);
300 if (!NT_STATUS_IS_OK(status
)) {
301 DEBUG(0, ("add_sid_to_array failed\n"));
307 status
= sid_array_from_info3(talloc_tos(), info3
,
311 if (!NT_STATUS_IS_OK(status
)) {
316 if (!NT_STATUS_IS_OK(status
= add_aliases(get_global_sam_sid(),
318 || !NT_STATUS_IS_OK(status
= add_aliases(&global_sid_Builtin
,
320 DEBUG(3, ("could not add aliases: %s\n",
326 security_token_debug(DBGC_CLASS
, 10, token
);
328 for (i
=0; i
<num_require_membership_of_sid
; i
++) {
329 DEBUG(10, ("Checking SID %s\n", sid_string_dbg(
330 &require_membership_of_sid
[i
])));
331 if (nt_token_check_sid(&require_membership_of_sid
[i
],
333 DEBUG(10, ("Access ok\n"));
339 /* Do not distinguish this error from a wrong username/pw */
342 return NT_STATUS_LOGON_FAILURE
;
345 struct winbindd_domain
*find_auth_domain(uint8_t flags
,
346 const char *domain_name
)
348 struct winbindd_domain
*domain
;
351 domain
= find_domain_from_name_noinit(domain_name
);
352 if (domain
== NULL
) {
353 DEBUG(3, ("Authentication for domain [%s] refused "
354 "as it is not a trusted domain\n",
360 if (strequal(domain_name
, get_global_sam_name())) {
361 return find_domain_from_name_noinit(domain_name
);
364 /* we can auth against trusted domains */
365 if (flags
& WBFLAG_PAM_CONTACT_TRUSTDOM
) {
366 domain
= find_domain_from_name_noinit(domain_name
);
367 if (domain
== NULL
) {
368 DEBUG(3, ("Authentication for domain [%s] skipped "
369 "as it is not a trusted domain\n",
376 return find_our_domain();
379 static void fill_in_password_policy(struct winbindd_response
*r
,
380 const struct samr_DomInfo1
*p
)
382 r
->data
.auth
.policy
.min_length_password
=
383 p
->min_password_length
;
384 r
->data
.auth
.policy
.password_history
=
385 p
->password_history_length
;
386 r
->data
.auth
.policy
.password_properties
=
387 p
->password_properties
;
388 r
->data
.auth
.policy
.expire
=
389 nt_time_to_unix_abs((const NTTIME
*)&(p
->max_password_age
));
390 r
->data
.auth
.policy
.min_passwordage
=
391 nt_time_to_unix_abs((const NTTIME
*)&(p
->min_password_age
));
394 static NTSTATUS
fillup_password_policy(struct winbindd_domain
*domain
,
395 struct winbindd_response
*response
)
397 TALLOC_CTX
*frame
= talloc_stackframe();
398 struct winbindd_methods
*methods
;
400 struct samr_DomInfo1 password_policy
;
402 if ( !winbindd_can_contact_domain( domain
) ) {
403 DEBUG(5,("fillup_password_policy: No inbound trust to "
404 "contact domain %s\n", domain
->name
));
405 status
= NT_STATUS_NOT_SUPPORTED
;
409 methods
= domain
->methods
;
411 status
= methods
->password_policy(domain
, talloc_tos(), &password_policy
);
412 if (NT_STATUS_IS_ERR(status
)) {
416 fill_in_password_policy(response
, &password_policy
);
423 static NTSTATUS
get_max_bad_attempts_from_lockout_policy(struct winbindd_domain
*domain
,
425 uint16
*lockout_threshold
)
427 struct winbindd_methods
*methods
;
428 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
429 struct samr_DomInfo12 lockout_policy
;
431 *lockout_threshold
= 0;
433 methods
= domain
->methods
;
435 status
= methods
->lockout_policy(domain
, mem_ctx
, &lockout_policy
);
436 if (NT_STATUS_IS_ERR(status
)) {
440 *lockout_threshold
= lockout_policy
.lockout_threshold
;
445 static NTSTATUS
get_pwd_properties(struct winbindd_domain
*domain
,
447 uint32
*password_properties
)
449 struct winbindd_methods
*methods
;
450 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
451 struct samr_DomInfo1 password_policy
;
453 *password_properties
= 0;
455 methods
= domain
->methods
;
457 status
= methods
->password_policy(domain
, mem_ctx
, &password_policy
);
458 if (NT_STATUS_IS_ERR(status
)) {
462 *password_properties
= password_policy
.password_properties
;
469 static const char *generate_krb5_ccache(TALLOC_CTX
*mem_ctx
,
472 const char **user_ccache_file
)
474 /* accept FILE and WRFILE as krb5_cc_type from the client and then
475 * build the full ccname string based on the user's uid here -
478 const char *gen_cc
= NULL
;
481 if (strequal(type
, "FILE")) {
482 gen_cc
= talloc_asprintf(
483 mem_ctx
, "FILE:/tmp/krb5cc_%d", uid
);
485 if (strequal(type
, "WRFILE")) {
486 gen_cc
= talloc_asprintf(
487 mem_ctx
, "WRFILE:/tmp/krb5cc_%d", uid
);
491 *user_ccache_file
= gen_cc
;
493 if (gen_cc
== NULL
) {
494 gen_cc
= talloc_strdup(mem_ctx
, "MEMORY:winbindd_pam_ccache");
496 if (gen_cc
== NULL
) {
497 DEBUG(0,("out of memory\n"));
501 DEBUG(10, ("using ccache: %s%s\n", gen_cc
,
502 (*user_ccache_file
== NULL
) ? " (internal)":""));
509 uid_t
get_uid_from_request(struct winbindd_request
*request
)
513 uid
= request
->data
.auth
.uid
;
516 DEBUG(1,("invalid uid: '%u'\n", (unsigned int)uid
));
522 /**********************************************************************
523 Authenticate a user with a clear text password using Kerberos and fill up
525 **********************************************************************/
527 static NTSTATUS
winbindd_raw_kerberos_login(TALLOC_CTX
*mem_ctx
,
528 struct winbindd_domain
*domain
,
531 const char *krb5_cc_type
,
533 struct netr_SamInfo3
**info3
,
537 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
538 krb5_error_code krb5_ret
;
539 const char *cc
= NULL
;
540 const char *principal_s
= NULL
;
541 const char *service
= NULL
;
543 fstring name_domain
, name_user
;
544 time_t ticket_lifetime
= 0;
545 time_t renewal_until
= 0;
547 time_t time_offset
= 0;
548 const char *user_ccache_file
;
549 struct PAC_LOGON_INFO
*logon_info
= NULL
;
554 * prepare a krb5_cc_cache string for the user */
557 DEBUG(0,("no valid uid\n"));
560 cc
= generate_krb5_ccache(mem_ctx
,
565 return NT_STATUS_NO_MEMORY
;
570 * get kerberos properties */
572 if (domain
->private_data
) {
573 ads
= (ADS_STRUCT
*)domain
->private_data
;
574 time_offset
= ads
->auth
.time_offset
;
579 * do kerberos auth and setup ccache as the user */
581 parse_domain_user(user
, name_domain
, name_user
);
583 realm
= domain
->alt_name
;
586 principal_s
= talloc_asprintf(mem_ctx
, "%s@%s", name_user
, realm
);
587 if (principal_s
== NULL
) {
588 return NT_STATUS_NO_MEMORY
;
591 service
= talloc_asprintf(mem_ctx
, "%s/%s@%s", KRB5_TGS_NAME
, realm
, realm
);
592 if (service
== NULL
) {
593 return NT_STATUS_NO_MEMORY
;
596 /* if this is a user ccache, we need to act as the user to let the krb5
597 * library handle the chown, etc. */
599 /************************ ENTERING NON-ROOT **********************/
601 if (user_ccache_file
!= NULL
) {
602 set_effective_uid(uid
);
603 DEBUG(10,("winbindd_raw_kerberos_login: uid is %d\n", uid
));
606 result
= kerberos_return_pac(mem_ctx
,
615 WINBINDD_PAM_AUTH_KRB5_RENEW_TIME
,
618 if (user_ccache_file
!= NULL
) {
619 gain_root_privilege();
622 /************************ RETURNED TO ROOT **********************/
624 if (!NT_STATUS_IS_OK(result
)) {
628 *info3
= &logon_info
->info3
;
630 DEBUG(10,("winbindd_raw_kerberos_login: winbindd validated ticket of %s\n",
633 /* if we had a user's ccache then return that string for the pam
636 if (user_ccache_file
!= NULL
) {
638 fstrcpy(krb5ccname
, user_ccache_file
);
640 result
= add_ccache_to_list(principal_s
,
651 if (!NT_STATUS_IS_OK(result
)) {
652 DEBUG(10,("winbindd_raw_kerberos_login: failed to add ccache to list: %s\n",
657 /* need to delete the memory cred cache, it is not used anymore */
659 krb5_ret
= ads_kdestroy(cc
);
661 DEBUG(3,("winbindd_raw_kerberos_login: "
662 "could not destroy krb5 credential cache: "
663 "%s\n", error_message(krb5_ret
)));
672 /* we could have created a new credential cache with a valid tgt in it
673 * but we werent able to get or verify the service ticket for this
674 * local host and therefor didn't get the PAC, we need to remove that
675 * cache entirely now */
677 krb5_ret
= ads_kdestroy(cc
);
679 DEBUG(3,("winbindd_raw_kerberos_login: "
680 "could not destroy krb5 credential cache: "
681 "%s\n", error_message(krb5_ret
)));
684 if (!NT_STATUS_IS_OK(remove_ccache(user
))) {
685 DEBUG(3,("winbindd_raw_kerberos_login: "
686 "could not remove ccache for user %s\n",
692 return NT_STATUS_NOT_SUPPORTED
;
693 #endif /* HAVE_KRB5 */
696 /****************************************************************
697 ****************************************************************/
699 bool check_request_flags(uint32_t flags
)
701 uint32_t flags_edata
= WBFLAG_PAM_AFS_TOKEN
|
702 WBFLAG_PAM_INFO3_TEXT
|
703 WBFLAG_PAM_INFO3_NDR
;
705 if ( ( (flags
& flags_edata
) == WBFLAG_PAM_AFS_TOKEN
) ||
706 ( (flags
& flags_edata
) == WBFLAG_PAM_INFO3_NDR
) ||
707 ( (flags
& flags_edata
) == WBFLAG_PAM_INFO3_TEXT
)||
708 !(flags
& flags_edata
) ) {
712 DEBUG(1, ("check_request_flags: invalid request flags[0x%08X]\n",
718 /****************************************************************
719 ****************************************************************/
721 static NTSTATUS
append_auth_data(TALLOC_CTX
*mem_ctx
,
722 struct winbindd_response
*resp
,
723 uint32_t request_flags
,
724 struct netr_SamInfo3
*info3
,
725 const char *name_domain
,
726 const char *name_user
)
730 if (request_flags
& WBFLAG_PAM_USER_SESSION_KEY
) {
731 memcpy(resp
->data
.auth
.user_session_key
,
733 sizeof(resp
->data
.auth
.user_session_key
)
737 if (request_flags
& WBFLAG_PAM_LMKEY
) {
738 memcpy(resp
->data
.auth
.first_8_lm_hash
,
739 info3
->base
.LMSessKey
.key
,
740 sizeof(resp
->data
.auth
.first_8_lm_hash
)
744 if (request_flags
& WBFLAG_PAM_UNIX_NAME
) {
745 result
= append_unix_username(mem_ctx
, resp
,
746 info3
, name_domain
, name_user
);
747 if (!NT_STATUS_IS_OK(result
)) {
748 DEBUG(10,("Failed to append Unix Username: %s\n",
754 /* currently, anything from here on potentially overwrites extra_data. */
756 if (request_flags
& WBFLAG_PAM_INFO3_NDR
) {
757 result
= append_info3_as_ndr(mem_ctx
, resp
, info3
);
758 if (!NT_STATUS_IS_OK(result
)) {
759 DEBUG(10,("Failed to append INFO3 (NDR): %s\n",
765 if (request_flags
& WBFLAG_PAM_INFO3_TEXT
) {
766 result
= append_info3_as_txt(mem_ctx
, resp
, info3
);
767 if (!NT_STATUS_IS_OK(result
)) {
768 DEBUG(10,("Failed to append INFO3 (TXT): %s\n",
774 if (request_flags
& WBFLAG_PAM_AFS_TOKEN
) {
775 result
= append_afs_token(mem_ctx
, resp
,
776 info3
, name_domain
, name_user
);
777 if (!NT_STATUS_IS_OK(result
)) {
778 DEBUG(10,("Failed to append AFS token: %s\n",
787 static NTSTATUS
winbindd_dual_pam_auth_cached(struct winbindd_domain
*domain
,
788 struct winbindd_cli_state
*state
,
789 struct netr_SamInfo3
**info3
)
791 NTSTATUS result
= NT_STATUS_LOGON_FAILURE
;
792 uint16 max_allowed_bad_attempts
;
793 fstring name_domain
, name_user
;
795 enum lsa_SidType type
;
796 uchar new_nt_pass
[NT_HASH_LEN
];
797 const uint8
*cached_nt_pass
;
798 const uint8
*cached_salt
;
799 struct netr_SamInfo3
*my_info3
;
800 time_t kickoff_time
, must_change_time
;
801 bool password_good
= false;
803 struct winbindd_tdc_domain
*tdc_domain
= NULL
;
810 DEBUG(10,("winbindd_dual_pam_auth_cached\n"));
812 /* Parse domain and username */
814 parse_domain_user(state
->request
->data
.auth
.user
, name_domain
, name_user
);
817 if (!lookup_cached_name(name_domain
,
821 DEBUG(10,("winbindd_dual_pam_auth_cached: no such user in the cache\n"));
822 return NT_STATUS_NO_SUCH_USER
;
825 if (type
!= SID_NAME_USER
) {
826 DEBUG(10,("winbindd_dual_pam_auth_cached: not a user (%s)\n", sid_type_lookup(type
)));
827 return NT_STATUS_LOGON_FAILURE
;
830 result
= winbindd_get_creds(domain
,
836 if (!NT_STATUS_IS_OK(result
)) {
837 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get creds: %s\n", nt_errstr(result
)));
843 E_md4hash(state
->request
->data
.auth
.pass
, new_nt_pass
);
845 dump_data_pw("new_nt_pass", new_nt_pass
, NT_HASH_LEN
);
846 dump_data_pw("cached_nt_pass", cached_nt_pass
, NT_HASH_LEN
);
848 dump_data_pw("cached_salt", cached_salt
, NT_HASH_LEN
);
852 /* In this case we didn't store the nt_hash itself,
853 but the MD5 combination of salt + nt_hash. */
854 uchar salted_hash
[NT_HASH_LEN
];
855 E_md5hash(cached_salt
, new_nt_pass
, salted_hash
);
857 password_good
= (memcmp(cached_nt_pass
, salted_hash
,
860 /* Old cached cred - direct store of nt_hash (bad bad bad !). */
861 password_good
= (memcmp(cached_nt_pass
, new_nt_pass
,
867 /* User *DOES* know the password, update logon_time and reset
870 my_info3
->base
.user_flags
|= NETLOGON_CACHED_ACCOUNT
;
872 if (my_info3
->base
.acct_flags
& ACB_AUTOLOCK
) {
873 return NT_STATUS_ACCOUNT_LOCKED_OUT
;
876 if (my_info3
->base
.acct_flags
& ACB_DISABLED
) {
877 return NT_STATUS_ACCOUNT_DISABLED
;
880 if (my_info3
->base
.acct_flags
& ACB_WSTRUST
) {
881 return NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT
;
884 if (my_info3
->base
.acct_flags
& ACB_SVRTRUST
) {
885 return NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT
;
888 if (my_info3
->base
.acct_flags
& ACB_DOMTRUST
) {
889 return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT
;
892 if (!(my_info3
->base
.acct_flags
& ACB_NORMAL
)) {
893 DEBUG(0,("winbindd_dual_pam_auth_cached: whats wrong with that one?: 0x%08x\n",
894 my_info3
->base
.acct_flags
));
895 return NT_STATUS_LOGON_FAILURE
;
898 kickoff_time
= nt_time_to_unix(my_info3
->base
.kickoff_time
);
899 if (kickoff_time
!= 0 && time(NULL
) > kickoff_time
) {
900 return NT_STATUS_ACCOUNT_EXPIRED
;
903 must_change_time
= nt_time_to_unix(my_info3
->base
.force_password_change
);
904 if (must_change_time
!= 0 && must_change_time
< time(NULL
)) {
905 /* we allow grace logons when the password has expired */
906 my_info3
->base
.user_flags
|= NETLOGON_GRACE_LOGON
;
907 /* return NT_STATUS_PASSWORD_EXPIRED; */
912 if ((state
->request
->flags
& WBFLAG_PAM_KRB5
) &&
913 ((tdc_domain
= wcache_tdc_fetch_domain(state
->mem_ctx
, name_domain
)) != NULL
) &&
914 ((tdc_domain
->trust_type
& NETR_TRUST_TYPE_UPLEVEL
) ||
915 /* used to cope with the case winbindd starting without network. */
916 !strequal(tdc_domain
->domain_name
, tdc_domain
->dns_name
))) {
919 const char *cc
= NULL
;
921 const char *principal_s
= NULL
;
922 const char *service
= NULL
;
923 const char *user_ccache_file
;
925 uid
= get_uid_from_request(state
->request
);
927 DEBUG(0,("winbindd_dual_pam_auth_cached: invalid uid\n"));
928 return NT_STATUS_INVALID_PARAMETER
;
931 cc
= generate_krb5_ccache(state
->mem_ctx
,
932 state
->request
->data
.auth
.krb5_cc_type
,
933 state
->request
->data
.auth
.uid
,
936 return NT_STATUS_NO_MEMORY
;
939 realm
= domain
->alt_name
;
942 principal_s
= talloc_asprintf(state
->mem_ctx
, "%s@%s", name_user
, realm
);
943 if (principal_s
== NULL
) {
944 return NT_STATUS_NO_MEMORY
;
947 service
= talloc_asprintf(state
->mem_ctx
, "%s/%s@%s", KRB5_TGS_NAME
, realm
, realm
);
948 if (service
== NULL
) {
949 return NT_STATUS_NO_MEMORY
;
952 if (user_ccache_file
!= NULL
) {
954 fstrcpy(state
->response
->data
.auth
.krb5ccname
,
957 result
= add_ccache_to_list(principal_s
,
960 state
->request
->data
.auth
.user
,
964 time(NULL
) + lp_winbind_cache_time(),
965 time(NULL
) + WINBINDD_PAM_AUTH_KRB5_RENEW_TIME
,
968 if (!NT_STATUS_IS_OK(result
)) {
969 DEBUG(10,("winbindd_dual_pam_auth_cached: failed "
970 "to add ccache to list: %s\n",
975 #endif /* HAVE_KRB5 */
977 /* FIXME: we possibly should handle logon hours as well (does xp when
978 * offline?) see auth/auth_sam.c:sam_account_ok for details */
980 unix_to_nt_time(&my_info3
->base
.logon_time
, time(NULL
));
981 my_info3
->base
.bad_password_count
= 0;
983 result
= winbindd_update_creds_by_info3(domain
,
984 state
->request
->data
.auth
.user
,
985 state
->request
->data
.auth
.pass
,
987 if (!NT_STATUS_IS_OK(result
)) {
988 DEBUG(1,("winbindd_dual_pam_auth_cached: failed to update creds: %s\n",
997 /* User does *NOT* know the correct password, modify info3 accordingly, but only if online */
998 if (domain
->online
== false) {
1002 /* failure of this is not critical */
1003 result
= get_max_bad_attempts_from_lockout_policy(domain
, state
->mem_ctx
, &max_allowed_bad_attempts
);
1004 if (!NT_STATUS_IS_OK(result
)) {
1005 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get max_allowed_bad_attempts. "
1006 "Won't be able to honour account lockout policies\n"));
1009 /* increase counter */
1010 my_info3
->base
.bad_password_count
++;
1012 if (max_allowed_bad_attempts
== 0) {
1017 if (my_info3
->base
.bad_password_count
>= max_allowed_bad_attempts
) {
1019 uint32 password_properties
;
1021 result
= get_pwd_properties(domain
, state
->mem_ctx
, &password_properties
);
1022 if (!NT_STATUS_IS_OK(result
)) {
1023 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get password properties.\n"));
1026 if ((my_info3
->base
.rid
!= DOMAIN_RID_ADMINISTRATOR
) ||
1027 (password_properties
& DOMAIN_PASSWORD_LOCKOUT_ADMINS
)) {
1028 my_info3
->base
.acct_flags
|= ACB_AUTOLOCK
;
1033 result
= winbindd_update_creds_by_info3(domain
,
1034 state
->request
->data
.auth
.user
,
1038 if (!NT_STATUS_IS_OK(result
)) {
1039 DEBUG(0,("winbindd_dual_pam_auth_cached: failed to update creds %s\n",
1040 nt_errstr(result
)));
1043 return NT_STATUS_LOGON_FAILURE
;
1046 static NTSTATUS
winbindd_dual_pam_auth_kerberos(struct winbindd_domain
*domain
,
1047 struct winbindd_cli_state
*state
,
1048 struct netr_SamInfo3
**info3
)
1050 struct winbindd_domain
*contact_domain
;
1051 fstring name_domain
, name_user
;
1054 DEBUG(10,("winbindd_dual_pam_auth_kerberos\n"));
1056 /* Parse domain and username */
1058 parse_domain_user(state
->request
->data
.auth
.user
, name_domain
, name_user
);
1060 /* what domain should we contact? */
1063 if (!(contact_domain
= find_domain_from_name(name_domain
))) {
1064 DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
1065 state
->request
->data
.auth
.user
, name_domain
, name_user
, name_domain
));
1066 result
= NT_STATUS_NO_SUCH_USER
;
1071 if (is_myname(name_domain
)) {
1072 DEBUG(3, ("Authentication for domain %s (local domain to this server) not supported at this stage\n", name_domain
));
1073 result
= NT_STATUS_NO_SUCH_USER
;
1077 contact_domain
= find_domain_from_name(name_domain
);
1078 if (contact_domain
== NULL
) {
1079 DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
1080 state
->request
->data
.auth
.user
, name_domain
, name_user
, name_domain
));
1082 result
= NT_STATUS_NO_SUCH_USER
;
1087 if (contact_domain
->initialized
&&
1088 contact_domain
->active_directory
) {
1092 if (!contact_domain
->initialized
) {
1093 init_dc_connection(contact_domain
);
1096 if (!contact_domain
->active_directory
) {
1097 DEBUG(3,("krb5 auth requested but domain is not Active Directory\n"));
1098 return NT_STATUS_INVALID_LOGON_TYPE
;
1101 result
= winbindd_raw_kerberos_login(
1102 state
->mem_ctx
, contact_domain
,
1103 state
->request
->data
.auth
.user
,
1104 state
->request
->data
.auth
.pass
,
1105 state
->request
->data
.auth
.krb5_cc_type
,
1106 get_uid_from_request(state
->request
),
1107 info3
, state
->response
->data
.auth
.krb5ccname
);
1112 static NTSTATUS
winbindd_dual_auth_passdb(TALLOC_CTX
*mem_ctx
,
1113 uint32_t logon_parameters
,
1114 const char *domain
, const char *user
,
1115 const DATA_BLOB
*challenge
,
1116 const DATA_BLOB
*lm_resp
,
1117 const DATA_BLOB
*nt_resp
,
1118 struct netr_SamInfo3
**pinfo3
)
1120 struct auth_usersupplied_info
*user_info
= NULL
;
1121 struct tsocket_address
*local
;
1125 rc
= tsocket_address_inet_from_strings(mem_ctx
,
1131 return NT_STATUS_NO_MEMORY
;
1133 status
= make_user_info(&user_info
, user
, user
, domain
, domain
,
1134 lp_netbios_name(), local
, lm_resp
, nt_resp
, NULL
, NULL
,
1135 NULL
, AUTH_PASSWORD_RESPONSE
);
1136 if (!NT_STATUS_IS_OK(status
)) {
1137 DEBUG(10, ("make_user_info failed: %s\n", nt_errstr(status
)));
1140 user_info
->logon_parameters
= logon_parameters
;
1142 /* We don't want any more mapping of the username */
1143 user_info
->mapped_state
= True
;
1145 status
= check_sam_security_info3(challenge
, talloc_tos(), user_info
,
1147 free_user_info(&user_info
);
1148 DEBUG(10, ("Authenticaticating user %s\\%s returned %s\n", domain
,
1149 user
, nt_errstr(status
)));
1153 static NTSTATUS
winbind_samlogon_retry_loop(struct winbindd_domain
*domain
,
1154 TALLOC_CTX
*mem_ctx
,
1155 uint32_t logon_parameters
,
1157 const char *username
,
1158 const char *domainname
,
1159 const char *workstation
,
1160 const uint8_t chal
[8],
1161 DATA_BLOB lm_response
,
1162 DATA_BLOB nt_response
,
1163 struct netr_SamInfo3
**info3
)
1170 struct rpc_pipe_client
*netlogon_pipe
;
1171 const struct pipe_auth_data
*auth
;
1172 uint32_t neg_flags
= 0;
1174 ZERO_STRUCTP(info3
);
1177 result
= cm_connect_netlogon(domain
, &netlogon_pipe
);
1179 if (!NT_STATUS_IS_OK(result
)) {
1180 DEBUG(3,("could not open handle to NETLOGON pipe (error: %s)\n",
1181 nt_errstr(result
)));
1184 auth
= netlogon_pipe
->auth
;
1185 if (netlogon_pipe
->dc
) {
1186 neg_flags
= netlogon_pipe
->dc
->negotiate_flags
;
1189 /* It is really important to try SamLogonEx here,
1190 * because in a clustered environment, we want to use
1191 * one machine account from multiple physical
1194 * With a normal SamLogon call, we must keep the
1195 * credentials chain updated and intact between all
1196 * users of the machine account (which would imply
1197 * cross-node communication for every NTLM logon).
1199 * (The credentials chain is not per NETLOGON pipe
1200 * connection, but globally on the server/client pair
1203 * When using SamLogonEx, the credentials are not
1204 * supplied, but the session key is implied by the
1205 * wrapping SamLogon context.
1207 * -- abartlet 21 April 2008
1209 * It's also important to use NetlogonValidationSamInfo4 (6),
1210 * because it relies on the rpc transport encryption
1211 * and avoids using the global netlogon schannel
1212 * session key to en/decrypt secret information
1213 * like the user_session_key for network logons.
1215 * [MS-APDS] 3.1.5.2 NTLM Network Logon
1216 * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
1217 * NETLOGON_NEG_AUTHENTICATED_RPC set together
1218 * are the indication that the server supports
1219 * NetlogonValidationSamInfo4 (6). And it must only
1220 * be used if "SealSecureChannel" is used.
1222 * -- metze 4 February 2011
1226 domain
->can_do_validation6
= false;
1227 } else if (auth
->auth_type
!= DCERPC_AUTH_TYPE_SCHANNEL
) {
1228 domain
->can_do_validation6
= false;
1229 } else if (auth
->auth_level
!= DCERPC_AUTH_LEVEL_PRIVACY
) {
1230 domain
->can_do_validation6
= false;
1231 } else if (!(neg_flags
& NETLOGON_NEG_CROSS_FOREST_TRUSTS
)) {
1232 domain
->can_do_validation6
= false;
1233 } else if (!(neg_flags
& NETLOGON_NEG_AUTHENTICATED_RPC
)) {
1234 domain
->can_do_validation6
= false;
1237 if (domain
->can_do_samlogon_ex
) {
1238 result
= rpccli_netlogon_sam_network_logon_ex(
1242 server
, /* server name */
1243 username
, /* user name */
1244 domainname
, /* target domain */
1245 workstation
, /* workstation */
1247 domain
->can_do_validation6
? 6 : 3,
1252 result
= rpccli_netlogon_sam_network_logon(
1256 server
, /* server name */
1257 username
, /* user name */
1258 domainname
, /* target domain */
1259 workstation
, /* workstation */
1261 domain
->can_do_validation6
? 6 : 3,
1267 if (NT_STATUS_EQUAL(result
, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
)) {
1270 * It's likely that the server also does not support
1271 * validation level 6
1273 domain
->can_do_validation6
= false;
1275 if (domain
->can_do_samlogon_ex
) {
1276 DEBUG(3, ("Got a DC that can not do NetSamLogonEx, "
1277 "retrying with NetSamLogon\n"));
1278 domain
->can_do_samlogon_ex
= false;
1284 /* Got DCERPC_FAULT_OP_RNG_ERROR for SamLogon
1285 * (no Ex). This happens against old Samba
1286 * DCs. Drop the connection.
1288 invalidate_cm_connection(&domain
->conn
);
1289 result
= NT_STATUS_LOGON_FAILURE
;
1293 if (domain
->can_do_validation6
&&
1294 (NT_STATUS_EQUAL(result
, NT_STATUS_INVALID_INFO_CLASS
) ||
1295 NT_STATUS_EQUAL(result
, NT_STATUS_INVALID_PARAMETER
) ||
1296 NT_STATUS_EQUAL(result
, NT_STATUS_BUFFER_TOO_SMALL
))) {
1297 DEBUG(3,("Got a DC that can not do validation level 6, "
1298 "retrying with level 3\n"));
1299 domain
->can_do_validation6
= false;
1305 * we increment this after the "feature negotiation"
1306 * for can_do_samlogon_ex and can_do_validation6
1310 /* We have to try a second time as cm_connect_netlogon
1311 might not yet have noticed that the DC has killed
1314 if (!rpccli_is_connected(netlogon_pipe
)) {
1319 /* if we get access denied, a possible cause was that we had
1320 and open connection to the DC, but someone changed our
1321 machine account password out from underneath us using 'net
1322 rpc changetrustpw' */
1324 if ( NT_STATUS_EQUAL(result
, NT_STATUS_ACCESS_DENIED
) ) {
1325 DEBUG(3,("winbindd_pam_auth: sam_logon returned "
1326 "ACCESS_DENIED. Maybe the trust account "
1327 "password was changed and we didn't know it. "
1328 "Killing connections to domain %s\n",
1330 invalidate_cm_connection(&domain
->conn
);
1334 } while ( (attempts
< 2) && retry
);
1339 static NTSTATUS
winbindd_dual_pam_auth_samlogon(TALLOC_CTX
*mem_ctx
,
1340 struct winbindd_domain
*domain
,
1343 uint32_t request_flags
,
1344 struct netr_SamInfo3
**info3
)
1350 unsigned char local_nt_response
[24];
1351 fstring name_domain
, name_user
;
1353 struct netr_SamInfo3
*my_info3
= NULL
;
1357 DEBUG(10,("winbindd_dual_pam_auth_samlogon\n"));
1359 /* Parse domain and username */
1361 parse_domain_user(user
, name_domain
, name_user
);
1363 /* do password magic */
1365 generate_random_buffer(chal
, sizeof(chal
));
1367 if (lp_client_ntlmv2_auth()) {
1368 DATA_BLOB server_chal
;
1369 DATA_BLOB names_blob
;
1370 server_chal
= data_blob_const(chal
, 8);
1372 /* note that the 'workgroup' here is for the local
1373 machine. The 'server name' must match the
1374 'workstation' passed to the actual SamLogon call.
1376 names_blob
= NTLMv2_generate_names_blob(
1377 mem_ctx
, lp_netbios_name(), lp_workgroup());
1379 if (!SMBNTLMv2encrypt(mem_ctx
, name_user
, name_domain
,
1383 &lm_resp
, &nt_resp
, NULL
, NULL
)) {
1384 data_blob_free(&names_blob
);
1385 DEBUG(0, ("winbindd_pam_auth: SMBNTLMv2encrypt() failed!\n"));
1386 result
= NT_STATUS_NO_MEMORY
;
1389 data_blob_free(&names_blob
);
1391 lm_resp
= data_blob_null
;
1392 SMBNTencrypt(pass
, chal
, local_nt_response
);
1394 nt_resp
= data_blob_talloc(mem_ctx
, local_nt_response
,
1395 sizeof(local_nt_response
));
1398 if (strequal(name_domain
, get_global_sam_name())) {
1399 DATA_BLOB chal_blob
= data_blob_const(chal
, sizeof(chal
));
1401 result
= winbindd_dual_auth_passdb(
1402 mem_ctx
, 0, name_domain
, name_user
,
1403 &chal_blob
, &lm_resp
, &nt_resp
, info3
);
1407 /* check authentication loop */
1409 result
= winbind_samlogon_retry_loop(domain
,
1420 if (!NT_STATUS_IS_OK(result
)) {
1424 /* handle the case where a NT4 DC does not fill in the acct_flags in
1425 * the samlogon reply info3. When accurate info3 is required by the
1426 * caller, we look up the account flags ourselve - gd */
1428 if ((request_flags
& WBFLAG_PAM_INFO3_TEXT
) &&
1429 NT_STATUS_IS_OK(result
) && (my_info3
->base
.acct_flags
== 0)) {
1431 struct rpc_pipe_client
*samr_pipe
;
1432 struct policy_handle samr_domain_handle
, user_pol
;
1433 union samr_UserInfo
*info
= NULL
;
1434 NTSTATUS status_tmp
, result_tmp
;
1436 struct dcerpc_binding_handle
*b
;
1438 status_tmp
= cm_connect_sam(domain
, mem_ctx
,
1439 &samr_pipe
, &samr_domain_handle
);
1441 if (!NT_STATUS_IS_OK(status_tmp
)) {
1442 DEBUG(3, ("could not open handle to SAMR pipe: %s\n",
1443 nt_errstr(status_tmp
)));
1447 b
= samr_pipe
->binding_handle
;
1449 status_tmp
= dcerpc_samr_OpenUser(b
, mem_ctx
,
1450 &samr_domain_handle
,
1451 MAXIMUM_ALLOWED_ACCESS
,
1456 if (!NT_STATUS_IS_OK(status_tmp
)) {
1457 DEBUG(3, ("could not open user handle on SAMR pipe: %s\n",
1458 nt_errstr(status_tmp
)));
1461 if (!NT_STATUS_IS_OK(result_tmp
)) {
1462 DEBUG(3, ("could not open user handle on SAMR pipe: %s\n",
1463 nt_errstr(result_tmp
)));
1467 status_tmp
= dcerpc_samr_QueryUserInfo(b
, mem_ctx
,
1473 if (!NT_STATUS_IS_OK(status_tmp
)) {
1474 DEBUG(3, ("could not query user info on SAMR pipe: %s\n",
1475 nt_errstr(status_tmp
)));
1476 dcerpc_samr_Close(b
, mem_ctx
, &user_pol
, &result_tmp
);
1479 if (!NT_STATUS_IS_OK(result_tmp
)) {
1480 DEBUG(3, ("could not query user info on SAMR pipe: %s\n",
1481 nt_errstr(result_tmp
)));
1482 dcerpc_samr_Close(b
, mem_ctx
, &user_pol
, &result_tmp
);
1486 acct_flags
= info
->info16
.acct_flags
;
1488 if (acct_flags
== 0) {
1489 dcerpc_samr_Close(b
, mem_ctx
, &user_pol
, &result_tmp
);
1493 my_info3
->base
.acct_flags
= acct_flags
;
1495 DEBUG(10,("successfully retrieved acct_flags 0x%x\n", acct_flags
));
1497 dcerpc_samr_Close(b
, mem_ctx
, &user_pol
, &result_tmp
);
1505 enum winbindd_result
winbindd_dual_pam_auth(struct winbindd_domain
*domain
,
1506 struct winbindd_cli_state
*state
)
1508 NTSTATUS result
= NT_STATUS_LOGON_FAILURE
;
1509 NTSTATUS krb5_result
= NT_STATUS_OK
;
1510 fstring name_domain
, name_user
;
1512 fstring domain_user
;
1513 struct netr_SamInfo3
*info3
= NULL
;
1514 NTSTATUS name_map_status
= NT_STATUS_UNSUCCESSFUL
;
1516 /* Ensure null termination */
1517 state
->request
->data
.auth
.user
[sizeof(state
->request
->data
.auth
.user
)-1]='\0';
1519 /* Ensure null termination */
1520 state
->request
->data
.auth
.pass
[sizeof(state
->request
->data
.auth
.pass
)-1]='\0';
1522 DEBUG(3, ("[%5lu]: dual pam auth %s\n", (unsigned long)state
->pid
,
1523 state
->request
->data
.auth
.user
));
1525 /* Parse domain and username */
1527 name_map_status
= normalize_name_unmap(state
->mem_ctx
,
1528 state
->request
->data
.auth
.user
,
1531 /* If the name normalization didnt' actually do anything,
1532 just use the original name */
1534 if (!NT_STATUS_IS_OK(name_map_status
) &&
1535 !NT_STATUS_EQUAL(name_map_status
, NT_STATUS_FILE_RENAMED
))
1537 mapped_user
= state
->request
->data
.auth
.user
;
1540 parse_domain_user(mapped_user
, name_domain
, name_user
);
1542 if ( mapped_user
!= state
->request
->data
.auth
.user
) {
1543 fstr_sprintf( domain_user
, "%s%c%s", name_domain
,
1544 *lp_winbind_separator(),
1546 strlcpy( state
->request
->data
.auth
.user
, domain_user
,
1547 sizeof(state
->request
->data
.auth
.user
));
1550 if (!domain
->online
) {
1551 result
= NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
;
1552 if (domain
->startup
) {
1553 /* Logons are very important to users. If we're offline and
1554 we get a request within the first 30 seconds of startup,
1555 try very hard to find a DC and go online. */
1557 DEBUG(10,("winbindd_dual_pam_auth: domain: %s offline and auth "
1558 "request in startup mode.\n", domain
->name
));
1560 winbindd_flush_negative_conn_cache(domain
);
1561 result
= init_dc_connection(domain
);
1565 DEBUG(10,("winbindd_dual_pam_auth: domain: %s last was %s\n", domain
->name
, domain
->online
? "online":"offline"));
1567 /* Check for Kerberos authentication */
1568 if (domain
->online
&& (state
->request
->flags
& WBFLAG_PAM_KRB5
)) {
1570 result
= winbindd_dual_pam_auth_kerberos(domain
, state
, &info3
);
1571 /* save for later */
1572 krb5_result
= result
;
1575 if (NT_STATUS_IS_OK(result
)) {
1576 DEBUG(10,("winbindd_dual_pam_auth_kerberos succeeded\n"));
1577 goto process_result
;
1579 DEBUG(10,("winbindd_dual_pam_auth_kerberos failed: %s\n", nt_errstr(result
)));
1582 if (NT_STATUS_EQUAL(result
, NT_STATUS_NO_LOGON_SERVERS
) ||
1583 NT_STATUS_EQUAL(result
, NT_STATUS_IO_TIMEOUT
) ||
1584 NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1585 DEBUG(10,("winbindd_dual_pam_auth_kerberos setting domain to offline\n"));
1586 set_domain_offline( domain
);
1590 /* there are quite some NT_STATUS errors where there is no
1591 * point in retrying with a samlogon, we explictly have to take
1592 * care not to increase the bad logon counter on the DC */
1594 if (NT_STATUS_EQUAL(result
, NT_STATUS_ACCOUNT_DISABLED
) ||
1595 NT_STATUS_EQUAL(result
, NT_STATUS_ACCOUNT_EXPIRED
) ||
1596 NT_STATUS_EQUAL(result
, NT_STATUS_ACCOUNT_LOCKED_OUT
) ||
1597 NT_STATUS_EQUAL(result
, NT_STATUS_INVALID_LOGON_HOURS
) ||
1598 NT_STATUS_EQUAL(result
, NT_STATUS_INVALID_WORKSTATION
) ||
1599 NT_STATUS_EQUAL(result
, NT_STATUS_LOGON_FAILURE
) ||
1600 NT_STATUS_EQUAL(result
, NT_STATUS_NO_SUCH_USER
) ||
1601 NT_STATUS_EQUAL(result
, NT_STATUS_PASSWORD_EXPIRED
) ||
1602 NT_STATUS_EQUAL(result
, NT_STATUS_PASSWORD_MUST_CHANGE
) ||
1603 NT_STATUS_EQUAL(result
, NT_STATUS_WRONG_PASSWORD
)) {
1607 if (state
->request
->flags
& WBFLAG_PAM_FALLBACK_AFTER_KRB5
) {
1608 DEBUG(3,("falling back to samlogon\n"));
1616 /* Check for Samlogon authentication */
1617 if (domain
->online
) {
1618 result
= winbindd_dual_pam_auth_samlogon(
1619 state
->mem_ctx
, domain
,
1620 state
->request
->data
.auth
.user
,
1621 state
->request
->data
.auth
.pass
,
1622 state
->request
->flags
,
1625 if (NT_STATUS_IS_OK(result
)) {
1626 DEBUG(10,("winbindd_dual_pam_auth_samlogon succeeded\n"));
1627 /* add the Krb5 err if we have one */
1628 if ( NT_STATUS_EQUAL(krb5_result
, NT_STATUS_TIME_DIFFERENCE_AT_DC
) ) {
1629 info3
->base
.user_flags
|= LOGON_KRB5_FAIL_CLOCK_SKEW
;
1631 goto process_result
;
1634 DEBUG(10,("winbindd_dual_pam_auth_samlogon failed: %s\n",
1635 nt_errstr(result
)));
1637 if (NT_STATUS_EQUAL(result
, NT_STATUS_NO_LOGON_SERVERS
) ||
1638 NT_STATUS_EQUAL(result
, NT_STATUS_IO_TIMEOUT
) ||
1639 NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
))
1641 DEBUG(10,("winbindd_dual_pam_auth_samlogon setting domain to offline\n"));
1642 set_domain_offline( domain
);
1646 if (domain
->online
) {
1647 /* We're still online - fail. */
1653 /* Check for Cached logons */
1654 if (!domain
->online
&& (state
->request
->flags
& WBFLAG_PAM_CACHED_LOGIN
) &&
1655 lp_winbind_offline_logon()) {
1657 result
= winbindd_dual_pam_auth_cached(domain
, state
, &info3
);
1659 if (NT_STATUS_IS_OK(result
)) {
1660 DEBUG(10,("winbindd_dual_pam_auth_cached succeeded\n"));
1661 goto process_result
;
1663 DEBUG(10,("winbindd_dual_pam_auth_cached failed: %s\n", nt_errstr(result
)));
1670 if (NT_STATUS_IS_OK(result
)) {
1672 struct dom_sid user_sid
;
1674 /* In all codepaths where result == NT_STATUS_OK info3 must have
1675 been initialized. */
1677 result
= NT_STATUS_INTERNAL_ERROR
;
1681 sid_compose(&user_sid
, info3
->base
.domain_sid
,
1684 wcache_invalidate_samlogon(find_domain_from_name(name_domain
),
1686 netsamlogon_cache_store(name_user
, info3
);
1688 /* save name_to_sid info as early as possible (only if
1689 this is our primary domain so we don't invalidate
1690 the cache entry by storing the seq_num for the wrong
1692 if ( domain
->primary
) {
1693 cache_name2sid(domain
, name_domain
, name_user
,
1694 SID_NAME_USER
, &user_sid
);
1697 /* Check if the user is in the right group */
1699 result
= check_info3_in_group(
1701 state
->request
->data
.auth
.require_membership_of_sid
);
1702 if (!NT_STATUS_IS_OK(result
)) {
1703 DEBUG(3, ("User %s is not in the required group (%s), so plaintext authentication is rejected\n",
1704 state
->request
->data
.auth
.user
,
1705 state
->request
->data
.auth
.require_membership_of_sid
));
1709 result
= append_auth_data(state
->mem_ctx
, state
->response
,
1710 state
->request
->flags
, info3
,
1711 name_domain
, name_user
);
1712 if (!NT_STATUS_IS_OK(result
)) {
1716 if ((state
->request
->flags
& WBFLAG_PAM_CACHED_LOGIN
)
1717 && lp_winbind_offline_logon()) {
1719 result
= winbindd_store_creds(domain
,
1720 state
->request
->data
.auth
.user
,
1721 state
->request
->data
.auth
.pass
,
1725 if (state
->request
->flags
& WBFLAG_PAM_GET_PWD_POLICY
) {
1726 struct winbindd_domain
*our_domain
= find_our_domain();
1728 /* This is not entirely correct I believe, but it is
1729 consistent. Only apply the password policy settings
1730 too warn users for our own domain. Cannot obtain these
1731 from trusted DCs all the time so don't do it at all.
1734 result
= NT_STATUS_NOT_SUPPORTED
;
1735 if (our_domain
== domain
) {
1736 result
= fillup_password_policy(
1737 our_domain
, state
->response
);
1740 if (!NT_STATUS_IS_OK(result
)
1741 && !NT_STATUS_EQUAL(result
, NT_STATUS_NOT_SUPPORTED
) )
1743 DEBUG(10,("Failed to get password policies for domain %s: %s\n",
1744 domain
->name
, nt_errstr(result
)));
1749 result
= NT_STATUS_OK
;
1753 /* give us a more useful (more correct?) error code */
1754 if ((NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ||
1755 (NT_STATUS_EQUAL(result
, NT_STATUS_UNSUCCESSFUL
)))) {
1756 result
= NT_STATUS_NO_LOGON_SERVERS
;
1759 set_auth_errors(state
->response
, result
);
1761 DEBUG(NT_STATUS_IS_OK(result
) ? 5 : 2, ("Plain-text authentication for user %s returned %s (PAM: %d)\n",
1762 state
->request
->data
.auth
.user
,
1763 state
->response
->data
.auth
.nt_status_string
,
1764 state
->response
->data
.auth
.pam_error
));
1766 return NT_STATUS_IS_OK(result
) ? WINBINDD_OK
: WINBINDD_ERROR
;
1769 enum winbindd_result
winbindd_dual_pam_auth_crap(struct winbindd_domain
*domain
,
1770 struct winbindd_cli_state
*state
)
1773 struct netr_SamInfo3
*info3
= NULL
;
1774 const char *name_user
= NULL
;
1775 const char *name_domain
= NULL
;
1776 const char *workstation
;
1778 DATA_BLOB lm_resp
, nt_resp
;
1780 /* This is child-only, so no check for privileged access is needed
1783 /* Ensure null termination */
1784 state
->request
->data
.auth_crap
.user
[sizeof(state
->request
->data
.auth_crap
.user
)-1]=0;
1785 state
->request
->data
.auth_crap
.domain
[sizeof(state
->request
->data
.auth_crap
.domain
)-1]=0;
1787 name_user
= state
->request
->data
.auth_crap
.user
;
1788 name_domain
= state
->request
->data
.auth_crap
.domain
;
1789 workstation
= state
->request
->data
.auth_crap
.workstation
;
1791 DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n", (unsigned long)state
->pid
,
1792 name_domain
, name_user
));
1794 if (state
->request
->data
.auth_crap
.lm_resp_len
> sizeof(state
->request
->data
.auth_crap
.lm_resp
)
1795 || state
->request
->data
.auth_crap
.nt_resp_len
> sizeof(state
->request
->data
.auth_crap
.nt_resp
)) {
1796 if (!(state
->request
->flags
& WBFLAG_BIG_NTLMV2_BLOB
) ||
1797 state
->request
->extra_len
!= state
->request
->data
.auth_crap
.nt_resp_len
) {
1798 DEBUG(0, ("winbindd_pam_auth_crap: invalid password length %u/%u\n",
1799 state
->request
->data
.auth_crap
.lm_resp_len
,
1800 state
->request
->data
.auth_crap
.nt_resp_len
));
1801 result
= NT_STATUS_INVALID_PARAMETER
;
1806 lm_resp
= data_blob_talloc(state
->mem_ctx
, state
->request
->data
.auth_crap
.lm_resp
,
1807 state
->request
->data
.auth_crap
.lm_resp_len
);
1809 if (state
->request
->flags
& WBFLAG_BIG_NTLMV2_BLOB
) {
1810 nt_resp
= data_blob_talloc(state
->mem_ctx
,
1811 state
->request
->extra_data
.data
,
1812 state
->request
->data
.auth_crap
.nt_resp_len
);
1814 nt_resp
= data_blob_talloc(state
->mem_ctx
,
1815 state
->request
->data
.auth_crap
.nt_resp
,
1816 state
->request
->data
.auth_crap
.nt_resp_len
);
1819 if (strequal(name_domain
, get_global_sam_name())) {
1820 DATA_BLOB chal_blob
= data_blob_const(
1821 state
->request
->data
.auth_crap
.chal
,
1822 sizeof(state
->request
->data
.auth_crap
.chal
));
1824 result
= winbindd_dual_auth_passdb(
1826 state
->request
->data
.auth_crap
.logon_parameters
,
1827 name_domain
, name_user
,
1828 &chal_blob
, &lm_resp
, &nt_resp
, &info3
);
1829 goto process_result
;
1832 result
= winbind_samlogon_retry_loop(domain
,
1834 state
->request
->data
.auth_crap
.logon_parameters
,
1838 /* Bug #3248 - found by Stefan Burkei. */
1839 workstation
, /* We carefully set this above so use it... */
1840 state
->request
->data
.auth_crap
.chal
,
1844 if (!NT_STATUS_IS_OK(result
)) {
1850 if (NT_STATUS_IS_OK(result
)) {
1851 struct dom_sid user_sid
;
1853 sid_compose(&user_sid
, info3
->base
.domain_sid
,
1855 wcache_invalidate_samlogon(find_domain_from_name(name_domain
),
1857 netsamlogon_cache_store(name_user
, info3
);
1859 /* Check if the user is in the right group */
1861 result
= check_info3_in_group(
1863 state
->request
->data
.auth_crap
.require_membership_of_sid
);
1864 if (!NT_STATUS_IS_OK(result
)) {
1865 DEBUG(3, ("User %s is not in the required group (%s), so "
1866 "crap authentication is rejected\n",
1867 state
->request
->data
.auth_crap
.user
,
1868 state
->request
->data
.auth_crap
.require_membership_of_sid
));
1872 result
= append_auth_data(state
->mem_ctx
, state
->response
,
1873 state
->request
->flags
, info3
,
1874 name_domain
, name_user
);
1875 if (!NT_STATUS_IS_OK(result
)) {
1882 /* give us a more useful (more correct?) error code */
1883 if ((NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ||
1884 (NT_STATUS_EQUAL(result
, NT_STATUS_UNSUCCESSFUL
)))) {
1885 result
= NT_STATUS_NO_LOGON_SERVERS
;
1888 if (state
->request
->flags
& WBFLAG_PAM_NT_STATUS_SQUASH
) {
1889 result
= nt_status_squash(result
);
1892 set_auth_errors(state
->response
, result
);
1894 DEBUG(NT_STATUS_IS_OK(result
) ? 5 : 2,
1895 ("NTLM CRAP authentication for user [%s]\\[%s] returned %s (PAM: %d)\n",
1898 state
->response
->data
.auth
.nt_status_string
,
1899 state
->response
->data
.auth
.pam_error
));
1901 return NT_STATUS_IS_OK(result
) ? WINBINDD_OK
: WINBINDD_ERROR
;
1904 enum winbindd_result
winbindd_dual_pam_chauthtok(struct winbindd_domain
*contact_domain
,
1905 struct winbindd_cli_state
*state
)
1908 char *newpass
= NULL
;
1909 struct policy_handle dom_pol
;
1910 struct rpc_pipe_client
*cli
= NULL
;
1911 bool got_info
= false;
1912 struct samr_DomInfo1
*info
= NULL
;
1913 struct userPwdChangeFailureInformation
*reject
= NULL
;
1914 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
1915 fstring domain
, user
;
1916 struct dcerpc_binding_handle
*b
= NULL
;
1918 ZERO_STRUCT(dom_pol
);
1920 DEBUG(3, ("[%5lu]: dual pam chauthtok %s\n", (unsigned long)state
->pid
,
1921 state
->request
->data
.auth
.user
));
1923 if (!parse_domain_user(state
->request
->data
.chauthtok
.user
, domain
, user
)) {
1927 /* Change password */
1929 oldpass
= state
->request
->data
.chauthtok
.oldpass
;
1930 newpass
= state
->request
->data
.chauthtok
.newpass
;
1932 /* Initialize reject reason */
1933 state
->response
->data
.auth
.reject_reason
= Undefined
;
1935 /* Get sam handle */
1937 result
= cm_connect_sam(contact_domain
, state
->mem_ctx
, &cli
,
1939 if (!NT_STATUS_IS_OK(result
)) {
1940 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain
));
1944 b
= cli
->binding_handle
;
1946 result
= rpccli_samr_chgpasswd_user3(cli
, state
->mem_ctx
,
1953 /* Windows 2003 returns NT_STATUS_PASSWORD_RESTRICTION */
1955 if (NT_STATUS_EQUAL(result
, NT_STATUS_PASSWORD_RESTRICTION
) ) {
1957 fill_in_password_policy(state
->response
, info
);
1959 state
->response
->data
.auth
.reject_reason
=
1960 reject
->extendedFailureReason
;
1965 /* atm the pidl generated rpccli_samr_ChangePasswordUser3 function will
1966 * return with NT_STATUS_BUFFER_TOO_SMALL for w2k dcs as w2k just
1967 * returns with 4byte error code (NT_STATUS_NOT_SUPPORTED) which is too
1968 * short to comply with the samr_ChangePasswordUser3 idl - gd */
1970 /* only fallback when the chgpasswd_user3 call is not supported */
1971 if (NT_STATUS_EQUAL(result
, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
) ||
1972 NT_STATUS_EQUAL(result
, NT_STATUS_NOT_SUPPORTED
) ||
1973 NT_STATUS_EQUAL(result
, NT_STATUS_BUFFER_TOO_SMALL
) ||
1974 NT_STATUS_EQUAL(result
, NT_STATUS_NOT_IMPLEMENTED
)) {
1976 DEBUG(10,("Password change with chgpasswd_user3 failed with: %s, retrying chgpasswd_user2\n",
1977 nt_errstr(result
)));
1979 result
= rpccli_samr_chgpasswd_user2(cli
, state
->mem_ctx
, user
, newpass
, oldpass
);
1981 /* Windows 2000 returns NT_STATUS_ACCOUNT_RESTRICTION.
1982 Map to the same status code as Windows 2003. */
1984 if ( NT_STATUS_EQUAL(NT_STATUS_ACCOUNT_RESTRICTION
, result
) ) {
1985 result
= NT_STATUS_PASSWORD_RESTRICTION
;
1991 if (NT_STATUS_IS_OK(result
)
1992 && (state
->request
->flags
& WBFLAG_PAM_CACHED_LOGIN
)
1993 && lp_winbind_offline_logon()) {
1994 result
= winbindd_update_creds_by_name(contact_domain
, user
,
1996 /* Again, this happens when we login from gdm or xdm
1997 * and the password expires, *BUT* cached crendentials
1998 * doesn't exist. winbindd_update_creds_by_name()
1999 * returns NT_STATUS_NO_SUCH_USER.
2000 * This is not a failure.
2003 if (NT_STATUS_EQUAL(result
, NT_STATUS_NO_SUCH_USER
)) {
2004 result
= NT_STATUS_OK
;
2007 if (!NT_STATUS_IS_OK(result
)) {
2008 DEBUG(10, ("Failed to store creds: %s\n",
2009 nt_errstr(result
)));
2010 goto process_result
;
2014 if (!NT_STATUS_IS_OK(result
) && !got_info
&& contact_domain
) {
2016 NTSTATUS policy_ret
;
2018 policy_ret
= fillup_password_policy(
2019 contact_domain
, state
->response
);
2021 /* failure of this is non critical, it will just provide no
2022 * additional information to the client why the change has
2023 * failed - Guenther */
2025 if (!NT_STATUS_IS_OK(policy_ret
)) {
2026 DEBUG(10,("Failed to get password policies: %s\n", nt_errstr(policy_ret
)));
2027 goto process_result
;
2033 if (strequal(contact_domain
->name
, get_global_sam_name())) {
2034 /* FIXME: internal rpc pipe does not cache handles yet */
2036 if (is_valid_policy_hnd(&dom_pol
)) {
2038 dcerpc_samr_Close(b
, state
->mem_ctx
, &dom_pol
, &_result
);
2044 set_auth_errors(state
->response
, result
);
2046 DEBUG(NT_STATUS_IS_OK(result
) ? 5 : 2,
2047 ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
2050 state
->response
->data
.auth
.nt_status_string
,
2051 state
->response
->data
.auth
.pam_error
));
2053 return NT_STATUS_IS_OK(result
) ? WINBINDD_OK
: WINBINDD_ERROR
;
2056 enum winbindd_result
winbindd_dual_pam_logoff(struct winbindd_domain
*domain
,
2057 struct winbindd_cli_state
*state
)
2059 NTSTATUS result
= NT_STATUS_NOT_SUPPORTED
;
2061 DEBUG(3, ("[%5lu]: pam dual logoff %s\n", (unsigned long)state
->pid
,
2062 state
->request
->data
.logoff
.user
));
2064 if (!(state
->request
->flags
& WBFLAG_PAM_KRB5
)) {
2065 result
= NT_STATUS_OK
;
2066 goto process_result
;
2069 if (state
->request
->data
.logoff
.krb5ccname
[0] == '\0') {
2070 result
= NT_STATUS_OK
;
2071 goto process_result
;
2076 if (state
->request
->data
.logoff
.uid
< 0) {
2077 DEBUG(0,("winbindd_pam_logoff: invalid uid\n"));
2078 goto process_result
;
2081 /* what we need here is to find the corresponding krb5 ccache name *we*
2082 * created for a given username and destroy it */
2084 if (!ccache_entry_exists(state
->request
->data
.logoff
.user
)) {
2085 result
= NT_STATUS_OK
;
2086 DEBUG(10,("winbindd_pam_logoff: no entry found.\n"));
2087 goto process_result
;
2090 if (!ccache_entry_identical(state
->request
->data
.logoff
.user
,
2091 state
->request
->data
.logoff
.uid
,
2092 state
->request
->data
.logoff
.krb5ccname
)) {
2093 DEBUG(0,("winbindd_pam_logoff: cached entry differs.\n"));
2094 goto process_result
;
2097 result
= remove_ccache(state
->request
->data
.logoff
.user
);
2098 if (!NT_STATUS_IS_OK(result
)) {
2099 DEBUG(0,("winbindd_pam_logoff: failed to remove ccache: %s\n",
2100 nt_errstr(result
)));
2101 goto process_result
;
2105 result
= NT_STATUS_NOT_SUPPORTED
;
2111 set_auth_errors(state
->response
, result
);
2113 return NT_STATUS_IS_OK(result
) ? WINBINDD_OK
: WINBINDD_ERROR
;
2116 /* Change user password with auth crap*/
2118 enum winbindd_result
winbindd_dual_pam_chng_pswd_auth_crap(struct winbindd_domain
*domainSt
, struct winbindd_cli_state
*state
)
2121 DATA_BLOB new_nt_password
;
2122 DATA_BLOB old_nt_hash_enc
;
2123 DATA_BLOB new_lm_password
;
2124 DATA_BLOB old_lm_hash_enc
;
2125 fstring domain
,user
;
2126 struct policy_handle dom_pol
;
2127 struct winbindd_domain
*contact_domain
= domainSt
;
2128 struct rpc_pipe_client
*cli
= NULL
;
2129 struct dcerpc_binding_handle
*b
= NULL
;
2131 ZERO_STRUCT(dom_pol
);
2133 /* Ensure null termination */
2134 state
->request
->data
.chng_pswd_auth_crap
.user
[
2135 sizeof(state
->request
->data
.chng_pswd_auth_crap
.user
)-1]=0;
2136 state
->request
->data
.chng_pswd_auth_crap
.domain
[
2137 sizeof(state
->request
->data
.chng_pswd_auth_crap
.domain
)-1]=0;
2141 DEBUG(3, ("[%5lu]: pam change pswd auth crap domain: %s user: %s\n",
2142 (unsigned long)state
->pid
,
2143 state
->request
->data
.chng_pswd_auth_crap
.domain
,
2144 state
->request
->data
.chng_pswd_auth_crap
.user
));
2146 if (lp_winbind_offline_logon()) {
2147 DEBUG(0,("Refusing password change as winbind offline logons are enabled. "));
2148 DEBUGADD(0,("Changing passwords here would risk inconsistent logons\n"));
2149 result
= NT_STATUS_ACCESS_DENIED
;
2153 if (*state
->request
->data
.chng_pswd_auth_crap
.domain
) {
2154 fstrcpy(domain
,state
->request
->data
.chng_pswd_auth_crap
.domain
);
2156 parse_domain_user(state
->request
->data
.chng_pswd_auth_crap
.user
,
2160 DEBUG(3,("no domain specified with username (%s) - "
2162 state
->request
->data
.chng_pswd_auth_crap
.user
));
2163 result
= NT_STATUS_NO_SUCH_USER
;
2168 if (!*domain
&& lp_winbind_use_default_domain()) {
2169 fstrcpy(domain
,lp_workgroup());
2173 fstrcpy(user
, state
->request
->data
.chng_pswd_auth_crap
.user
);
2176 DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n",
2177 (unsigned long)state
->pid
, domain
, user
));
2179 /* Change password */
2180 new_nt_password
= data_blob_const(
2181 state
->request
->data
.chng_pswd_auth_crap
.new_nt_pswd
,
2182 state
->request
->data
.chng_pswd_auth_crap
.new_nt_pswd_len
);
2184 old_nt_hash_enc
= data_blob_const(
2185 state
->request
->data
.chng_pswd_auth_crap
.old_nt_hash_enc
,
2186 state
->request
->data
.chng_pswd_auth_crap
.old_nt_hash_enc_len
);
2188 if(state
->request
->data
.chng_pswd_auth_crap
.new_lm_pswd_len
> 0) {
2189 new_lm_password
= data_blob_const(
2190 state
->request
->data
.chng_pswd_auth_crap
.new_lm_pswd
,
2191 state
->request
->data
.chng_pswd_auth_crap
.new_lm_pswd_len
);
2193 old_lm_hash_enc
= data_blob_const(
2194 state
->request
->data
.chng_pswd_auth_crap
.old_lm_hash_enc
,
2195 state
->request
->data
.chng_pswd_auth_crap
.old_lm_hash_enc_len
);
2197 new_lm_password
.length
= 0;
2198 old_lm_hash_enc
.length
= 0;
2201 /* Get sam handle */
2203 result
= cm_connect_sam(contact_domain
, state
->mem_ctx
, &cli
, &dom_pol
);
2204 if (!NT_STATUS_IS_OK(result
)) {
2205 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain
));
2209 b
= cli
->binding_handle
;
2211 result
= rpccli_samr_chng_pswd_auth_crap(
2212 cli
, state
->mem_ctx
, user
, new_nt_password
, old_nt_hash_enc
,
2213 new_lm_password
, old_lm_hash_enc
);
2217 if (strequal(contact_domain
->name
, get_global_sam_name())) {
2218 /* FIXME: internal rpc pipe does not cache handles yet */
2220 if (is_valid_policy_hnd(&dom_pol
)) {
2222 dcerpc_samr_Close(b
, state
->mem_ctx
, &dom_pol
, &_result
);
2228 set_auth_errors(state
->response
, result
);
2230 DEBUG(NT_STATUS_IS_OK(result
) ? 5 : 2,
2231 ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
2233 state
->response
->data
.auth
.nt_status_string
,
2234 state
->response
->data
.auth
.pam_error
));
2236 return NT_STATUS_IS_OK(result
) ? WINBINDD_OK
: WINBINDD_ERROR
;