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/cli_samr.h"
29 #include "rpc_client/cli_samr.h"
30 #include "../librpc/gen_ndr/ndr_netlogon.h"
31 #include "rpc_client/cli_netlogon.h"
33 #include "../lib/crypto/arcfour.h"
36 #define DBGC_CLASS DBGC_WINBIND
38 #define LOGON_KRB5_FAIL_CLOCK_SKEW 0x02000000
40 static NTSTATUS
append_info3_as_txt(TALLOC_CTX
*mem_ctx
,
41 struct winbindd_cli_state
*state
,
42 struct netr_SamInfo3
*info3
)
47 state
->response
->data
.auth
.info3
.logon_time
=
48 nt_time_to_unix(info3
->base
.last_logon
);
49 state
->response
->data
.auth
.info3
.logoff_time
=
50 nt_time_to_unix(info3
->base
.last_logoff
);
51 state
->response
->data
.auth
.info3
.kickoff_time
=
52 nt_time_to_unix(info3
->base
.acct_expiry
);
53 state
->response
->data
.auth
.info3
.pass_last_set_time
=
54 nt_time_to_unix(info3
->base
.last_password_change
);
55 state
->response
->data
.auth
.info3
.pass_can_change_time
=
56 nt_time_to_unix(info3
->base
.allow_password_change
);
57 state
->response
->data
.auth
.info3
.pass_must_change_time
=
58 nt_time_to_unix(info3
->base
.force_password_change
);
60 state
->response
->data
.auth
.info3
.logon_count
= info3
->base
.logon_count
;
61 state
->response
->data
.auth
.info3
.bad_pw_count
= info3
->base
.bad_password_count
;
63 state
->response
->data
.auth
.info3
.user_rid
= info3
->base
.rid
;
64 state
->response
->data
.auth
.info3
.group_rid
= info3
->base
.primary_gid
;
65 sid_to_fstring(state
->response
->data
.auth
.info3
.dom_sid
, info3
->base
.domain_sid
);
67 state
->response
->data
.auth
.info3
.num_groups
= info3
->base
.groups
.count
;
68 state
->response
->data
.auth
.info3
.user_flgs
= info3
->base
.user_flags
;
70 state
->response
->data
.auth
.info3
.acct_flags
= info3
->base
.acct_flags
;
71 state
->response
->data
.auth
.info3
.num_other_sids
= info3
->sidcount
;
73 fstrcpy(state
->response
->data
.auth
.info3
.user_name
,
74 info3
->base
.account_name
.string
);
75 fstrcpy(state
->response
->data
.auth
.info3
.full_name
,
76 info3
->base
.full_name
.string
);
77 fstrcpy(state
->response
->data
.auth
.info3
.logon_script
,
78 info3
->base
.logon_script
.string
);
79 fstrcpy(state
->response
->data
.auth
.info3
.profile_path
,
80 info3
->base
.profile_path
.string
);
81 fstrcpy(state
->response
->data
.auth
.info3
.home_dir
,
82 info3
->base
.home_directory
.string
);
83 fstrcpy(state
->response
->data
.auth
.info3
.dir_drive
,
84 info3
->base
.home_drive
.string
);
86 fstrcpy(state
->response
->data
.auth
.info3
.logon_srv
,
87 info3
->base
.logon_server
.string
);
88 fstrcpy(state
->response
->data
.auth
.info3
.logon_dom
,
89 info3
->base
.domain
.string
);
91 ex
= talloc_strdup(state
->mem_ctx
, "");
92 NT_STATUS_HAVE_NO_MEMORY(ex
);
94 for (i
=0; i
< info3
->base
.groups
.count
; i
++) {
95 ex
= talloc_asprintf_append_buffer(ex
, "0x%08X:0x%08X\n",
96 info3
->base
.groups
.rids
[i
].rid
,
97 info3
->base
.groups
.rids
[i
].attributes
);
98 NT_STATUS_HAVE_NO_MEMORY(ex
);
101 for (i
=0; i
< info3
->sidcount
; i
++) {
104 sid
= dom_sid_string(mem_ctx
, info3
->sids
[i
].sid
);
105 NT_STATUS_HAVE_NO_MEMORY(sid
);
107 ex
= talloc_asprintf_append_buffer(ex
, "%s:0x%08X\n",
109 info3
->sids
[i
].attributes
);
110 NT_STATUS_HAVE_NO_MEMORY(ex
);
115 state
->response
->extra_data
.data
= ex
;
116 state
->response
->length
+= talloc_get_size(ex
);
121 static NTSTATUS
append_info3_as_ndr(TALLOC_CTX
*mem_ctx
,
122 struct winbindd_cli_state
*state
,
123 struct netr_SamInfo3
*info3
)
126 enum ndr_err_code ndr_err
;
128 ndr_err
= ndr_push_struct_blob(&blob
, mem_ctx
, info3
,
129 (ndr_push_flags_fn_t
)ndr_push_netr_SamInfo3
);
130 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
131 DEBUG(0,("append_info3_as_ndr: failed to append\n"));
132 return ndr_map_error2ntstatus(ndr_err
);
135 state
->response
->extra_data
.data
= blob
.data
;
136 state
->response
->length
+= blob
.length
;
141 static NTSTATUS
append_unix_username(TALLOC_CTX
*mem_ctx
,
142 struct winbindd_cli_state
*state
,
143 const struct netr_SamInfo3
*info3
,
144 const char *name_domain
,
145 const char *name_user
)
147 /* We've been asked to return the unix username, per
148 'winbind use default domain' settings and the like */
150 const char *nt_username
, *nt_domain
;
152 nt_domain
= talloc_strdup(mem_ctx
, info3
->base
.domain
.string
);
154 /* If the server didn't give us one, just use the one
156 nt_domain
= name_domain
;
159 nt_username
= talloc_strdup(mem_ctx
, info3
->base
.account_name
.string
);
161 /* If the server didn't give us one, just use the one
163 nt_username
= name_user
;
166 fill_domain_username(state
->response
->data
.auth
.unix_username
,
167 nt_domain
, nt_username
, true);
169 DEBUG(5,("Setting unix username to [%s]\n",
170 state
->response
->data
.auth
.unix_username
));
175 static NTSTATUS
append_afs_token(TALLOC_CTX
*mem_ctx
,
176 struct winbindd_cli_state
*state
,
177 const struct netr_SamInfo3
*info3
,
178 const char *name_domain
,
179 const char *name_user
)
181 char *afsname
= NULL
;
185 afsname
= talloc_strdup(mem_ctx
, lp_afs_username_map());
186 if (afsname
== NULL
) {
187 return NT_STATUS_NO_MEMORY
;
190 afsname
= talloc_string_sub(mem_ctx
,
191 lp_afs_username_map(),
193 afsname
= talloc_string_sub(mem_ctx
, afsname
,
195 afsname
= talloc_string_sub(mem_ctx
, afsname
,
202 sid_compose(&user_sid
, info3
->base
.domain_sid
,
204 sid_to_fstring(sidstr
, &user_sid
);
205 afsname
= talloc_string_sub(mem_ctx
, afsname
,
209 if (afsname
== NULL
) {
210 return NT_STATUS_NO_MEMORY
;
215 DEBUG(10, ("Generating token for user %s\n", afsname
));
217 cell
= strchr(afsname
, '@');
220 return NT_STATUS_NO_MEMORY
;
226 token
= afs_createtoken_str(afsname
, cell
);
230 state
->response
->extra_data
.data
= talloc_strdup(state
->mem_ctx
,
232 if (state
->response
->extra_data
.data
== NULL
) {
233 return NT_STATUS_NO_MEMORY
;
235 state
->response
->length
+=
236 strlen((const char *)state
->response
->extra_data
.data
)+1;
241 static NTSTATUS
check_info3_in_group(struct netr_SamInfo3
*info3
,
242 const char *group_sid
)
244 * Check whether a user belongs to a group or list of groups.
246 * @param mem_ctx talloc memory context.
247 * @param info3 user information, including group membership info.
248 * @param group_sid One or more groups , separated by commas.
250 * @return NT_STATUS_OK on success,
251 * NT_STATUS_LOGON_FAILURE if the user does not belong,
252 * or other NT_STATUS_IS_ERR(status) for other kinds of failure.
255 DOM_SID
*require_membership_of_sid
;
256 size_t num_require_membership_of_sid
;
261 struct nt_user_token
*token
;
262 TALLOC_CTX
*frame
= talloc_stackframe();
265 /* Parse the 'required group' SID */
267 if (!group_sid
|| !group_sid
[0]) {
268 /* NO sid supplied, all users may access */
272 token
= talloc_zero(talloc_tos(), struct nt_user_token
);
274 DEBUG(0, ("talloc failed\n"));
276 return NT_STATUS_NO_MEMORY
;
279 num_require_membership_of_sid
= 0;
280 require_membership_of_sid
= NULL
;
284 while (next_token_talloc(talloc_tos(), &p
, &req_sid
, ",")) {
285 if (!string_to_sid(&sid
, req_sid
)) {
286 DEBUG(0, ("check_info3_in_group: could not parse %s "
287 "as a SID!", req_sid
));
289 return NT_STATUS_INVALID_PARAMETER
;
292 status
= add_sid_to_array(talloc_tos(), &sid
,
293 &require_membership_of_sid
,
294 &num_require_membership_of_sid
);
295 if (!NT_STATUS_IS_OK(status
)) {
296 DEBUG(0, ("add_sid_to_array failed\n"));
302 status
= sid_array_from_info3(talloc_tos(), info3
,
306 if (!NT_STATUS_IS_OK(status
)) {
311 if (!NT_STATUS_IS_OK(status
= add_aliases(get_global_sam_sid(),
313 || !NT_STATUS_IS_OK(status
= add_aliases(&global_sid_Builtin
,
315 DEBUG(3, ("could not add aliases: %s\n",
321 debug_nt_user_token(DBGC_CLASS
, 10, token
);
323 for (i
=0; i
<num_require_membership_of_sid
; i
++) {
324 DEBUG(10, ("Checking SID %s\n", sid_string_dbg(
325 &require_membership_of_sid
[i
])));
326 if (nt_token_check_sid(&require_membership_of_sid
[i
],
328 DEBUG(10, ("Access ok\n"));
334 /* Do not distinguish this error from a wrong username/pw */
337 return NT_STATUS_LOGON_FAILURE
;
340 struct winbindd_domain
*find_auth_domain(uint8_t flags
,
341 const char *domain_name
)
343 struct winbindd_domain
*domain
;
346 domain
= find_domain_from_name_noinit(domain_name
);
347 if (domain
== NULL
) {
348 DEBUG(3, ("Authentication for domain [%s] refused "
349 "as it is not a trusted domain\n",
355 if (strequal(domain_name
, get_global_sam_name())) {
356 return find_domain_from_name_noinit(domain_name
);
359 /* we can auth against trusted domains */
360 if (flags
& WBFLAG_PAM_CONTACT_TRUSTDOM
) {
361 domain
= find_domain_from_name_noinit(domain_name
);
362 if (domain
== NULL
) {
363 DEBUG(3, ("Authentication for domain [%s] skipped "
364 "as it is not a trusted domain\n",
371 return find_our_domain();
374 static void fill_in_password_policy(struct winbindd_response
*r
,
375 const struct samr_DomInfo1
*p
)
377 r
->data
.auth
.policy
.min_length_password
=
378 p
->min_password_length
;
379 r
->data
.auth
.policy
.password_history
=
380 p
->password_history_length
;
381 r
->data
.auth
.policy
.password_properties
=
382 p
->password_properties
;
383 r
->data
.auth
.policy
.expire
=
384 nt_time_to_unix_abs((NTTIME
*)&(p
->max_password_age
));
385 r
->data
.auth
.policy
.min_passwordage
=
386 nt_time_to_unix_abs((NTTIME
*)&(p
->min_password_age
));
389 static NTSTATUS
fillup_password_policy(struct winbindd_domain
*domain
,
390 struct winbindd_cli_state
*state
)
392 struct winbindd_methods
*methods
;
393 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
394 struct samr_DomInfo1 password_policy
;
396 if ( !winbindd_can_contact_domain( domain
) ) {
397 DEBUG(5,("fillup_password_policy: No inbound trust to "
398 "contact domain %s\n", domain
->name
));
399 return NT_STATUS_NOT_SUPPORTED
;
402 methods
= domain
->methods
;
404 status
= methods
->password_policy(domain
, state
->mem_ctx
, &password_policy
);
405 if (NT_STATUS_IS_ERR(status
)) {
409 fill_in_password_policy(state
->response
, &password_policy
);
414 static NTSTATUS
get_max_bad_attempts_from_lockout_policy(struct winbindd_domain
*domain
,
416 uint16
*lockout_threshold
)
418 struct winbindd_methods
*methods
;
419 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
420 struct samr_DomInfo12 lockout_policy
;
422 *lockout_threshold
= 0;
424 methods
= domain
->methods
;
426 status
= methods
->lockout_policy(domain
, mem_ctx
, &lockout_policy
);
427 if (NT_STATUS_IS_ERR(status
)) {
431 *lockout_threshold
= lockout_policy
.lockout_threshold
;
436 static NTSTATUS
get_pwd_properties(struct winbindd_domain
*domain
,
438 uint32
*password_properties
)
440 struct winbindd_methods
*methods
;
441 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
442 struct samr_DomInfo1 password_policy
;
444 *password_properties
= 0;
446 methods
= domain
->methods
;
448 status
= methods
->password_policy(domain
, mem_ctx
, &password_policy
);
449 if (NT_STATUS_IS_ERR(status
)) {
453 *password_properties
= password_policy
.password_properties
;
460 static const char *generate_krb5_ccache(TALLOC_CTX
*mem_ctx
,
463 bool *internal_ccache
)
465 /* accept FILE and WRFILE as krb5_cc_type from the client and then
466 * build the full ccname string based on the user's uid here -
469 const char *gen_cc
= NULL
;
471 *internal_ccache
= true;
477 if (!type
|| type
[0] == '\0') {
481 if (strequal(type
, "FILE")) {
482 gen_cc
= talloc_asprintf(mem_ctx
, "FILE:/tmp/krb5cc_%d", uid
);
483 } else if (strequal(type
, "WRFILE")) {
484 gen_cc
= talloc_asprintf(mem_ctx
, "WRFILE:/tmp/krb5cc_%d", uid
);
486 DEBUG(10,("we don't allow to set a %s type ccache\n", type
));
490 *internal_ccache
= false;
494 gen_cc
= talloc_strdup(mem_ctx
, "MEMORY:winbindd_pam_ccache");
497 if (gen_cc
== NULL
) {
498 DEBUG(0,("out of memory\n"));
502 DEBUG(10,("using ccache: %s %s\n", gen_cc
, *internal_ccache
? "(internal)":""));
507 static void setup_return_cc_name(struct winbindd_cli_state
*state
, const char *cc
)
509 const char *type
= state
->request
->data
.auth
.krb5_cc_type
;
511 state
->response
->data
.auth
.krb5ccname
[0] = '\0';
513 if (type
[0] == '\0') {
517 if (!strequal(type
, "FILE") &&
518 !strequal(type
, "WRFILE")) {
519 DEBUG(10,("won't return krbccname for a %s type ccache\n",
524 fstrcpy(state
->response
->data
.auth
.krb5ccname
, cc
);
529 uid_t
get_uid_from_request(struct winbindd_request
*request
)
533 uid
= request
->data
.auth
.uid
;
536 DEBUG(1,("invalid uid: '%u'\n", (unsigned int)uid
));
542 static uid_t
get_uid_from_state(struct winbindd_cli_state
*state
)
544 return get_uid_from_request(state
->request
);
547 /**********************************************************************
548 Authenticate a user with a clear text password using Kerberos and fill up
550 **********************************************************************/
552 static NTSTATUS
winbindd_raw_kerberos_login(struct winbindd_domain
*domain
,
553 struct winbindd_cli_state
*state
,
554 struct netr_SamInfo3
**info3
)
557 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
558 krb5_error_code krb5_ret
;
559 const char *cc
= NULL
;
560 const char *principal_s
= NULL
;
561 const char *service
= NULL
;
563 fstring name_domain
, name_user
;
564 time_t ticket_lifetime
= 0;
565 time_t renewal_until
= 0;
568 time_t time_offset
= 0;
569 bool internal_ccache
= true;
570 struct PAC_LOGON_INFO
*logon_info
= NULL
;
575 * prepare a krb5_cc_cache string for the user */
577 uid
= get_uid_from_state(state
);
579 DEBUG(0,("no valid uid\n"));
582 cc
= generate_krb5_ccache(state
->mem_ctx
,
583 state
->request
->data
.auth
.krb5_cc_type
,
584 state
->request
->data
.auth
.uid
,
587 return NT_STATUS_NO_MEMORY
;
592 * get kerberos properties */
594 if (domain
->private_data
) {
595 ads
= (ADS_STRUCT
*)domain
->private_data
;
596 time_offset
= ads
->auth
.time_offset
;
601 * do kerberos auth and setup ccache as the user */
603 parse_domain_user(state
->request
->data
.auth
.user
, name_domain
, name_user
);
605 realm
= domain
->alt_name
;
608 principal_s
= talloc_asprintf(state
->mem_ctx
, "%s@%s", name_user
, realm
);
609 if (principal_s
== NULL
) {
610 return NT_STATUS_NO_MEMORY
;
613 service
= talloc_asprintf(state
->mem_ctx
, "%s/%s@%s", KRB5_TGS_NAME
, realm
, realm
);
614 if (service
== NULL
) {
615 return NT_STATUS_NO_MEMORY
;
618 /* if this is a user ccache, we need to act as the user to let the krb5
619 * library handle the chown, etc. */
621 /************************ ENTERING NON-ROOT **********************/
623 if (!internal_ccache
) {
624 set_effective_uid(uid
);
625 DEBUG(10,("winbindd_raw_kerberos_login: uid is %d\n", uid
));
628 result
= kerberos_return_pac(state
->mem_ctx
,
630 state
->request
->data
.auth
.pass
,
637 WINBINDD_PAM_AUTH_KRB5_RENEW_TIME
,
640 if (!internal_ccache
) {
641 gain_root_privilege();
644 /************************ RETURNED TO ROOT **********************/
646 if (!NT_STATUS_IS_OK(result
)) {
650 *info3
= &logon_info
->info3
;
652 DEBUG(10,("winbindd_raw_kerberos_login: winbindd validated ticket of %s\n",
655 /* if we had a user's ccache then return that string for the pam
658 if (!internal_ccache
) {
660 setup_return_cc_name(state
, cc
);
662 result
= add_ccache_to_list(principal_s
,
665 state
->request
->data
.auth
.user
,
673 if (!NT_STATUS_IS_OK(result
)) {
674 DEBUG(10,("winbindd_raw_kerberos_login: failed to add ccache to list: %s\n",
679 /* need to delete the memory cred cache, it is not used anymore */
681 krb5_ret
= ads_kdestroy(cc
);
683 DEBUG(3,("winbindd_raw_kerberos_login: "
684 "could not destroy krb5 credential cache: "
685 "%s\n", error_message(krb5_ret
)));
694 /* we could have created a new credential cache with a valid tgt in it
695 * but we werent able to get or verify the service ticket for this
696 * local host and therefor didn't get the PAC, we need to remove that
697 * cache entirely now */
699 krb5_ret
= ads_kdestroy(cc
);
701 DEBUG(3,("winbindd_raw_kerberos_login: "
702 "could not destroy krb5 credential cache: "
703 "%s\n", error_message(krb5_ret
)));
706 if (!NT_STATUS_IS_OK(remove_ccache(state
->request
->data
.auth
.user
))) {
707 DEBUG(3,("winbindd_raw_kerberos_login: "
708 "could not remove ccache for user %s\n",
709 state
->request
->data
.auth
.user
));
714 return NT_STATUS_NOT_SUPPORTED
;
715 #endif /* HAVE_KRB5 */
718 /****************************************************************
719 ****************************************************************/
721 bool check_request_flags(uint32_t flags
)
723 uint32_t flags_edata
= WBFLAG_PAM_AFS_TOKEN
|
724 WBFLAG_PAM_INFO3_TEXT
|
725 WBFLAG_PAM_INFO3_NDR
;
727 if ( ( (flags
& flags_edata
) == WBFLAG_PAM_AFS_TOKEN
) ||
728 ( (flags
& flags_edata
) == WBFLAG_PAM_INFO3_NDR
) ||
729 ( (flags
& flags_edata
) == WBFLAG_PAM_INFO3_TEXT
)||
730 !(flags
& flags_edata
) ) {
734 DEBUG(1, ("check_request_flags: invalid request flags[0x%08X]\n",
740 /****************************************************************
741 ****************************************************************/
743 static NTSTATUS
append_auth_data(struct winbindd_cli_state
*state
,
744 struct netr_SamInfo3
*info3
,
745 const char *name_domain
,
746 const char *name_user
)
749 uint32_t flags
= state
->request
->flags
;
751 if (flags
& WBFLAG_PAM_USER_SESSION_KEY
) {
752 memcpy(state
->response
->data
.auth
.user_session_key
,
754 sizeof(state
->response
->data
.auth
.user_session_key
)
758 if (flags
& WBFLAG_PAM_LMKEY
) {
759 memcpy(state
->response
->data
.auth
.first_8_lm_hash
,
760 info3
->base
.LMSessKey
.key
,
761 sizeof(state
->response
->data
.auth
.first_8_lm_hash
)
765 if (flags
& WBFLAG_PAM_UNIX_NAME
) {
766 result
= append_unix_username(state
->mem_ctx
, state
, info3
,
767 name_domain
, name_user
);
768 if (!NT_STATUS_IS_OK(result
)) {
769 DEBUG(10,("Failed to append Unix Username: %s\n",
775 /* currently, anything from here on potentially overwrites extra_data. */
777 if (flags
& WBFLAG_PAM_INFO3_NDR
) {
778 result
= append_info3_as_ndr(state
->mem_ctx
, state
, info3
);
779 if (!NT_STATUS_IS_OK(result
)) {
780 DEBUG(10,("Failed to append INFO3 (NDR): %s\n",
786 if (flags
& WBFLAG_PAM_INFO3_TEXT
) {
787 result
= append_info3_as_txt(state
->mem_ctx
, state
, info3
);
788 if (!NT_STATUS_IS_OK(result
)) {
789 DEBUG(10,("Failed to append INFO3 (TXT): %s\n",
795 if (flags
& WBFLAG_PAM_AFS_TOKEN
) {
796 result
= append_afs_token(state
->mem_ctx
, state
, info3
,
797 name_domain
, name_user
);
798 if (!NT_STATUS_IS_OK(result
)) {
799 DEBUG(10,("Failed to append AFS token: %s\n",
808 static NTSTATUS
winbindd_dual_pam_auth_cached(struct winbindd_domain
*domain
,
809 struct winbindd_cli_state
*state
,
810 struct netr_SamInfo3
**info3
)
812 NTSTATUS result
= NT_STATUS_LOGON_FAILURE
;
813 uint16 max_allowed_bad_attempts
;
814 fstring name_domain
, name_user
;
816 enum lsa_SidType type
;
817 uchar new_nt_pass
[NT_HASH_LEN
];
818 const uint8
*cached_nt_pass
;
819 const uint8
*cached_salt
;
820 struct netr_SamInfo3
*my_info3
;
821 time_t kickoff_time
, must_change_time
;
822 bool password_good
= false;
824 struct winbindd_tdc_domain
*tdc_domain
= NULL
;
831 DEBUG(10,("winbindd_dual_pam_auth_cached\n"));
833 /* Parse domain and username */
835 parse_domain_user(state
->request
->data
.auth
.user
, name_domain
, name_user
);
838 if (!lookup_cached_name(state
->mem_ctx
,
843 DEBUG(10,("winbindd_dual_pam_auth_cached: no such user in the cache\n"));
844 return NT_STATUS_NO_SUCH_USER
;
847 if (type
!= SID_NAME_USER
) {
848 DEBUG(10,("winbindd_dual_pam_auth_cached: not a user (%s)\n", sid_type_lookup(type
)));
849 return NT_STATUS_LOGON_FAILURE
;
852 result
= winbindd_get_creds(domain
,
858 if (!NT_STATUS_IS_OK(result
)) {
859 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get creds: %s\n", nt_errstr(result
)));
865 E_md4hash(state
->request
->data
.auth
.pass
, new_nt_pass
);
867 dump_data_pw("new_nt_pass", new_nt_pass
, NT_HASH_LEN
);
868 dump_data_pw("cached_nt_pass", cached_nt_pass
, NT_HASH_LEN
);
870 dump_data_pw("cached_salt", cached_salt
, NT_HASH_LEN
);
874 /* In this case we didn't store the nt_hash itself,
875 but the MD5 combination of salt + nt_hash. */
876 uchar salted_hash
[NT_HASH_LEN
];
877 E_md5hash(cached_salt
, new_nt_pass
, salted_hash
);
879 password_good
= (memcmp(cached_nt_pass
, salted_hash
,
882 /* Old cached cred - direct store of nt_hash (bad bad bad !). */
883 password_good
= (memcmp(cached_nt_pass
, new_nt_pass
,
889 /* User *DOES* know the password, update logon_time and reset
892 my_info3
->base
.user_flags
|= NETLOGON_CACHED_ACCOUNT
;
894 if (my_info3
->base
.acct_flags
& ACB_AUTOLOCK
) {
895 return NT_STATUS_ACCOUNT_LOCKED_OUT
;
898 if (my_info3
->base
.acct_flags
& ACB_DISABLED
) {
899 return NT_STATUS_ACCOUNT_DISABLED
;
902 if (my_info3
->base
.acct_flags
& ACB_WSTRUST
) {
903 return NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT
;
906 if (my_info3
->base
.acct_flags
& ACB_SVRTRUST
) {
907 return NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT
;
910 if (my_info3
->base
.acct_flags
& ACB_DOMTRUST
) {
911 return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT
;
914 if (!(my_info3
->base
.acct_flags
& ACB_NORMAL
)) {
915 DEBUG(0,("winbindd_dual_pam_auth_cached: whats wrong with that one?: 0x%08x\n",
916 my_info3
->base
.acct_flags
));
917 return NT_STATUS_LOGON_FAILURE
;
920 kickoff_time
= nt_time_to_unix(my_info3
->base
.acct_expiry
);
921 if (kickoff_time
!= 0 && time(NULL
) > kickoff_time
) {
922 return NT_STATUS_ACCOUNT_EXPIRED
;
925 must_change_time
= nt_time_to_unix(my_info3
->base
.force_password_change
);
926 if (must_change_time
!= 0 && must_change_time
< time(NULL
)) {
927 /* we allow grace logons when the password has expired */
928 my_info3
->base
.user_flags
|= NETLOGON_GRACE_LOGON
;
929 /* return NT_STATUS_PASSWORD_EXPIRED; */
934 if ((state
->request
->flags
& WBFLAG_PAM_KRB5
) &&
935 ((tdc_domain
= wcache_tdc_fetch_domain(state
->mem_ctx
, name_domain
)) != NULL
) &&
936 ((tdc_domain
->trust_type
& NETR_TRUST_TYPE_UPLEVEL
) ||
937 /* used to cope with the case winbindd starting without network. */
938 !strequal(tdc_domain
->domain_name
, tdc_domain
->dns_name
))) {
941 const char *cc
= NULL
;
943 const char *principal_s
= NULL
;
944 const char *service
= NULL
;
945 bool internal_ccache
= false;
947 uid
= get_uid_from_state(state
);
949 DEBUG(0,("winbindd_dual_pam_auth_cached: invalid uid\n"));
950 return NT_STATUS_INVALID_PARAMETER
;
953 cc
= generate_krb5_ccache(state
->mem_ctx
,
954 state
->request
->data
.auth
.krb5_cc_type
,
955 state
->request
->data
.auth
.uid
,
958 return NT_STATUS_NO_MEMORY
;
961 realm
= domain
->alt_name
;
964 principal_s
= talloc_asprintf(state
->mem_ctx
, "%s@%s", name_user
, realm
);
965 if (principal_s
== NULL
) {
966 return NT_STATUS_NO_MEMORY
;
969 service
= talloc_asprintf(state
->mem_ctx
, "%s/%s@%s", KRB5_TGS_NAME
, realm
, realm
);
970 if (service
== NULL
) {
971 return NT_STATUS_NO_MEMORY
;
974 if (!internal_ccache
) {
976 setup_return_cc_name(state
, cc
);
978 result
= add_ccache_to_list(principal_s
,
981 state
->request
->data
.auth
.user
,
985 time(NULL
) + lp_winbind_cache_time(),
986 time(NULL
) + WINBINDD_PAM_AUTH_KRB5_RENEW_TIME
,
989 if (!NT_STATUS_IS_OK(result
)) {
990 DEBUG(10,("winbindd_dual_pam_auth_cached: failed "
991 "to add ccache to list: %s\n",
996 #endif /* HAVE_KRB5 */
998 /* FIXME: we possibly should handle logon hours as well (does xp when
999 * offline?) see auth/auth_sam.c:sam_account_ok for details */
1001 unix_to_nt_time(&my_info3
->base
.last_logon
, time(NULL
));
1002 my_info3
->base
.bad_password_count
= 0;
1004 result
= winbindd_update_creds_by_info3(domain
,
1006 state
->request
->data
.auth
.user
,
1007 state
->request
->data
.auth
.pass
,
1009 if (!NT_STATUS_IS_OK(result
)) {
1010 DEBUG(1,("winbindd_dual_pam_auth_cached: failed to update creds: %s\n",
1011 nt_errstr(result
)));
1015 return NT_STATUS_OK
;
1019 /* User does *NOT* know the correct password, modify info3 accordingly */
1021 /* failure of this is not critical */
1022 result
= get_max_bad_attempts_from_lockout_policy(domain
, state
->mem_ctx
, &max_allowed_bad_attempts
);
1023 if (!NT_STATUS_IS_OK(result
)) {
1024 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get max_allowed_bad_attempts. "
1025 "Won't be able to honour account lockout policies\n"));
1028 /* increase counter */
1029 my_info3
->base
.bad_password_count
++;
1031 if (max_allowed_bad_attempts
== 0) {
1036 if (my_info3
->base
.bad_password_count
>= max_allowed_bad_attempts
) {
1038 uint32 password_properties
;
1040 result
= get_pwd_properties(domain
, state
->mem_ctx
, &password_properties
);
1041 if (!NT_STATUS_IS_OK(result
)) {
1042 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get password properties.\n"));
1045 if ((my_info3
->base
.rid
!= DOMAIN_RID_ADMINISTRATOR
) ||
1046 (password_properties
& DOMAIN_PASSWORD_LOCKOUT_ADMINS
)) {
1047 my_info3
->base
.acct_flags
|= ACB_AUTOLOCK
;
1052 result
= winbindd_update_creds_by_info3(domain
,
1054 state
->request
->data
.auth
.user
,
1058 if (!NT_STATUS_IS_OK(result
)) {
1059 DEBUG(0,("winbindd_dual_pam_auth_cached: failed to update creds %s\n",
1060 nt_errstr(result
)));
1063 return NT_STATUS_LOGON_FAILURE
;
1066 static NTSTATUS
winbindd_dual_pam_auth_kerberos(struct winbindd_domain
*domain
,
1067 struct winbindd_cli_state
*state
,
1068 struct netr_SamInfo3
**info3
)
1070 struct winbindd_domain
*contact_domain
;
1071 fstring name_domain
, name_user
;
1074 DEBUG(10,("winbindd_dual_pam_auth_kerberos\n"));
1076 /* Parse domain and username */
1078 parse_domain_user(state
->request
->data
.auth
.user
, name_domain
, name_user
);
1080 /* what domain should we contact? */
1083 if (!(contact_domain
= find_domain_from_name(name_domain
))) {
1084 DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
1085 state
->request
->data
.auth
.user
, name_domain
, name_user
, name_domain
));
1086 result
= NT_STATUS_NO_SUCH_USER
;
1091 if (is_myname(name_domain
)) {
1092 DEBUG(3, ("Authentication for domain %s (local domain to this server) not supported at this stage\n", name_domain
));
1093 result
= NT_STATUS_NO_SUCH_USER
;
1097 contact_domain
= find_domain_from_name(name_domain
);
1098 if (contact_domain
== NULL
) {
1099 DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
1100 state
->request
->data
.auth
.user
, name_domain
, name_user
, name_domain
));
1102 contact_domain
= find_our_domain();
1106 if (contact_domain
->initialized
&&
1107 contact_domain
->active_directory
) {
1111 if (!contact_domain
->initialized
) {
1112 init_dc_connection(contact_domain
);
1115 if (!contact_domain
->active_directory
) {
1116 DEBUG(3,("krb5 auth requested but domain is not Active Directory\n"));
1117 return NT_STATUS_INVALID_LOGON_TYPE
;
1120 result
= winbindd_raw_kerberos_login(contact_domain
, state
, info3
);
1125 static NTSTATUS
winbindd_dual_auth_passdb(TALLOC_CTX
*mem_ctx
,
1126 const char *domain
, const char *user
,
1127 const DATA_BLOB
*challenge
,
1128 const DATA_BLOB
*lm_resp
,
1129 const DATA_BLOB
*nt_resp
,
1130 struct netr_SamInfo3
**pinfo3
)
1132 struct auth_usersupplied_info
*user_info
= NULL
;
1133 struct auth_serversupplied_info
*server_info
= NULL
;
1134 struct netr_SamInfo3
*info3
;
1137 status
= make_user_info(&user_info
, user
, user
, domain
, domain
,
1138 global_myname(), lm_resp
, nt_resp
, NULL
, NULL
,
1140 if (!NT_STATUS_IS_OK(status
)) {
1141 DEBUG(10, ("make_user_info failed: %s\n", nt_errstr(status
)));
1145 status
= check_sam_security(challenge
, talloc_tos(), user_info
,
1147 free_user_info(&user_info
);
1149 if (!NT_STATUS_IS_OK(status
)) {
1150 DEBUG(10, ("check_ntlm_password failed: %s\n",
1151 nt_errstr(status
)));
1155 info3
= TALLOC_ZERO_P(mem_ctx
, struct netr_SamInfo3
);
1156 if (info3
== NULL
) {
1157 return NT_STATUS_NO_MEMORY
;
1160 status
= serverinfo_to_SamInfo3(server_info
, NULL
, 0, info3
);
1161 if (!NT_STATUS_IS_OK(status
)) {
1162 DEBUG(10, ("serverinfo_to_SamInfo3 failed: %s\n",
1163 nt_errstr(status
)));
1167 DEBUG(10, ("Authenticated user %s\\%s successfully\n", domain
, user
));
1169 return NT_STATUS_OK
;
1172 typedef NTSTATUS (*netlogon_fn_t
)(struct rpc_pipe_client
*cli
,
1173 TALLOC_CTX
*mem_ctx
,
1174 uint32 logon_parameters
,
1176 const char *username
,
1178 const char *workstation
,
1179 const uint8 chal
[8],
1180 DATA_BLOB lm_response
,
1181 DATA_BLOB nt_response
,
1182 struct netr_SamInfo3
**info3
);
1184 static NTSTATUS
winbindd_dual_pam_auth_samlogon(struct winbindd_domain
*domain
,
1185 struct winbindd_cli_state
*state
,
1186 struct netr_SamInfo3
**info3
)
1189 struct rpc_pipe_client
*netlogon_pipe
;
1194 unsigned char local_lm_response
[24];
1195 unsigned char local_nt_response
[24];
1196 fstring name_domain
, name_user
;
1199 struct netr_SamInfo3
*my_info3
= NULL
;
1203 DEBUG(10,("winbindd_dual_pam_auth_samlogon\n"));
1205 /* Parse domain and username */
1207 parse_domain_user(state
->request
->data
.auth
.user
, name_domain
, name_user
);
1209 /* do password magic */
1211 generate_random_buffer(chal
, sizeof(chal
));
1213 if (lp_client_ntlmv2_auth()) {
1214 DATA_BLOB server_chal
;
1215 DATA_BLOB names_blob
;
1216 DATA_BLOB nt_response
;
1217 DATA_BLOB lm_response
;
1218 server_chal
= data_blob_talloc(state
->mem_ctx
, chal
, 8);
1220 /* note that the 'workgroup' here is a best guess - we don't know
1221 the server's domain at this point. The 'server name' is also
1224 names_blob
= NTLMv2_generate_names_blob(state
->mem_ctx
, global_myname(), lp_workgroup());
1226 if (!SMBNTLMv2encrypt(NULL
, name_user
, name_domain
,
1227 state
->request
->data
.auth
.pass
,
1230 &lm_response
, &nt_response
, NULL
, NULL
)) {
1231 data_blob_free(&names_blob
);
1232 data_blob_free(&server_chal
);
1233 DEBUG(0, ("winbindd_pam_auth: SMBNTLMv2encrypt() failed!\n"));
1234 result
= NT_STATUS_NO_MEMORY
;
1237 data_blob_free(&names_blob
);
1238 data_blob_free(&server_chal
);
1239 lm_resp
= data_blob_talloc(state
->mem_ctx
, lm_response
.data
,
1240 lm_response
.length
);
1241 nt_resp
= data_blob_talloc(state
->mem_ctx
, nt_response
.data
,
1242 nt_response
.length
);
1243 data_blob_free(&lm_response
);
1244 data_blob_free(&nt_response
);
1247 if (lp_client_lanman_auth()
1248 && SMBencrypt(state
->request
->data
.auth
.pass
,
1250 local_lm_response
)) {
1251 lm_resp
= data_blob_talloc(state
->mem_ctx
,
1253 sizeof(local_lm_response
));
1255 lm_resp
= data_blob_null
;
1257 SMBNTencrypt(state
->request
->data
.auth
.pass
,
1261 nt_resp
= data_blob_talloc(state
->mem_ctx
,
1263 sizeof(local_nt_response
));
1266 if (strequal(name_domain
, get_global_sam_name())) {
1267 DATA_BLOB chal_blob
= data_blob_const(chal
, sizeof(chal
));
1269 result
= winbindd_dual_auth_passdb(
1270 state
->mem_ctx
, name_domain
, name_user
,
1271 &chal_blob
, &lm_resp
, &nt_resp
, info3
);
1275 /* check authentication loop */
1278 netlogon_fn_t logon_fn
;
1280 ZERO_STRUCTP(my_info3
);
1283 result
= cm_connect_netlogon(domain
, &netlogon_pipe
);
1285 if (!NT_STATUS_IS_OK(result
)) {
1286 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
1290 /* It is really important to try SamLogonEx here,
1291 * because in a clustered environment, we want to use
1292 * one machine account from multiple physical
1295 * With a normal SamLogon call, we must keep the
1296 * credentials chain updated and intact between all
1297 * users of the machine account (which would imply
1298 * cross-node communication for every NTLM logon).
1300 * (The credentials chain is not per NETLOGON pipe
1301 * connection, but globally on the server/client pair
1304 * When using SamLogonEx, the credentials are not
1305 * supplied, but the session key is implied by the
1306 * wrapping SamLogon context.
1308 * -- abartlet 21 April 2008
1311 logon_fn
= domain
->can_do_samlogon_ex
1312 ? rpccli_netlogon_sam_network_logon_ex
1313 : rpccli_netlogon_sam_network_logon
;
1315 result
= logon_fn(netlogon_pipe
,
1318 domain
->dcname
, /* server name */
1319 name_user
, /* user name */
1320 name_domain
, /* target domain */
1321 global_myname(), /* workstation */
1328 if ((NT_STATUS_V(result
) == DCERPC_FAULT_OP_RNG_ERROR
)
1329 && domain
->can_do_samlogon_ex
) {
1330 DEBUG(3, ("Got a DC that can not do NetSamLogonEx, "
1331 "retrying with NetSamLogon\n"));
1332 domain
->can_do_samlogon_ex
= false;
1337 /* We have to try a second time as cm_connect_netlogon
1338 might not yet have noticed that the DC has killed
1341 if (!rpccli_is_connected(netlogon_pipe
)) {
1346 /* if we get access denied, a possible cause was that we had
1347 and open connection to the DC, but someone changed our
1348 machine account password out from underneath us using 'net
1349 rpc changetrustpw' */
1351 if ( NT_STATUS_EQUAL(result
, NT_STATUS_ACCESS_DENIED
) ) {
1352 DEBUG(3,("winbindd_pam_auth: sam_logon returned "
1353 "ACCESS_DENIED. Maybe the trust account "
1354 "password was changed and we didn't know it. "
1355 "Killing connections to domain %s\n",
1357 invalidate_cm_connection(&domain
->conn
);
1361 } while ( (attempts
< 2) && retry
);
1363 /* handle the case where a NT4 DC does not fill in the acct_flags in
1364 * the samlogon reply info3. When accurate info3 is required by the
1365 * caller, we look up the account flags ourselve - gd */
1367 if ((state
->request
->flags
& WBFLAG_PAM_INFO3_TEXT
) &&
1368 NT_STATUS_IS_OK(result
) && (my_info3
->base
.acct_flags
== 0)) {
1370 struct rpc_pipe_client
*samr_pipe
;
1371 struct policy_handle samr_domain_handle
, user_pol
;
1372 union samr_UserInfo
*info
= NULL
;
1373 NTSTATUS status_tmp
;
1376 status_tmp
= cm_connect_sam(domain
, state
->mem_ctx
,
1377 &samr_pipe
, &samr_domain_handle
);
1379 if (!NT_STATUS_IS_OK(status_tmp
)) {
1380 DEBUG(3, ("could not open handle to SAMR pipe: %s\n",
1381 nt_errstr(status_tmp
)));
1385 status_tmp
= rpccli_samr_OpenUser(samr_pipe
, state
->mem_ctx
,
1386 &samr_domain_handle
,
1387 MAXIMUM_ALLOWED_ACCESS
,
1391 if (!NT_STATUS_IS_OK(status_tmp
)) {
1392 DEBUG(3, ("could not open user handle on SAMR pipe: %s\n",
1393 nt_errstr(status_tmp
)));
1397 status_tmp
= rpccli_samr_QueryUserInfo(samr_pipe
, state
->mem_ctx
,
1402 if (!NT_STATUS_IS_OK(status_tmp
)) {
1403 DEBUG(3, ("could not query user info on SAMR pipe: %s\n",
1404 nt_errstr(status_tmp
)));
1405 rpccli_samr_Close(samr_pipe
, state
->mem_ctx
, &user_pol
);
1409 acct_flags
= info
->info16
.acct_flags
;
1411 if (acct_flags
== 0) {
1412 rpccli_samr_Close(samr_pipe
, state
->mem_ctx
, &user_pol
);
1416 my_info3
->base
.acct_flags
= acct_flags
;
1418 DEBUG(10,("successfully retrieved acct_flags 0x%x\n", acct_flags
));
1420 rpccli_samr_Close(samr_pipe
, state
->mem_ctx
, &user_pol
);
1428 enum winbindd_result
winbindd_dual_pam_auth(struct winbindd_domain
*domain
,
1429 struct winbindd_cli_state
*state
)
1431 NTSTATUS result
= NT_STATUS_LOGON_FAILURE
;
1432 NTSTATUS krb5_result
= NT_STATUS_OK
;
1433 fstring name_domain
, name_user
;
1435 fstring domain_user
;
1436 struct netr_SamInfo3
*info3
= NULL
;
1437 NTSTATUS name_map_status
= NT_STATUS_UNSUCCESSFUL
;
1439 /* Ensure null termination */
1440 state
->request
->data
.auth
.user
[sizeof(state
->request
->data
.auth
.user
)-1]='\0';
1442 /* Ensure null termination */
1443 state
->request
->data
.auth
.pass
[sizeof(state
->request
->data
.auth
.pass
)-1]='\0';
1445 DEBUG(3, ("[%5lu]: dual pam auth %s\n", (unsigned long)state
->pid
,
1446 state
->request
->data
.auth
.user
));
1448 if (!check_request_flags(state
->request
->flags
)) {
1449 result
= NT_STATUS_INVALID_PARAMETER_MIX
;
1453 /* Parse domain and username */
1455 name_map_status
= normalize_name_unmap(state
->mem_ctx
,
1456 state
->request
->data
.auth
.user
,
1459 /* If the name normalization didnt' actually do anything,
1460 just use the original name */
1462 if (!NT_STATUS_IS_OK(name_map_status
) &&
1463 !NT_STATUS_EQUAL(name_map_status
, NT_STATUS_FILE_RENAMED
))
1465 mapped_user
= state
->request
->data
.auth
.user
;
1468 parse_domain_user(mapped_user
, name_domain
, name_user
);
1470 if ( mapped_user
!= state
->request
->data
.auth
.user
) {
1471 fstr_sprintf( domain_user
, "%s\\%s", name_domain
, name_user
);
1472 safe_strcpy( state
->request
->data
.auth
.user
, domain_user
,
1473 sizeof(state
->request
->data
.auth
.user
)-1 );
1476 if (domain
->online
== false) {
1477 result
= NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
;
1478 if (domain
->startup
) {
1479 /* Logons are very important to users. If we're offline and
1480 we get a request within the first 30 seconds of startup,
1481 try very hard to find a DC and go online. */
1483 DEBUG(10,("winbindd_dual_pam_auth: domain: %s offline and auth "
1484 "request in startup mode.\n", domain
->name
));
1486 winbindd_flush_negative_conn_cache(domain
);
1487 result
= init_dc_connection(domain
);
1491 DEBUG(10,("winbindd_dual_pam_auth: domain: %s last was %s\n", domain
->name
, domain
->online
? "online":"offline"));
1493 /* Check for Kerberos authentication */
1494 if (domain
->online
&& (state
->request
->flags
& WBFLAG_PAM_KRB5
)) {
1496 result
= winbindd_dual_pam_auth_kerberos(domain
, state
, &info3
);
1497 /* save for later */
1498 krb5_result
= result
;
1501 if (NT_STATUS_IS_OK(result
)) {
1502 DEBUG(10,("winbindd_dual_pam_auth_kerberos succeeded\n"));
1503 goto process_result
;
1505 DEBUG(10,("winbindd_dual_pam_auth_kerberos failed: %s\n", nt_errstr(result
)));
1508 if (NT_STATUS_EQUAL(result
, NT_STATUS_NO_LOGON_SERVERS
) ||
1509 NT_STATUS_EQUAL(result
, NT_STATUS_IO_TIMEOUT
) ||
1510 NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1511 DEBUG(10,("winbindd_dual_pam_auth_kerberos setting domain to offline\n"));
1512 set_domain_offline( domain
);
1516 /* there are quite some NT_STATUS errors where there is no
1517 * point in retrying with a samlogon, we explictly have to take
1518 * care not to increase the bad logon counter on the DC */
1520 if (NT_STATUS_EQUAL(result
, NT_STATUS_ACCOUNT_DISABLED
) ||
1521 NT_STATUS_EQUAL(result
, NT_STATUS_ACCOUNT_EXPIRED
) ||
1522 NT_STATUS_EQUAL(result
, NT_STATUS_ACCOUNT_LOCKED_OUT
) ||
1523 NT_STATUS_EQUAL(result
, NT_STATUS_INVALID_LOGON_HOURS
) ||
1524 NT_STATUS_EQUAL(result
, NT_STATUS_INVALID_WORKSTATION
) ||
1525 NT_STATUS_EQUAL(result
, NT_STATUS_LOGON_FAILURE
) ||
1526 NT_STATUS_EQUAL(result
, NT_STATUS_NO_SUCH_USER
) ||
1527 NT_STATUS_EQUAL(result
, NT_STATUS_PASSWORD_EXPIRED
) ||
1528 NT_STATUS_EQUAL(result
, NT_STATUS_PASSWORD_MUST_CHANGE
) ||
1529 NT_STATUS_EQUAL(result
, NT_STATUS_WRONG_PASSWORD
)) {
1533 if (state
->request
->flags
& WBFLAG_PAM_FALLBACK_AFTER_KRB5
) {
1534 DEBUG(3,("falling back to samlogon\n"));
1542 /* Check for Samlogon authentication */
1543 if (domain
->online
) {
1544 result
= winbindd_dual_pam_auth_samlogon(domain
, state
, &info3
);
1546 if (NT_STATUS_IS_OK(result
)) {
1547 DEBUG(10,("winbindd_dual_pam_auth_samlogon succeeded\n"));
1548 /* add the Krb5 err if we have one */
1549 if ( NT_STATUS_EQUAL(krb5_result
, NT_STATUS_TIME_DIFFERENCE_AT_DC
) ) {
1550 info3
->base
.user_flags
|= LOGON_KRB5_FAIL_CLOCK_SKEW
;
1552 goto process_result
;
1555 DEBUG(10,("winbindd_dual_pam_auth_samlogon failed: %s\n",
1556 nt_errstr(result
)));
1558 if (NT_STATUS_EQUAL(result
, NT_STATUS_NO_LOGON_SERVERS
) ||
1559 NT_STATUS_EQUAL(result
, NT_STATUS_IO_TIMEOUT
) ||
1560 NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
))
1562 DEBUG(10,("winbindd_dual_pam_auth_samlogon setting domain to offline\n"));
1563 set_domain_offline( domain
);
1567 if (domain
->online
) {
1568 /* We're still online - fail. */
1574 /* Check for Cached logons */
1575 if (!domain
->online
&& (state
->request
->flags
& WBFLAG_PAM_CACHED_LOGIN
) &&
1576 lp_winbind_offline_logon()) {
1578 result
= winbindd_dual_pam_auth_cached(domain
, state
, &info3
);
1580 if (NT_STATUS_IS_OK(result
)) {
1581 DEBUG(10,("winbindd_dual_pam_auth_cached succeeded\n"));
1582 goto process_result
;
1584 DEBUG(10,("winbindd_dual_pam_auth_cached failed: %s\n", nt_errstr(result
)));
1591 if (NT_STATUS_IS_OK(result
)) {
1595 /* In all codepaths where result == NT_STATUS_OK info3 must have
1596 been initialized. */
1598 result
= NT_STATUS_INTERNAL_ERROR
;
1602 wcache_invalidate_samlogon(find_domain_from_name(name_domain
), info3
);
1603 netsamlogon_cache_store(name_user
, info3
);
1605 /* save name_to_sid info as early as possible (only if
1606 this is our primary domain so we don't invalidate
1607 the cache entry by storing the seq_num for the wrong
1609 if ( domain
->primary
) {
1610 sid_compose(&user_sid
, info3
->base
.domain_sid
,
1612 cache_name2sid(domain
, name_domain
, name_user
,
1613 SID_NAME_USER
, &user_sid
);
1616 /* Check if the user is in the right group */
1618 result
= check_info3_in_group(
1620 state
->request
->data
.auth
.require_membership_of_sid
);
1621 if (!NT_STATUS_IS_OK(result
)) {
1622 DEBUG(3, ("User %s is not in the required group (%s), so plaintext authentication is rejected\n",
1623 state
->request
->data
.auth
.user
,
1624 state
->request
->data
.auth
.require_membership_of_sid
));
1628 result
= append_auth_data(state
, info3
, name_domain
,
1630 if (!NT_STATUS_IS_OK(result
)) {
1634 if ((state
->request
->flags
& WBFLAG_PAM_CACHED_LOGIN
)) {
1636 if (lp_winbind_offline_logon()) {
1637 result
= winbindd_store_creds(domain
,
1639 state
->request
->data
.auth
.user
,
1640 state
->request
->data
.auth
.pass
,
1646 if (state
->request
->flags
& WBFLAG_PAM_GET_PWD_POLICY
) {
1647 struct winbindd_domain
*our_domain
= find_our_domain();
1649 /* This is not entirely correct I believe, but it is
1650 consistent. Only apply the password policy settings
1651 too warn users for our own domain. Cannot obtain these
1652 from trusted DCs all the time so don't do it at all.
1655 result
= NT_STATUS_NOT_SUPPORTED
;
1656 if (our_domain
== domain
) {
1657 result
= fillup_password_policy(our_domain
, state
);
1660 if (!NT_STATUS_IS_OK(result
)
1661 && !NT_STATUS_EQUAL(result
, NT_STATUS_NOT_SUPPORTED
) )
1663 DEBUG(10,("Failed to get password policies for domain %s: %s\n",
1664 domain
->name
, nt_errstr(result
)));
1669 result
= NT_STATUS_OK
;
1673 /* give us a more useful (more correct?) error code */
1674 if ((NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ||
1675 (NT_STATUS_EQUAL(result
, NT_STATUS_UNSUCCESSFUL
)))) {
1676 result
= NT_STATUS_NO_LOGON_SERVERS
;
1679 set_auth_errors(state
->response
, result
);
1681 DEBUG(NT_STATUS_IS_OK(result
) ? 5 : 2, ("Plain-text authentication for user %s returned %s (PAM: %d)\n",
1682 state
->request
->data
.auth
.user
,
1683 state
->response
->data
.auth
.nt_status_string
,
1684 state
->response
->data
.auth
.pam_error
));
1686 return NT_STATUS_IS_OK(result
) ? WINBINDD_OK
: WINBINDD_ERROR
;
1689 enum winbindd_result
winbindd_dual_pam_auth_crap(struct winbindd_domain
*domain
,
1690 struct winbindd_cli_state
*state
)
1693 struct netr_SamInfo3
*info3
= NULL
;
1694 struct rpc_pipe_client
*netlogon_pipe
;
1695 const char *name_user
= NULL
;
1696 const char *name_domain
= NULL
;
1697 const char *workstation
;
1701 DATA_BLOB lm_resp
, nt_resp
;
1703 /* This is child-only, so no check for privileged access is needed
1706 /* Ensure null termination */
1707 state
->request
->data
.auth_crap
.user
[sizeof(state
->request
->data
.auth_crap
.user
)-1]=0;
1708 state
->request
->data
.auth_crap
.domain
[sizeof(state
->request
->data
.auth_crap
.domain
)-1]=0;
1710 if (!check_request_flags(state
->request
->flags
)) {
1711 result
= NT_STATUS_INVALID_PARAMETER_MIX
;
1715 name_user
= state
->request
->data
.auth_crap
.user
;
1717 if (*state
->request
->data
.auth_crap
.domain
) {
1718 name_domain
= state
->request
->data
.auth_crap
.domain
;
1719 } else if (lp_winbind_use_default_domain()) {
1720 name_domain
= lp_workgroup();
1722 DEBUG(5,("no domain specified with username (%s) - failing auth\n",
1724 result
= NT_STATUS_NO_SUCH_USER
;
1728 DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n", (unsigned long)state
->pid
,
1729 name_domain
, name_user
));
1731 if (*state
->request
->data
.auth_crap
.workstation
) {
1732 workstation
= state
->request
->data
.auth_crap
.workstation
;
1734 workstation
= global_myname();
1737 if (state
->request
->data
.auth_crap
.lm_resp_len
> sizeof(state
->request
->data
.auth_crap
.lm_resp
)
1738 || state
->request
->data
.auth_crap
.nt_resp_len
> sizeof(state
->request
->data
.auth_crap
.nt_resp
)) {
1739 if (!(state
->request
->flags
& WBFLAG_BIG_NTLMV2_BLOB
) ||
1740 state
->request
->extra_len
!= state
->request
->data
.auth_crap
.nt_resp_len
) {
1741 DEBUG(0, ("winbindd_pam_auth_crap: invalid password length %u/%u\n",
1742 state
->request
->data
.auth_crap
.lm_resp_len
,
1743 state
->request
->data
.auth_crap
.nt_resp_len
));
1744 result
= NT_STATUS_INVALID_PARAMETER
;
1749 lm_resp
= data_blob_talloc(state
->mem_ctx
, state
->request
->data
.auth_crap
.lm_resp
,
1750 state
->request
->data
.auth_crap
.lm_resp_len
);
1752 if (state
->request
->flags
& WBFLAG_BIG_NTLMV2_BLOB
) {
1753 nt_resp
= data_blob_talloc(state
->mem_ctx
,
1754 state
->request
->extra_data
.data
,
1755 state
->request
->data
.auth_crap
.nt_resp_len
);
1757 nt_resp
= data_blob_talloc(state
->mem_ctx
,
1758 state
->request
->data
.auth_crap
.nt_resp
,
1759 state
->request
->data
.auth_crap
.nt_resp_len
);
1762 if (strequal(name_domain
, get_global_sam_name())) {
1763 DATA_BLOB chal_blob
= data_blob_const(
1764 state
->request
->data
.auth_crap
.chal
,
1765 sizeof(state
->request
->data
.auth_crap
.chal
));
1767 result
= winbindd_dual_auth_passdb(
1768 state
->mem_ctx
, name_domain
, name_user
,
1769 &chal_blob
, &lm_resp
, &nt_resp
, &info3
);
1770 goto process_result
;
1774 netlogon_fn_t logon_fn
;
1778 netlogon_pipe
= NULL
;
1779 result
= cm_connect_netlogon(domain
, &netlogon_pipe
);
1781 if (!NT_STATUS_IS_OK(result
)) {
1782 DEBUG(3, ("could not open handle to NETLOGON pipe (error: %s)\n",
1783 nt_errstr(result
)));
1787 logon_fn
= domain
->can_do_samlogon_ex
1788 ? rpccli_netlogon_sam_network_logon_ex
1789 : rpccli_netlogon_sam_network_logon
;
1791 result
= logon_fn(netlogon_pipe
,
1793 state
->request
->data
.auth_crap
.logon_parameters
,
1797 /* Bug #3248 - found by Stefan Burkei. */
1798 workstation
, /* We carefully set this above so use it... */
1799 state
->request
->data
.auth_crap
.chal
,
1804 if ((NT_STATUS_V(result
) == DCERPC_FAULT_OP_RNG_ERROR
)
1805 && domain
->can_do_samlogon_ex
) {
1806 DEBUG(3, ("Got a DC that can not do NetSamLogonEx, "
1807 "retrying with NetSamLogon\n"));
1808 domain
->can_do_samlogon_ex
= false;
1815 /* We have to try a second time as cm_connect_netlogon
1816 might not yet have noticed that the DC has killed
1819 if (!rpccli_is_connected(netlogon_pipe
)) {
1824 /* if we get access denied, a possible cause was that we had and open
1825 connection to the DC, but someone changed our machine account password
1826 out from underneath us using 'net rpc changetrustpw' */
1828 if ( NT_STATUS_EQUAL(result
, NT_STATUS_ACCESS_DENIED
) ) {
1829 DEBUG(3,("winbindd_pam_auth: sam_logon returned "
1830 "ACCESS_DENIED. Maybe the trust account "
1831 "password was changed and we didn't know it. "
1832 "Killing connections to domain %s\n",
1834 invalidate_cm_connection(&domain
->conn
);
1838 } while ( (attempts
< 2) && retry
);
1842 if (NT_STATUS_IS_OK(result
)) {
1844 wcache_invalidate_samlogon(find_domain_from_name(name_domain
), info3
);
1845 netsamlogon_cache_store(name_user
, info3
);
1847 /* Check if the user is in the right group */
1849 result
= check_info3_in_group(
1851 state
->request
->data
.auth_crap
.require_membership_of_sid
);
1852 if (!NT_STATUS_IS_OK(result
)) {
1853 DEBUG(3, ("User %s is not in the required group (%s), so "
1854 "crap authentication is rejected\n",
1855 state
->request
->data
.auth_crap
.user
,
1856 state
->request
->data
.auth_crap
.require_membership_of_sid
));
1860 result
= append_auth_data(state
, info3
, name_domain
,
1862 if (!NT_STATUS_IS_OK(result
)) {
1869 /* give us a more useful (more correct?) error code */
1870 if ((NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ||
1871 (NT_STATUS_EQUAL(result
, NT_STATUS_UNSUCCESSFUL
)))) {
1872 result
= NT_STATUS_NO_LOGON_SERVERS
;
1875 if (state
->request
->flags
& WBFLAG_PAM_NT_STATUS_SQUASH
) {
1876 result
= nt_status_squash(result
);
1879 set_auth_errors(state
->response
, result
);
1881 DEBUG(NT_STATUS_IS_OK(result
) ? 5 : 2,
1882 ("NTLM CRAP authentication for user [%s]\\[%s] returned %s (PAM: %d)\n",
1885 state
->response
->data
.auth
.nt_status_string
,
1886 state
->response
->data
.auth
.pam_error
));
1888 return NT_STATUS_IS_OK(result
) ? WINBINDD_OK
: WINBINDD_ERROR
;
1891 enum winbindd_result
winbindd_dual_pam_chauthtok(struct winbindd_domain
*contact_domain
,
1892 struct winbindd_cli_state
*state
)
1895 char *newpass
= NULL
;
1896 struct policy_handle dom_pol
;
1897 struct rpc_pipe_client
*cli
;
1898 bool got_info
= false;
1899 struct samr_DomInfo1
*info
= NULL
;
1900 struct userPwdChangeFailureInformation
*reject
= NULL
;
1901 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
1902 fstring domain
, user
;
1904 DEBUG(3, ("[%5lu]: dual pam chauthtok %s\n", (unsigned long)state
->pid
,
1905 state
->request
->data
.auth
.user
));
1907 if (!parse_domain_user(state
->request
->data
.chauthtok
.user
, domain
, user
)) {
1911 /* Change password */
1913 oldpass
= state
->request
->data
.chauthtok
.oldpass
;
1914 newpass
= state
->request
->data
.chauthtok
.newpass
;
1916 /* Initialize reject reason */
1917 state
->response
->data
.auth
.reject_reason
= Undefined
;
1919 if (strequal(domain
, get_global_sam_name())) {
1920 struct samr_CryptPassword new_nt_password
;
1921 struct samr_CryptPassword new_lm_password
;
1922 struct samr_Password old_nt_hash_enc
;
1923 struct samr_Password old_lanman_hash_enc
;
1924 enum samPwdChangeReason rejectReason
;
1926 uchar old_nt_hash
[16];
1927 uchar old_lanman_hash
[16];
1928 uchar new_nt_hash
[16];
1929 uchar new_lanman_hash
[16];
1931 contact_domain
= NULL
;
1933 E_md4hash(oldpass
, old_nt_hash
);
1934 E_md4hash(newpass
, new_nt_hash
);
1936 if (lp_client_lanman_auth() &&
1937 E_deshash(newpass
, new_lanman_hash
) &&
1938 E_deshash(oldpass
, old_lanman_hash
)) {
1940 /* E_deshash returns false for 'long' passwords (> 14
1941 DOS chars). This allows us to match Win2k, which
1942 does not store a LM hash for these passwords (which
1943 would reduce the effective password length to 14) */
1945 encode_pw_buffer(new_lm_password
.data
, newpass
, STR_UNICODE
);
1946 arcfour_crypt(new_lm_password
.data
, old_nt_hash
, 516);
1947 E_old_pw_hash(new_nt_hash
, old_lanman_hash
, old_lanman_hash_enc
.hash
);
1949 ZERO_STRUCT(new_lm_password
);
1950 ZERO_STRUCT(old_lanman_hash_enc
);
1953 encode_pw_buffer(new_nt_password
.data
, newpass
, STR_UNICODE
);
1955 arcfour_crypt(new_nt_password
.data
, old_nt_hash
, 516);
1956 E_old_pw_hash(new_nt_hash
, old_nt_hash
, old_nt_hash_enc
.hash
);
1958 result
= pass_oem_change(
1960 new_lm_password
.data
, old_lanman_hash_enc
.hash
,
1961 new_nt_password
.data
, old_nt_hash_enc
.hash
,
1966 /* Get sam handle */
1968 result
= cm_connect_sam(contact_domain
, state
->mem_ctx
, &cli
,
1970 if (!NT_STATUS_IS_OK(result
)) {
1971 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain
));
1975 result
= rpccli_samr_chgpasswd_user3(cli
, state
->mem_ctx
,
1982 /* Windows 2003 returns NT_STATUS_PASSWORD_RESTRICTION */
1984 if (NT_STATUS_EQUAL(result
, NT_STATUS_PASSWORD_RESTRICTION
) ) {
1986 fill_in_password_policy(state
->response
, info
);
1988 state
->response
->data
.auth
.reject_reason
=
1989 reject
->extendedFailureReason
;
1994 /* atm the pidl generated rpccli_samr_ChangePasswordUser3 function will
1995 * return with NT_STATUS_BUFFER_TOO_SMALL for w2k dcs as w2k just
1996 * returns with 4byte error code (NT_STATUS_NOT_SUPPORTED) which is too
1997 * short to comply with the samr_ChangePasswordUser3 idl - gd */
1999 /* only fallback when the chgpasswd_user3 call is not supported */
2000 if ((NT_STATUS_EQUAL(result
, NT_STATUS(DCERPC_FAULT_OP_RNG_ERROR
))) ||
2001 (NT_STATUS_EQUAL(result
, NT_STATUS_NOT_SUPPORTED
)) ||
2002 (NT_STATUS_EQUAL(result
, NT_STATUS_BUFFER_TOO_SMALL
)) ||
2003 (NT_STATUS_EQUAL(result
, NT_STATUS_NOT_IMPLEMENTED
))) {
2005 DEBUG(10,("Password change with chgpasswd_user3 failed with: %s, retrying chgpasswd_user2\n",
2006 nt_errstr(result
)));
2008 result
= rpccli_samr_chgpasswd_user2(cli
, state
->mem_ctx
, user
, newpass
, oldpass
);
2010 /* Windows 2000 returns NT_STATUS_ACCOUNT_RESTRICTION.
2011 Map to the same status code as Windows 2003. */
2013 if ( NT_STATUS_EQUAL(NT_STATUS_ACCOUNT_RESTRICTION
, result
) ) {
2014 result
= NT_STATUS_PASSWORD_RESTRICTION
;
2020 if (NT_STATUS_IS_OK(result
) && (state
->request
->flags
& WBFLAG_PAM_CACHED_LOGIN
)) {
2021 if (lp_winbind_offline_logon()) {
2022 result
= winbindd_update_creds_by_name(contact_domain
,
2023 state
->mem_ctx
, user
,
2025 /* Again, this happens when we login from gdm or xdm
2026 * and the password expires, *BUT* cached crendentials
2027 * doesn't exist. winbindd_update_creds_by_name()
2028 * returns NT_STATUS_NO_SUCH_USER.
2029 * This is not a failure.
2032 if (NT_STATUS_EQUAL(result
, NT_STATUS_NO_SUCH_USER
)) {
2033 result
= NT_STATUS_OK
;
2036 if (!NT_STATUS_IS_OK(result
)) {
2037 DEBUG(10,("Failed to store creds: %s\n", nt_errstr(result
)));
2038 goto process_result
;
2043 if (!NT_STATUS_IS_OK(result
) && !got_info
&& contact_domain
) {
2045 NTSTATUS policy_ret
;
2047 policy_ret
= fillup_password_policy(contact_domain
, state
);
2049 /* failure of this is non critical, it will just provide no
2050 * additional information to the client why the change has
2051 * failed - Guenther */
2053 if (!NT_STATUS_IS_OK(policy_ret
)) {
2054 DEBUG(10,("Failed to get password policies: %s\n", nt_errstr(policy_ret
)));
2055 goto process_result
;
2061 set_auth_errors(state
->response
, result
);
2063 DEBUG(NT_STATUS_IS_OK(result
) ? 5 : 2,
2064 ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
2067 state
->response
->data
.auth
.nt_status_string
,
2068 state
->response
->data
.auth
.pam_error
));
2070 return NT_STATUS_IS_OK(result
) ? WINBINDD_OK
: WINBINDD_ERROR
;
2073 enum winbindd_result
winbindd_dual_pam_logoff(struct winbindd_domain
*domain
,
2074 struct winbindd_cli_state
*state
)
2076 NTSTATUS result
= NT_STATUS_NOT_SUPPORTED
;
2078 DEBUG(3, ("[%5lu]: pam dual logoff %s\n", (unsigned long)state
->pid
,
2079 state
->request
->data
.logoff
.user
));
2081 if (!(state
->request
->flags
& WBFLAG_PAM_KRB5
)) {
2082 result
= NT_STATUS_OK
;
2083 goto process_result
;
2086 if (state
->request
->data
.logoff
.krb5ccname
[0] == '\0') {
2087 result
= NT_STATUS_OK
;
2088 goto process_result
;
2093 if (state
->request
->data
.logoff
.uid
< 0) {
2094 DEBUG(0,("winbindd_pam_logoff: invalid uid\n"));
2095 goto process_result
;
2098 /* what we need here is to find the corresponding krb5 ccache name *we*
2099 * created for a given username and destroy it */
2101 if (!ccache_entry_exists(state
->request
->data
.logoff
.user
)) {
2102 result
= NT_STATUS_OK
;
2103 DEBUG(10,("winbindd_pam_logoff: no entry found.\n"));
2104 goto process_result
;
2107 if (!ccache_entry_identical(state
->request
->data
.logoff
.user
,
2108 state
->request
->data
.logoff
.uid
,
2109 state
->request
->data
.logoff
.krb5ccname
)) {
2110 DEBUG(0,("winbindd_pam_logoff: cached entry differs.\n"));
2111 goto process_result
;
2114 result
= remove_ccache(state
->request
->data
.logoff
.user
);
2115 if (!NT_STATUS_IS_OK(result
)) {
2116 DEBUG(0,("winbindd_pam_logoff: failed to remove ccache: %s\n",
2117 nt_errstr(result
)));
2118 goto process_result
;
2122 result
= NT_STATUS_NOT_SUPPORTED
;
2128 set_auth_errors(state
->response
, result
);
2130 return NT_STATUS_IS_OK(result
) ? WINBINDD_OK
: WINBINDD_ERROR
;
2133 /* Change user password with auth crap*/
2135 enum winbindd_result
winbindd_dual_pam_chng_pswd_auth_crap(struct winbindd_domain
*domainSt
, struct winbindd_cli_state
*state
)
2138 DATA_BLOB new_nt_password
;
2139 DATA_BLOB old_nt_hash_enc
;
2140 DATA_BLOB new_lm_password
;
2141 DATA_BLOB old_lm_hash_enc
;
2142 fstring domain
,user
;
2143 struct policy_handle dom_pol
;
2144 struct winbindd_domain
*contact_domain
= domainSt
;
2145 struct rpc_pipe_client
*cli
;
2147 /* Ensure null termination */
2148 state
->request
->data
.chng_pswd_auth_crap
.user
[
2149 sizeof(state
->request
->data
.chng_pswd_auth_crap
.user
)-1]=0;
2150 state
->request
->data
.chng_pswd_auth_crap
.domain
[
2151 sizeof(state
->request
->data
.chng_pswd_auth_crap
.domain
)-1]=0;
2155 DEBUG(3, ("[%5lu]: pam change pswd auth crap domain: %s user: %s\n",
2156 (unsigned long)state
->pid
,
2157 state
->request
->data
.chng_pswd_auth_crap
.domain
,
2158 state
->request
->data
.chng_pswd_auth_crap
.user
));
2160 if (lp_winbind_offline_logon()) {
2161 DEBUG(0,("Refusing password change as winbind offline logons are enabled. "));
2162 DEBUGADD(0,("Changing passwords here would risk inconsistent logons\n"));
2163 result
= NT_STATUS_ACCESS_DENIED
;
2167 if (*state
->request
->data
.chng_pswd_auth_crap
.domain
) {
2168 fstrcpy(domain
,state
->request
->data
.chng_pswd_auth_crap
.domain
);
2170 parse_domain_user(state
->request
->data
.chng_pswd_auth_crap
.user
,
2174 DEBUG(3,("no domain specified with username (%s) - "
2176 state
->request
->data
.chng_pswd_auth_crap
.user
));
2177 result
= NT_STATUS_NO_SUCH_USER
;
2182 if (!*domain
&& lp_winbind_use_default_domain()) {
2183 fstrcpy(domain
,(char *)lp_workgroup());
2187 fstrcpy(user
, state
->request
->data
.chng_pswd_auth_crap
.user
);
2190 DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n",
2191 (unsigned long)state
->pid
, domain
, user
));
2193 if (strequal(domain
, get_global_sam_name())) {
2194 enum samPwdChangeReason reject_reason
;
2196 result
= pass_oem_change(
2198 state
->request
->data
.chng_pswd_auth_crap
.new_lm_pswd
,
2199 state
->request
->data
.chng_pswd_auth_crap
.old_lm_hash_enc
,
2200 state
->request
->data
.chng_pswd_auth_crap
.new_nt_pswd
,
2201 state
->request
->data
.chng_pswd_auth_crap
.old_nt_hash_enc
,
2203 DEBUG(10, ("pass_oem_change returned %s\n",
2204 nt_errstr(result
)));
2208 /* Change password */
2209 new_nt_password
= data_blob_const(
2210 state
->request
->data
.chng_pswd_auth_crap
.new_nt_pswd
,
2211 state
->request
->data
.chng_pswd_auth_crap
.new_nt_pswd_len
);
2213 old_nt_hash_enc
= data_blob_const(
2214 state
->request
->data
.chng_pswd_auth_crap
.old_nt_hash_enc
,
2215 state
->request
->data
.chng_pswd_auth_crap
.old_nt_hash_enc_len
);
2217 if(state
->request
->data
.chng_pswd_auth_crap
.new_lm_pswd_len
> 0) {
2218 new_lm_password
= data_blob_const(
2219 state
->request
->data
.chng_pswd_auth_crap
.new_lm_pswd
,
2220 state
->request
->data
.chng_pswd_auth_crap
.new_lm_pswd_len
);
2222 old_lm_hash_enc
= data_blob_const(
2223 state
->request
->data
.chng_pswd_auth_crap
.old_lm_hash_enc
,
2224 state
->request
->data
.chng_pswd_auth_crap
.old_lm_hash_enc_len
);
2226 new_lm_password
.length
= 0;
2227 old_lm_hash_enc
.length
= 0;
2230 /* Get sam handle */
2232 result
= cm_connect_sam(contact_domain
, state
->mem_ctx
, &cli
, &dom_pol
);
2233 if (!NT_STATUS_IS_OK(result
)) {
2234 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain
));
2238 result
= rpccli_samr_chng_pswd_auth_crap(
2239 cli
, state
->mem_ctx
, user
, new_nt_password
, old_nt_hash_enc
,
2240 new_lm_password
, old_lm_hash_enc
);
2244 set_auth_errors(state
->response
, result
);
2246 DEBUG(NT_STATUS_IS_OK(result
) ? 5 : 2,
2247 ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
2249 state
->response
->data
.auth
.nt_status_string
,
2250 state
->response
->data
.auth
.pam_error
));
2252 return NT_STATUS_IS_OK(result
) ? WINBINDD_OK
: WINBINDD_ERROR
;