2 Unix SMB/CIFS implementation.
4 Winbind daemon - pam auth funcions
6 Copyright (C) Andrew Tridgell 2000
7 Copyright (C) Tim Potter 2001
8 Copyright (C) Andrew Bartlett 2001-2002
9 Copyright (C) Guenther Deschner 2005
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 #include "../libcli/auth/libcli_auth.h"
28 #include "../librpc/gen_ndr/cli_samr.h"
29 #include "rpc_client/cli_samr.h"
30 #include "../librpc/gen_ndr/ndr_netlogon.h"
31 #include "rpc_client/cli_netlogon.h"
33 #include "../lib/crypto/arcfour.h"
34 #include "../libcli/security/dom_sid.h"
37 #define DBGC_CLASS DBGC_WINBIND
39 #define LOGON_KRB5_FAIL_CLOCK_SKEW 0x02000000
41 static NTSTATUS append_info3_as_txt(TALLOC_CTX *mem_ctx,
42 struct winbindd_cli_state *state,
43 struct netr_SamInfo3 *info3)
48 state->response->data.auth.info3.logon_time =
49 nt_time_to_unix(info3->base.last_logon);
50 state->response->data.auth.info3.logoff_time =
51 nt_time_to_unix(info3->base.last_logoff);
52 state->response->data.auth.info3.kickoff_time =
53 nt_time_to_unix(info3->base.acct_expiry);
54 state->response->data.auth.info3.pass_last_set_time =
55 nt_time_to_unix(info3->base.last_password_change);
56 state->response->data.auth.info3.pass_can_change_time =
57 nt_time_to_unix(info3->base.allow_password_change);
58 state->response->data.auth.info3.pass_must_change_time =
59 nt_time_to_unix(info3->base.force_password_change);
61 state->response->data.auth.info3.logon_count = info3->base.logon_count;
62 state->response->data.auth.info3.bad_pw_count = info3->base.bad_password_count;
64 state->response->data.auth.info3.user_rid = info3->base.rid;
65 state->response->data.auth.info3.group_rid = info3->base.primary_gid;
66 sid_to_fstring(state->response->data.auth.info3.dom_sid, info3->base.domain_sid);
68 state->response->data.auth.info3.num_groups = info3->base.groups.count;
69 state->response->data.auth.info3.user_flgs = info3->base.user_flags;
71 state->response->data.auth.info3.acct_flags = info3->base.acct_flags;
72 state->response->data.auth.info3.num_other_sids = info3->sidcount;
74 fstrcpy(state->response->data.auth.info3.user_name,
75 info3->base.account_name.string);
76 fstrcpy(state->response->data.auth.info3.full_name,
77 info3->base.full_name.string);
78 fstrcpy(state->response->data.auth.info3.logon_script,
79 info3->base.logon_script.string);
80 fstrcpy(state->response->data.auth.info3.profile_path,
81 info3->base.profile_path.string);
82 fstrcpy(state->response->data.auth.info3.home_dir,
83 info3->base.home_directory.string);
84 fstrcpy(state->response->data.auth.info3.dir_drive,
85 info3->base.home_drive.string);
87 fstrcpy(state->response->data.auth.info3.logon_srv,
88 info3->base.logon_server.string);
89 fstrcpy(state->response->data.auth.info3.logon_dom,
90 info3->base.domain.string);
92 ex = talloc_strdup(state->mem_ctx, "");
93 NT_STATUS_HAVE_NO_MEMORY(ex);
95 for (i=0; i < info3->base.groups.count; i++) {
96 ex = talloc_asprintf_append_buffer(ex, "0x%08X:0x%08X\n",
97 info3->base.groups.rids[i].rid,
98 info3->base.groups.rids[i].attributes);
99 NT_STATUS_HAVE_NO_MEMORY(ex);
102 for (i=0; i < info3->sidcount; i++) {
105 sid = dom_sid_string(mem_ctx, info3->sids[i].sid);
106 NT_STATUS_HAVE_NO_MEMORY(sid);
108 ex = talloc_asprintf_append_buffer(ex, "%s:0x%08X\n",
110 info3->sids[i].attributes);
111 NT_STATUS_HAVE_NO_MEMORY(ex);
116 state->response->extra_data.data = ex;
117 state->response->length += talloc_get_size(ex);
122 static NTSTATUS append_info3_as_ndr(TALLOC_CTX *mem_ctx,
123 struct winbindd_cli_state *state,
124 struct netr_SamInfo3 *info3)
127 enum ndr_err_code ndr_err;
129 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, info3,
130 (ndr_push_flags_fn_t)ndr_push_netr_SamInfo3);
131 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
132 DEBUG(0,("append_info3_as_ndr: failed to append\n"));
133 return ndr_map_error2ntstatus(ndr_err);
136 state->response->extra_data.data = blob.data;
137 state->response->length += blob.length;
142 static NTSTATUS append_unix_username(TALLOC_CTX *mem_ctx,
143 struct winbindd_cli_state *state,
144 const struct netr_SamInfo3 *info3,
145 const char *name_domain,
146 const char *name_user)
148 /* We've been asked to return the unix username, per
149 'winbind use default domain' settings and the like */
151 const char *nt_username, *nt_domain;
153 nt_domain = talloc_strdup(mem_ctx, info3->base.domain.string);
155 /* If the server didn't give us one, just use the one
157 nt_domain = name_domain;
160 nt_username = talloc_strdup(mem_ctx, info3->base.account_name.string);
162 /* If the server didn't give us one, just use the one
164 nt_username = name_user;
167 fill_domain_username(state->response->data.auth.unix_username,
168 nt_domain, nt_username, true);
170 DEBUG(5,("Setting unix username to [%s]\n",
171 state->response->data.auth.unix_username));
176 static NTSTATUS append_afs_token(TALLOC_CTX *mem_ctx,
177 struct winbindd_cli_state *state,
178 const struct netr_SamInfo3 *info3,
179 const char *name_domain,
180 const char *name_user)
182 char *afsname = NULL;
186 afsname = talloc_strdup(mem_ctx, lp_afs_username_map());
187 if (afsname == NULL) {
188 return NT_STATUS_NO_MEMORY;
191 afsname = talloc_string_sub(mem_ctx,
192 lp_afs_username_map(),
194 afsname = talloc_string_sub(mem_ctx, afsname,
196 afsname = talloc_string_sub(mem_ctx, afsname,
200 struct dom_sid user_sid;
203 sid_compose(&user_sid, info3->base.domain_sid,
205 sid_to_fstring(sidstr, &user_sid);
206 afsname = talloc_string_sub(mem_ctx, afsname,
210 if (afsname == NULL) {
211 return NT_STATUS_NO_MEMORY;
216 DEBUG(10, ("Generating token for user %s\n", afsname));
218 cell = strchr(afsname, '@');
221 return NT_STATUS_NO_MEMORY;
227 token = afs_createtoken_str(afsname, cell);
231 state->response->extra_data.data = talloc_strdup(state->mem_ctx,
233 if (state->response->extra_data.data == NULL) {
234 return NT_STATUS_NO_MEMORY;
236 state->response->length +=
237 strlen((const char *)state->response->extra_data.data)+1;
242 static NTSTATUS check_info3_in_group(struct netr_SamInfo3 *info3,
243 const char *group_sid)
245 * Check whether a user belongs to a group or list of groups.
247 * @param mem_ctx talloc memory context.
248 * @param info3 user information, including group membership info.
249 * @param group_sid One or more groups , separated by commas.
251 * @return NT_STATUS_OK on success,
252 * NT_STATUS_LOGON_FAILURE if the user does not belong,
253 * or other NT_STATUS_IS_ERR(status) for other kinds of failure.
256 struct dom_sid *require_membership_of_sid;
257 size_t num_require_membership_of_sid;
262 struct nt_user_token *token;
263 TALLOC_CTX *frame = talloc_stackframe();
266 /* Parse the 'required group' SID */
268 if (!group_sid || !group_sid[0]) {
269 /* NO sid supplied, all users may access */
273 token = talloc_zero(talloc_tos(), struct nt_user_token);
275 DEBUG(0, ("talloc failed\n"));
277 return NT_STATUS_NO_MEMORY;
280 num_require_membership_of_sid = 0;
281 require_membership_of_sid = NULL;
285 while (next_token_talloc(talloc_tos(), &p, &req_sid, ",")) {
286 if (!string_to_sid(&sid, req_sid)) {
287 DEBUG(0, ("check_info3_in_group: could not parse %s "
288 "as a SID!", req_sid));
290 return NT_STATUS_INVALID_PARAMETER;
293 status = add_sid_to_array(talloc_tos(), &sid,
294 &require_membership_of_sid,
295 &num_require_membership_of_sid);
296 if (!NT_STATUS_IS_OK(status)) {
297 DEBUG(0, ("add_sid_to_array failed\n"));
303 status = sid_array_from_info3(talloc_tos(), info3,
307 if (!NT_STATUS_IS_OK(status)) {
312 if (!NT_STATUS_IS_OK(status = add_aliases(get_global_sam_sid(),
314 || !NT_STATUS_IS_OK(status = add_aliases(&global_sid_Builtin,
316 DEBUG(3, ("could not add aliases: %s\n",
322 debug_nt_user_token(DBGC_CLASS, 10, token);
324 for (i=0; i<num_require_membership_of_sid; i++) {
325 DEBUG(10, ("Checking SID %s\n", sid_string_dbg(
326 &require_membership_of_sid[i])));
327 if (nt_token_check_sid(&require_membership_of_sid[i],
329 DEBUG(10, ("Access ok\n"));
335 /* Do not distinguish this error from a wrong username/pw */
338 return NT_STATUS_LOGON_FAILURE;
341 struct winbindd_domain *find_auth_domain(uint8_t flags,
342 const char *domain_name)
344 struct winbindd_domain *domain;
347 domain = find_domain_from_name_noinit(domain_name);
348 if (domain == NULL) {
349 DEBUG(3, ("Authentication for domain [%s] refused "
350 "as it is not a trusted domain\n",
356 if (strequal(domain_name, get_global_sam_name())) {
357 return find_domain_from_name_noinit(domain_name);
360 /* we can auth against trusted domains */
361 if (flags & WBFLAG_PAM_CONTACT_TRUSTDOM) {
362 domain = find_domain_from_name_noinit(domain_name);
363 if (domain == NULL) {
364 DEBUG(3, ("Authentication for domain [%s] skipped "
365 "as it is not a trusted domain\n",
372 return find_our_domain();
375 static void fill_in_password_policy(struct winbindd_response *r,
376 const struct samr_DomInfo1 *p)
378 r->data.auth.policy.min_length_password =
379 p->min_password_length;
380 r->data.auth.policy.password_history =
381 p->password_history_length;
382 r->data.auth.policy.password_properties =
383 p->password_properties;
384 r->data.auth.policy.expire =
385 nt_time_to_unix_abs((NTTIME *)&(p->max_password_age));
386 r->data.auth.policy.min_passwordage =
387 nt_time_to_unix_abs((NTTIME *)&(p->min_password_age));
390 static NTSTATUS fillup_password_policy(struct winbindd_domain *domain,
391 struct winbindd_cli_state *state)
393 struct winbindd_methods *methods;
394 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
395 struct samr_DomInfo1 password_policy;
397 if ( !winbindd_can_contact_domain( domain ) ) {
398 DEBUG(5,("fillup_password_policy: No inbound trust to "
399 "contact domain %s\n", domain->name));
400 return NT_STATUS_NOT_SUPPORTED;
403 methods = domain->methods;
405 status = methods->password_policy(domain, state->mem_ctx, &password_policy);
406 if (NT_STATUS_IS_ERR(status)) {
410 fill_in_password_policy(state->response, &password_policy);
415 static NTSTATUS get_max_bad_attempts_from_lockout_policy(struct winbindd_domain *domain,
417 uint16 *lockout_threshold)
419 struct winbindd_methods *methods;
420 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
421 struct samr_DomInfo12 lockout_policy;
423 *lockout_threshold = 0;
425 methods = domain->methods;
427 status = methods->lockout_policy(domain, mem_ctx, &lockout_policy);
428 if (NT_STATUS_IS_ERR(status)) {
432 *lockout_threshold = lockout_policy.lockout_threshold;
437 static NTSTATUS get_pwd_properties(struct winbindd_domain *domain,
439 uint32 *password_properties)
441 struct winbindd_methods *methods;
442 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
443 struct samr_DomInfo1 password_policy;
445 *password_properties = 0;
447 methods = domain->methods;
449 status = methods->password_policy(domain, mem_ctx, &password_policy);
450 if (NT_STATUS_IS_ERR(status)) {
454 *password_properties = password_policy.password_properties;
461 static const char *generate_krb5_ccache(TALLOC_CTX *mem_ctx,
464 bool *internal_ccache)
466 /* accept FILE and WRFILE as krb5_cc_type from the client and then
467 * build the full ccname string based on the user's uid here -
470 const char *gen_cc = NULL;
472 *internal_ccache = true;
478 if (!type || type[0] == '\0') {
482 if (strequal(type, "FILE")) {
483 gen_cc = talloc_asprintf(mem_ctx, "FILE:/tmp/krb5cc_%d", uid);
484 } else if (strequal(type, "WRFILE")) {
485 gen_cc = talloc_asprintf(mem_ctx, "WRFILE:/tmp/krb5cc_%d", uid);
487 DEBUG(10,("we don't allow to set a %s type ccache\n", type));
491 *internal_ccache = false;
495 gen_cc = talloc_strdup(mem_ctx, "MEMORY:winbindd_pam_ccache");
498 if (gen_cc == NULL) {
499 DEBUG(0,("out of memory\n"));
503 DEBUG(10,("using ccache: %s %s\n", gen_cc, *internal_ccache ? "(internal)":""));
508 static void setup_return_cc_name(struct winbindd_cli_state *state, const char *cc)
510 const char *type = state->request->data.auth.krb5_cc_type;
512 state->response->data.auth.krb5ccname[0] = '\0';
514 if (type[0] == '\0') {
518 if (!strequal(type, "FILE") &&
519 !strequal(type, "WRFILE")) {
520 DEBUG(10,("won't return krbccname for a %s type ccache\n",
525 fstrcpy(state->response->data.auth.krb5ccname, cc);
530 uid_t get_uid_from_request(struct winbindd_request *request)
534 uid = request->data.auth.uid;
537 DEBUG(1,("invalid uid: '%u'\n", (unsigned int)uid));
543 static uid_t get_uid_from_state(struct winbindd_cli_state *state)
545 return get_uid_from_request(state->request);
548 /**********************************************************************
549 Authenticate a user with a clear text password using Kerberos and fill up
551 **********************************************************************/
553 static NTSTATUS winbindd_raw_kerberos_login(struct winbindd_domain *domain,
554 struct winbindd_cli_state *state,
555 struct netr_SamInfo3 **info3)
558 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
559 krb5_error_code krb5_ret;
560 const char *cc = NULL;
561 const char *principal_s = NULL;
562 const char *service = NULL;
564 fstring name_domain, name_user;
565 time_t ticket_lifetime = 0;
566 time_t renewal_until = 0;
569 time_t time_offset = 0;
570 bool internal_ccache = true;
571 struct PAC_LOGON_INFO *logon_info = NULL;
576 * prepare a krb5_cc_cache string for the user */
578 uid = get_uid_from_state(state);
580 DEBUG(0,("no valid uid\n"));
583 cc = generate_krb5_ccache(state->mem_ctx,
584 state->request->data.auth.krb5_cc_type,
585 state->request->data.auth.uid,
588 return NT_STATUS_NO_MEMORY;
593 * get kerberos properties */
595 if (domain->private_data) {
596 ads = (ADS_STRUCT *)domain->private_data;
597 time_offset = ads->auth.time_offset;
602 * do kerberos auth and setup ccache as the user */
604 parse_domain_user(state->request->data.auth.user, name_domain, name_user);
606 realm = domain->alt_name;
609 principal_s = talloc_asprintf(state->mem_ctx, "%s@%s", name_user, realm);
610 if (principal_s == NULL) {
611 return NT_STATUS_NO_MEMORY;
614 service = talloc_asprintf(state->mem_ctx, "%s/%s@%s", KRB5_TGS_NAME, realm, realm);
615 if (service == NULL) {
616 return NT_STATUS_NO_MEMORY;
619 /* if this is a user ccache, we need to act as the user to let the krb5
620 * library handle the chown, etc. */
622 /************************ ENTERING NON-ROOT **********************/
624 if (!internal_ccache) {
625 set_effective_uid(uid);
626 DEBUG(10,("winbindd_raw_kerberos_login: uid is %d\n", uid));
629 result = kerberos_return_pac(state->mem_ctx,
631 state->request->data.auth.pass,
638 WINBINDD_PAM_AUTH_KRB5_RENEW_TIME,
641 if (!internal_ccache) {
642 gain_root_privilege();
645 /************************ RETURNED TO ROOT **********************/
647 if (!NT_STATUS_IS_OK(result)) {
651 *info3 = &logon_info->info3;
653 DEBUG(10,("winbindd_raw_kerberos_login: winbindd validated ticket of %s\n",
656 /* if we had a user's ccache then return that string for the pam
659 if (!internal_ccache) {
661 setup_return_cc_name(state, cc);
663 result = add_ccache_to_list(principal_s,
666 state->request->data.auth.user,
674 if (!NT_STATUS_IS_OK(result)) {
675 DEBUG(10,("winbindd_raw_kerberos_login: failed to add ccache to list: %s\n",
680 /* need to delete the memory cred cache, it is not used anymore */
682 krb5_ret = ads_kdestroy(cc);
684 DEBUG(3,("winbindd_raw_kerberos_login: "
685 "could not destroy krb5 credential cache: "
686 "%s\n", error_message(krb5_ret)));
695 /* we could have created a new credential cache with a valid tgt in it
696 * but we werent able to get or verify the service ticket for this
697 * local host and therefor didn't get the PAC, we need to remove that
698 * cache entirely now */
700 krb5_ret = ads_kdestroy(cc);
702 DEBUG(3,("winbindd_raw_kerberos_login: "
703 "could not destroy krb5 credential cache: "
704 "%s\n", error_message(krb5_ret)));
707 if (!NT_STATUS_IS_OK(remove_ccache(state->request->data.auth.user))) {
708 DEBUG(3,("winbindd_raw_kerberos_login: "
709 "could not remove ccache for user %s\n",
710 state->request->data.auth.user));
715 return NT_STATUS_NOT_SUPPORTED;
716 #endif /* HAVE_KRB5 */
719 /****************************************************************
720 ****************************************************************/
722 bool check_request_flags(uint32_t flags)
724 uint32_t flags_edata = WBFLAG_PAM_AFS_TOKEN |
725 WBFLAG_PAM_INFO3_TEXT |
726 WBFLAG_PAM_INFO3_NDR;
728 if ( ( (flags & flags_edata) == WBFLAG_PAM_AFS_TOKEN) ||
729 ( (flags & flags_edata) == WBFLAG_PAM_INFO3_NDR) ||
730 ( (flags & flags_edata) == WBFLAG_PAM_INFO3_TEXT)||
731 !(flags & flags_edata) ) {
735 DEBUG(1, ("check_request_flags: invalid request flags[0x%08X]\n",
741 /****************************************************************
742 ****************************************************************/
744 static NTSTATUS append_auth_data(struct winbindd_cli_state *state,
745 struct netr_SamInfo3 *info3,
746 const char *name_domain,
747 const char *name_user)
750 uint32_t flags = state->request->flags;
752 if (flags & WBFLAG_PAM_USER_SESSION_KEY) {
753 memcpy(state->response->data.auth.user_session_key,
755 sizeof(state->response->data.auth.user_session_key)
759 if (flags & WBFLAG_PAM_LMKEY) {
760 memcpy(state->response->data.auth.first_8_lm_hash,
761 info3->base.LMSessKey.key,
762 sizeof(state->response->data.auth.first_8_lm_hash)
766 if (flags & WBFLAG_PAM_UNIX_NAME) {
767 result = append_unix_username(state->mem_ctx, state, info3,
768 name_domain, name_user);
769 if (!NT_STATUS_IS_OK(result)) {
770 DEBUG(10,("Failed to append Unix Username: %s\n",
776 /* currently, anything from here on potentially overwrites extra_data. */
778 if (flags & WBFLAG_PAM_INFO3_NDR) {
779 result = append_info3_as_ndr(state->mem_ctx, state, info3);
780 if (!NT_STATUS_IS_OK(result)) {
781 DEBUG(10,("Failed to append INFO3 (NDR): %s\n",
787 if (flags & WBFLAG_PAM_INFO3_TEXT) {
788 result = append_info3_as_txt(state->mem_ctx, state, info3);
789 if (!NT_STATUS_IS_OK(result)) {
790 DEBUG(10,("Failed to append INFO3 (TXT): %s\n",
796 if (flags & WBFLAG_PAM_AFS_TOKEN) {
797 result = append_afs_token(state->mem_ctx, state, info3,
798 name_domain, name_user);
799 if (!NT_STATUS_IS_OK(result)) {
800 DEBUG(10,("Failed to append AFS token: %s\n",
809 static NTSTATUS winbindd_dual_pam_auth_cached(struct winbindd_domain *domain,
810 struct winbindd_cli_state *state,
811 struct netr_SamInfo3 **info3)
813 NTSTATUS result = NT_STATUS_LOGON_FAILURE;
814 uint16 max_allowed_bad_attempts;
815 fstring name_domain, name_user;
817 enum lsa_SidType type;
818 uchar new_nt_pass[NT_HASH_LEN];
819 const uint8 *cached_nt_pass;
820 const uint8 *cached_salt;
821 struct netr_SamInfo3 *my_info3;
822 time_t kickoff_time, must_change_time;
823 bool password_good = false;
825 struct winbindd_tdc_domain *tdc_domain = NULL;
832 DEBUG(10,("winbindd_dual_pam_auth_cached\n"));
834 /* Parse domain and username */
836 parse_domain_user(state->request->data.auth.user, name_domain, name_user);
839 if (!lookup_cached_name(state->mem_ctx,
844 DEBUG(10,("winbindd_dual_pam_auth_cached: no such user in the cache\n"));
845 return NT_STATUS_NO_SUCH_USER;
848 if (type != SID_NAME_USER) {
849 DEBUG(10,("winbindd_dual_pam_auth_cached: not a user (%s)\n", sid_type_lookup(type)));
850 return NT_STATUS_LOGON_FAILURE;
853 result = winbindd_get_creds(domain,
859 if (!NT_STATUS_IS_OK(result)) {
860 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get creds: %s\n", nt_errstr(result)));
866 E_md4hash(state->request->data.auth.pass, new_nt_pass);
868 dump_data_pw("new_nt_pass", new_nt_pass, NT_HASH_LEN);
869 dump_data_pw("cached_nt_pass", cached_nt_pass, NT_HASH_LEN);
871 dump_data_pw("cached_salt", cached_salt, NT_HASH_LEN);
875 /* In this case we didn't store the nt_hash itself,
876 but the MD5 combination of salt + nt_hash. */
877 uchar salted_hash[NT_HASH_LEN];
878 E_md5hash(cached_salt, new_nt_pass, salted_hash);
880 password_good = (memcmp(cached_nt_pass, salted_hash,
883 /* Old cached cred - direct store of nt_hash (bad bad bad !). */
884 password_good = (memcmp(cached_nt_pass, new_nt_pass,
890 /* User *DOES* know the password, update logon_time and reset
893 my_info3->base.user_flags |= NETLOGON_CACHED_ACCOUNT;
895 if (my_info3->base.acct_flags & ACB_AUTOLOCK) {
896 return NT_STATUS_ACCOUNT_LOCKED_OUT;
899 if (my_info3->base.acct_flags & ACB_DISABLED) {
900 return NT_STATUS_ACCOUNT_DISABLED;
903 if (my_info3->base.acct_flags & ACB_WSTRUST) {
904 return NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
907 if (my_info3->base.acct_flags & ACB_SVRTRUST) {
908 return NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT;
911 if (my_info3->base.acct_flags & ACB_DOMTRUST) {
912 return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT;
915 if (!(my_info3->base.acct_flags & ACB_NORMAL)) {
916 DEBUG(0,("winbindd_dual_pam_auth_cached: whats wrong with that one?: 0x%08x\n",
917 my_info3->base.acct_flags));
918 return NT_STATUS_LOGON_FAILURE;
921 kickoff_time = nt_time_to_unix(my_info3->base.acct_expiry);
922 if (kickoff_time != 0 && time(NULL) > kickoff_time) {
923 return NT_STATUS_ACCOUNT_EXPIRED;
926 must_change_time = nt_time_to_unix(my_info3->base.force_password_change);
927 if (must_change_time != 0 && must_change_time < time(NULL)) {
928 /* we allow grace logons when the password has expired */
929 my_info3->base.user_flags |= NETLOGON_GRACE_LOGON;
930 /* return NT_STATUS_PASSWORD_EXPIRED; */
935 if ((state->request->flags & WBFLAG_PAM_KRB5) &&
936 ((tdc_domain = wcache_tdc_fetch_domain(state->mem_ctx, name_domain)) != NULL) &&
937 ((tdc_domain->trust_type & NETR_TRUST_TYPE_UPLEVEL) ||
938 /* used to cope with the case winbindd starting without network. */
939 !strequal(tdc_domain->domain_name, tdc_domain->dns_name))) {
942 const char *cc = NULL;
944 const char *principal_s = NULL;
945 const char *service = NULL;
946 bool internal_ccache = false;
948 uid = get_uid_from_state(state);
950 DEBUG(0,("winbindd_dual_pam_auth_cached: invalid uid\n"));
951 return NT_STATUS_INVALID_PARAMETER;
954 cc = generate_krb5_ccache(state->mem_ctx,
955 state->request->data.auth.krb5_cc_type,
956 state->request->data.auth.uid,
959 return NT_STATUS_NO_MEMORY;
962 realm = domain->alt_name;
965 principal_s = talloc_asprintf(state->mem_ctx, "%s@%s", name_user, realm);
966 if (principal_s == NULL) {
967 return NT_STATUS_NO_MEMORY;
970 service = talloc_asprintf(state->mem_ctx, "%s/%s@%s", KRB5_TGS_NAME, realm, realm);
971 if (service == NULL) {
972 return NT_STATUS_NO_MEMORY;
975 if (!internal_ccache) {
977 setup_return_cc_name(state, cc);
979 result = add_ccache_to_list(principal_s,
982 state->request->data.auth.user,
986 time(NULL) + lp_winbind_cache_time(),
987 time(NULL) + WINBINDD_PAM_AUTH_KRB5_RENEW_TIME,
990 if (!NT_STATUS_IS_OK(result)) {
991 DEBUG(10,("winbindd_dual_pam_auth_cached: failed "
992 "to add ccache to list: %s\n",
997 #endif /* HAVE_KRB5 */
999 /* FIXME: we possibly should handle logon hours as well (does xp when
1000 * offline?) see auth/auth_sam.c:sam_account_ok for details */
1002 unix_to_nt_time(&my_info3->base.last_logon, time(NULL));
1003 my_info3->base.bad_password_count = 0;
1005 result = winbindd_update_creds_by_info3(domain,
1007 state->request->data.auth.user,
1008 state->request->data.auth.pass,
1010 if (!NT_STATUS_IS_OK(result)) {
1011 DEBUG(1,("winbindd_dual_pam_auth_cached: failed to update creds: %s\n",
1012 nt_errstr(result)));
1016 return NT_STATUS_OK;
1020 /* User does *NOT* know the correct password, modify info3 accordingly */
1022 /* failure of this is not critical */
1023 result = get_max_bad_attempts_from_lockout_policy(domain, state->mem_ctx, &max_allowed_bad_attempts);
1024 if (!NT_STATUS_IS_OK(result)) {
1025 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get max_allowed_bad_attempts. "
1026 "Won't be able to honour account lockout policies\n"));
1029 /* increase counter */
1030 my_info3->base.bad_password_count++;
1032 if (max_allowed_bad_attempts == 0) {
1037 if (my_info3->base.bad_password_count >= max_allowed_bad_attempts) {
1039 uint32 password_properties;
1041 result = get_pwd_properties(domain, state->mem_ctx, &password_properties);
1042 if (!NT_STATUS_IS_OK(result)) {
1043 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get password properties.\n"));
1046 if ((my_info3->base.rid != DOMAIN_RID_ADMINISTRATOR) ||
1047 (password_properties & DOMAIN_PASSWORD_LOCKOUT_ADMINS)) {
1048 my_info3->base.acct_flags |= ACB_AUTOLOCK;
1053 result = winbindd_update_creds_by_info3(domain,
1055 state->request->data.auth.user,
1059 if (!NT_STATUS_IS_OK(result)) {
1060 DEBUG(0,("winbindd_dual_pam_auth_cached: failed to update creds %s\n",
1061 nt_errstr(result)));
1064 return NT_STATUS_LOGON_FAILURE;
1067 static NTSTATUS winbindd_dual_pam_auth_kerberos(struct winbindd_domain *domain,
1068 struct winbindd_cli_state *state,
1069 struct netr_SamInfo3 **info3)
1071 struct winbindd_domain *contact_domain;
1072 fstring name_domain, name_user;
1075 DEBUG(10,("winbindd_dual_pam_auth_kerberos\n"));
1077 /* Parse domain and username */
1079 parse_domain_user(state->request->data.auth.user, name_domain, name_user);
1081 /* what domain should we contact? */
1084 if (!(contact_domain = find_domain_from_name(name_domain))) {
1085 DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
1086 state->request->data.auth.user, name_domain, name_user, name_domain));
1087 result = NT_STATUS_NO_SUCH_USER;
1092 if (is_myname(name_domain)) {
1093 DEBUG(3, ("Authentication for domain %s (local domain to this server) not supported at this stage\n", name_domain));
1094 result = NT_STATUS_NO_SUCH_USER;
1098 contact_domain = find_domain_from_name(name_domain);
1099 if (contact_domain == NULL) {
1100 DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
1101 state->request->data.auth.user, name_domain, name_user, name_domain));
1103 contact_domain = find_our_domain();
1107 if (contact_domain->initialized &&
1108 contact_domain->active_directory) {
1112 if (!contact_domain->initialized) {
1113 init_dc_connection(contact_domain);
1116 if (!contact_domain->active_directory) {
1117 DEBUG(3,("krb5 auth requested but domain is not Active Directory\n"));
1118 return NT_STATUS_INVALID_LOGON_TYPE;
1121 result = winbindd_raw_kerberos_login(contact_domain, state, info3);
1126 static NTSTATUS winbindd_dual_auth_passdb(TALLOC_CTX *mem_ctx,
1127 const char *domain, const char *user,
1128 const DATA_BLOB *challenge,
1129 const DATA_BLOB *lm_resp,
1130 const DATA_BLOB *nt_resp,
1131 struct netr_SamInfo3 **pinfo3)
1133 struct auth_usersupplied_info *user_info = NULL;
1136 status = make_user_info(&user_info, user, user, domain, domain,
1137 global_myname(), lm_resp, nt_resp, NULL, NULL,
1138 NULL, AUTH_PASSWORD_RESPONSE);
1139 if (!NT_STATUS_IS_OK(status)) {
1140 DEBUG(10, ("make_user_info failed: %s\n", nt_errstr(status)));
1144 /* We don't want any more mapping of the username */
1145 user_info->mapped_state = True;
1147 status = check_sam_security_info3(challenge, talloc_tos(), user_info,
1149 free_user_info(&user_info);
1150 DEBUG(10, ("Authenticated user %s\\%s successfully\n", domain, user));
1151 return NT_STATUS_OK;
1154 typedef NTSTATUS (*netlogon_fn_t)(struct rpc_pipe_client *cli,
1155 TALLOC_CTX *mem_ctx,
1156 uint32 logon_parameters,
1158 const char *username,
1160 const char *workstation,
1161 const uint8 chal[8],
1162 DATA_BLOB lm_response,
1163 DATA_BLOB nt_response,
1164 struct netr_SamInfo3 **info3);
1166 static NTSTATUS winbindd_dual_pam_auth_samlogon(struct winbindd_domain *domain,
1167 struct winbindd_cli_state *state,
1168 struct netr_SamInfo3 **info3)
1171 struct rpc_pipe_client *netlogon_pipe;
1176 unsigned char local_lm_response[24];
1177 unsigned char local_nt_response[24];
1178 fstring name_domain, name_user;
1181 struct netr_SamInfo3 *my_info3 = NULL;
1185 DEBUG(10,("winbindd_dual_pam_auth_samlogon\n"));
1187 /* Parse domain and username */
1189 parse_domain_user(state->request->data.auth.user, name_domain, name_user);
1191 /* do password magic */
1193 generate_random_buffer(chal, sizeof(chal));
1195 if (lp_client_ntlmv2_auth()) {
1196 DATA_BLOB server_chal;
1197 DATA_BLOB names_blob;
1198 DATA_BLOB nt_response;
1199 DATA_BLOB lm_response;
1200 server_chal = data_blob_talloc(state->mem_ctx, chal, 8);
1202 /* note that the 'workgroup' here is a best guess - we don't know
1203 the server's domain at this point. The 'server name' is also
1206 names_blob = NTLMv2_generate_names_blob(state->mem_ctx, global_myname(), lp_workgroup());
1208 if (!SMBNTLMv2encrypt(NULL, name_user, name_domain,
1209 state->request->data.auth.pass,
1212 &lm_response, &nt_response, NULL, NULL)) {
1213 data_blob_free(&names_blob);
1214 data_blob_free(&server_chal);
1215 DEBUG(0, ("winbindd_pam_auth: SMBNTLMv2encrypt() failed!\n"));
1216 result = NT_STATUS_NO_MEMORY;
1219 data_blob_free(&names_blob);
1220 data_blob_free(&server_chal);
1221 lm_resp = data_blob_talloc(state->mem_ctx, lm_response.data,
1222 lm_response.length);
1223 nt_resp = data_blob_talloc(state->mem_ctx, nt_response.data,
1224 nt_response.length);
1225 data_blob_free(&lm_response);
1226 data_blob_free(&nt_response);
1229 if (lp_client_lanman_auth()
1230 && SMBencrypt(state->request->data.auth.pass,
1232 local_lm_response)) {
1233 lm_resp = data_blob_talloc(state->mem_ctx,
1235 sizeof(local_lm_response));
1237 lm_resp = data_blob_null;
1239 SMBNTencrypt(state->request->data.auth.pass,
1243 nt_resp = data_blob_talloc(state->mem_ctx,
1245 sizeof(local_nt_response));
1248 if (strequal(name_domain, get_global_sam_name())) {
1249 DATA_BLOB chal_blob = data_blob_const(chal, sizeof(chal));
1251 result = winbindd_dual_auth_passdb(
1252 state->mem_ctx, name_domain, name_user,
1253 &chal_blob, &lm_resp, &nt_resp, info3);
1257 /* check authentication loop */
1260 netlogon_fn_t logon_fn;
1262 ZERO_STRUCTP(my_info3);
1265 result = cm_connect_netlogon(domain, &netlogon_pipe);
1267 if (!NT_STATUS_IS_OK(result)) {
1268 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
1272 /* It is really important to try SamLogonEx here,
1273 * because in a clustered environment, we want to use
1274 * one machine account from multiple physical
1277 * With a normal SamLogon call, we must keep the
1278 * credentials chain updated and intact between all
1279 * users of the machine account (which would imply
1280 * cross-node communication for every NTLM logon).
1282 * (The credentials chain is not per NETLOGON pipe
1283 * connection, but globally on the server/client pair
1286 * When using SamLogonEx, the credentials are not
1287 * supplied, but the session key is implied by the
1288 * wrapping SamLogon context.
1290 * -- abartlet 21 April 2008
1293 logon_fn = domain->can_do_samlogon_ex
1294 ? rpccli_netlogon_sam_network_logon_ex
1295 : rpccli_netlogon_sam_network_logon;
1297 result = logon_fn(netlogon_pipe,
1300 domain->dcname, /* server name */
1301 name_user, /* user name */
1302 name_domain, /* target domain */
1303 global_myname(), /* workstation */
1310 if ((NT_STATUS_V(result) == DCERPC_FAULT_OP_RNG_ERROR)
1311 && domain->can_do_samlogon_ex) {
1312 DEBUG(3, ("Got a DC that can not do NetSamLogonEx, "
1313 "retrying with NetSamLogon\n"));
1314 domain->can_do_samlogon_ex = false;
1319 /* We have to try a second time as cm_connect_netlogon
1320 might not yet have noticed that the DC has killed
1323 if (!rpccli_is_connected(netlogon_pipe)) {
1328 /* if we get access denied, a possible cause was that we had
1329 and open connection to the DC, but someone changed our
1330 machine account password out from underneath us using 'net
1331 rpc changetrustpw' */
1333 if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
1334 DEBUG(3,("winbindd_pam_auth: sam_logon returned "
1335 "ACCESS_DENIED. Maybe the trust account "
1336 "password was changed and we didn't know it. "
1337 "Killing connections to domain %s\n",
1339 invalidate_cm_connection(&domain->conn);
1343 } while ( (attempts < 2) && retry );
1345 /* handle the case where a NT4 DC does not fill in the acct_flags in
1346 * the samlogon reply info3. When accurate info3 is required by the
1347 * caller, we look up the account flags ourselve - gd */
1349 if ((state->request->flags & WBFLAG_PAM_INFO3_TEXT) &&
1350 NT_STATUS_IS_OK(result) && (my_info3->base.acct_flags == 0)) {
1352 struct rpc_pipe_client *samr_pipe;
1353 struct policy_handle samr_domain_handle, user_pol;
1354 union samr_UserInfo *info = NULL;
1355 NTSTATUS status_tmp;
1358 status_tmp = cm_connect_sam(domain, state->mem_ctx,
1359 &samr_pipe, &samr_domain_handle);
1361 if (!NT_STATUS_IS_OK(status_tmp)) {
1362 DEBUG(3, ("could not open handle to SAMR pipe: %s\n",
1363 nt_errstr(status_tmp)));
1367 status_tmp = rpccli_samr_OpenUser(samr_pipe, state->mem_ctx,
1368 &samr_domain_handle,
1369 MAXIMUM_ALLOWED_ACCESS,
1373 if (!NT_STATUS_IS_OK(status_tmp)) {
1374 DEBUG(3, ("could not open user handle on SAMR pipe: %s\n",
1375 nt_errstr(status_tmp)));
1379 status_tmp = rpccli_samr_QueryUserInfo(samr_pipe, state->mem_ctx,
1384 if (!NT_STATUS_IS_OK(status_tmp)) {
1385 DEBUG(3, ("could not query user info on SAMR pipe: %s\n",
1386 nt_errstr(status_tmp)));
1387 rpccli_samr_Close(samr_pipe, state->mem_ctx, &user_pol);
1391 acct_flags = info->info16.acct_flags;
1393 if (acct_flags == 0) {
1394 rpccli_samr_Close(samr_pipe, state->mem_ctx, &user_pol);
1398 my_info3->base.acct_flags = acct_flags;
1400 DEBUG(10,("successfully retrieved acct_flags 0x%x\n", acct_flags));
1402 rpccli_samr_Close(samr_pipe, state->mem_ctx, &user_pol);
1410 enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain,
1411 struct winbindd_cli_state *state)
1413 NTSTATUS result = NT_STATUS_LOGON_FAILURE;
1414 NTSTATUS krb5_result = NT_STATUS_OK;
1415 fstring name_domain, name_user;
1417 fstring domain_user;
1418 struct netr_SamInfo3 *info3 = NULL;
1419 NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL;
1421 /* Ensure null termination */
1422 state->request->data.auth.user[sizeof(state->request->data.auth.user)-1]='\0';
1424 /* Ensure null termination */
1425 state->request->data.auth.pass[sizeof(state->request->data.auth.pass)-1]='\0';
1427 DEBUG(3, ("[%5lu]: dual pam auth %s\n", (unsigned long)state->pid,
1428 state->request->data.auth.user));
1430 if (!check_request_flags(state->request->flags)) {
1431 result = NT_STATUS_INVALID_PARAMETER_MIX;
1435 /* Parse domain and username */
1437 name_map_status = normalize_name_unmap(state->mem_ctx,
1438 state->request->data.auth.user,
1441 /* If the name normalization didnt' actually do anything,
1442 just use the original name */
1444 if (!NT_STATUS_IS_OK(name_map_status) &&
1445 !NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED))
1447 mapped_user = state->request->data.auth.user;
1450 parse_domain_user(mapped_user, name_domain, name_user);
1452 if ( mapped_user != state->request->data.auth.user ) {
1453 fstr_sprintf( domain_user, "%s\\%s", name_domain, name_user );
1454 safe_strcpy( state->request->data.auth.user, domain_user,
1455 sizeof(state->request->data.auth.user)-1 );
1458 if (domain->online == false) {
1459 result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
1460 if (domain->startup) {
1461 /* Logons are very important to users. If we're offline and
1462 we get a request within the first 30 seconds of startup,
1463 try very hard to find a DC and go online. */
1465 DEBUG(10,("winbindd_dual_pam_auth: domain: %s offline and auth "
1466 "request in startup mode.\n", domain->name ));
1468 winbindd_flush_negative_conn_cache(domain);
1469 result = init_dc_connection(domain);
1473 DEBUG(10,("winbindd_dual_pam_auth: domain: %s last was %s\n", domain->name, domain->online ? "online":"offline"));
1475 /* Check for Kerberos authentication */
1476 if (domain->online && (state->request->flags & WBFLAG_PAM_KRB5)) {
1478 result = winbindd_dual_pam_auth_kerberos(domain, state, &info3);
1479 /* save for later */
1480 krb5_result = result;
1483 if (NT_STATUS_IS_OK(result)) {
1484 DEBUG(10,("winbindd_dual_pam_auth_kerberos succeeded\n"));
1485 goto process_result;
1487 DEBUG(10,("winbindd_dual_pam_auth_kerberos failed: %s\n", nt_errstr(result)));
1490 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
1491 NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
1492 NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1493 DEBUG(10,("winbindd_dual_pam_auth_kerberos setting domain to offline\n"));
1494 set_domain_offline( domain );
1498 /* there are quite some NT_STATUS errors where there is no
1499 * point in retrying with a samlogon, we explictly have to take
1500 * care not to increase the bad logon counter on the DC */
1502 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_DISABLED) ||
1503 NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_EXPIRED) ||
1504 NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_LOCKED_OUT) ||
1505 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_LOGON_HOURS) ||
1506 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_WORKSTATION) ||
1507 NT_STATUS_EQUAL(result, NT_STATUS_LOGON_FAILURE) ||
1508 NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER) ||
1509 NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_EXPIRED) ||
1510 NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_MUST_CHANGE) ||
1511 NT_STATUS_EQUAL(result, NT_STATUS_WRONG_PASSWORD)) {
1515 if (state->request->flags & WBFLAG_PAM_FALLBACK_AFTER_KRB5) {
1516 DEBUG(3,("falling back to samlogon\n"));
1524 /* Check for Samlogon authentication */
1525 if (domain->online) {
1526 result = winbindd_dual_pam_auth_samlogon(domain, state, &info3);
1528 if (NT_STATUS_IS_OK(result)) {
1529 DEBUG(10,("winbindd_dual_pam_auth_samlogon succeeded\n"));
1530 /* add the Krb5 err if we have one */
1531 if ( NT_STATUS_EQUAL(krb5_result, NT_STATUS_TIME_DIFFERENCE_AT_DC ) ) {
1532 info3->base.user_flags |= LOGON_KRB5_FAIL_CLOCK_SKEW;
1534 goto process_result;
1537 DEBUG(10,("winbindd_dual_pam_auth_samlogon failed: %s\n",
1538 nt_errstr(result)));
1540 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
1541 NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
1542 NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND))
1544 DEBUG(10,("winbindd_dual_pam_auth_samlogon setting domain to offline\n"));
1545 set_domain_offline( domain );
1549 if (domain->online) {
1550 /* We're still online - fail. */
1556 /* Check for Cached logons */
1557 if (!domain->online && (state->request->flags & WBFLAG_PAM_CACHED_LOGIN) &&
1558 lp_winbind_offline_logon()) {
1560 result = winbindd_dual_pam_auth_cached(domain, state, &info3);
1562 if (NT_STATUS_IS_OK(result)) {
1563 DEBUG(10,("winbindd_dual_pam_auth_cached succeeded\n"));
1564 goto process_result;
1566 DEBUG(10,("winbindd_dual_pam_auth_cached failed: %s\n", nt_errstr(result)));
1573 if (NT_STATUS_IS_OK(result)) {
1575 struct dom_sid user_sid;
1577 /* In all codepaths where result == NT_STATUS_OK info3 must have
1578 been initialized. */
1580 result = NT_STATUS_INTERNAL_ERROR;
1584 wcache_invalidate_samlogon(find_domain_from_name(name_domain), info3);
1585 netsamlogon_cache_store(name_user, info3);
1587 /* save name_to_sid info as early as possible (only if
1588 this is our primary domain so we don't invalidate
1589 the cache entry by storing the seq_num for the wrong
1591 if ( domain->primary ) {
1592 sid_compose(&user_sid, info3->base.domain_sid,
1594 cache_name2sid(domain, name_domain, name_user,
1595 SID_NAME_USER, &user_sid);
1598 /* Check if the user is in the right group */
1600 result = check_info3_in_group(
1602 state->request->data.auth.require_membership_of_sid);
1603 if (!NT_STATUS_IS_OK(result)) {
1604 DEBUG(3, ("User %s is not in the required group (%s), so plaintext authentication is rejected\n",
1605 state->request->data.auth.user,
1606 state->request->data.auth.require_membership_of_sid));
1610 result = append_auth_data(state, info3, name_domain,
1612 if (!NT_STATUS_IS_OK(result)) {
1616 if ((state->request->flags & WBFLAG_PAM_CACHED_LOGIN)) {
1618 if (lp_winbind_offline_logon()) {
1619 result = winbindd_store_creds(domain,
1621 state->request->data.auth.user,
1622 state->request->data.auth.pass,
1628 if (state->request->flags & WBFLAG_PAM_GET_PWD_POLICY) {
1629 struct winbindd_domain *our_domain = find_our_domain();
1631 /* This is not entirely correct I believe, but it is
1632 consistent. Only apply the password policy settings
1633 too warn users for our own domain. Cannot obtain these
1634 from trusted DCs all the time so don't do it at all.
1637 result = NT_STATUS_NOT_SUPPORTED;
1638 if (our_domain == domain ) {
1639 result = fillup_password_policy(our_domain, state);
1642 if (!NT_STATUS_IS_OK(result)
1643 && !NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED) )
1645 DEBUG(10,("Failed to get password policies for domain %s: %s\n",
1646 domain->name, nt_errstr(result)));
1651 result = NT_STATUS_OK;
1655 /* give us a more useful (more correct?) error code */
1656 if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
1657 (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
1658 result = NT_STATUS_NO_LOGON_SERVERS;
1661 set_auth_errors(state->response, result);
1663 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, ("Plain-text authentication for user %s returned %s (PAM: %d)\n",
1664 state->request->data.auth.user,
1665 state->response->data.auth.nt_status_string,
1666 state->response->data.auth.pam_error));
1668 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
1671 enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain,
1672 struct winbindd_cli_state *state)
1675 struct netr_SamInfo3 *info3 = NULL;
1676 struct rpc_pipe_client *netlogon_pipe;
1677 const char *name_user = NULL;
1678 const char *name_domain = NULL;
1679 const char *workstation;
1683 DATA_BLOB lm_resp, nt_resp;
1685 /* This is child-only, so no check for privileged access is needed
1688 /* Ensure null termination */
1689 state->request->data.auth_crap.user[sizeof(state->request->data.auth_crap.user)-1]=0;
1690 state->request->data.auth_crap.domain[sizeof(state->request->data.auth_crap.domain)-1]=0;
1692 if (!check_request_flags(state->request->flags)) {
1693 result = NT_STATUS_INVALID_PARAMETER_MIX;
1697 name_user = state->request->data.auth_crap.user;
1699 if (*state->request->data.auth_crap.domain) {
1700 name_domain = state->request->data.auth_crap.domain;
1701 } else if (lp_winbind_use_default_domain()) {
1702 name_domain = lp_workgroup();
1704 DEBUG(5,("no domain specified with username (%s) - failing auth\n",
1706 result = NT_STATUS_NO_SUCH_USER;
1710 DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n", (unsigned long)state->pid,
1711 name_domain, name_user));
1713 if (*state->request->data.auth_crap.workstation) {
1714 workstation = state->request->data.auth_crap.workstation;
1716 workstation = global_myname();
1719 if (state->request->data.auth_crap.lm_resp_len > sizeof(state->request->data.auth_crap.lm_resp)
1720 || state->request->data.auth_crap.nt_resp_len > sizeof(state->request->data.auth_crap.nt_resp)) {
1721 if (!(state->request->flags & WBFLAG_BIG_NTLMV2_BLOB) ||
1722 state->request->extra_len != state->request->data.auth_crap.nt_resp_len) {
1723 DEBUG(0, ("winbindd_pam_auth_crap: invalid password length %u/%u\n",
1724 state->request->data.auth_crap.lm_resp_len,
1725 state->request->data.auth_crap.nt_resp_len));
1726 result = NT_STATUS_INVALID_PARAMETER;
1731 lm_resp = data_blob_talloc(state->mem_ctx, state->request->data.auth_crap.lm_resp,
1732 state->request->data.auth_crap.lm_resp_len);
1734 if (state->request->flags & WBFLAG_BIG_NTLMV2_BLOB) {
1735 nt_resp = data_blob_talloc(state->mem_ctx,
1736 state->request->extra_data.data,
1737 state->request->data.auth_crap.nt_resp_len);
1739 nt_resp = data_blob_talloc(state->mem_ctx,
1740 state->request->data.auth_crap.nt_resp,
1741 state->request->data.auth_crap.nt_resp_len);
1744 if (strequal(name_domain, get_global_sam_name())) {
1745 DATA_BLOB chal_blob = data_blob_const(
1746 state->request->data.auth_crap.chal,
1747 sizeof(state->request->data.auth_crap.chal));
1749 result = winbindd_dual_auth_passdb(
1750 state->mem_ctx, name_domain, name_user,
1751 &chal_blob, &lm_resp, &nt_resp, &info3);
1752 goto process_result;
1756 netlogon_fn_t logon_fn;
1760 netlogon_pipe = NULL;
1761 result = cm_connect_netlogon(domain, &netlogon_pipe);
1763 if (!NT_STATUS_IS_OK(result)) {
1764 DEBUG(3, ("could not open handle to NETLOGON pipe (error: %s)\n",
1765 nt_errstr(result)));
1769 logon_fn = domain->can_do_samlogon_ex
1770 ? rpccli_netlogon_sam_network_logon_ex
1771 : rpccli_netlogon_sam_network_logon;
1773 result = logon_fn(netlogon_pipe,
1775 state->request->data.auth_crap.logon_parameters,
1779 /* Bug #3248 - found by Stefan Burkei. */
1780 workstation, /* We carefully set this above so use it... */
1781 state->request->data.auth_crap.chal,
1786 if ((NT_STATUS_V(result) == DCERPC_FAULT_OP_RNG_ERROR)
1787 && domain->can_do_samlogon_ex) {
1788 DEBUG(3, ("Got a DC that can not do NetSamLogonEx, "
1789 "retrying with NetSamLogon\n"));
1790 domain->can_do_samlogon_ex = false;
1797 /* We have to try a second time as cm_connect_netlogon
1798 might not yet have noticed that the DC has killed
1801 if (!rpccli_is_connected(netlogon_pipe)) {
1806 /* if we get access denied, a possible cause was that we had and open
1807 connection to the DC, but someone changed our machine account password
1808 out from underneath us using 'net rpc changetrustpw' */
1810 if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
1811 DEBUG(3,("winbindd_pam_auth: sam_logon returned "
1812 "ACCESS_DENIED. Maybe the trust account "
1813 "password was changed and we didn't know it. "
1814 "Killing connections to domain %s\n",
1816 invalidate_cm_connection(&domain->conn);
1820 } while ( (attempts < 2) && retry );
1824 if (NT_STATUS_IS_OK(result)) {
1826 wcache_invalidate_samlogon(find_domain_from_name(name_domain), info3);
1827 netsamlogon_cache_store(name_user, info3);
1829 /* Check if the user is in the right group */
1831 result = check_info3_in_group(
1833 state->request->data.auth_crap.require_membership_of_sid);
1834 if (!NT_STATUS_IS_OK(result)) {
1835 DEBUG(3, ("User %s is not in the required group (%s), so "
1836 "crap authentication is rejected\n",
1837 state->request->data.auth_crap.user,
1838 state->request->data.auth_crap.require_membership_of_sid));
1842 result = append_auth_data(state, info3, name_domain,
1844 if (!NT_STATUS_IS_OK(result)) {
1851 /* give us a more useful (more correct?) error code */
1852 if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
1853 (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
1854 result = NT_STATUS_NO_LOGON_SERVERS;
1857 if (state->request->flags & WBFLAG_PAM_NT_STATUS_SQUASH) {
1858 result = nt_status_squash(result);
1861 set_auth_errors(state->response, result);
1863 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
1864 ("NTLM CRAP authentication for user [%s]\\[%s] returned %s (PAM: %d)\n",
1867 state->response->data.auth.nt_status_string,
1868 state->response->data.auth.pam_error));
1870 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
1873 enum winbindd_result winbindd_dual_pam_chauthtok(struct winbindd_domain *contact_domain,
1874 struct winbindd_cli_state *state)
1877 char *newpass = NULL;
1878 struct policy_handle dom_pol;
1879 struct rpc_pipe_client *cli = NULL;
1880 bool got_info = false;
1881 struct samr_DomInfo1 *info = NULL;
1882 struct userPwdChangeFailureInformation *reject = NULL;
1883 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1884 fstring domain, user;
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 result = rpccli_samr_chgpasswd_user3(cli, state->mem_ctx,
1919 /* Windows 2003 returns NT_STATUS_PASSWORD_RESTRICTION */
1921 if (NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_RESTRICTION) ) {
1923 fill_in_password_policy(state->response, info);
1925 state->response->data.auth.reject_reason =
1926 reject->extendedFailureReason;
1931 /* atm the pidl generated rpccli_samr_ChangePasswordUser3 function will
1932 * return with NT_STATUS_BUFFER_TOO_SMALL for w2k dcs as w2k just
1933 * returns with 4byte error code (NT_STATUS_NOT_SUPPORTED) which is too
1934 * short to comply with the samr_ChangePasswordUser3 idl - gd */
1936 /* only fallback when the chgpasswd_user3 call is not supported */
1937 if ((NT_STATUS_EQUAL(result, NT_STATUS(DCERPC_FAULT_OP_RNG_ERROR))) ||
1938 (NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED)) ||
1939 (NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)) ||
1940 (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED))) {
1942 DEBUG(10,("Password change with chgpasswd_user3 failed with: %s, retrying chgpasswd_user2\n",
1943 nt_errstr(result)));
1945 result = rpccli_samr_chgpasswd_user2(cli, state->mem_ctx, user, newpass, oldpass);
1947 /* Windows 2000 returns NT_STATUS_ACCOUNT_RESTRICTION.
1948 Map to the same status code as Windows 2003. */
1950 if ( NT_STATUS_EQUAL(NT_STATUS_ACCOUNT_RESTRICTION, result ) ) {
1951 result = NT_STATUS_PASSWORD_RESTRICTION;
1957 if (NT_STATUS_IS_OK(result) && (state->request->flags & WBFLAG_PAM_CACHED_LOGIN)) {
1958 if (lp_winbind_offline_logon()) {
1959 result = winbindd_update_creds_by_name(contact_domain,
1960 state->mem_ctx, user,
1962 /* Again, this happens when we login from gdm or xdm
1963 * and the password expires, *BUT* cached crendentials
1964 * doesn't exist. winbindd_update_creds_by_name()
1965 * returns NT_STATUS_NO_SUCH_USER.
1966 * This is not a failure.
1969 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER)) {
1970 result = NT_STATUS_OK;
1973 if (!NT_STATUS_IS_OK(result)) {
1974 DEBUG(10,("Failed to store creds: %s\n", nt_errstr(result)));
1975 goto process_result;
1980 if (!NT_STATUS_IS_OK(result) && !got_info && contact_domain) {
1982 NTSTATUS policy_ret;
1984 policy_ret = fillup_password_policy(contact_domain, state);
1986 /* failure of this is non critical, it will just provide no
1987 * additional information to the client why the change has
1988 * failed - Guenther */
1990 if (!NT_STATUS_IS_OK(policy_ret)) {
1991 DEBUG(10,("Failed to get password policies: %s\n", nt_errstr(policy_ret)));
1992 goto process_result;
1998 if (strequal(contact_domain->name, get_global_sam_name())) {
1999 /* FIXME: internal rpc pipe does not cache handles yet */
2001 if (is_valid_policy_hnd(&dom_pol)) {
2002 rpccli_samr_Close(cli, state->mem_ctx, &dom_pol);
2008 set_auth_errors(state->response, result);
2010 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
2011 ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
2014 state->response->data.auth.nt_status_string,
2015 state->response->data.auth.pam_error));
2017 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2020 enum winbindd_result winbindd_dual_pam_logoff(struct winbindd_domain *domain,
2021 struct winbindd_cli_state *state)
2023 NTSTATUS result = NT_STATUS_NOT_SUPPORTED;
2025 DEBUG(3, ("[%5lu]: pam dual logoff %s\n", (unsigned long)state->pid,
2026 state->request->data.logoff.user));
2028 if (!(state->request->flags & WBFLAG_PAM_KRB5)) {
2029 result = NT_STATUS_OK;
2030 goto process_result;
2033 if (state->request->data.logoff.krb5ccname[0] == '\0') {
2034 result = NT_STATUS_OK;
2035 goto process_result;
2040 if (state->request->data.logoff.uid < 0) {
2041 DEBUG(0,("winbindd_pam_logoff: invalid uid\n"));
2042 goto process_result;
2045 /* what we need here is to find the corresponding krb5 ccache name *we*
2046 * created for a given username and destroy it */
2048 if (!ccache_entry_exists(state->request->data.logoff.user)) {
2049 result = NT_STATUS_OK;
2050 DEBUG(10,("winbindd_pam_logoff: no entry found.\n"));
2051 goto process_result;
2054 if (!ccache_entry_identical(state->request->data.logoff.user,
2055 state->request->data.logoff.uid,
2056 state->request->data.logoff.krb5ccname)) {
2057 DEBUG(0,("winbindd_pam_logoff: cached entry differs.\n"));
2058 goto process_result;
2061 result = remove_ccache(state->request->data.logoff.user);
2062 if (!NT_STATUS_IS_OK(result)) {
2063 DEBUG(0,("winbindd_pam_logoff: failed to remove ccache: %s\n",
2064 nt_errstr(result)));
2065 goto process_result;
2069 result = NT_STATUS_NOT_SUPPORTED;
2075 set_auth_errors(state->response, result);
2077 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2080 /* Change user password with auth crap*/
2082 enum winbindd_result winbindd_dual_pam_chng_pswd_auth_crap(struct winbindd_domain *domainSt, struct winbindd_cli_state *state)
2085 DATA_BLOB new_nt_password;
2086 DATA_BLOB old_nt_hash_enc;
2087 DATA_BLOB new_lm_password;
2088 DATA_BLOB old_lm_hash_enc;
2089 fstring domain,user;
2090 struct policy_handle dom_pol;
2091 struct winbindd_domain *contact_domain = domainSt;
2092 struct rpc_pipe_client *cli = NULL;
2094 ZERO_STRUCT(dom_pol);
2096 /* Ensure null termination */
2097 state->request->data.chng_pswd_auth_crap.user[
2098 sizeof(state->request->data.chng_pswd_auth_crap.user)-1]=0;
2099 state->request->data.chng_pswd_auth_crap.domain[
2100 sizeof(state->request->data.chng_pswd_auth_crap.domain)-1]=0;
2104 DEBUG(3, ("[%5lu]: pam change pswd auth crap domain: %s user: %s\n",
2105 (unsigned long)state->pid,
2106 state->request->data.chng_pswd_auth_crap.domain,
2107 state->request->data.chng_pswd_auth_crap.user));
2109 if (lp_winbind_offline_logon()) {
2110 DEBUG(0,("Refusing password change as winbind offline logons are enabled. "));
2111 DEBUGADD(0,("Changing passwords here would risk inconsistent logons\n"));
2112 result = NT_STATUS_ACCESS_DENIED;
2116 if (*state->request->data.chng_pswd_auth_crap.domain) {
2117 fstrcpy(domain,state->request->data.chng_pswd_auth_crap.domain);
2119 parse_domain_user(state->request->data.chng_pswd_auth_crap.user,
2123 DEBUG(3,("no domain specified with username (%s) - "
2125 state->request->data.chng_pswd_auth_crap.user));
2126 result = NT_STATUS_NO_SUCH_USER;
2131 if (!*domain && lp_winbind_use_default_domain()) {
2132 fstrcpy(domain,(char *)lp_workgroup());
2136 fstrcpy(user, state->request->data.chng_pswd_auth_crap.user);
2139 DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n",
2140 (unsigned long)state->pid, domain, user));
2142 /* Change password */
2143 new_nt_password = data_blob_const(
2144 state->request->data.chng_pswd_auth_crap.new_nt_pswd,
2145 state->request->data.chng_pswd_auth_crap.new_nt_pswd_len);
2147 old_nt_hash_enc = data_blob_const(
2148 state->request->data.chng_pswd_auth_crap.old_nt_hash_enc,
2149 state->request->data.chng_pswd_auth_crap.old_nt_hash_enc_len);
2151 if(state->request->data.chng_pswd_auth_crap.new_lm_pswd_len > 0) {
2152 new_lm_password = data_blob_const(
2153 state->request->data.chng_pswd_auth_crap.new_lm_pswd,
2154 state->request->data.chng_pswd_auth_crap.new_lm_pswd_len);
2156 old_lm_hash_enc = data_blob_const(
2157 state->request->data.chng_pswd_auth_crap.old_lm_hash_enc,
2158 state->request->data.chng_pswd_auth_crap.old_lm_hash_enc_len);
2160 new_lm_password.length = 0;
2161 old_lm_hash_enc.length = 0;
2164 /* Get sam handle */
2166 result = cm_connect_sam(contact_domain, state->mem_ctx, &cli, &dom_pol);
2167 if (!NT_STATUS_IS_OK(result)) {
2168 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
2172 result = rpccli_samr_chng_pswd_auth_crap(
2173 cli, state->mem_ctx, user, new_nt_password, old_nt_hash_enc,
2174 new_lm_password, old_lm_hash_enc);
2178 if (strequal(contact_domain->name, get_global_sam_name())) {
2179 /* FIXME: internal rpc pipe does not cache handles yet */
2181 if (is_valid_policy_hnd(&dom_pol)) {
2182 rpccli_samr_Close(cli, state->mem_ctx, &dom_pol);
2188 set_auth_errors(state->response, result);
2190 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
2191 ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
2193 state->response->data.auth.nt_status_string,
2194 state->response->data.auth.pam_error));
2196 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;