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"
32 #define DBGC_CLASS DBGC_WINBIND
34 #define LOGON_KRB5_FAIL_CLOCK_SKEW 0x02000000
36 static NTSTATUS
append_info3_as_txt(TALLOC_CTX
*mem_ctx
,
37 struct winbindd_cli_state
*state
,
38 struct netr_SamInfo3
*info3
)
43 state
->response
->data
.auth
.info3
.logon_time
=
44 nt_time_to_unix(info3
->base
.last_logon
);
45 state
->response
->data
.auth
.info3
.logoff_time
=
46 nt_time_to_unix(info3
->base
.last_logoff
);
47 state
->response
->data
.auth
.info3
.kickoff_time
=
48 nt_time_to_unix(info3
->base
.acct_expiry
);
49 state
->response
->data
.auth
.info3
.pass_last_set_time
=
50 nt_time_to_unix(info3
->base
.last_password_change
);
51 state
->response
->data
.auth
.info3
.pass_can_change_time
=
52 nt_time_to_unix(info3
->base
.allow_password_change
);
53 state
->response
->data
.auth
.info3
.pass_must_change_time
=
54 nt_time_to_unix(info3
->base
.force_password_change
);
56 state
->response
->data
.auth
.info3
.logon_count
= info3
->base
.logon_count
;
57 state
->response
->data
.auth
.info3
.bad_pw_count
= info3
->base
.bad_password_count
;
59 state
->response
->data
.auth
.info3
.user_rid
= info3
->base
.rid
;
60 state
->response
->data
.auth
.info3
.group_rid
= info3
->base
.primary_gid
;
61 sid_to_fstring(state
->response
->data
.auth
.info3
.dom_sid
, info3
->base
.domain_sid
);
63 state
->response
->data
.auth
.info3
.num_groups
= info3
->base
.groups
.count
;
64 state
->response
->data
.auth
.info3
.user_flgs
= info3
->base
.user_flags
;
66 state
->response
->data
.auth
.info3
.acct_flags
= info3
->base
.acct_flags
;
67 state
->response
->data
.auth
.info3
.num_other_sids
= info3
->sidcount
;
69 fstrcpy(state
->response
->data
.auth
.info3
.user_name
,
70 info3
->base
.account_name
.string
);
71 fstrcpy(state
->response
->data
.auth
.info3
.full_name
,
72 info3
->base
.full_name
.string
);
73 fstrcpy(state
->response
->data
.auth
.info3
.logon_script
,
74 info3
->base
.logon_script
.string
);
75 fstrcpy(state
->response
->data
.auth
.info3
.profile_path
,
76 info3
->base
.profile_path
.string
);
77 fstrcpy(state
->response
->data
.auth
.info3
.home_dir
,
78 info3
->base
.home_directory
.string
);
79 fstrcpy(state
->response
->data
.auth
.info3
.dir_drive
,
80 info3
->base
.home_drive
.string
);
82 fstrcpy(state
->response
->data
.auth
.info3
.logon_srv
,
83 info3
->base
.logon_server
.string
);
84 fstrcpy(state
->response
->data
.auth
.info3
.logon_dom
,
85 info3
->base
.domain
.string
);
87 ex
= talloc_strdup(state
->mem_ctx
, "");
88 NT_STATUS_HAVE_NO_MEMORY(ex
);
90 for (i
=0; i
< info3
->base
.groups
.count
; i
++) {
91 ex
= talloc_asprintf_append_buffer(ex
, "0x%08X:0x%08X\n",
92 info3
->base
.groups
.rids
[i
].rid
,
93 info3
->base
.groups
.rids
[i
].attributes
);
94 NT_STATUS_HAVE_NO_MEMORY(ex
);
97 for (i
=0; i
< info3
->sidcount
; i
++) {
100 sid
= dom_sid_string(mem_ctx
, info3
->sids
[i
].sid
);
101 NT_STATUS_HAVE_NO_MEMORY(sid
);
103 ex
= talloc_asprintf_append_buffer(ex
, "%s:0x%08X\n",
105 info3
->sids
[i
].attributes
);
106 NT_STATUS_HAVE_NO_MEMORY(ex
);
111 state
->response
->extra_data
.data
= ex
;
112 state
->response
->length
+= talloc_get_size(ex
);
117 static NTSTATUS
append_info3_as_ndr(TALLOC_CTX
*mem_ctx
,
118 struct winbindd_cli_state
*state
,
119 struct netr_SamInfo3
*info3
)
122 enum ndr_err_code ndr_err
;
124 ndr_err
= ndr_push_struct_blob(&blob
, mem_ctx
, NULL
, info3
,
125 (ndr_push_flags_fn_t
)ndr_push_netr_SamInfo3
);
126 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
127 DEBUG(0,("append_info3_as_ndr: failed to append\n"));
128 return ndr_map_error2ntstatus(ndr_err
);
131 state
->response
->extra_data
.data
= blob
.data
;
132 state
->response
->length
+= blob
.length
;
137 static NTSTATUS
append_unix_username(TALLOC_CTX
*mem_ctx
,
138 struct winbindd_cli_state
*state
,
139 const struct netr_SamInfo3
*info3
,
140 const char *name_domain
,
141 const char *name_user
)
143 /* We've been asked to return the unix username, per
144 'winbind use default domain' settings and the like */
146 const char *nt_username
, *nt_domain
;
148 nt_domain
= talloc_strdup(mem_ctx
, info3
->base
.domain
.string
);
150 /* If the server didn't give us one, just use the one
152 nt_domain
= name_domain
;
155 nt_username
= talloc_strdup(mem_ctx
, info3
->base
.account_name
.string
);
157 /* If the server didn't give us one, just use the one
159 nt_username
= name_user
;
162 fill_domain_username(state
->response
->data
.auth
.unix_username
,
163 nt_domain
, nt_username
, true);
165 DEBUG(5,("Setting unix username to [%s]\n",
166 state
->response
->data
.auth
.unix_username
));
171 static NTSTATUS
append_afs_token(TALLOC_CTX
*mem_ctx
,
172 struct winbindd_cli_state
*state
,
173 const struct netr_SamInfo3
*info3
,
174 const char *name_domain
,
175 const char *name_user
)
177 char *afsname
= NULL
;
181 afsname
= talloc_strdup(mem_ctx
, lp_afs_username_map());
182 if (afsname
== NULL
) {
183 return NT_STATUS_NO_MEMORY
;
186 afsname
= talloc_string_sub(mem_ctx
,
187 lp_afs_username_map(),
189 afsname
= talloc_string_sub(mem_ctx
, afsname
,
191 afsname
= talloc_string_sub(mem_ctx
, afsname
,
198 sid_compose(&user_sid
, info3
->base
.domain_sid
,
200 sid_to_fstring(sidstr
, &user_sid
);
201 afsname
= talloc_string_sub(mem_ctx
, afsname
,
205 if (afsname
== NULL
) {
206 return NT_STATUS_NO_MEMORY
;
211 DEBUG(10, ("Generating token for user %s\n", afsname
));
213 cell
= strchr(afsname
, '@');
216 return NT_STATUS_NO_MEMORY
;
222 token
= afs_createtoken_str(afsname
, cell
);
226 state
->response
->extra_data
.data
= talloc_strdup(state
->mem_ctx
,
228 if (state
->response
->extra_data
.data
== NULL
) {
229 return NT_STATUS_NO_MEMORY
;
231 state
->response
->length
+=
232 strlen((const char *)state
->response
->extra_data
.data
)+1;
237 static NTSTATUS
check_info3_in_group(struct netr_SamInfo3
*info3
,
238 const char *group_sid
)
240 * Check whether a user belongs to a group or list of groups.
242 * @param mem_ctx talloc memory context.
243 * @param info3 user information, including group membership info.
244 * @param group_sid One or more groups , separated by commas.
246 * @return NT_STATUS_OK on success,
247 * NT_STATUS_LOGON_FAILURE if the user does not belong,
248 * or other NT_STATUS_IS_ERR(status) for other kinds of failure.
251 DOM_SID
*require_membership_of_sid
;
252 size_t num_require_membership_of_sid
;
257 struct nt_user_token
*token
;
258 TALLOC_CTX
*frame
= talloc_stackframe();
261 /* Parse the 'required group' SID */
263 if (!group_sid
|| !group_sid
[0]) {
264 /* NO sid supplied, all users may access */
268 token
= talloc_zero(talloc_tos(), struct nt_user_token
);
270 DEBUG(0, ("talloc failed\n"));
272 return NT_STATUS_NO_MEMORY
;
275 num_require_membership_of_sid
= 0;
276 require_membership_of_sid
= NULL
;
280 while (next_token_talloc(talloc_tos(), &p
, &req_sid
, ",")) {
281 if (!string_to_sid(&sid
, req_sid
)) {
282 DEBUG(0, ("check_info3_in_group: could not parse %s "
283 "as a SID!", req_sid
));
285 return NT_STATUS_INVALID_PARAMETER
;
288 status
= add_sid_to_array(talloc_tos(), &sid
,
289 &require_membership_of_sid
,
290 &num_require_membership_of_sid
);
291 if (!NT_STATUS_IS_OK(status
)) {
292 DEBUG(0, ("add_sid_to_array failed\n"));
298 status
= sid_array_from_info3(talloc_tos(), info3
,
302 if (!NT_STATUS_IS_OK(status
)) {
307 if (!NT_STATUS_IS_OK(status
= add_aliases(get_global_sam_sid(),
309 || !NT_STATUS_IS_OK(status
= add_aliases(&global_sid_Builtin
,
311 DEBUG(3, ("could not add aliases: %s\n",
317 debug_nt_user_token(DBGC_CLASS
, 10, token
);
319 for (i
=0; i
<num_require_membership_of_sid
; i
++) {
320 DEBUG(10, ("Checking SID %s\n", sid_string_dbg(
321 &require_membership_of_sid
[i
])));
322 if (nt_token_check_sid(&require_membership_of_sid
[i
],
324 DEBUG(10, ("Access ok\n"));
330 /* Do not distinguish this error from a wrong username/pw */
333 return NT_STATUS_LOGON_FAILURE
;
336 struct winbindd_domain
*find_auth_domain(uint8_t flags
,
337 const char *domain_name
)
339 struct winbindd_domain
*domain
;
342 domain
= find_domain_from_name_noinit(domain_name
);
343 if (domain
== NULL
) {
344 DEBUG(3, ("Authentication for domain [%s] refused "
345 "as it is not a trusted domain\n",
351 if (strequal(domain_name
, get_global_sam_name())) {
352 return find_domain_from_name_noinit(domain_name
);
355 /* we can auth against trusted domains */
356 if (flags
& WBFLAG_PAM_CONTACT_TRUSTDOM
) {
357 domain
= find_domain_from_name_noinit(domain_name
);
358 if (domain
== NULL
) {
359 DEBUG(3, ("Authentication for domain [%s] skipped "
360 "as it is not a trusted domain\n",
367 return find_our_domain();
370 static void fill_in_password_policy(struct winbindd_response
*r
,
371 const struct samr_DomInfo1
*p
)
373 r
->data
.auth
.policy
.min_length_password
=
374 p
->min_password_length
;
375 r
->data
.auth
.policy
.password_history
=
376 p
->password_history_length
;
377 r
->data
.auth
.policy
.password_properties
=
378 p
->password_properties
;
379 r
->data
.auth
.policy
.expire
=
380 nt_time_to_unix_abs((NTTIME
*)&(p
->max_password_age
));
381 r
->data
.auth
.policy
.min_passwordage
=
382 nt_time_to_unix_abs((NTTIME
*)&(p
->min_password_age
));
385 static NTSTATUS
fillup_password_policy(struct winbindd_domain
*domain
,
386 struct winbindd_cli_state
*state
)
388 struct winbindd_methods
*methods
;
389 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
390 struct samr_DomInfo1 password_policy
;
392 if ( !winbindd_can_contact_domain( domain
) ) {
393 DEBUG(5,("fillup_password_policy: No inbound trust to "
394 "contact domain %s\n", domain
->name
));
395 return NT_STATUS_NOT_SUPPORTED
;
398 methods
= domain
->methods
;
400 status
= methods
->password_policy(domain
, state
->mem_ctx
, &password_policy
);
401 if (NT_STATUS_IS_ERR(status
)) {
405 fill_in_password_policy(state
->response
, &password_policy
);
410 static NTSTATUS
get_max_bad_attempts_from_lockout_policy(struct winbindd_domain
*domain
,
412 uint16
*lockout_threshold
)
414 struct winbindd_methods
*methods
;
415 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
416 struct samr_DomInfo12 lockout_policy
;
418 *lockout_threshold
= 0;
420 methods
= domain
->methods
;
422 status
= methods
->lockout_policy(domain
, mem_ctx
, &lockout_policy
);
423 if (NT_STATUS_IS_ERR(status
)) {
427 *lockout_threshold
= lockout_policy
.lockout_threshold
;
432 static NTSTATUS
get_pwd_properties(struct winbindd_domain
*domain
,
434 uint32
*password_properties
)
436 struct winbindd_methods
*methods
;
437 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
438 struct samr_DomInfo1 password_policy
;
440 *password_properties
= 0;
442 methods
= domain
->methods
;
444 status
= methods
->password_policy(domain
, mem_ctx
, &password_policy
);
445 if (NT_STATUS_IS_ERR(status
)) {
449 *password_properties
= password_policy
.password_properties
;
456 static const char *generate_krb5_ccache(TALLOC_CTX
*mem_ctx
,
459 bool *internal_ccache
)
461 /* accept FILE and WRFILE as krb5_cc_type from the client and then
462 * build the full ccname string based on the user's uid here -
465 const char *gen_cc
= NULL
;
467 *internal_ccache
= true;
473 if (!type
|| type
[0] == '\0') {
477 if (strequal(type
, "FILE")) {
478 gen_cc
= talloc_asprintf(mem_ctx
, "FILE:/tmp/krb5cc_%d", uid
);
479 } else if (strequal(type
, "WRFILE")) {
480 gen_cc
= talloc_asprintf(mem_ctx
, "WRFILE:/tmp/krb5cc_%d", uid
);
482 DEBUG(10,("we don't allow to set a %s type ccache\n", type
));
486 *internal_ccache
= false;
490 gen_cc
= talloc_strdup(mem_ctx
, "MEMORY:winbindd_pam_ccache");
493 if (gen_cc
== NULL
) {
494 DEBUG(0,("out of memory\n"));
498 DEBUG(10,("using ccache: %s %s\n", gen_cc
, *internal_ccache
? "(internal)":""));
503 static void setup_return_cc_name(struct winbindd_cli_state
*state
, const char *cc
)
505 const char *type
= state
->request
->data
.auth
.krb5_cc_type
;
507 state
->response
->data
.auth
.krb5ccname
[0] = '\0';
509 if (type
[0] == '\0') {
513 if (!strequal(type
, "FILE") &&
514 !strequal(type
, "WRFILE")) {
515 DEBUG(10,("won't return krbccname for a %s type ccache\n",
520 fstrcpy(state
->response
->data
.auth
.krb5ccname
, cc
);
525 static uid_t
get_uid_from_state(struct winbindd_cli_state
*state
)
529 uid
= state
->request
->data
.auth
.uid
;
532 DEBUG(1,("invalid uid: '%u'\n", (unsigned int)uid
));
538 /**********************************************************************
539 Authenticate a user with a clear text password using Kerberos and fill up
541 **********************************************************************/
543 static NTSTATUS
winbindd_raw_kerberos_login(struct winbindd_domain
*domain
,
544 struct winbindd_cli_state
*state
,
545 struct netr_SamInfo3
**info3
)
548 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
549 krb5_error_code krb5_ret
;
550 const char *cc
= NULL
;
551 const char *principal_s
= NULL
;
552 const char *service
= NULL
;
554 fstring name_domain
, name_user
;
555 time_t ticket_lifetime
= 0;
556 time_t renewal_until
= 0;
559 time_t time_offset
= 0;
560 bool internal_ccache
= true;
567 * prepare a krb5_cc_cache string for the user */
569 uid
= get_uid_from_state(state
);
571 DEBUG(0,("no valid uid\n"));
574 cc
= generate_krb5_ccache(state
->mem_ctx
,
575 state
->request
->data
.auth
.krb5_cc_type
,
576 state
->request
->data
.auth
.uid
,
579 return NT_STATUS_NO_MEMORY
;
584 * get kerberos properties */
586 if (domain
->private_data
) {
587 ads
= (ADS_STRUCT
*)domain
->private_data
;
588 time_offset
= ads
->auth
.time_offset
;
593 * do kerberos auth and setup ccache as the user */
595 parse_domain_user(state
->request
->data
.auth
.user
, name_domain
, name_user
);
597 realm
= domain
->alt_name
;
600 principal_s
= talloc_asprintf(state
->mem_ctx
, "%s@%s", name_user
, realm
);
601 if (principal_s
== NULL
) {
602 return NT_STATUS_NO_MEMORY
;
605 service
= talloc_asprintf(state
->mem_ctx
, "%s/%s@%s", KRB5_TGS_NAME
, realm
, realm
);
606 if (service
== NULL
) {
607 return NT_STATUS_NO_MEMORY
;
610 /* if this is a user ccache, we need to act as the user to let the krb5
611 * library handle the chown, etc. */
613 /************************ ENTERING NON-ROOT **********************/
615 if (!internal_ccache
) {
616 set_effective_uid(uid
);
617 DEBUG(10,("winbindd_raw_kerberos_login: uid is %d\n", uid
));
620 result
= kerberos_return_info3_from_pac(state
->mem_ctx
,
622 state
->request
->data
.auth
.pass
,
629 WINBINDD_PAM_AUTH_KRB5_RENEW_TIME
,
632 if (!internal_ccache
) {
633 gain_root_privilege();
636 /************************ RETURNED TO ROOT **********************/
638 if (!NT_STATUS_IS_OK(result
)) {
642 DEBUG(10,("winbindd_raw_kerberos_login: winbindd validated ticket of %s\n",
645 /* if we had a user's ccache then return that string for the pam
648 if (!internal_ccache
) {
650 setup_return_cc_name(state
, cc
);
652 result
= add_ccache_to_list(principal_s
,
655 state
->request
->data
.auth
.user
,
663 if (!NT_STATUS_IS_OK(result
)) {
664 DEBUG(10,("winbindd_raw_kerberos_login: failed to add ccache to list: %s\n",
669 /* need to delete the memory cred cache, it is not used anymore */
671 krb5_ret
= ads_kdestroy(cc
);
673 DEBUG(3,("winbindd_raw_kerberos_login: "
674 "could not destroy krb5 credential cache: "
675 "%s\n", error_message(krb5_ret
)));
684 /* we could have created a new credential cache with a valid tgt in it
685 * but we werent able to get or verify the service ticket for this
686 * local host and therefor didn't get the PAC, we need to remove that
687 * cache entirely now */
689 krb5_ret
= ads_kdestroy(cc
);
691 DEBUG(3,("winbindd_raw_kerberos_login: "
692 "could not destroy krb5 credential cache: "
693 "%s\n", error_message(krb5_ret
)));
696 if (!NT_STATUS_IS_OK(remove_ccache(state
->request
->data
.auth
.user
))) {
697 DEBUG(3,("winbindd_raw_kerberos_login: "
698 "could not remove ccache for user %s\n",
699 state
->request
->data
.auth
.user
));
704 return NT_STATUS_NOT_SUPPORTED
;
705 #endif /* HAVE_KRB5 */
708 /****************************************************************
709 ****************************************************************/
711 bool check_request_flags(uint32_t flags
)
713 uint32_t flags_edata
= WBFLAG_PAM_AFS_TOKEN
|
714 WBFLAG_PAM_INFO3_TEXT
|
715 WBFLAG_PAM_INFO3_NDR
;
717 if ( ( (flags
& flags_edata
) == WBFLAG_PAM_AFS_TOKEN
) ||
718 ( (flags
& flags_edata
) == WBFLAG_PAM_INFO3_NDR
) ||
719 ( (flags
& flags_edata
) == WBFLAG_PAM_INFO3_TEXT
)||
720 !(flags
& flags_edata
) ) {
724 DEBUG(1, ("check_request_flags: invalid request flags[0x%08X]\n",
730 /****************************************************************
731 ****************************************************************/
733 static NTSTATUS
append_auth_data(struct winbindd_cli_state
*state
,
734 struct netr_SamInfo3
*info3
,
735 const char *name_domain
,
736 const char *name_user
)
739 uint32_t flags
= state
->request
->flags
;
741 if (flags
& WBFLAG_PAM_USER_SESSION_KEY
) {
742 memcpy(state
->response
->data
.auth
.user_session_key
,
744 sizeof(state
->response
->data
.auth
.user_session_key
)
748 if (flags
& WBFLAG_PAM_LMKEY
) {
749 memcpy(state
->response
->data
.auth
.first_8_lm_hash
,
750 info3
->base
.LMSessKey
.key
,
751 sizeof(state
->response
->data
.auth
.first_8_lm_hash
)
755 if (flags
& WBFLAG_PAM_INFO3_TEXT
) {
756 result
= append_info3_as_txt(state
->mem_ctx
, state
, info3
);
757 if (!NT_STATUS_IS_OK(result
)) {
758 DEBUG(10,("Failed to append INFO3 (TXT): %s\n",
764 /* currently, anything from here on potentially overwrites extra_data. */
766 if (flags
& WBFLAG_PAM_INFO3_NDR
) {
767 result
= append_info3_as_ndr(state
->mem_ctx
, state
, info3
);
768 if (!NT_STATUS_IS_OK(result
)) {
769 DEBUG(10,("Failed to append INFO3 (NDR): %s\n",
775 if (flags
& WBFLAG_PAM_UNIX_NAME
) {
776 result
= append_unix_username(state
->mem_ctx
, state
, info3
,
777 name_domain
, name_user
);
778 if (!NT_STATUS_IS_OK(result
)) {
779 DEBUG(10,("Failed to append Unix Username: %s\n",
785 if (flags
& WBFLAG_PAM_AFS_TOKEN
) {
786 result
= append_afs_token(state
->mem_ctx
, state
, info3
,
787 name_domain
, name_user
);
788 if (!NT_STATUS_IS_OK(result
)) {
789 DEBUG(10,("Failed to append AFS token: %s\n",
798 static NTSTATUS
winbindd_dual_pam_auth_cached(struct winbindd_domain
*domain
,
799 struct winbindd_cli_state
*state
,
800 struct netr_SamInfo3
**info3
)
802 NTSTATUS result
= NT_STATUS_LOGON_FAILURE
;
803 uint16 max_allowed_bad_attempts
;
804 fstring name_domain
, name_user
;
806 enum lsa_SidType type
;
807 uchar new_nt_pass
[NT_HASH_LEN
];
808 const uint8
*cached_nt_pass
;
809 const uint8
*cached_salt
;
810 struct netr_SamInfo3
*my_info3
;
811 time_t kickoff_time
, must_change_time
;
812 bool password_good
= false;
814 struct winbindd_tdc_domain
*tdc_domain
= NULL
;
821 DEBUG(10,("winbindd_dual_pam_auth_cached\n"));
823 /* Parse domain and username */
825 parse_domain_user(state
->request
->data
.auth
.user
, name_domain
, name_user
);
828 if (!lookup_cached_name(state
->mem_ctx
,
833 DEBUG(10,("winbindd_dual_pam_auth_cached: no such user in the cache\n"));
834 return NT_STATUS_NO_SUCH_USER
;
837 if (type
!= SID_NAME_USER
) {
838 DEBUG(10,("winbindd_dual_pam_auth_cached: not a user (%s)\n", sid_type_lookup(type
)));
839 return NT_STATUS_LOGON_FAILURE
;
842 result
= winbindd_get_creds(domain
,
848 if (!NT_STATUS_IS_OK(result
)) {
849 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get creds: %s\n", nt_errstr(result
)));
855 E_md4hash(state
->request
->data
.auth
.pass
, new_nt_pass
);
857 dump_data_pw("new_nt_pass", new_nt_pass
, NT_HASH_LEN
);
858 dump_data_pw("cached_nt_pass", cached_nt_pass
, NT_HASH_LEN
);
860 dump_data_pw("cached_salt", cached_salt
, NT_HASH_LEN
);
864 /* In this case we didn't store the nt_hash itself,
865 but the MD5 combination of salt + nt_hash. */
866 uchar salted_hash
[NT_HASH_LEN
];
867 E_md5hash(cached_salt
, new_nt_pass
, salted_hash
);
869 password_good
= (memcmp(cached_nt_pass
, salted_hash
,
872 /* Old cached cred - direct store of nt_hash (bad bad bad !). */
873 password_good
= (memcmp(cached_nt_pass
, new_nt_pass
,
879 /* User *DOES* know the password, update logon_time and reset
882 my_info3
->base
.user_flags
|= NETLOGON_CACHED_ACCOUNT
;
884 if (my_info3
->base
.acct_flags
& ACB_AUTOLOCK
) {
885 return NT_STATUS_ACCOUNT_LOCKED_OUT
;
888 if (my_info3
->base
.acct_flags
& ACB_DISABLED
) {
889 return NT_STATUS_ACCOUNT_DISABLED
;
892 if (my_info3
->base
.acct_flags
& ACB_WSTRUST
) {
893 return NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT
;
896 if (my_info3
->base
.acct_flags
& ACB_SVRTRUST
) {
897 return NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT
;
900 if (my_info3
->base
.acct_flags
& ACB_DOMTRUST
) {
901 return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT
;
904 if (!(my_info3
->base
.acct_flags
& ACB_NORMAL
)) {
905 DEBUG(0,("winbindd_dual_pam_auth_cached: whats wrong with that one?: 0x%08x\n",
906 my_info3
->base
.acct_flags
));
907 return NT_STATUS_LOGON_FAILURE
;
910 kickoff_time
= nt_time_to_unix(my_info3
->base
.acct_expiry
);
911 if (kickoff_time
!= 0 && time(NULL
) > kickoff_time
) {
912 return NT_STATUS_ACCOUNT_EXPIRED
;
915 must_change_time
= nt_time_to_unix(my_info3
->base
.force_password_change
);
916 if (must_change_time
!= 0 && must_change_time
< time(NULL
)) {
917 /* we allow grace logons when the password has expired */
918 my_info3
->base
.user_flags
|= NETLOGON_GRACE_LOGON
;
919 /* return NT_STATUS_PASSWORD_EXPIRED; */
924 if ((state
->request
->flags
& WBFLAG_PAM_KRB5
) &&
925 ((tdc_domain
= wcache_tdc_fetch_domain(state
->mem_ctx
, name_domain
)) != NULL
) &&
926 ((tdc_domain
->trust_type
& NETR_TRUST_TYPE_UPLEVEL
) ||
927 /* used to cope with the case winbindd starting without network. */
928 !strequal(tdc_domain
->domain_name
, tdc_domain
->dns_name
))) {
931 const char *cc
= NULL
;
933 const char *principal_s
= NULL
;
934 const char *service
= NULL
;
935 bool internal_ccache
= false;
937 uid
= get_uid_from_state(state
);
939 DEBUG(0,("winbindd_dual_pam_auth_cached: invalid uid\n"));
940 return NT_STATUS_INVALID_PARAMETER
;
943 cc
= generate_krb5_ccache(state
->mem_ctx
,
944 state
->request
->data
.auth
.krb5_cc_type
,
945 state
->request
->data
.auth
.uid
,
948 return NT_STATUS_NO_MEMORY
;
951 realm
= domain
->alt_name
;
954 principal_s
= talloc_asprintf(state
->mem_ctx
, "%s@%s", name_user
, realm
);
955 if (principal_s
== NULL
) {
956 return NT_STATUS_NO_MEMORY
;
959 service
= talloc_asprintf(state
->mem_ctx
, "%s/%s@%s", KRB5_TGS_NAME
, realm
, realm
);
960 if (service
== NULL
) {
961 return NT_STATUS_NO_MEMORY
;
964 if (!internal_ccache
) {
966 setup_return_cc_name(state
, cc
);
968 result
= add_ccache_to_list(principal_s
,
971 state
->request
->data
.auth
.user
,
975 time(NULL
) + lp_winbind_cache_time(),
976 time(NULL
) + WINBINDD_PAM_AUTH_KRB5_RENEW_TIME
,
979 if (!NT_STATUS_IS_OK(result
)) {
980 DEBUG(10,("winbindd_dual_pam_auth_cached: failed "
981 "to add ccache to list: %s\n",
986 #endif /* HAVE_KRB5 */
988 /* FIXME: we possibly should handle logon hours as well (does xp when
989 * offline?) see auth/auth_sam.c:sam_account_ok for details */
991 unix_to_nt_time(&my_info3
->base
.last_logon
, time(NULL
));
992 my_info3
->base
.bad_password_count
= 0;
994 result
= winbindd_update_creds_by_info3(domain
,
996 state
->request
->data
.auth
.user
,
997 state
->request
->data
.auth
.pass
,
999 if (!NT_STATUS_IS_OK(result
)) {
1000 DEBUG(1,("winbindd_dual_pam_auth_cached: failed to update creds: %s\n",
1001 nt_errstr(result
)));
1005 return NT_STATUS_OK
;
1009 /* User does *NOT* know the correct password, modify info3 accordingly */
1011 /* failure of this is not critical */
1012 result
= get_max_bad_attempts_from_lockout_policy(domain
, state
->mem_ctx
, &max_allowed_bad_attempts
);
1013 if (!NT_STATUS_IS_OK(result
)) {
1014 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get max_allowed_bad_attempts. "
1015 "Won't be able to honour account lockout policies\n"));
1018 /* increase counter */
1019 my_info3
->base
.bad_password_count
++;
1021 if (max_allowed_bad_attempts
== 0) {
1026 if (my_info3
->base
.bad_password_count
>= max_allowed_bad_attempts
) {
1028 uint32 password_properties
;
1030 result
= get_pwd_properties(domain
, state
->mem_ctx
, &password_properties
);
1031 if (!NT_STATUS_IS_OK(result
)) {
1032 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get password properties.\n"));
1035 if ((my_info3
->base
.rid
!= DOMAIN_USER_RID_ADMIN
) ||
1036 (password_properties
& DOMAIN_PASSWORD_LOCKOUT_ADMINS
)) {
1037 my_info3
->base
.acct_flags
|= ACB_AUTOLOCK
;
1042 result
= winbindd_update_creds_by_info3(domain
,
1044 state
->request
->data
.auth
.user
,
1048 if (!NT_STATUS_IS_OK(result
)) {
1049 DEBUG(0,("winbindd_dual_pam_auth_cached: failed to update creds %s\n",
1050 nt_errstr(result
)));
1053 return NT_STATUS_LOGON_FAILURE
;
1056 static NTSTATUS
winbindd_dual_pam_auth_kerberos(struct winbindd_domain
*domain
,
1057 struct winbindd_cli_state
*state
,
1058 struct netr_SamInfo3
**info3
)
1060 struct winbindd_domain
*contact_domain
;
1061 fstring name_domain
, name_user
;
1064 DEBUG(10,("winbindd_dual_pam_auth_kerberos\n"));
1066 /* Parse domain and username */
1068 parse_domain_user(state
->request
->data
.auth
.user
, name_domain
, name_user
);
1070 /* what domain should we contact? */
1073 if (!(contact_domain
= find_domain_from_name(name_domain
))) {
1074 DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
1075 state
->request
->data
.auth
.user
, name_domain
, name_user
, name_domain
));
1076 result
= NT_STATUS_NO_SUCH_USER
;
1081 if (is_myname(name_domain
)) {
1082 DEBUG(3, ("Authentication for domain %s (local domain to this server) not supported at this stage\n", name_domain
));
1083 result
= NT_STATUS_NO_SUCH_USER
;
1087 contact_domain
= find_domain_from_name(name_domain
);
1088 if (contact_domain
== NULL
) {
1089 DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
1090 state
->request
->data
.auth
.user
, name_domain
, name_user
, name_domain
));
1092 contact_domain
= find_our_domain();
1096 if (contact_domain
->initialized
&&
1097 contact_domain
->active_directory
) {
1101 if (!contact_domain
->initialized
) {
1102 init_dc_connection(contact_domain
);
1105 if (!contact_domain
->active_directory
) {
1106 DEBUG(3,("krb5 auth requested but domain is not Active Directory\n"));
1107 return NT_STATUS_INVALID_LOGON_TYPE
;
1110 result
= winbindd_raw_kerberos_login(contact_domain
, state
, info3
);
1115 static NTSTATUS
winbindd_dual_auth_passdb(TALLOC_CTX
*mem_ctx
,
1116 const char *domain
, const char *user
,
1117 const DATA_BLOB
*challenge
,
1118 const DATA_BLOB
*lm_resp
,
1119 const DATA_BLOB
*nt_resp
,
1120 struct netr_SamInfo3
**pinfo3
)
1122 struct auth_usersupplied_info
*user_info
= NULL
;
1123 struct auth_serversupplied_info
*server_info
= NULL
;
1124 struct netr_SamInfo3
*info3
;
1127 status
= make_user_info(&user_info
, user
, user
, domain
, domain
,
1128 global_myname(), lm_resp
, nt_resp
, NULL
, NULL
,
1130 if (!NT_STATUS_IS_OK(status
)) {
1131 DEBUG(10, ("make_user_info failed: %s\n", nt_errstr(status
)));
1135 status
= check_sam_security(challenge
, talloc_tos(), user_info
,
1137 free_user_info(&user_info
);
1139 if (!NT_STATUS_IS_OK(status
)) {
1140 DEBUG(10, ("check_ntlm_password failed: %s\n",
1141 nt_errstr(status
)));
1145 info3
= TALLOC_ZERO_P(mem_ctx
, struct netr_SamInfo3
);
1146 if (info3
== NULL
) {
1147 return NT_STATUS_NO_MEMORY
;
1150 status
= serverinfo_to_SamInfo3(server_info
, NULL
, 0, info3
);
1151 if (!NT_STATUS_IS_OK(status
)) {
1152 DEBUG(10, ("serverinfo_to_SamInfo3 failed: %s\n",
1153 nt_errstr(status
)));
1157 DEBUG(10, ("Authenticated user %s\\%s successfully\n", domain
, user
));
1159 return NT_STATUS_OK
;
1162 typedef NTSTATUS (*netlogon_fn_t
)(struct rpc_pipe_client
*cli
,
1163 TALLOC_CTX
*mem_ctx
,
1164 uint32 logon_parameters
,
1166 const char *username
,
1168 const char *workstation
,
1169 const uint8 chal
[8],
1170 DATA_BLOB lm_response
,
1171 DATA_BLOB nt_response
,
1172 struct netr_SamInfo3
**info3
);
1174 static NTSTATUS
winbindd_dual_pam_auth_samlogon(struct winbindd_domain
*domain
,
1175 struct winbindd_cli_state
*state
,
1176 struct netr_SamInfo3
**info3
)
1179 struct rpc_pipe_client
*netlogon_pipe
;
1184 unsigned char local_lm_response
[24];
1185 unsigned char local_nt_response
[24];
1186 fstring name_domain
, name_user
;
1189 struct netr_SamInfo3
*my_info3
= NULL
;
1193 DEBUG(10,("winbindd_dual_pam_auth_samlogon\n"));
1195 /* Parse domain and username */
1197 parse_domain_user(state
->request
->data
.auth
.user
, name_domain
, name_user
);
1199 /* do password magic */
1201 generate_random_buffer(chal
, sizeof(chal
));
1203 if (lp_client_ntlmv2_auth()) {
1204 DATA_BLOB server_chal
;
1205 DATA_BLOB names_blob
;
1206 DATA_BLOB nt_response
;
1207 DATA_BLOB lm_response
;
1208 server_chal
= data_blob_talloc(state
->mem_ctx
, chal
, 8);
1210 /* note that the 'workgroup' here is a best guess - we don't know
1211 the server's domain at this point. The 'server name' is also
1214 names_blob
= NTLMv2_generate_names_blob(state
->mem_ctx
, global_myname(), lp_workgroup());
1216 if (!SMBNTLMv2encrypt(NULL
, name_user
, name_domain
,
1217 state
->request
->data
.auth
.pass
,
1220 &lm_response
, &nt_response
, NULL
, NULL
)) {
1221 data_blob_free(&names_blob
);
1222 data_blob_free(&server_chal
);
1223 DEBUG(0, ("winbindd_pam_auth: SMBNTLMv2encrypt() failed!\n"));
1224 result
= NT_STATUS_NO_MEMORY
;
1227 data_blob_free(&names_blob
);
1228 data_blob_free(&server_chal
);
1229 lm_resp
= data_blob_talloc(state
->mem_ctx
, lm_response
.data
,
1230 lm_response
.length
);
1231 nt_resp
= data_blob_talloc(state
->mem_ctx
, nt_response
.data
,
1232 nt_response
.length
);
1233 data_blob_free(&lm_response
);
1234 data_blob_free(&nt_response
);
1237 if (lp_client_lanman_auth()
1238 && SMBencrypt(state
->request
->data
.auth
.pass
,
1240 local_lm_response
)) {
1241 lm_resp
= data_blob_talloc(state
->mem_ctx
,
1243 sizeof(local_lm_response
));
1245 lm_resp
= data_blob_null
;
1247 SMBNTencrypt(state
->request
->data
.auth
.pass
,
1251 nt_resp
= data_blob_talloc(state
->mem_ctx
,
1253 sizeof(local_nt_response
));
1256 if (strequal(name_domain
, get_global_sam_name())) {
1257 DATA_BLOB chal_blob
= data_blob_const(chal
, sizeof(chal
));
1259 result
= winbindd_dual_auth_passdb(
1260 state
->mem_ctx
, name_domain
, name_user
,
1261 &chal_blob
, &lm_resp
, &nt_resp
, info3
);
1265 /* check authentication loop */
1268 netlogon_fn_t logon_fn
;
1270 ZERO_STRUCTP(my_info3
);
1273 result
= cm_connect_netlogon(domain
, &netlogon_pipe
);
1275 if (!NT_STATUS_IS_OK(result
)) {
1276 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
1280 /* It is really important to try SamLogonEx here,
1281 * because in a clustered environment, we want to use
1282 * one machine account from multiple physical
1285 * With a normal SamLogon call, we must keep the
1286 * credentials chain updated and intact between all
1287 * users of the machine account (which would imply
1288 * cross-node communication for every NTLM logon).
1290 * (The credentials chain is not per NETLOGON pipe
1291 * connection, but globally on the server/client pair
1294 * When using SamLogonEx, the credentials are not
1295 * supplied, but the session key is implied by the
1296 * wrapping SamLogon context.
1298 * -- abartlet 21 April 2008
1301 logon_fn
= domain
->can_do_samlogon_ex
1302 ? rpccli_netlogon_sam_network_logon_ex
1303 : rpccli_netlogon_sam_network_logon
;
1305 result
= logon_fn(netlogon_pipe
,
1308 domain
->dcname
, /* server name */
1309 name_user
, /* user name */
1310 name_domain
, /* target domain */
1311 global_myname(), /* workstation */
1318 if ((NT_STATUS_V(result
) == DCERPC_FAULT_OP_RNG_ERROR
)
1319 && domain
->can_do_samlogon_ex
) {
1320 DEBUG(3, ("Got a DC that can not do NetSamLogonEx, "
1321 "retrying with NetSamLogon\n"));
1322 domain
->can_do_samlogon_ex
= false;
1327 /* We have to try a second time as cm_connect_netlogon
1328 might not yet have noticed that the DC has killed
1331 if (!rpccli_is_connected(netlogon_pipe
)) {
1336 /* if we get access denied, a possible cause was that we had
1337 and open connection to the DC, but someone changed our
1338 machine account password out from underneath us using 'net
1339 rpc changetrustpw' */
1341 if ( NT_STATUS_EQUAL(result
, NT_STATUS_ACCESS_DENIED
) ) {
1342 DEBUG(3,("winbindd_pam_auth: sam_logon returned "
1343 "ACCESS_DENIED. Maybe the trust account "
1344 "password was changed and we didn't know it. "
1345 "Killing connections to domain %s\n",
1347 invalidate_cm_connection(&domain
->conn
);
1351 } while ( (attempts
< 2) && retry
);
1353 /* handle the case where a NT4 DC does not fill in the acct_flags in
1354 * the samlogon reply info3. When accurate info3 is required by the
1355 * caller, we look up the account flags ourselve - gd */
1357 if ((state
->request
->flags
& WBFLAG_PAM_INFO3_TEXT
) &&
1358 NT_STATUS_IS_OK(result
) && (my_info3
->base
.acct_flags
== 0)) {
1360 struct rpc_pipe_client
*samr_pipe
;
1361 struct policy_handle samr_domain_handle
, user_pol
;
1362 union samr_UserInfo
*info
= NULL
;
1363 NTSTATUS status_tmp
;
1366 status_tmp
= cm_connect_sam(domain
, state
->mem_ctx
,
1367 &samr_pipe
, &samr_domain_handle
);
1369 if (!NT_STATUS_IS_OK(status_tmp
)) {
1370 DEBUG(3, ("could not open handle to SAMR pipe: %s\n",
1371 nt_errstr(status_tmp
)));
1375 status_tmp
= rpccli_samr_OpenUser(samr_pipe
, state
->mem_ctx
,
1376 &samr_domain_handle
,
1377 MAXIMUM_ALLOWED_ACCESS
,
1381 if (!NT_STATUS_IS_OK(status_tmp
)) {
1382 DEBUG(3, ("could not open user handle on SAMR pipe: %s\n",
1383 nt_errstr(status_tmp
)));
1387 status_tmp
= rpccli_samr_QueryUserInfo(samr_pipe
, state
->mem_ctx
,
1392 if (!NT_STATUS_IS_OK(status_tmp
)) {
1393 DEBUG(3, ("could not query user info on SAMR pipe: %s\n",
1394 nt_errstr(status_tmp
)));
1395 rpccli_samr_Close(samr_pipe
, state
->mem_ctx
, &user_pol
);
1399 acct_flags
= info
->info16
.acct_flags
;
1401 if (acct_flags
== 0) {
1402 rpccli_samr_Close(samr_pipe
, state
->mem_ctx
, &user_pol
);
1406 my_info3
->base
.acct_flags
= acct_flags
;
1408 DEBUG(10,("successfully retrieved acct_flags 0x%x\n", acct_flags
));
1410 rpccli_samr_Close(samr_pipe
, state
->mem_ctx
, &user_pol
);
1418 enum winbindd_result
winbindd_dual_pam_auth(struct winbindd_domain
*domain
,
1419 struct winbindd_cli_state
*state
)
1421 NTSTATUS result
= NT_STATUS_LOGON_FAILURE
;
1422 NTSTATUS krb5_result
= NT_STATUS_OK
;
1423 fstring name_domain
, name_user
;
1425 fstring domain_user
;
1426 struct netr_SamInfo3
*info3
= NULL
;
1427 NTSTATUS name_map_status
= NT_STATUS_UNSUCCESSFUL
;
1429 /* Ensure null termination */
1430 state
->request
->data
.auth
.user
[sizeof(state
->request
->data
.auth
.user
)-1]='\0';
1432 /* Ensure null termination */
1433 state
->request
->data
.auth
.pass
[sizeof(state
->request
->data
.auth
.pass
)-1]='\0';
1435 DEBUG(3, ("[%5lu]: dual pam auth %s\n", (unsigned long)state
->pid
,
1436 state
->request
->data
.auth
.user
));
1438 if (!check_request_flags(state
->request
->flags
)) {
1439 result
= NT_STATUS_INVALID_PARAMETER_MIX
;
1443 /* Parse domain and username */
1445 name_map_status
= normalize_name_unmap(state
->mem_ctx
,
1446 state
->request
->data
.auth
.user
,
1449 /* If the name normalization didnt' actually do anything,
1450 just use the original name */
1452 if (!NT_STATUS_IS_OK(name_map_status
) &&
1453 !NT_STATUS_EQUAL(name_map_status
, NT_STATUS_FILE_RENAMED
))
1455 mapped_user
= state
->request
->data
.auth
.user
;
1458 parse_domain_user(mapped_user
, name_domain
, name_user
);
1460 if ( mapped_user
!= state
->request
->data
.auth
.user
) {
1461 fstr_sprintf( domain_user
, "%s\\%s", name_domain
, name_user
);
1462 safe_strcpy( state
->request
->data
.auth
.user
, domain_user
,
1463 sizeof(state
->request
->data
.auth
.user
)-1 );
1466 if (domain
->online
== false) {
1467 result
= NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
;
1468 if (domain
->startup
) {
1469 /* Logons are very important to users. If we're offline and
1470 we get a request within the first 30 seconds of startup,
1471 try very hard to find a DC and go online. */
1473 DEBUG(10,("winbindd_dual_pam_auth: domain: %s offline and auth "
1474 "request in startup mode.\n", domain
->name
));
1476 winbindd_flush_negative_conn_cache(domain
);
1477 result
= init_dc_connection(domain
);
1481 DEBUG(10,("winbindd_dual_pam_auth: domain: %s last was %s\n", domain
->name
, domain
->online
? "online":"offline"));
1483 /* Check for Kerberos authentication */
1484 if (domain
->online
&& (state
->request
->flags
& WBFLAG_PAM_KRB5
)) {
1486 result
= winbindd_dual_pam_auth_kerberos(domain
, state
, &info3
);
1487 /* save for later */
1488 krb5_result
= result
;
1491 if (NT_STATUS_IS_OK(result
)) {
1492 DEBUG(10,("winbindd_dual_pam_auth_kerberos succeeded\n"));
1493 goto process_result
;
1495 DEBUG(10,("winbindd_dual_pam_auth_kerberos failed: %s\n", nt_errstr(result
)));
1498 if (NT_STATUS_EQUAL(result
, NT_STATUS_NO_LOGON_SERVERS
) ||
1499 NT_STATUS_EQUAL(result
, NT_STATUS_IO_TIMEOUT
) ||
1500 NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1501 DEBUG(10,("winbindd_dual_pam_auth_kerberos setting domain to offline\n"));
1502 set_domain_offline( domain
);
1506 /* there are quite some NT_STATUS errors where there is no
1507 * point in retrying with a samlogon, we explictly have to take
1508 * care not to increase the bad logon counter on the DC */
1510 if (NT_STATUS_EQUAL(result
, NT_STATUS_ACCOUNT_DISABLED
) ||
1511 NT_STATUS_EQUAL(result
, NT_STATUS_ACCOUNT_EXPIRED
) ||
1512 NT_STATUS_EQUAL(result
, NT_STATUS_ACCOUNT_LOCKED_OUT
) ||
1513 NT_STATUS_EQUAL(result
, NT_STATUS_INVALID_LOGON_HOURS
) ||
1514 NT_STATUS_EQUAL(result
, NT_STATUS_INVALID_WORKSTATION
) ||
1515 NT_STATUS_EQUAL(result
, NT_STATUS_LOGON_FAILURE
) ||
1516 NT_STATUS_EQUAL(result
, NT_STATUS_NO_SUCH_USER
) ||
1517 NT_STATUS_EQUAL(result
, NT_STATUS_PASSWORD_EXPIRED
) ||
1518 NT_STATUS_EQUAL(result
, NT_STATUS_PASSWORD_MUST_CHANGE
) ||
1519 NT_STATUS_EQUAL(result
, NT_STATUS_WRONG_PASSWORD
)) {
1523 if (state
->request
->flags
& WBFLAG_PAM_FALLBACK_AFTER_KRB5
) {
1524 DEBUG(3,("falling back to samlogon\n"));
1532 /* Check for Samlogon authentication */
1533 if (domain
->online
) {
1534 result
= winbindd_dual_pam_auth_samlogon(domain
, state
, &info3
);
1536 if (NT_STATUS_IS_OK(result
)) {
1537 DEBUG(10,("winbindd_dual_pam_auth_samlogon succeeded\n"));
1538 /* add the Krb5 err if we have one */
1539 if ( NT_STATUS_EQUAL(krb5_result
, NT_STATUS_TIME_DIFFERENCE_AT_DC
) ) {
1540 info3
->base
.user_flags
|= LOGON_KRB5_FAIL_CLOCK_SKEW
;
1542 goto process_result
;
1545 DEBUG(10,("winbindd_dual_pam_auth_samlogon failed: %s\n",
1546 nt_errstr(result
)));
1548 if (NT_STATUS_EQUAL(result
, NT_STATUS_NO_LOGON_SERVERS
) ||
1549 NT_STATUS_EQUAL(result
, NT_STATUS_IO_TIMEOUT
) ||
1550 NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
))
1552 DEBUG(10,("winbindd_dual_pam_auth_samlogon setting domain to offline\n"));
1553 set_domain_offline( domain
);
1557 if (domain
->online
) {
1558 /* We're still online - fail. */
1564 /* Check for Cached logons */
1565 if (!domain
->online
&& (state
->request
->flags
& WBFLAG_PAM_CACHED_LOGIN
) &&
1566 lp_winbind_offline_logon()) {
1568 result
= winbindd_dual_pam_auth_cached(domain
, state
, &info3
);
1570 if (NT_STATUS_IS_OK(result
)) {
1571 DEBUG(10,("winbindd_dual_pam_auth_cached succeeded\n"));
1572 goto process_result
;
1574 DEBUG(10,("winbindd_dual_pam_auth_cached failed: %s\n", nt_errstr(result
)));
1581 if (NT_STATUS_IS_OK(result
)) {
1585 /* In all codepaths where result == NT_STATUS_OK info3 must have
1586 been initialized. */
1588 result
= NT_STATUS_INTERNAL_ERROR
;
1592 wcache_invalidate_samlogon(find_domain_from_name(name_domain
), info3
);
1593 netsamlogon_cache_store(name_user
, info3
);
1595 /* save name_to_sid info as early as possible (only if
1596 this is our primary domain so we don't invalidate
1597 the cache entry by storing the seq_num for the wrong
1599 if ( domain
->primary
) {
1600 sid_compose(&user_sid
, info3
->base
.domain_sid
,
1602 cache_name2sid(domain
, name_domain
, name_user
,
1603 SID_NAME_USER
, &user_sid
);
1606 /* Check if the user is in the right group */
1608 result
= check_info3_in_group(
1610 state
->request
->data
.auth
.require_membership_of_sid
);
1611 if (!NT_STATUS_IS_OK(result
)) {
1612 DEBUG(3, ("User %s is not in the required group (%s), so plaintext authentication is rejected\n",
1613 state
->request
->data
.auth
.user
,
1614 state
->request
->data
.auth
.require_membership_of_sid
));
1618 result
= append_auth_data(state
, info3
, name_domain
,
1620 if (!NT_STATUS_IS_OK(result
)) {
1624 if ((state
->request
->flags
& WBFLAG_PAM_CACHED_LOGIN
)) {
1626 /* Store in-memory creds for single-signon using ntlm_auth. */
1627 result
= winbindd_add_memory_creds(state
->request
->data
.auth
.user
,
1628 get_uid_from_state(state
),
1629 state
->request
->data
.auth
.pass
);
1631 if (!NT_STATUS_IS_OK(result
)) {
1632 DEBUG(10,("Failed to store memory creds: %s\n", nt_errstr(result
)));
1636 if (lp_winbind_offline_logon()) {
1637 result
= winbindd_store_creds(domain
,
1639 state
->request
->data
.auth
.user
,
1640 state
->request
->data
.auth
.pass
,
1642 if (!NT_STATUS_IS_OK(result
)) {
1644 /* Release refcount. */
1645 winbindd_delete_memory_creds(state
->request
->data
.auth
.user
);
1647 DEBUG(10,("Failed to store creds: %s\n", nt_errstr(result
)));
1654 if (state
->request
->flags
& WBFLAG_PAM_GET_PWD_POLICY
) {
1655 struct winbindd_domain
*our_domain
= find_our_domain();
1657 /* This is not entirely correct I believe, but it is
1658 consistent. Only apply the password policy settings
1659 too warn users for our own domain. Cannot obtain these
1660 from trusted DCs all the time so don't do it at all.
1663 result
= NT_STATUS_NOT_SUPPORTED
;
1664 if (our_domain
== domain
) {
1665 result
= fillup_password_policy(our_domain
, state
);
1668 if (!NT_STATUS_IS_OK(result
)
1669 && !NT_STATUS_EQUAL(result
, NT_STATUS_NOT_SUPPORTED
) )
1671 DEBUG(10,("Failed to get password policies for domain %s: %s\n",
1672 domain
->name
, nt_errstr(result
)));
1677 result
= NT_STATUS_OK
;
1681 /* give us a more useful (more correct?) error code */
1682 if ((NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ||
1683 (NT_STATUS_EQUAL(result
, NT_STATUS_UNSUCCESSFUL
)))) {
1684 result
= NT_STATUS_NO_LOGON_SERVERS
;
1687 set_auth_errors(state
->response
, result
);
1689 DEBUG(NT_STATUS_IS_OK(result
) ? 5 : 2, ("Plain-text authentication for user %s returned %s (PAM: %d)\n",
1690 state
->request
->data
.auth
.user
,
1691 state
->response
->data
.auth
.nt_status_string
,
1692 state
->response
->data
.auth
.pam_error
));
1694 return NT_STATUS_IS_OK(result
) ? WINBINDD_OK
: WINBINDD_ERROR
;
1698 /**********************************************************************
1699 Challenge Response Authentication Protocol
1700 **********************************************************************/
1702 void winbindd_pam_auth_crap(struct winbindd_cli_state
*state
)
1704 struct winbindd_domain
*domain
= NULL
;
1705 const char *domain_name
= NULL
;
1708 if (!check_request_flags(state
->request
->flags
)) {
1709 result
= NT_STATUS_INVALID_PARAMETER_MIX
;
1713 if (!state
->privileged
) {
1714 DEBUG(2, ("winbindd_pam_auth_crap: non-privileged access "
1716 DEBUGADD(2, ("winbindd_pam_auth_crap: Ensure permissions "
1717 "on %s are set correctly.\n",
1718 get_winbind_priv_pipe_dir()));
1719 /* send a better message than ACCESS_DENIED */
1720 fstr_sprintf(state
->response
->data
.auth
.error_string
,
1721 "winbind client not authorized to use "
1722 "winbindd_pam_auth_crap. Ensure permissions on "
1723 "%s are set correctly.",
1724 get_winbind_priv_pipe_dir());
1725 result
= NT_STATUS_ACCESS_DENIED
;
1729 /* Ensure null termination */
1730 state
->request
->data
.auth_crap
.user
1731 [sizeof(state
->request
->data
.auth_crap
.user
)-1]=0;
1732 state
->request
->data
.auth_crap
.domain
1733 [sizeof(state
->request
->data
.auth_crap
.domain
)-1]=0;
1735 DEBUG(3, ("[%5lu]: pam auth crap domain: [%s] user: %s\n",
1736 (unsigned long)state
->pid
,
1737 state
->request
->data
.auth_crap
.domain
,
1738 state
->request
->data
.auth_crap
.user
));
1740 if (*state
->request
->data
.auth_crap
.domain
!= '\0') {
1741 domain_name
= state
->request
->data
.auth_crap
.domain
;
1742 } else if (lp_winbind_use_default_domain()) {
1743 domain_name
= lp_workgroup();
1746 if (domain_name
!= NULL
)
1747 domain
= find_auth_domain(state
->request
->flags
, domain_name
);
1749 if (domain
!= NULL
) {
1750 sendto_domain(state
, domain
);
1754 result
= NT_STATUS_NO_SUCH_USER
;
1757 set_auth_errors(state
->response
, result
);
1758 DEBUG(5, ("CRAP authentication for %s\\%s returned %s (PAM: %d)\n",
1759 state
->request
->data
.auth_crap
.domain
,
1760 state
->request
->data
.auth_crap
.user
,
1761 state
->response
->data
.auth
.nt_status_string
,
1762 state
->response
->data
.auth
.pam_error
));
1763 request_error(state
);
1768 enum winbindd_result
winbindd_dual_pam_auth_crap(struct winbindd_domain
*domain
,
1769 struct winbindd_cli_state
*state
)
1772 struct netr_SamInfo3
*info3
= NULL
;
1773 struct rpc_pipe_client
*netlogon_pipe
;
1774 const char *name_user
= NULL
;
1775 const char *name_domain
= NULL
;
1776 const char *workstation
;
1780 DATA_BLOB lm_resp
, nt_resp
;
1782 /* This is child-only, so no check for privileged access is needed
1785 /* Ensure null termination */
1786 state
->request
->data
.auth_crap
.user
[sizeof(state
->request
->data
.auth_crap
.user
)-1]=0;
1787 state
->request
->data
.auth_crap
.domain
[sizeof(state
->request
->data
.auth_crap
.domain
)-1]=0;
1789 if (!check_request_flags(state
->request
->flags
)) {
1790 result
= NT_STATUS_INVALID_PARAMETER_MIX
;
1794 name_user
= state
->request
->data
.auth_crap
.user
;
1796 if (*state
->request
->data
.auth_crap
.domain
) {
1797 name_domain
= state
->request
->data
.auth_crap
.domain
;
1798 } else if (lp_winbind_use_default_domain()) {
1799 name_domain
= lp_workgroup();
1801 DEBUG(5,("no domain specified with username (%s) - failing auth\n",
1803 result
= NT_STATUS_NO_SUCH_USER
;
1807 DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n", (unsigned long)state
->pid
,
1808 name_domain
, name_user
));
1810 if (*state
->request
->data
.auth_crap
.workstation
) {
1811 workstation
= state
->request
->data
.auth_crap
.workstation
;
1813 workstation
= global_myname();
1816 if (state
->request
->data
.auth_crap
.lm_resp_len
> sizeof(state
->request
->data
.auth_crap
.lm_resp
)
1817 || state
->request
->data
.auth_crap
.nt_resp_len
> sizeof(state
->request
->data
.auth_crap
.nt_resp
)) {
1818 if (!(state
->request
->flags
& WBFLAG_BIG_NTLMV2_BLOB
) ||
1819 state
->request
->extra_len
!= state
->request
->data
.auth_crap
.nt_resp_len
) {
1820 DEBUG(0, ("winbindd_pam_auth_crap: invalid password length %u/%u\n",
1821 state
->request
->data
.auth_crap
.lm_resp_len
,
1822 state
->request
->data
.auth_crap
.nt_resp_len
));
1823 result
= NT_STATUS_INVALID_PARAMETER
;
1828 lm_resp
= data_blob_talloc(state
->mem_ctx
, state
->request
->data
.auth_crap
.lm_resp
,
1829 state
->request
->data
.auth_crap
.lm_resp_len
);
1831 if (state
->request
->flags
& WBFLAG_BIG_NTLMV2_BLOB
) {
1832 nt_resp
= data_blob_talloc(state
->mem_ctx
,
1833 state
->request
->extra_data
.data
,
1834 state
->request
->data
.auth_crap
.nt_resp_len
);
1836 nt_resp
= data_blob_talloc(state
->mem_ctx
,
1837 state
->request
->data
.auth_crap
.nt_resp
,
1838 state
->request
->data
.auth_crap
.nt_resp_len
);
1841 if (strequal(name_domain
, get_global_sam_name())) {
1842 DATA_BLOB chal_blob
= data_blob_const(
1843 state
->request
->data
.auth_crap
.chal
,
1844 sizeof(state
->request
->data
.auth_crap
.chal
));
1846 result
= winbindd_dual_auth_passdb(
1847 state
->mem_ctx
, name_domain
, name_user
,
1848 &chal_blob
, &lm_resp
, &nt_resp
, &info3
);
1849 goto process_result
;
1853 netlogon_fn_t logon_fn
;
1857 netlogon_pipe
= NULL
;
1858 result
= cm_connect_netlogon(domain
, &netlogon_pipe
);
1860 if (!NT_STATUS_IS_OK(result
)) {
1861 DEBUG(3, ("could not open handle to NETLOGON pipe (error: %s)\n",
1862 nt_errstr(result
)));
1866 logon_fn
= domain
->can_do_samlogon_ex
1867 ? rpccli_netlogon_sam_network_logon_ex
1868 : rpccli_netlogon_sam_network_logon
;
1870 result
= logon_fn(netlogon_pipe
,
1872 state
->request
->data
.auth_crap
.logon_parameters
,
1876 /* Bug #3248 - found by Stefan Burkei. */
1877 workstation
, /* We carefully set this above so use it... */
1878 state
->request
->data
.auth_crap
.chal
,
1883 if ((NT_STATUS_V(result
) == DCERPC_FAULT_OP_RNG_ERROR
)
1884 && domain
->can_do_samlogon_ex
) {
1885 DEBUG(3, ("Got a DC that can not do NetSamLogonEx, "
1886 "retrying with NetSamLogon\n"));
1887 domain
->can_do_samlogon_ex
= false;
1894 /* We have to try a second time as cm_connect_netlogon
1895 might not yet have noticed that the DC has killed
1898 if (!rpccli_is_connected(netlogon_pipe
)) {
1903 /* if we get access denied, a possible cause was that we had and open
1904 connection to the DC, but someone changed our machine account password
1905 out from underneath us using 'net rpc changetrustpw' */
1907 if ( NT_STATUS_EQUAL(result
, NT_STATUS_ACCESS_DENIED
) ) {
1908 DEBUG(3,("winbindd_pam_auth: sam_logon returned "
1909 "ACCESS_DENIED. Maybe the trust account "
1910 "password was changed and we didn't know it. "
1911 "Killing connections to domain %s\n",
1913 invalidate_cm_connection(&domain
->conn
);
1917 } while ( (attempts
< 2) && retry
);
1921 if (NT_STATUS_IS_OK(result
)) {
1923 wcache_invalidate_samlogon(find_domain_from_name(name_domain
), info3
);
1924 netsamlogon_cache_store(name_user
, info3
);
1926 /* Check if the user is in the right group */
1928 result
= check_info3_in_group(
1930 state
->request
->data
.auth_crap
.require_membership_of_sid
);
1931 if (!NT_STATUS_IS_OK(result
)) {
1932 DEBUG(3, ("User %s is not in the required group (%s), so "
1933 "crap authentication is rejected\n",
1934 state
->request
->data
.auth_crap
.user
,
1935 state
->request
->data
.auth_crap
.require_membership_of_sid
));
1939 result
= append_auth_data(state
, info3
, name_domain
,
1941 if (!NT_STATUS_IS_OK(result
)) {
1948 /* give us a more useful (more correct?) error code */
1949 if ((NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ||
1950 (NT_STATUS_EQUAL(result
, NT_STATUS_UNSUCCESSFUL
)))) {
1951 result
= NT_STATUS_NO_LOGON_SERVERS
;
1954 if (state
->request
->flags
& WBFLAG_PAM_NT_STATUS_SQUASH
) {
1955 result
= nt_status_squash(result
);
1958 set_auth_errors(state
->response
, result
);
1960 DEBUG(NT_STATUS_IS_OK(result
) ? 5 : 2,
1961 ("NTLM CRAP authentication for user [%s]\\[%s] returned %s (PAM: %d)\n",
1964 state
->response
->data
.auth
.nt_status_string
,
1965 state
->response
->data
.auth
.pam_error
));
1967 return NT_STATUS_IS_OK(result
) ? WINBINDD_OK
: WINBINDD_ERROR
;
1970 /* Change a user password */
1972 void winbindd_pam_chauthtok(struct winbindd_cli_state
*state
)
1974 fstring domain
, user
;
1976 struct winbindd_domain
*contact_domain
;
1977 NTSTATUS nt_status
= NT_STATUS_UNSUCCESSFUL
;
1979 /* Ensure null termination */
1980 state
->request
->data
.chauthtok
.user
[
1981 sizeof(state
->request
->data
.chauthtok
.user
)-1]='\0';
1983 DEBUG(3, ("[%5lu]: pam chauthtok %s\n", (unsigned long)state
->pid
,
1984 state
->request
->data
.chauthtok
.user
));
1988 nt_status
= normalize_name_unmap(state
->mem_ctx
,
1989 state
->request
->data
.chauthtok
.user
,
1992 /* Update the chauthtok name if we did any mapping */
1994 if (NT_STATUS_IS_OK(nt_status
) ||
1995 NT_STATUS_EQUAL(nt_status
, NT_STATUS_FILE_RENAMED
))
1997 fstrcpy(state
->request
->data
.chauthtok
.user
, mapped_user
);
2000 /* Must pass in state->...chauthtok.user because
2001 canonicalize_username() assumes an fstring(). Since
2002 we have already copied it (if necessary), this is ok. */
2004 if (!canonicalize_username(state
->request
->data
.chauthtok
.user
, domain
, user
)) {
2005 set_auth_errors(state
->response
, NT_STATUS_NO_SUCH_USER
);
2006 DEBUG(5, ("winbindd_pam_chauthtok: canonicalize_username %s failed with %s"
2008 state
->request
->data
.chauthtok
.user
,
2009 state
->response
->data
.auth
.nt_status_string
,
2010 state
->response
->data
.auth
.pam_error
));
2011 request_error(state
);
2015 contact_domain
= find_domain_from_name(domain
);
2016 if (!contact_domain
) {
2017 set_auth_errors(state
->response
, NT_STATUS_NO_SUCH_USER
);
2018 DEBUG(3, ("Cannot change password for [%s] -> [%s]\\[%s] as %s is not a trusted domain\n",
2019 state
->request
->data
.chauthtok
.user
, domain
, user
, domain
));
2020 request_error(state
);
2024 sendto_domain(state
, contact_domain
);
2027 enum winbindd_result
winbindd_dual_pam_chauthtok(struct winbindd_domain
*contact_domain
,
2028 struct winbindd_cli_state
*state
)
2031 char *newpass
= NULL
;
2032 struct policy_handle dom_pol
;
2033 struct rpc_pipe_client
*cli
;
2034 bool got_info
= false;
2035 struct samr_DomInfo1
*info
= NULL
;
2036 struct userPwdChangeFailureInformation
*reject
= NULL
;
2037 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
2038 fstring domain
, user
;
2040 DEBUG(3, ("[%5lu]: dual pam chauthtok %s\n", (unsigned long)state
->pid
,
2041 state
->request
->data
.auth
.user
));
2043 if (!parse_domain_user(state
->request
->data
.chauthtok
.user
, domain
, user
)) {
2047 /* Change password */
2049 oldpass
= state
->request
->data
.chauthtok
.oldpass
;
2050 newpass
= state
->request
->data
.chauthtok
.newpass
;
2052 /* Initialize reject reason */
2053 state
->response
->data
.auth
.reject_reason
= Undefined
;
2055 /* Get sam handle */
2057 result
= cm_connect_sam(contact_domain
, state
->mem_ctx
, &cli
,
2059 if (!NT_STATUS_IS_OK(result
)) {
2060 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain
));
2064 result
= rpccli_samr_chgpasswd_user3(cli
, state
->mem_ctx
,
2071 /* Windows 2003 returns NT_STATUS_PASSWORD_RESTRICTION */
2073 if (NT_STATUS_EQUAL(result
, NT_STATUS_PASSWORD_RESTRICTION
) ) {
2075 fill_in_password_policy(state
->response
, info
);
2077 state
->response
->data
.auth
.reject_reason
=
2078 reject
->extendedFailureReason
;
2083 /* atm the pidl generated rpccli_samr_ChangePasswordUser3 function will
2084 * return with NT_STATUS_BUFFER_TOO_SMALL for w2k dcs as w2k just
2085 * returns with 4byte error code (NT_STATUS_NOT_SUPPORTED) which is too
2086 * short to comply with the samr_ChangePasswordUser3 idl - gd */
2088 /* only fallback when the chgpasswd_user3 call is not supported */
2089 if ((NT_STATUS_EQUAL(result
, NT_STATUS(DCERPC_FAULT_OP_RNG_ERROR
))) ||
2090 (NT_STATUS_EQUAL(result
, NT_STATUS_NOT_SUPPORTED
)) ||
2091 (NT_STATUS_EQUAL(result
, NT_STATUS_BUFFER_TOO_SMALL
)) ||
2092 (NT_STATUS_EQUAL(result
, NT_STATUS_NOT_IMPLEMENTED
))) {
2094 DEBUG(10,("Password change with chgpasswd_user3 failed with: %s, retrying chgpasswd_user2\n",
2095 nt_errstr(result
)));
2097 result
= rpccli_samr_chgpasswd_user2(cli
, state
->mem_ctx
, user
, newpass
, oldpass
);
2099 /* Windows 2000 returns NT_STATUS_ACCOUNT_RESTRICTION.
2100 Map to the same status code as Windows 2003. */
2102 if ( NT_STATUS_EQUAL(NT_STATUS_ACCOUNT_RESTRICTION
, result
) ) {
2103 result
= NT_STATUS_PASSWORD_RESTRICTION
;
2109 if (NT_STATUS_IS_OK(result
) && (state
->request
->flags
& WBFLAG_PAM_CACHED_LOGIN
)) {
2111 /* Update the single sign-on memory creds. */
2112 result
= winbindd_replace_memory_creds(state
->request
->data
.chauthtok
.user
,
2115 /* When we login from gdm or xdm and password expires,
2116 * we change password, but there are no memory crendentials
2117 * So, winbindd_replace_memory_creds() returns
2118 * NT_STATUS_OBJECT_NAME_NOT_FOUND. This is not a failure.
2121 if (NT_STATUS_EQUAL(result
, NT_STATUS_OBJECT_NAME_NOT_FOUND
)) {
2122 result
= NT_STATUS_OK
;
2125 if (!NT_STATUS_IS_OK(result
)) {
2126 DEBUG(10,("Failed to replace memory creds: %s\n", nt_errstr(result
)));
2127 goto process_result
;
2130 if (lp_winbind_offline_logon()) {
2131 result
= winbindd_update_creds_by_name(contact_domain
,
2132 state
->mem_ctx
, user
,
2134 /* Again, this happens when we login from gdm or xdm
2135 * and the password expires, *BUT* cached crendentials
2136 * doesn't exist. winbindd_update_creds_by_name()
2137 * returns NT_STATUS_NO_SUCH_USER.
2138 * This is not a failure.
2141 if (NT_STATUS_EQUAL(result
, NT_STATUS_NO_SUCH_USER
)) {
2142 result
= NT_STATUS_OK
;
2145 if (!NT_STATUS_IS_OK(result
)) {
2146 DEBUG(10,("Failed to store creds: %s\n", nt_errstr(result
)));
2147 goto process_result
;
2152 if (!NT_STATUS_IS_OK(result
) && !got_info
&& contact_domain
) {
2154 NTSTATUS policy_ret
;
2156 policy_ret
= fillup_password_policy(contact_domain
, state
);
2158 /* failure of this is non critical, it will just provide no
2159 * additional information to the client why the change has
2160 * failed - Guenther */
2162 if (!NT_STATUS_IS_OK(policy_ret
)) {
2163 DEBUG(10,("Failed to get password policies: %s\n", nt_errstr(policy_ret
)));
2164 goto process_result
;
2170 set_auth_errors(state
->response
, result
);
2172 DEBUG(NT_STATUS_IS_OK(result
) ? 5 : 2,
2173 ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
2176 state
->response
->data
.auth
.nt_status_string
,
2177 state
->response
->data
.auth
.pam_error
));
2179 return NT_STATUS_IS_OK(result
) ? WINBINDD_OK
: WINBINDD_ERROR
;
2182 void winbindd_pam_logoff(struct winbindd_cli_state
*state
)
2184 struct winbindd_domain
*domain
;
2185 fstring name_domain
, user
;
2186 uid_t caller_uid
= (uid_t
)-1;
2187 uid_t request_uid
= state
->request
->data
.logoff
.uid
;
2189 /* Ensure null termination */
2190 state
->request
->data
.logoff
.user
2191 [sizeof(state
->request
->data
.logoff
.user
)-1]='\0';
2193 state
->request
->data
.logoff
.krb5ccname
2194 [sizeof(state
->request
->data
.logoff
.krb5ccname
)-1]='\0';
2196 DEBUG(3, ("[%5lu]: pam logoff %s\n", (unsigned long)state
->pid
,
2197 state
->request
->data
.logoff
.user
));
2199 if (request_uid
== (uid_t
)-1) {
2203 if (!canonicalize_username(state
->request
->data
.logoff
.user
, name_domain
, user
)) {
2207 if ((domain
= find_auth_domain(state
->request
->flags
,
2208 name_domain
)) == NULL
) {
2212 if ((sys_getpeereid(state
->sock
, &caller_uid
)) != 0) {
2213 DEBUG(1,("winbindd_pam_logoff: failed to check peerid: %s\n",
2218 switch (caller_uid
) {
2222 /* root must be able to logoff any user - gd */
2223 state
->request
->data
.logoff
.uid
= request_uid
;
2226 if (caller_uid
!= request_uid
) {
2227 DEBUG(1,("winbindd_pam_logoff: caller requested invalid uid\n"));
2230 state
->request
->data
.logoff
.uid
= caller_uid
;
2234 sendto_domain(state
, domain
);
2238 set_auth_errors(state
->response
, NT_STATUS_NO_SUCH_USER
);
2239 DEBUG(5, ("Pam Logoff for %s returned %s "
2241 state
->request
->data
.logoff
.user
,
2242 state
->response
->data
.auth
.nt_status_string
,
2243 state
->response
->data
.auth
.pam_error
));
2244 request_error(state
);
2248 enum winbindd_result
winbindd_dual_pam_logoff(struct winbindd_domain
*domain
,
2249 struct winbindd_cli_state
*state
)
2251 NTSTATUS result
= NT_STATUS_NOT_SUPPORTED
;
2253 DEBUG(3, ("[%5lu]: pam dual logoff %s\n", (unsigned long)state
->pid
,
2254 state
->request
->data
.logoff
.user
));
2256 if (!(state
->request
->flags
& WBFLAG_PAM_KRB5
)) {
2257 result
= NT_STATUS_OK
;
2258 goto process_result
;
2261 if (state
->request
->data
.logoff
.krb5ccname
[0] == '\0') {
2262 result
= NT_STATUS_OK
;
2263 goto process_result
;
2268 if (state
->request
->data
.logoff
.uid
< 0) {
2269 DEBUG(0,("winbindd_pam_logoff: invalid uid\n"));
2270 goto process_result
;
2273 /* what we need here is to find the corresponding krb5 ccache name *we*
2274 * created for a given username and destroy it */
2276 if (!ccache_entry_exists(state
->request
->data
.logoff
.user
)) {
2277 result
= NT_STATUS_OK
;
2278 DEBUG(10,("winbindd_pam_logoff: no entry found.\n"));
2279 goto process_result
;
2282 if (!ccache_entry_identical(state
->request
->data
.logoff
.user
,
2283 state
->request
->data
.logoff
.uid
,
2284 state
->request
->data
.logoff
.krb5ccname
)) {
2285 DEBUG(0,("winbindd_pam_logoff: cached entry differs.\n"));
2286 goto process_result
;
2289 result
= remove_ccache(state
->request
->data
.logoff
.user
);
2290 if (!NT_STATUS_IS_OK(result
)) {
2291 DEBUG(0,("winbindd_pam_logoff: failed to remove ccache: %s\n",
2292 nt_errstr(result
)));
2293 goto process_result
;
2297 result
= NT_STATUS_NOT_SUPPORTED
;
2302 winbindd_delete_memory_creds(state
->request
->data
.logoff
.user
);
2304 set_auth_errors(state
->response
, result
);
2306 return NT_STATUS_IS_OK(result
) ? WINBINDD_OK
: WINBINDD_ERROR
;
2309 /* Change user password with auth crap*/
2311 void winbindd_pam_chng_pswd_auth_crap(struct winbindd_cli_state
*state
)
2313 struct winbindd_domain
*domain
= NULL
;
2314 const char *domain_name
= NULL
;
2316 /* Ensure null termination */
2317 state
->request
->data
.chng_pswd_auth_crap
.user
[
2318 sizeof(state
->request
->data
.chng_pswd_auth_crap
.user
)-1]=0;
2319 state
->request
->data
.chng_pswd_auth_crap
.domain
[
2320 sizeof(state
->request
->data
.chng_pswd_auth_crap
.domain
)-1]=0;
2322 DEBUG(3, ("[%5lu]: pam change pswd auth crap domain: %s user: %s\n",
2323 (unsigned long)state
->pid
,
2324 state
->request
->data
.chng_pswd_auth_crap
.domain
,
2325 state
->request
->data
.chng_pswd_auth_crap
.user
));
2327 if (*state
->request
->data
.chng_pswd_auth_crap
.domain
!= '\0') {
2328 domain_name
= state
->request
->data
.chng_pswd_auth_crap
.domain
;
2329 } else if (lp_winbind_use_default_domain()) {
2330 domain_name
= lp_workgroup();
2333 if (domain_name
!= NULL
)
2334 domain
= find_domain_from_name(domain_name
);
2336 if (domain
!= NULL
) {
2337 DEBUG(7, ("[%5lu]: pam auth crap changing pswd in domain: "
2338 "%s\n", (unsigned long)state
->pid
,domain
->name
));
2339 sendto_domain(state
, domain
);
2343 set_auth_errors(state
->response
, NT_STATUS_NO_SUCH_USER
);
2344 DEBUG(5, ("CRAP change password for %s\\%s returned %s (PAM: %d)\n",
2345 state
->request
->data
.chng_pswd_auth_crap
.domain
,
2346 state
->request
->data
.chng_pswd_auth_crap
.user
,
2347 state
->response
->data
.auth
.nt_status_string
,
2348 state
->response
->data
.auth
.pam_error
));
2349 request_error(state
);
2353 enum winbindd_result
winbindd_dual_pam_chng_pswd_auth_crap(struct winbindd_domain
*domainSt
, struct winbindd_cli_state
*state
)
2356 DATA_BLOB new_nt_password
;
2357 DATA_BLOB old_nt_hash_enc
;
2358 DATA_BLOB new_lm_password
;
2359 DATA_BLOB old_lm_hash_enc
;
2360 fstring domain
,user
;
2361 struct policy_handle dom_pol
;
2362 struct winbindd_domain
*contact_domain
= domainSt
;
2363 struct rpc_pipe_client
*cli
;
2365 /* Ensure null termination */
2366 state
->request
->data
.chng_pswd_auth_crap
.user
[
2367 sizeof(state
->request
->data
.chng_pswd_auth_crap
.user
)-1]=0;
2368 state
->request
->data
.chng_pswd_auth_crap
.domain
[
2369 sizeof(state
->request
->data
.chng_pswd_auth_crap
.domain
)-1]=0;
2373 DEBUG(3, ("[%5lu]: pam change pswd auth crap domain: %s user: %s\n",
2374 (unsigned long)state
->pid
,
2375 state
->request
->data
.chng_pswd_auth_crap
.domain
,
2376 state
->request
->data
.chng_pswd_auth_crap
.user
));
2378 if (lp_winbind_offline_logon()) {
2379 DEBUG(0,("Refusing password change as winbind offline logons are enabled. "));
2380 DEBUGADD(0,("Changing passwords here would risk inconsistent logons\n"));
2381 result
= NT_STATUS_ACCESS_DENIED
;
2385 if (*state
->request
->data
.chng_pswd_auth_crap
.domain
) {
2386 fstrcpy(domain
,state
->request
->data
.chng_pswd_auth_crap
.domain
);
2388 parse_domain_user(state
->request
->data
.chng_pswd_auth_crap
.user
,
2392 DEBUG(3,("no domain specified with username (%s) - "
2394 state
->request
->data
.chng_pswd_auth_crap
.user
));
2395 result
= NT_STATUS_NO_SUCH_USER
;
2400 if (!*domain
&& lp_winbind_use_default_domain()) {
2401 fstrcpy(domain
,(char *)lp_workgroup());
2405 fstrcpy(user
, state
->request
->data
.chng_pswd_auth_crap
.user
);
2408 DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n",
2409 (unsigned long)state
->pid
, domain
, user
));
2411 /* Change password */
2412 new_nt_password
= data_blob_talloc(
2414 state
->request
->data
.chng_pswd_auth_crap
.new_nt_pswd
,
2415 state
->request
->data
.chng_pswd_auth_crap
.new_nt_pswd_len
);
2417 old_nt_hash_enc
= data_blob_talloc(
2419 state
->request
->data
.chng_pswd_auth_crap
.old_nt_hash_enc
,
2420 state
->request
->data
.chng_pswd_auth_crap
.old_nt_hash_enc_len
);
2422 if(state
->request
->data
.chng_pswd_auth_crap
.new_lm_pswd_len
> 0) {
2423 new_lm_password
= data_blob_talloc(
2425 state
->request
->data
.chng_pswd_auth_crap
.new_lm_pswd
,
2426 state
->request
->data
.chng_pswd_auth_crap
.new_lm_pswd_len
);
2428 old_lm_hash_enc
= data_blob_talloc(
2430 state
->request
->data
.chng_pswd_auth_crap
.old_lm_hash_enc
,
2431 state
->request
->data
.chng_pswd_auth_crap
.old_lm_hash_enc_len
);
2433 new_lm_password
.length
= 0;
2434 old_lm_hash_enc
.length
= 0;
2437 /* Get sam handle */
2439 result
= cm_connect_sam(contact_domain
, state
->mem_ctx
, &cli
, &dom_pol
);
2440 if (!NT_STATUS_IS_OK(result
)) {
2441 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain
));
2445 result
= rpccli_samr_chng_pswd_auth_crap(
2446 cli
, state
->mem_ctx
, user
, new_nt_password
, old_nt_hash_enc
,
2447 new_lm_password
, old_lm_hash_enc
);
2451 set_auth_errors(state
->response
, result
);
2453 DEBUG(NT_STATUS_IS_OK(result
) ? 5 : 2,
2454 ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
2456 state
->response
->data
.auth
.nt_status_string
,
2457 state
->response
->data
.auth
.pam_error
));
2459 return NT_STATUS_IS_OK(result
) ? WINBINDD_OK
: WINBINDD_ERROR
;