2 Unix SMB/CIFS implementation.
4 Winbind daemon - pam auth funcions
6 Copyright (C) Andrew Tridgell 2000
7 Copyright (C) Tim Potter 2001
8 Copyright (C) Andrew Bartlett 2001-2002
9 Copyright (C) Guenther Deschner 2005
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 #include "../libcli/auth/libcli_auth.h"
28 #include "../librpc/gen_ndr/ndr_samr_c.h"
29 #include "rpc_client/cli_pipe.h"
30 #include "rpc_client/cli_samr.h"
31 #include "../librpc/gen_ndr/ndr_netlogon.h"
32 #include "rpc_client/cli_netlogon.h"
34 #include "../lib/crypto/arcfour.h"
35 #include "../libcli/security/security.h"
37 #include "../librpc/gen_ndr/krb5pac.h"
38 #include "passdb/machine_sid.h"
41 #define DBGC_CLASS DBGC_WINBIND
43 #define LOGON_KRB5_FAIL_CLOCK_SKEW 0x02000000
45 static NTSTATUS append_info3_as_txt(TALLOC_CTX *mem_ctx,
46 struct winbindd_response *resp,
47 struct netr_SamInfo3 *info3)
52 resp->data.auth.info3.logon_time =
53 nt_time_to_unix(info3->base.last_logon);
54 resp->data.auth.info3.logoff_time =
55 nt_time_to_unix(info3->base.last_logoff);
56 resp->data.auth.info3.kickoff_time =
57 nt_time_to_unix(info3->base.acct_expiry);
58 resp->data.auth.info3.pass_last_set_time =
59 nt_time_to_unix(info3->base.last_password_change);
60 resp->data.auth.info3.pass_can_change_time =
61 nt_time_to_unix(info3->base.allow_password_change);
62 resp->data.auth.info3.pass_must_change_time =
63 nt_time_to_unix(info3->base.force_password_change);
65 resp->data.auth.info3.logon_count = info3->base.logon_count;
66 resp->data.auth.info3.bad_pw_count = info3->base.bad_password_count;
68 resp->data.auth.info3.user_rid = info3->base.rid;
69 resp->data.auth.info3.group_rid = info3->base.primary_gid;
70 sid_to_fstring(resp->data.auth.info3.dom_sid, info3->base.domain_sid);
72 resp->data.auth.info3.num_groups = info3->base.groups.count;
73 resp->data.auth.info3.user_flgs = info3->base.user_flags;
75 resp->data.auth.info3.acct_flags = info3->base.acct_flags;
76 resp->data.auth.info3.num_other_sids = info3->sidcount;
78 fstrcpy(resp->data.auth.info3.user_name,
79 info3->base.account_name.string);
80 fstrcpy(resp->data.auth.info3.full_name,
81 info3->base.full_name.string);
82 fstrcpy(resp->data.auth.info3.logon_script,
83 info3->base.logon_script.string);
84 fstrcpy(resp->data.auth.info3.profile_path,
85 info3->base.profile_path.string);
86 fstrcpy(resp->data.auth.info3.home_dir,
87 info3->base.home_directory.string);
88 fstrcpy(resp->data.auth.info3.dir_drive,
89 info3->base.home_drive.string);
91 fstrcpy(resp->data.auth.info3.logon_srv,
92 info3->base.logon_server.string);
93 fstrcpy(resp->data.auth.info3.logon_dom,
94 info3->base.domain.string);
96 ex = talloc_strdup(mem_ctx, "");
97 NT_STATUS_HAVE_NO_MEMORY(ex);
99 for (i=0; i < info3->base.groups.count; i++) {
100 ex = talloc_asprintf_append_buffer(ex, "0x%08X:0x%08X\n",
101 info3->base.groups.rids[i].rid,
102 info3->base.groups.rids[i].attributes);
103 NT_STATUS_HAVE_NO_MEMORY(ex);
106 for (i=0; i < info3->sidcount; i++) {
109 sid = dom_sid_string(mem_ctx, info3->sids[i].sid);
110 NT_STATUS_HAVE_NO_MEMORY(sid);
112 ex = talloc_asprintf_append_buffer(ex, "%s:0x%08X\n",
114 info3->sids[i].attributes);
115 NT_STATUS_HAVE_NO_MEMORY(ex);
120 resp->extra_data.data = ex;
121 resp->length += talloc_get_size(ex);
126 static NTSTATUS append_info3_as_ndr(TALLOC_CTX *mem_ctx,
127 struct winbindd_response *resp,
128 struct netr_SamInfo3 *info3)
131 enum ndr_err_code ndr_err;
133 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, info3,
134 (ndr_push_flags_fn_t)ndr_push_netr_SamInfo3);
135 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
136 DEBUG(0,("append_info3_as_ndr: failed to append\n"));
137 return ndr_map_error2ntstatus(ndr_err);
140 resp->extra_data.data = blob.data;
141 resp->length += blob.length;
146 static NTSTATUS append_unix_username(TALLOC_CTX *mem_ctx,
147 struct winbindd_response *resp,
148 const struct netr_SamInfo3 *info3,
149 const char *name_domain,
150 const char *name_user)
152 /* We've been asked to return the unix username, per
153 'winbind use default domain' settings and the like */
155 const char *nt_username, *nt_domain;
157 nt_domain = talloc_strdup(mem_ctx, info3->base.domain.string);
159 /* If the server didn't give us one, just use the one
161 nt_domain = name_domain;
164 nt_username = talloc_strdup(mem_ctx, info3->base.account_name.string);
166 /* If the server didn't give us one, just use the one
168 nt_username = name_user;
171 fill_domain_username(resp->data.auth.unix_username,
172 nt_domain, nt_username, true);
174 DEBUG(5, ("Setting unix username to [%s]\n",
175 resp->data.auth.unix_username));
180 static NTSTATUS append_afs_token(TALLOC_CTX *mem_ctx,
181 struct winbindd_response *resp,
182 const struct netr_SamInfo3 *info3,
183 const char *name_domain,
184 const char *name_user)
186 char *afsname = NULL;
190 afsname = talloc_strdup(mem_ctx, lp_afs_username_map());
191 if (afsname == NULL) {
192 return NT_STATUS_NO_MEMORY;
195 afsname = talloc_string_sub(mem_ctx,
196 lp_afs_username_map(),
198 afsname = talloc_string_sub(mem_ctx, afsname,
200 afsname = talloc_string_sub(mem_ctx, afsname,
204 struct dom_sid user_sid;
207 sid_compose(&user_sid, info3->base.domain_sid,
209 sid_to_fstring(sidstr, &user_sid);
210 afsname = talloc_string_sub(mem_ctx, afsname,
214 if (afsname == NULL) {
215 return NT_STATUS_NO_MEMORY;
220 DEBUG(10, ("Generating token for user %s\n", afsname));
222 cell = strchr(afsname, '@');
225 return NT_STATUS_NO_MEMORY;
231 token = afs_createtoken_str(afsname, cell);
235 resp->extra_data.data = talloc_strdup(mem_ctx, token);
236 if (resp->extra_data.data == NULL) {
237 return NT_STATUS_NO_MEMORY;
239 resp->length += strlen((const char *)resp->extra_data.data)+1;
244 static NTSTATUS check_info3_in_group(struct netr_SamInfo3 *info3,
245 const char *group_sid)
247 * Check whether a user belongs to a group or list of groups.
249 * @param mem_ctx talloc memory context.
250 * @param info3 user information, including group membership info.
251 * @param group_sid One or more groups , separated by commas.
253 * @return NT_STATUS_OK on success,
254 * NT_STATUS_LOGON_FAILURE if the user does not belong,
255 * or other NT_STATUS_IS_ERR(status) for other kinds of failure.
258 struct dom_sid *require_membership_of_sid;
259 uint32_t num_require_membership_of_sid;
264 struct security_token *token;
265 TALLOC_CTX *frame = talloc_stackframe();
268 /* Parse the 'required group' SID */
270 if (!group_sid || !group_sid[0]) {
271 /* NO sid supplied, all users may access */
275 token = talloc_zero(talloc_tos(), struct security_token);
277 DEBUG(0, ("talloc failed\n"));
279 return NT_STATUS_NO_MEMORY;
282 num_require_membership_of_sid = 0;
283 require_membership_of_sid = NULL;
287 while (next_token_talloc(talloc_tos(), &p, &req_sid, ",")) {
288 if (!string_to_sid(&sid, req_sid)) {
289 DEBUG(0, ("check_info3_in_group: could not parse %s "
290 "as a SID!", req_sid));
292 return NT_STATUS_INVALID_PARAMETER;
295 status = add_sid_to_array(talloc_tos(), &sid,
296 &require_membership_of_sid,
297 &num_require_membership_of_sid);
298 if (!NT_STATUS_IS_OK(status)) {
299 DEBUG(0, ("add_sid_to_array failed\n"));
305 status = sid_array_from_info3(talloc_tos(), info3,
309 if (!NT_STATUS_IS_OK(status)) {
314 if (!NT_STATUS_IS_OK(status = add_aliases(get_global_sam_sid(),
316 || !NT_STATUS_IS_OK(status = add_aliases(&global_sid_Builtin,
318 DEBUG(3, ("could not add aliases: %s\n",
324 security_token_debug(DBGC_CLASS, 10, token);
326 for (i=0; i<num_require_membership_of_sid; i++) {
327 DEBUG(10, ("Checking SID %s\n", sid_string_dbg(
328 &require_membership_of_sid[i])));
329 if (nt_token_check_sid(&require_membership_of_sid[i],
331 DEBUG(10, ("Access ok\n"));
337 /* Do not distinguish this error from a wrong username/pw */
340 return NT_STATUS_LOGON_FAILURE;
343 struct winbindd_domain *find_auth_domain(uint8_t flags,
344 const char *domain_name)
346 struct winbindd_domain *domain;
349 domain = find_domain_from_name_noinit(domain_name);
350 if (domain == NULL) {
351 DEBUG(3, ("Authentication for domain [%s] refused "
352 "as it is not a trusted domain\n",
358 if (strequal(domain_name, get_global_sam_name())) {
359 return find_domain_from_name_noinit(domain_name);
362 /* we can auth against trusted domains */
363 if (flags & WBFLAG_PAM_CONTACT_TRUSTDOM) {
364 domain = find_domain_from_name_noinit(domain_name);
365 if (domain == NULL) {
366 DEBUG(3, ("Authentication for domain [%s] skipped "
367 "as it is not a trusted domain\n",
374 return find_our_domain();
377 static void fill_in_password_policy(struct winbindd_response *r,
378 const struct samr_DomInfo1 *p)
380 r->data.auth.policy.min_length_password =
381 p->min_password_length;
382 r->data.auth.policy.password_history =
383 p->password_history_length;
384 r->data.auth.policy.password_properties =
385 p->password_properties;
386 r->data.auth.policy.expire =
387 nt_time_to_unix_abs((NTTIME *)&(p->max_password_age));
388 r->data.auth.policy.min_passwordage =
389 nt_time_to_unix_abs((NTTIME *)&(p->min_password_age));
392 static NTSTATUS fillup_password_policy(struct winbindd_domain *domain,
393 struct winbindd_response *response)
395 TALLOC_CTX *frame = talloc_stackframe();
396 struct winbindd_methods *methods;
398 struct samr_DomInfo1 password_policy;
400 if ( !winbindd_can_contact_domain( domain ) ) {
401 DEBUG(5,("fillup_password_policy: No inbound trust to "
402 "contact domain %s\n", domain->name));
403 status = NT_STATUS_NOT_SUPPORTED;
407 methods = domain->methods;
409 status = methods->password_policy(domain, talloc_tos(), &password_policy);
410 if (NT_STATUS_IS_ERR(status)) {
414 fill_in_password_policy(response, &password_policy);
421 static NTSTATUS get_max_bad_attempts_from_lockout_policy(struct winbindd_domain *domain,
423 uint16 *lockout_threshold)
425 struct winbindd_methods *methods;
426 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
427 struct samr_DomInfo12 lockout_policy;
429 *lockout_threshold = 0;
431 methods = domain->methods;
433 status = methods->lockout_policy(domain, mem_ctx, &lockout_policy);
434 if (NT_STATUS_IS_ERR(status)) {
438 *lockout_threshold = lockout_policy.lockout_threshold;
443 static NTSTATUS get_pwd_properties(struct winbindd_domain *domain,
445 uint32 *password_properties)
447 struct winbindd_methods *methods;
448 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
449 struct samr_DomInfo1 password_policy;
451 *password_properties = 0;
453 methods = domain->methods;
455 status = methods->password_policy(domain, mem_ctx, &password_policy);
456 if (NT_STATUS_IS_ERR(status)) {
460 *password_properties = password_policy.password_properties;
467 static const char *generate_krb5_ccache(TALLOC_CTX *mem_ctx,
470 const char **user_ccache_file)
472 /* accept FILE and WRFILE as krb5_cc_type from the client and then
473 * build the full ccname string based on the user's uid here -
476 const char *gen_cc = NULL;
479 if (strequal(type, "FILE")) {
480 gen_cc = talloc_asprintf(
481 mem_ctx, "FILE:/tmp/krb5cc_%d", uid);
483 if (strequal(type, "WRFILE")) {
484 gen_cc = talloc_asprintf(
485 mem_ctx, "WRFILE:/tmp/krb5cc_%d", uid);
489 *user_ccache_file = gen_cc;
491 if (gen_cc == NULL) {
492 gen_cc = talloc_strdup(mem_ctx, "MEMORY:winbindd_pam_ccache");
494 if (gen_cc == NULL) {
495 DEBUG(0,("out of memory\n"));
499 DEBUG(10, ("using ccache: %s%s\n", gen_cc,
500 (*user_ccache_file == NULL) ? " (internal)":""));
507 uid_t get_uid_from_request(struct winbindd_request *request)
511 uid = request->data.auth.uid;
514 DEBUG(1,("invalid uid: '%u'\n", (unsigned int)uid));
520 /**********************************************************************
521 Authenticate a user with a clear text password using Kerberos and fill up
523 **********************************************************************/
525 static NTSTATUS winbindd_raw_kerberos_login(TALLOC_CTX *mem_ctx,
526 struct winbindd_domain *domain,
529 const char *krb5_cc_type,
531 struct netr_SamInfo3 **info3,
535 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
536 krb5_error_code krb5_ret;
537 const char *cc = NULL;
538 const char *principal_s = NULL;
539 const char *service = NULL;
541 fstring name_domain, name_user;
542 time_t ticket_lifetime = 0;
543 time_t renewal_until = 0;
545 time_t time_offset = 0;
546 const char *user_ccache_file;
547 struct PAC_LOGON_INFO *logon_info = NULL;
552 * prepare a krb5_cc_cache string for the user */
555 DEBUG(0,("no valid uid\n"));
558 cc = generate_krb5_ccache(mem_ctx,
563 return NT_STATUS_NO_MEMORY;
568 * get kerberos properties */
570 if (domain->private_data) {
571 ads = (ADS_STRUCT *)domain->private_data;
572 time_offset = ads->auth.time_offset;
577 * do kerberos auth and setup ccache as the user */
579 parse_domain_user(user, name_domain, name_user);
581 realm = domain->alt_name;
584 principal_s = talloc_asprintf(mem_ctx, "%s@%s", name_user, realm);
585 if (principal_s == NULL) {
586 return NT_STATUS_NO_MEMORY;
589 service = talloc_asprintf(mem_ctx, "%s/%s@%s", KRB5_TGS_NAME, realm, realm);
590 if (service == NULL) {
591 return NT_STATUS_NO_MEMORY;
594 /* if this is a user ccache, we need to act as the user to let the krb5
595 * library handle the chown, etc. */
597 /************************ ENTERING NON-ROOT **********************/
599 if (user_ccache_file != NULL) {
600 set_effective_uid(uid);
601 DEBUG(10,("winbindd_raw_kerberos_login: uid is %d\n", uid));
604 result = kerberos_return_pac(mem_ctx,
613 WINBINDD_PAM_AUTH_KRB5_RENEW_TIME,
616 if (user_ccache_file != NULL) {
617 gain_root_privilege();
620 /************************ RETURNED TO ROOT **********************/
622 if (!NT_STATUS_IS_OK(result)) {
626 *info3 = &logon_info->info3;
628 DEBUG(10,("winbindd_raw_kerberos_login: winbindd validated ticket of %s\n",
631 /* if we had a user's ccache then return that string for the pam
634 if (user_ccache_file != NULL) {
636 fstrcpy(krb5ccname, user_ccache_file);
638 result = add_ccache_to_list(principal_s,
649 if (!NT_STATUS_IS_OK(result)) {
650 DEBUG(10,("winbindd_raw_kerberos_login: failed to add ccache to list: %s\n",
655 /* need to delete the memory cred cache, it is not used anymore */
657 krb5_ret = ads_kdestroy(cc);
659 DEBUG(3,("winbindd_raw_kerberos_login: "
660 "could not destroy krb5 credential cache: "
661 "%s\n", error_message(krb5_ret)));
670 /* we could have created a new credential cache with a valid tgt in it
671 * but we werent able to get or verify the service ticket for this
672 * local host and therefor didn't get the PAC, we need to remove that
673 * cache entirely now */
675 krb5_ret = ads_kdestroy(cc);
677 DEBUG(3,("winbindd_raw_kerberos_login: "
678 "could not destroy krb5 credential cache: "
679 "%s\n", error_message(krb5_ret)));
682 if (!NT_STATUS_IS_OK(remove_ccache(user))) {
683 DEBUG(3,("winbindd_raw_kerberos_login: "
684 "could not remove ccache for user %s\n",
690 return NT_STATUS_NOT_SUPPORTED;
691 #endif /* HAVE_KRB5 */
694 /****************************************************************
695 ****************************************************************/
697 bool check_request_flags(uint32_t flags)
699 uint32_t flags_edata = WBFLAG_PAM_AFS_TOKEN |
700 WBFLAG_PAM_INFO3_TEXT |
701 WBFLAG_PAM_INFO3_NDR;
703 if ( ( (flags & flags_edata) == WBFLAG_PAM_AFS_TOKEN) ||
704 ( (flags & flags_edata) == WBFLAG_PAM_INFO3_NDR) ||
705 ( (flags & flags_edata) == WBFLAG_PAM_INFO3_TEXT)||
706 !(flags & flags_edata) ) {
710 DEBUG(1, ("check_request_flags: invalid request flags[0x%08X]\n",
716 /****************************************************************
717 ****************************************************************/
719 static NTSTATUS append_auth_data(TALLOC_CTX *mem_ctx,
720 struct winbindd_response *resp,
721 uint32_t request_flags,
722 struct netr_SamInfo3 *info3,
723 const char *name_domain,
724 const char *name_user)
728 if (request_flags & WBFLAG_PAM_USER_SESSION_KEY) {
729 memcpy(resp->data.auth.user_session_key,
731 sizeof(resp->data.auth.user_session_key)
735 if (request_flags & WBFLAG_PAM_LMKEY) {
736 memcpy(resp->data.auth.first_8_lm_hash,
737 info3->base.LMSessKey.key,
738 sizeof(resp->data.auth.first_8_lm_hash)
742 if (request_flags & WBFLAG_PAM_UNIX_NAME) {
743 result = append_unix_username(mem_ctx, resp,
744 info3, name_domain, name_user);
745 if (!NT_STATUS_IS_OK(result)) {
746 DEBUG(10,("Failed to append Unix Username: %s\n",
752 /* currently, anything from here on potentially overwrites extra_data. */
754 if (request_flags & WBFLAG_PAM_INFO3_NDR) {
755 result = append_info3_as_ndr(mem_ctx, resp, info3);
756 if (!NT_STATUS_IS_OK(result)) {
757 DEBUG(10,("Failed to append INFO3 (NDR): %s\n",
763 if (request_flags & WBFLAG_PAM_INFO3_TEXT) {
764 result = append_info3_as_txt(mem_ctx, resp, info3);
765 if (!NT_STATUS_IS_OK(result)) {
766 DEBUG(10,("Failed to append INFO3 (TXT): %s\n",
772 if (request_flags & WBFLAG_PAM_AFS_TOKEN) {
773 result = append_afs_token(mem_ctx, resp,
774 info3, name_domain, name_user);
775 if (!NT_STATUS_IS_OK(result)) {
776 DEBUG(10,("Failed to append AFS token: %s\n",
785 static NTSTATUS winbindd_dual_pam_auth_cached(struct winbindd_domain *domain,
786 struct winbindd_cli_state *state,
787 struct netr_SamInfo3 **info3)
789 NTSTATUS result = NT_STATUS_LOGON_FAILURE;
790 uint16 max_allowed_bad_attempts;
791 fstring name_domain, name_user;
793 enum lsa_SidType type;
794 uchar new_nt_pass[NT_HASH_LEN];
795 const uint8 *cached_nt_pass;
796 const uint8 *cached_salt;
797 struct netr_SamInfo3 *my_info3;
798 time_t kickoff_time, must_change_time;
799 bool password_good = false;
801 struct winbindd_tdc_domain *tdc_domain = NULL;
808 DEBUG(10,("winbindd_dual_pam_auth_cached\n"));
810 /* Parse domain and username */
812 parse_domain_user(state->request->data.auth.user, name_domain, name_user);
815 if (!lookup_cached_name(name_domain,
819 DEBUG(10,("winbindd_dual_pam_auth_cached: no such user in the cache\n"));
820 return NT_STATUS_NO_SUCH_USER;
823 if (type != SID_NAME_USER) {
824 DEBUG(10,("winbindd_dual_pam_auth_cached: not a user (%s)\n", sid_type_lookup(type)));
825 return NT_STATUS_LOGON_FAILURE;
828 result = winbindd_get_creds(domain,
834 if (!NT_STATUS_IS_OK(result)) {
835 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get creds: %s\n", nt_errstr(result)));
841 E_md4hash(state->request->data.auth.pass, new_nt_pass);
843 dump_data_pw("new_nt_pass", new_nt_pass, NT_HASH_LEN);
844 dump_data_pw("cached_nt_pass", cached_nt_pass, NT_HASH_LEN);
846 dump_data_pw("cached_salt", cached_salt, NT_HASH_LEN);
850 /* In this case we didn't store the nt_hash itself,
851 but the MD5 combination of salt + nt_hash. */
852 uchar salted_hash[NT_HASH_LEN];
853 E_md5hash(cached_salt, new_nt_pass, salted_hash);
855 password_good = (memcmp(cached_nt_pass, salted_hash,
858 /* Old cached cred - direct store of nt_hash (bad bad bad !). */
859 password_good = (memcmp(cached_nt_pass, new_nt_pass,
865 /* User *DOES* know the password, update logon_time and reset
868 my_info3->base.user_flags |= NETLOGON_CACHED_ACCOUNT;
870 if (my_info3->base.acct_flags & ACB_AUTOLOCK) {
871 return NT_STATUS_ACCOUNT_LOCKED_OUT;
874 if (my_info3->base.acct_flags & ACB_DISABLED) {
875 return NT_STATUS_ACCOUNT_DISABLED;
878 if (my_info3->base.acct_flags & ACB_WSTRUST) {
879 return NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
882 if (my_info3->base.acct_flags & ACB_SVRTRUST) {
883 return NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT;
886 if (my_info3->base.acct_flags & ACB_DOMTRUST) {
887 return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT;
890 if (!(my_info3->base.acct_flags & ACB_NORMAL)) {
891 DEBUG(0,("winbindd_dual_pam_auth_cached: whats wrong with that one?: 0x%08x\n",
892 my_info3->base.acct_flags));
893 return NT_STATUS_LOGON_FAILURE;
896 kickoff_time = nt_time_to_unix(my_info3->base.acct_expiry);
897 if (kickoff_time != 0 && time(NULL) > kickoff_time) {
898 return NT_STATUS_ACCOUNT_EXPIRED;
901 must_change_time = nt_time_to_unix(my_info3->base.force_password_change);
902 if (must_change_time != 0 && must_change_time < time(NULL)) {
903 /* we allow grace logons when the password has expired */
904 my_info3->base.user_flags |= NETLOGON_GRACE_LOGON;
905 /* return NT_STATUS_PASSWORD_EXPIRED; */
910 if ((state->request->flags & WBFLAG_PAM_KRB5) &&
911 ((tdc_domain = wcache_tdc_fetch_domain(state->mem_ctx, name_domain)) != NULL) &&
912 ((tdc_domain->trust_type & NETR_TRUST_TYPE_UPLEVEL) ||
913 /* used to cope with the case winbindd starting without network. */
914 !strequal(tdc_domain->domain_name, tdc_domain->dns_name))) {
917 const char *cc = NULL;
919 const char *principal_s = NULL;
920 const char *service = NULL;
921 const char *user_ccache_file;
923 uid = get_uid_from_request(state->request);
925 DEBUG(0,("winbindd_dual_pam_auth_cached: invalid uid\n"));
926 return NT_STATUS_INVALID_PARAMETER;
929 cc = generate_krb5_ccache(state->mem_ctx,
930 state->request->data.auth.krb5_cc_type,
931 state->request->data.auth.uid,
934 return NT_STATUS_NO_MEMORY;
937 realm = domain->alt_name;
940 principal_s = talloc_asprintf(state->mem_ctx, "%s@%s", name_user, realm);
941 if (principal_s == NULL) {
942 return NT_STATUS_NO_MEMORY;
945 service = talloc_asprintf(state->mem_ctx, "%s/%s@%s", KRB5_TGS_NAME, realm, realm);
946 if (service == NULL) {
947 return NT_STATUS_NO_MEMORY;
950 if (user_ccache_file != NULL) {
952 fstrcpy(state->response->data.auth.krb5ccname,
955 result = add_ccache_to_list(principal_s,
958 state->request->data.auth.user,
962 time(NULL) + lp_winbind_cache_time(),
963 time(NULL) + WINBINDD_PAM_AUTH_KRB5_RENEW_TIME,
966 if (!NT_STATUS_IS_OK(result)) {
967 DEBUG(10,("winbindd_dual_pam_auth_cached: failed "
968 "to add ccache to list: %s\n",
973 #endif /* HAVE_KRB5 */
975 /* FIXME: we possibly should handle logon hours as well (does xp when
976 * offline?) see auth/auth_sam.c:sam_account_ok for details */
978 unix_to_nt_time(&my_info3->base.last_logon, time(NULL));
979 my_info3->base.bad_password_count = 0;
981 result = winbindd_update_creds_by_info3(domain,
982 state->request->data.auth.user,
983 state->request->data.auth.pass,
985 if (!NT_STATUS_IS_OK(result)) {
986 DEBUG(1,("winbindd_dual_pam_auth_cached: failed to update creds: %s\n",
995 /* User does *NOT* know the correct password, modify info3 accordingly */
997 /* failure of this is not critical */
998 result = get_max_bad_attempts_from_lockout_policy(domain, state->mem_ctx, &max_allowed_bad_attempts);
999 if (!NT_STATUS_IS_OK(result)) {
1000 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get max_allowed_bad_attempts. "
1001 "Won't be able to honour account lockout policies\n"));
1004 /* increase counter */
1005 my_info3->base.bad_password_count++;
1007 if (max_allowed_bad_attempts == 0) {
1012 if (my_info3->base.bad_password_count >= max_allowed_bad_attempts) {
1014 uint32 password_properties;
1016 result = get_pwd_properties(domain, state->mem_ctx, &password_properties);
1017 if (!NT_STATUS_IS_OK(result)) {
1018 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get password properties.\n"));
1021 if ((my_info3->base.rid != DOMAIN_RID_ADMINISTRATOR) ||
1022 (password_properties & DOMAIN_PASSWORD_LOCKOUT_ADMINS)) {
1023 my_info3->base.acct_flags |= ACB_AUTOLOCK;
1028 result = winbindd_update_creds_by_info3(domain,
1029 state->request->data.auth.user,
1033 if (!NT_STATUS_IS_OK(result)) {
1034 DEBUG(0,("winbindd_dual_pam_auth_cached: failed to update creds %s\n",
1035 nt_errstr(result)));
1038 return NT_STATUS_LOGON_FAILURE;
1041 static NTSTATUS winbindd_dual_pam_auth_kerberos(struct winbindd_domain *domain,
1042 struct winbindd_cli_state *state,
1043 struct netr_SamInfo3 **info3)
1045 struct winbindd_domain *contact_domain;
1046 fstring name_domain, name_user;
1049 DEBUG(10,("winbindd_dual_pam_auth_kerberos\n"));
1051 /* Parse domain and username */
1053 parse_domain_user(state->request->data.auth.user, name_domain, name_user);
1055 /* what domain should we contact? */
1058 if (!(contact_domain = find_domain_from_name(name_domain))) {
1059 DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
1060 state->request->data.auth.user, name_domain, name_user, name_domain));
1061 result = NT_STATUS_NO_SUCH_USER;
1066 if (is_myname(name_domain)) {
1067 DEBUG(3, ("Authentication for domain %s (local domain to this server) not supported at this stage\n", name_domain));
1068 result = NT_STATUS_NO_SUCH_USER;
1072 contact_domain = find_domain_from_name(name_domain);
1073 if (contact_domain == NULL) {
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));
1077 contact_domain = find_our_domain();
1081 if (contact_domain->initialized &&
1082 contact_domain->active_directory) {
1086 if (!contact_domain->initialized) {
1087 init_dc_connection(contact_domain);
1090 if (!contact_domain->active_directory) {
1091 DEBUG(3,("krb5 auth requested but domain is not Active Directory\n"));
1092 return NT_STATUS_INVALID_LOGON_TYPE;
1095 result = winbindd_raw_kerberos_login(
1096 state->mem_ctx, contact_domain,
1097 state->request->data.auth.user,
1098 state->request->data.auth.pass,
1099 state->request->data.auth.krb5_cc_type,
1100 get_uid_from_request(state->request),
1101 info3, state->response->data.auth.krb5ccname);
1106 static NTSTATUS winbindd_dual_auth_passdb(TALLOC_CTX *mem_ctx,
1107 const char *domain, const char *user,
1108 const DATA_BLOB *challenge,
1109 const DATA_BLOB *lm_resp,
1110 const DATA_BLOB *nt_resp,
1111 struct netr_SamInfo3 **pinfo3)
1113 struct auth_usersupplied_info *user_info = NULL;
1116 status = make_user_info(&user_info, user, user, domain, domain,
1117 global_myname(), lm_resp, nt_resp, NULL, NULL,
1118 NULL, AUTH_PASSWORD_RESPONSE);
1119 if (!NT_STATUS_IS_OK(status)) {
1120 DEBUG(10, ("make_user_info failed: %s\n", nt_errstr(status)));
1124 /* We don't want any more mapping of the username */
1125 user_info->mapped_state = True;
1127 status = check_sam_security_info3(challenge, talloc_tos(), user_info,
1129 free_user_info(&user_info);
1130 DEBUG(10, ("Authenticaticating user %s\\%s returned %s\n", domain,
1131 user, nt_errstr(status)));
1135 static NTSTATUS winbind_samlogon_retry_loop(struct winbindd_domain *domain,
1136 TALLOC_CTX *mem_ctx,
1137 uint32_t logon_parameters,
1139 const char *username,
1140 const char *domainname,
1141 const char *workstation,
1142 const uint8_t chal[8],
1143 DATA_BLOB lm_response,
1144 DATA_BLOB nt_response,
1145 struct netr_SamInfo3 **info3)
1152 struct rpc_pipe_client *netlogon_pipe;
1153 const struct pipe_auth_data *auth;
1154 uint32_t neg_flags = 0;
1156 ZERO_STRUCTP(info3);
1159 result = cm_connect_netlogon(domain, &netlogon_pipe);
1161 if (!NT_STATUS_IS_OK(result)) {
1162 DEBUG(3,("could not open handle to NETLOGON pipe (error: %s)\n",
1163 nt_errstr(result)));
1166 auth = netlogon_pipe->auth;
1167 if (netlogon_pipe->dc) {
1168 neg_flags = netlogon_pipe->dc->negotiate_flags;
1171 /* It is really important to try SamLogonEx here,
1172 * because in a clustered environment, we want to use
1173 * one machine account from multiple physical
1176 * With a normal SamLogon call, we must keep the
1177 * credentials chain updated and intact between all
1178 * users of the machine account (which would imply
1179 * cross-node communication for every NTLM logon).
1181 * (The credentials chain is not per NETLOGON pipe
1182 * connection, but globally on the server/client pair
1185 * When using SamLogonEx, the credentials are not
1186 * supplied, but the session key is implied by the
1187 * wrapping SamLogon context.
1189 * -- abartlet 21 April 2008
1191 * It's also important to use NetlogonValidationSamInfo4 (6),
1192 * because it relies on the rpc transport encryption
1193 * and avoids using the global netlogon schannel
1194 * session key to en/decrypt secret information
1195 * like the user_session_key for network logons.
1197 * [MS-APDS] 3.1.5.2 NTLM Network Logon
1198 * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
1199 * NETLOGON_NEG_AUTHENTICATED_RPC set together
1200 * are the indication that the server supports
1201 * NetlogonValidationSamInfo4 (6). And it must only
1202 * be used if "SealSecureChannel" is used.
1204 * -- metze 4 February 2011
1208 domain->can_do_validation6 = false;
1209 } else if (auth->auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
1210 domain->can_do_validation6 = false;
1211 } else if (auth->auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
1212 domain->can_do_validation6 = false;
1213 } else if (!(neg_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
1214 domain->can_do_validation6 = false;
1215 } else if (!(neg_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
1216 domain->can_do_validation6 = false;
1219 if (domain->can_do_samlogon_ex) {
1220 result = rpccli_netlogon_sam_network_logon_ex(
1224 server, /* server name */
1225 username, /* user name */
1226 domainname, /* target domain */
1227 workstation, /* workstation */
1229 domain->can_do_validation6 ? 6 : 3,
1234 result = rpccli_netlogon_sam_network_logon(
1238 server, /* server name */
1239 username, /* user name */
1240 domainname, /* target domain */
1241 workstation, /* workstation */
1243 domain->can_do_validation6 ? 6 : 3,
1249 if ((NT_STATUS_V(result) == DCERPC_FAULT_OP_RNG_ERROR)
1250 && domain->can_do_samlogon_ex) {
1251 DEBUG(3, ("Got a DC that can not do NetSamLogonEx, "
1252 "retrying with NetSamLogon\n"));
1253 domain->can_do_samlogon_ex = false;
1255 * It's likely that the server also does not support
1256 * validation level 6
1258 domain->can_do_validation6 = false;
1263 if (domain->can_do_validation6 &&
1264 (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
1265 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
1266 NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL))) {
1267 DEBUG(3,("Got a DC that can not do validation level 6, "
1268 "retrying with level 3\n"));
1269 domain->can_do_validation6 = false;
1275 * we increment this after the "feature negotiation"
1276 * for can_do_samlogon_ex and can_do_validation6
1280 /* We have to try a second time as cm_connect_netlogon
1281 might not yet have noticed that the DC has killed
1284 if (!rpccli_is_connected(netlogon_pipe)) {
1289 /* if we get access denied, a possible cause was that we had
1290 and open connection to the DC, but someone changed our
1291 machine account password out from underneath us using 'net
1292 rpc changetrustpw' */
1294 if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
1295 DEBUG(3,("winbindd_pam_auth: sam_logon returned "
1296 "ACCESS_DENIED. Maybe the trust account "
1297 "password was changed and we didn't know it. "
1298 "Killing connections to domain %s\n",
1300 invalidate_cm_connection(&domain->conn);
1304 } while ( (attempts < 2) && retry );
1309 static NTSTATUS winbindd_dual_pam_auth_samlogon(TALLOC_CTX *mem_ctx,
1310 struct winbindd_domain *domain,
1313 uint32_t request_flags,
1314 struct netr_SamInfo3 **info3)
1320 unsigned char local_nt_response[24];
1321 fstring name_domain, name_user;
1323 struct netr_SamInfo3 *my_info3 = NULL;
1327 DEBUG(10,("winbindd_dual_pam_auth_samlogon\n"));
1329 /* Parse domain and username */
1331 parse_domain_user(user, name_domain, name_user);
1333 /* do password magic */
1335 generate_random_buffer(chal, sizeof(chal));
1337 if (lp_client_ntlmv2_auth()) {
1338 DATA_BLOB server_chal;
1339 DATA_BLOB names_blob;
1340 server_chal = data_blob_const(chal, 8);
1342 /* note that the 'workgroup' here is for the local
1343 machine. The 'server name' must match the
1344 'workstation' passed to the actual SamLogon call.
1346 names_blob = NTLMv2_generate_names_blob(
1347 mem_ctx, global_myname(), lp_workgroup());
1349 if (!SMBNTLMv2encrypt(mem_ctx, name_user, name_domain,
1353 &lm_resp, &nt_resp, NULL, NULL)) {
1354 data_blob_free(&names_blob);
1355 DEBUG(0, ("winbindd_pam_auth: SMBNTLMv2encrypt() failed!\n"));
1356 result = NT_STATUS_NO_MEMORY;
1359 data_blob_free(&names_blob);
1361 lm_resp = data_blob_null;
1362 SMBNTencrypt(pass, chal, local_nt_response);
1364 nt_resp = data_blob_talloc(mem_ctx, local_nt_response,
1365 sizeof(local_nt_response));
1368 if (strequal(name_domain, get_global_sam_name())) {
1369 DATA_BLOB chal_blob = data_blob_const(chal, sizeof(chal));
1371 result = winbindd_dual_auth_passdb(
1372 mem_ctx, name_domain, name_user,
1373 &chal_blob, &lm_resp, &nt_resp, info3);
1377 /* check authentication loop */
1379 result = winbind_samlogon_retry_loop(domain,
1390 if (!NT_STATUS_IS_OK(result)) {
1394 /* handle the case where a NT4 DC does not fill in the acct_flags in
1395 * the samlogon reply info3. When accurate info3 is required by the
1396 * caller, we look up the account flags ourselve - gd */
1398 if ((request_flags & WBFLAG_PAM_INFO3_TEXT) &&
1399 NT_STATUS_IS_OK(result) && (my_info3->base.acct_flags == 0)) {
1401 struct rpc_pipe_client *samr_pipe;
1402 struct policy_handle samr_domain_handle, user_pol;
1403 union samr_UserInfo *info = NULL;
1404 NTSTATUS status_tmp, result_tmp;
1406 struct dcerpc_binding_handle *b;
1408 status_tmp = cm_connect_sam(domain, mem_ctx,
1409 &samr_pipe, &samr_domain_handle);
1411 if (!NT_STATUS_IS_OK(status_tmp)) {
1412 DEBUG(3, ("could not open handle to SAMR pipe: %s\n",
1413 nt_errstr(status_tmp)));
1417 b = samr_pipe->binding_handle;
1419 status_tmp = dcerpc_samr_OpenUser(b, mem_ctx,
1420 &samr_domain_handle,
1421 MAXIMUM_ALLOWED_ACCESS,
1426 if (!NT_STATUS_IS_OK(status_tmp)) {
1427 DEBUG(3, ("could not open user handle on SAMR pipe: %s\n",
1428 nt_errstr(status_tmp)));
1431 if (!NT_STATUS_IS_OK(result_tmp)) {
1432 DEBUG(3, ("could not open user handle on SAMR pipe: %s\n",
1433 nt_errstr(result_tmp)));
1437 status_tmp = dcerpc_samr_QueryUserInfo(b, mem_ctx,
1443 if (!NT_STATUS_IS_OK(status_tmp)) {
1444 DEBUG(3, ("could not query user info on SAMR pipe: %s\n",
1445 nt_errstr(status_tmp)));
1446 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
1449 if (!NT_STATUS_IS_OK(result_tmp)) {
1450 DEBUG(3, ("could not query user info on SAMR pipe: %s\n",
1451 nt_errstr(result_tmp)));
1452 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
1456 acct_flags = info->info16.acct_flags;
1458 if (acct_flags == 0) {
1459 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
1463 my_info3->base.acct_flags = acct_flags;
1465 DEBUG(10,("successfully retrieved acct_flags 0x%x\n", acct_flags));
1467 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
1475 enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain,
1476 struct winbindd_cli_state *state)
1478 NTSTATUS result = NT_STATUS_LOGON_FAILURE;
1479 NTSTATUS krb5_result = NT_STATUS_OK;
1480 fstring name_domain, name_user;
1482 fstring domain_user;
1483 struct netr_SamInfo3 *info3 = NULL;
1484 NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL;
1486 /* Ensure null termination */
1487 state->request->data.auth.user[sizeof(state->request->data.auth.user)-1]='\0';
1489 /* Ensure null termination */
1490 state->request->data.auth.pass[sizeof(state->request->data.auth.pass)-1]='\0';
1492 DEBUG(3, ("[%5lu]: dual pam auth %s\n", (unsigned long)state->pid,
1493 state->request->data.auth.user));
1495 /* Parse domain and username */
1497 name_map_status = normalize_name_unmap(state->mem_ctx,
1498 state->request->data.auth.user,
1501 /* If the name normalization didnt' actually do anything,
1502 just use the original name */
1504 if (!NT_STATUS_IS_OK(name_map_status) &&
1505 !NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED))
1507 mapped_user = state->request->data.auth.user;
1510 parse_domain_user(mapped_user, name_domain, name_user);
1512 if ( mapped_user != state->request->data.auth.user ) {
1513 fstr_sprintf( domain_user, "%s%c%s", name_domain,
1514 *lp_winbind_separator(),
1516 safe_strcpy( state->request->data.auth.user, domain_user,
1517 sizeof(state->request->data.auth.user)-1 );
1520 if (!domain->online) {
1521 result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
1522 if (domain->startup) {
1523 /* Logons are very important to users. If we're offline and
1524 we get a request within the first 30 seconds of startup,
1525 try very hard to find a DC and go online. */
1527 DEBUG(10,("winbindd_dual_pam_auth: domain: %s offline and auth "
1528 "request in startup mode.\n", domain->name ));
1530 winbindd_flush_negative_conn_cache(domain);
1531 result = init_dc_connection(domain);
1535 DEBUG(10,("winbindd_dual_pam_auth: domain: %s last was %s\n", domain->name, domain->online ? "online":"offline"));
1537 /* Check for Kerberos authentication */
1538 if (domain->online && (state->request->flags & WBFLAG_PAM_KRB5)) {
1540 result = winbindd_dual_pam_auth_kerberos(domain, state, &info3);
1541 /* save for later */
1542 krb5_result = result;
1545 if (NT_STATUS_IS_OK(result)) {
1546 DEBUG(10,("winbindd_dual_pam_auth_kerberos succeeded\n"));
1547 goto process_result;
1549 DEBUG(10,("winbindd_dual_pam_auth_kerberos failed: %s\n", nt_errstr(result)));
1552 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
1553 NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
1554 NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1555 DEBUG(10,("winbindd_dual_pam_auth_kerberos setting domain to offline\n"));
1556 set_domain_offline( domain );
1560 /* there are quite some NT_STATUS errors where there is no
1561 * point in retrying with a samlogon, we explictly have to take
1562 * care not to increase the bad logon counter on the DC */
1564 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_DISABLED) ||
1565 NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_EXPIRED) ||
1566 NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_LOCKED_OUT) ||
1567 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_LOGON_HOURS) ||
1568 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_WORKSTATION) ||
1569 NT_STATUS_EQUAL(result, NT_STATUS_LOGON_FAILURE) ||
1570 NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER) ||
1571 NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_EXPIRED) ||
1572 NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_MUST_CHANGE) ||
1573 NT_STATUS_EQUAL(result, NT_STATUS_WRONG_PASSWORD)) {
1577 if (state->request->flags & WBFLAG_PAM_FALLBACK_AFTER_KRB5) {
1578 DEBUG(3,("falling back to samlogon\n"));
1586 /* Check for Samlogon authentication */
1587 if (domain->online) {
1588 result = winbindd_dual_pam_auth_samlogon(
1589 state->mem_ctx, domain,
1590 state->request->data.auth.user,
1591 state->request->data.auth.pass,
1592 state->request->flags,
1595 if (NT_STATUS_IS_OK(result)) {
1596 DEBUG(10,("winbindd_dual_pam_auth_samlogon succeeded\n"));
1597 /* add the Krb5 err if we have one */
1598 if ( NT_STATUS_EQUAL(krb5_result, NT_STATUS_TIME_DIFFERENCE_AT_DC ) ) {
1599 info3->base.user_flags |= LOGON_KRB5_FAIL_CLOCK_SKEW;
1601 goto process_result;
1604 DEBUG(10,("winbindd_dual_pam_auth_samlogon failed: %s\n",
1605 nt_errstr(result)));
1607 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
1608 NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
1609 NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND))
1611 DEBUG(10,("winbindd_dual_pam_auth_samlogon setting domain to offline\n"));
1612 set_domain_offline( domain );
1616 if (domain->online) {
1617 /* We're still online - fail. */
1623 /* Check for Cached logons */
1624 if (!domain->online && (state->request->flags & WBFLAG_PAM_CACHED_LOGIN) &&
1625 lp_winbind_offline_logon()) {
1627 result = winbindd_dual_pam_auth_cached(domain, state, &info3);
1629 if (NT_STATUS_IS_OK(result)) {
1630 DEBUG(10,("winbindd_dual_pam_auth_cached succeeded\n"));
1631 goto process_result;
1633 DEBUG(10,("winbindd_dual_pam_auth_cached failed: %s\n", nt_errstr(result)));
1640 if (NT_STATUS_IS_OK(result)) {
1642 struct dom_sid user_sid;
1644 /* In all codepaths where result == NT_STATUS_OK info3 must have
1645 been initialized. */
1647 result = NT_STATUS_INTERNAL_ERROR;
1651 sid_compose(&user_sid, info3->base.domain_sid,
1654 wcache_invalidate_samlogon(find_domain_from_name(name_domain),
1656 netsamlogon_cache_store(name_user, info3);
1658 /* save name_to_sid info as early as possible (only if
1659 this is our primary domain so we don't invalidate
1660 the cache entry by storing the seq_num for the wrong
1662 if ( domain->primary ) {
1663 cache_name2sid(domain, name_domain, name_user,
1664 SID_NAME_USER, &user_sid);
1667 /* Check if the user is in the right group */
1669 result = check_info3_in_group(
1671 state->request->data.auth.require_membership_of_sid);
1672 if (!NT_STATUS_IS_OK(result)) {
1673 DEBUG(3, ("User %s is not in the required group (%s), so plaintext authentication is rejected\n",
1674 state->request->data.auth.user,
1675 state->request->data.auth.require_membership_of_sid));
1679 result = append_auth_data(state->mem_ctx, state->response,
1680 state->request->flags, info3,
1681 name_domain, name_user);
1682 if (!NT_STATUS_IS_OK(result)) {
1686 if ((state->request->flags & WBFLAG_PAM_CACHED_LOGIN)
1687 && lp_winbind_offline_logon()) {
1689 result = winbindd_store_creds(domain,
1690 state->request->data.auth.user,
1691 state->request->data.auth.pass,
1695 if (state->request->flags & WBFLAG_PAM_GET_PWD_POLICY) {
1696 struct winbindd_domain *our_domain = find_our_domain();
1698 /* This is not entirely correct I believe, but it is
1699 consistent. Only apply the password policy settings
1700 too warn users for our own domain. Cannot obtain these
1701 from trusted DCs all the time so don't do it at all.
1704 result = NT_STATUS_NOT_SUPPORTED;
1705 if (our_domain == domain ) {
1706 result = fillup_password_policy(
1707 our_domain, state->response);
1710 if (!NT_STATUS_IS_OK(result)
1711 && !NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED) )
1713 DEBUG(10,("Failed to get password policies for domain %s: %s\n",
1714 domain->name, nt_errstr(result)));
1719 result = NT_STATUS_OK;
1723 /* give us a more useful (more correct?) error code */
1724 if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
1725 (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
1726 result = NT_STATUS_NO_LOGON_SERVERS;
1729 set_auth_errors(state->response, result);
1731 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, ("Plain-text authentication for user %s returned %s (PAM: %d)\n",
1732 state->request->data.auth.user,
1733 state->response->data.auth.nt_status_string,
1734 state->response->data.auth.pam_error));
1736 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
1739 enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain,
1740 struct winbindd_cli_state *state)
1743 struct netr_SamInfo3 *info3 = NULL;
1744 const char *name_user = NULL;
1745 const char *name_domain = NULL;
1746 const char *workstation;
1748 DATA_BLOB lm_resp, nt_resp;
1750 /* This is child-only, so no check for privileged access is needed
1753 /* Ensure null termination */
1754 state->request->data.auth_crap.user[sizeof(state->request->data.auth_crap.user)-1]=0;
1755 state->request->data.auth_crap.domain[sizeof(state->request->data.auth_crap.domain)-1]=0;
1757 name_user = state->request->data.auth_crap.user;
1758 name_domain = state->request->data.auth_crap.domain;
1759 workstation = state->request->data.auth_crap.workstation;
1761 DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n", (unsigned long)state->pid,
1762 name_domain, name_user));
1764 if (state->request->data.auth_crap.lm_resp_len > sizeof(state->request->data.auth_crap.lm_resp)
1765 || state->request->data.auth_crap.nt_resp_len > sizeof(state->request->data.auth_crap.nt_resp)) {
1766 if (!(state->request->flags & WBFLAG_BIG_NTLMV2_BLOB) ||
1767 state->request->extra_len != state->request->data.auth_crap.nt_resp_len) {
1768 DEBUG(0, ("winbindd_pam_auth_crap: invalid password length %u/%u\n",
1769 state->request->data.auth_crap.lm_resp_len,
1770 state->request->data.auth_crap.nt_resp_len));
1771 result = NT_STATUS_INVALID_PARAMETER;
1776 lm_resp = data_blob_talloc(state->mem_ctx, state->request->data.auth_crap.lm_resp,
1777 state->request->data.auth_crap.lm_resp_len);
1779 if (state->request->flags & WBFLAG_BIG_NTLMV2_BLOB) {
1780 nt_resp = data_blob_talloc(state->mem_ctx,
1781 state->request->extra_data.data,
1782 state->request->data.auth_crap.nt_resp_len);
1784 nt_resp = data_blob_talloc(state->mem_ctx,
1785 state->request->data.auth_crap.nt_resp,
1786 state->request->data.auth_crap.nt_resp_len);
1789 if (strequal(name_domain, get_global_sam_name())) {
1790 DATA_BLOB chal_blob = data_blob_const(
1791 state->request->data.auth_crap.chal,
1792 sizeof(state->request->data.auth_crap.chal));
1794 result = winbindd_dual_auth_passdb(
1795 state->mem_ctx, name_domain, name_user,
1796 &chal_blob, &lm_resp, &nt_resp, &info3);
1797 goto process_result;
1800 result = winbind_samlogon_retry_loop(domain,
1802 state->request->data.auth_crap.logon_parameters,
1806 /* Bug #3248 - found by Stefan Burkei. */
1807 workstation, /* We carefully set this above so use it... */
1808 state->request->data.auth_crap.chal,
1812 if (!NT_STATUS_IS_OK(result)) {
1818 if (NT_STATUS_IS_OK(result)) {
1819 struct dom_sid user_sid;
1821 sid_compose(&user_sid, info3->base.domain_sid,
1823 wcache_invalidate_samlogon(find_domain_from_name(name_domain),
1825 netsamlogon_cache_store(name_user, info3);
1827 /* Check if the user is in the right group */
1829 result = check_info3_in_group(
1831 state->request->data.auth_crap.require_membership_of_sid);
1832 if (!NT_STATUS_IS_OK(result)) {
1833 DEBUG(3, ("User %s is not in the required group (%s), so "
1834 "crap authentication is rejected\n",
1835 state->request->data.auth_crap.user,
1836 state->request->data.auth_crap.require_membership_of_sid));
1840 result = append_auth_data(state->mem_ctx, state->response,
1841 state->request->flags, info3,
1842 name_domain, name_user);
1843 if (!NT_STATUS_IS_OK(result)) {
1850 /* give us a more useful (more correct?) error code */
1851 if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
1852 (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
1853 result = NT_STATUS_NO_LOGON_SERVERS;
1856 if (state->request->flags & WBFLAG_PAM_NT_STATUS_SQUASH) {
1857 result = nt_status_squash(result);
1860 set_auth_errors(state->response, result);
1862 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
1863 ("NTLM CRAP authentication for user [%s]\\[%s] returned %s (PAM: %d)\n",
1866 state->response->data.auth.nt_status_string,
1867 state->response->data.auth.pam_error));
1869 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
1872 enum winbindd_result winbindd_dual_pam_chauthtok(struct winbindd_domain *contact_domain,
1873 struct winbindd_cli_state *state)
1876 char *newpass = NULL;
1877 struct policy_handle dom_pol;
1878 struct rpc_pipe_client *cli = NULL;
1879 bool got_info = false;
1880 struct samr_DomInfo1 *info = NULL;
1881 struct userPwdChangeFailureInformation *reject = NULL;
1882 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1883 fstring domain, user;
1884 struct dcerpc_binding_handle *b = NULL;
1886 ZERO_STRUCT(dom_pol);
1888 DEBUG(3, ("[%5lu]: dual pam chauthtok %s\n", (unsigned long)state->pid,
1889 state->request->data.auth.user));
1891 if (!parse_domain_user(state->request->data.chauthtok.user, domain, user)) {
1895 /* Change password */
1897 oldpass = state->request->data.chauthtok.oldpass;
1898 newpass = state->request->data.chauthtok.newpass;
1900 /* Initialize reject reason */
1901 state->response->data.auth.reject_reason = Undefined;
1903 /* Get sam handle */
1905 result = cm_connect_sam(contact_domain, state->mem_ctx, &cli,
1907 if (!NT_STATUS_IS_OK(result)) {
1908 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
1912 b = cli->binding_handle;
1914 result = rpccli_samr_chgpasswd_user3(cli, state->mem_ctx,
1921 /* Windows 2003 returns NT_STATUS_PASSWORD_RESTRICTION */
1923 if (NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_RESTRICTION) ) {
1925 fill_in_password_policy(state->response, info);
1927 state->response->data.auth.reject_reason =
1928 reject->extendedFailureReason;
1933 /* atm the pidl generated rpccli_samr_ChangePasswordUser3 function will
1934 * return with NT_STATUS_BUFFER_TOO_SMALL for w2k dcs as w2k just
1935 * returns with 4byte error code (NT_STATUS_NOT_SUPPORTED) which is too
1936 * short to comply with the samr_ChangePasswordUser3 idl - gd */
1938 /* only fallback when the chgpasswd_user3 call is not supported */
1939 if ((NT_STATUS_EQUAL(result, NT_STATUS(DCERPC_FAULT_OP_RNG_ERROR))) ||
1940 (NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED)) ||
1941 (NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)) ||
1942 (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED))) {
1944 DEBUG(10,("Password change with chgpasswd_user3 failed with: %s, retrying chgpasswd_user2\n",
1945 nt_errstr(result)));
1947 result = rpccli_samr_chgpasswd_user2(cli, state->mem_ctx, user, newpass, oldpass);
1949 /* Windows 2000 returns NT_STATUS_ACCOUNT_RESTRICTION.
1950 Map to the same status code as Windows 2003. */
1952 if ( NT_STATUS_EQUAL(NT_STATUS_ACCOUNT_RESTRICTION, result ) ) {
1953 result = NT_STATUS_PASSWORD_RESTRICTION;
1959 if (NT_STATUS_IS_OK(result)
1960 && (state->request->flags & WBFLAG_PAM_CACHED_LOGIN)
1961 && lp_winbind_offline_logon()) {
1962 result = winbindd_update_creds_by_name(contact_domain, user,
1964 /* Again, this happens when we login from gdm or xdm
1965 * and the password expires, *BUT* cached crendentials
1966 * doesn't exist. winbindd_update_creds_by_name()
1967 * returns NT_STATUS_NO_SUCH_USER.
1968 * This is not a failure.
1971 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER)) {
1972 result = NT_STATUS_OK;
1975 if (!NT_STATUS_IS_OK(result)) {
1976 DEBUG(10, ("Failed to store creds: %s\n",
1977 nt_errstr(result)));
1978 goto process_result;
1982 if (!NT_STATUS_IS_OK(result) && !got_info && contact_domain) {
1984 NTSTATUS policy_ret;
1986 policy_ret = fillup_password_policy(
1987 contact_domain, state->response);
1989 /* failure of this is non critical, it will just provide no
1990 * additional information to the client why the change has
1991 * failed - Guenther */
1993 if (!NT_STATUS_IS_OK(policy_ret)) {
1994 DEBUG(10,("Failed to get password policies: %s\n", nt_errstr(policy_ret)));
1995 goto process_result;
2001 if (strequal(contact_domain->name, get_global_sam_name())) {
2002 /* FIXME: internal rpc pipe does not cache handles yet */
2004 if (is_valid_policy_hnd(&dom_pol)) {
2006 dcerpc_samr_Close(b, state->mem_ctx, &dom_pol, &_result);
2012 set_auth_errors(state->response, result);
2014 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
2015 ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
2018 state->response->data.auth.nt_status_string,
2019 state->response->data.auth.pam_error));
2021 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2024 enum winbindd_result winbindd_dual_pam_logoff(struct winbindd_domain *domain,
2025 struct winbindd_cli_state *state)
2027 NTSTATUS result = NT_STATUS_NOT_SUPPORTED;
2029 DEBUG(3, ("[%5lu]: pam dual logoff %s\n", (unsigned long)state->pid,
2030 state->request->data.logoff.user));
2032 if (!(state->request->flags & WBFLAG_PAM_KRB5)) {
2033 result = NT_STATUS_OK;
2034 goto process_result;
2037 if (state->request->data.logoff.krb5ccname[0] == '\0') {
2038 result = NT_STATUS_OK;
2039 goto process_result;
2044 if (state->request->data.logoff.uid < 0) {
2045 DEBUG(0,("winbindd_pam_logoff: invalid uid\n"));
2046 goto process_result;
2049 /* what we need here is to find the corresponding krb5 ccache name *we*
2050 * created for a given username and destroy it */
2052 if (!ccache_entry_exists(state->request->data.logoff.user)) {
2053 result = NT_STATUS_OK;
2054 DEBUG(10,("winbindd_pam_logoff: no entry found.\n"));
2055 goto process_result;
2058 if (!ccache_entry_identical(state->request->data.logoff.user,
2059 state->request->data.logoff.uid,
2060 state->request->data.logoff.krb5ccname)) {
2061 DEBUG(0,("winbindd_pam_logoff: cached entry differs.\n"));
2062 goto process_result;
2065 result = remove_ccache(state->request->data.logoff.user);
2066 if (!NT_STATUS_IS_OK(result)) {
2067 DEBUG(0,("winbindd_pam_logoff: failed to remove ccache: %s\n",
2068 nt_errstr(result)));
2069 goto process_result;
2073 result = NT_STATUS_NOT_SUPPORTED;
2079 set_auth_errors(state->response, result);
2081 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2084 /* Change user password with auth crap*/
2086 enum winbindd_result winbindd_dual_pam_chng_pswd_auth_crap(struct winbindd_domain *domainSt, struct winbindd_cli_state *state)
2089 DATA_BLOB new_nt_password;
2090 DATA_BLOB old_nt_hash_enc;
2091 DATA_BLOB new_lm_password;
2092 DATA_BLOB old_lm_hash_enc;
2093 fstring domain,user;
2094 struct policy_handle dom_pol;
2095 struct winbindd_domain *contact_domain = domainSt;
2096 struct rpc_pipe_client *cli = NULL;
2097 struct dcerpc_binding_handle *b = NULL;
2099 ZERO_STRUCT(dom_pol);
2101 /* Ensure null termination */
2102 state->request->data.chng_pswd_auth_crap.user[
2103 sizeof(state->request->data.chng_pswd_auth_crap.user)-1]=0;
2104 state->request->data.chng_pswd_auth_crap.domain[
2105 sizeof(state->request->data.chng_pswd_auth_crap.domain)-1]=0;
2109 DEBUG(3, ("[%5lu]: pam change pswd auth crap domain: %s user: %s\n",
2110 (unsigned long)state->pid,
2111 state->request->data.chng_pswd_auth_crap.domain,
2112 state->request->data.chng_pswd_auth_crap.user));
2114 if (lp_winbind_offline_logon()) {
2115 DEBUG(0,("Refusing password change as winbind offline logons are enabled. "));
2116 DEBUGADD(0,("Changing passwords here would risk inconsistent logons\n"));
2117 result = NT_STATUS_ACCESS_DENIED;
2121 if (*state->request->data.chng_pswd_auth_crap.domain) {
2122 fstrcpy(domain,state->request->data.chng_pswd_auth_crap.domain);
2124 parse_domain_user(state->request->data.chng_pswd_auth_crap.user,
2128 DEBUG(3,("no domain specified with username (%s) - "
2130 state->request->data.chng_pswd_auth_crap.user));
2131 result = NT_STATUS_NO_SUCH_USER;
2136 if (!*domain && lp_winbind_use_default_domain()) {
2137 fstrcpy(domain,(char *)lp_workgroup());
2141 fstrcpy(user, state->request->data.chng_pswd_auth_crap.user);
2144 DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n",
2145 (unsigned long)state->pid, domain, user));
2147 /* Change password */
2148 new_nt_password = data_blob_const(
2149 state->request->data.chng_pswd_auth_crap.new_nt_pswd,
2150 state->request->data.chng_pswd_auth_crap.new_nt_pswd_len);
2152 old_nt_hash_enc = data_blob_const(
2153 state->request->data.chng_pswd_auth_crap.old_nt_hash_enc,
2154 state->request->data.chng_pswd_auth_crap.old_nt_hash_enc_len);
2156 if(state->request->data.chng_pswd_auth_crap.new_lm_pswd_len > 0) {
2157 new_lm_password = data_blob_const(
2158 state->request->data.chng_pswd_auth_crap.new_lm_pswd,
2159 state->request->data.chng_pswd_auth_crap.new_lm_pswd_len);
2161 old_lm_hash_enc = data_blob_const(
2162 state->request->data.chng_pswd_auth_crap.old_lm_hash_enc,
2163 state->request->data.chng_pswd_auth_crap.old_lm_hash_enc_len);
2165 new_lm_password.length = 0;
2166 old_lm_hash_enc.length = 0;
2169 /* Get sam handle */
2171 result = cm_connect_sam(contact_domain, state->mem_ctx, &cli, &dom_pol);
2172 if (!NT_STATUS_IS_OK(result)) {
2173 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
2177 b = cli->binding_handle;
2179 result = rpccli_samr_chng_pswd_auth_crap(
2180 cli, state->mem_ctx, user, new_nt_password, old_nt_hash_enc,
2181 new_lm_password, old_lm_hash_enc);
2185 if (strequal(contact_domain->name, get_global_sam_name())) {
2186 /* FIXME: internal rpc pipe does not cache handles yet */
2188 if (is_valid_policy_hnd(&dom_pol)) {
2190 dcerpc_samr_Close(b, state->mem_ctx, &dom_pol, &_result);
2196 set_auth_errors(state->response, result);
2198 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
2199 ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
2201 state->response->data.auth.nt_status_string,
2202 state->response->data.auth.pam_error));
2204 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;