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;
1134 struct auth_serversupplied_info *server_info = NULL;
1135 struct netr_SamInfo3 *info3;
1138 status = make_user_info(&user_info, user, user, domain, domain,
1139 global_myname(), lm_resp, nt_resp, NULL, NULL,
1141 if (!NT_STATUS_IS_OK(status)) {
1142 DEBUG(10, ("make_user_info failed: %s\n", nt_errstr(status)));
1146 status = check_sam_security(challenge, talloc_tos(), user_info,
1148 free_user_info(&user_info);
1150 if (!NT_STATUS_IS_OK(status)) {
1151 DEBUG(10, ("check_ntlm_password failed: %s\n",
1152 nt_errstr(status)));
1156 info3 = TALLOC_ZERO_P(mem_ctx, struct netr_SamInfo3);
1157 if (info3 == NULL) {
1158 return NT_STATUS_NO_MEMORY;
1161 status = serverinfo_to_SamInfo3(server_info, NULL, 0, info3);
1162 if (!NT_STATUS_IS_OK(status)) {
1163 DEBUG(10, ("serverinfo_to_SamInfo3 failed: %s\n",
1164 nt_errstr(status)));
1168 DEBUG(10, ("Authenticated user %s\\%s successfully\n", domain, user));
1170 return NT_STATUS_OK;
1173 typedef NTSTATUS (*netlogon_fn_t)(struct rpc_pipe_client *cli,
1174 TALLOC_CTX *mem_ctx,
1175 uint32 logon_parameters,
1177 const char *username,
1179 const char *workstation,
1180 const uint8 chal[8],
1181 DATA_BLOB lm_response,
1182 DATA_BLOB nt_response,
1183 struct netr_SamInfo3 **info3);
1185 static NTSTATUS winbindd_dual_pam_auth_samlogon(struct winbindd_domain *domain,
1186 struct winbindd_cli_state *state,
1187 struct netr_SamInfo3 **info3)
1190 struct rpc_pipe_client *netlogon_pipe;
1195 unsigned char local_lm_response[24];
1196 unsigned char local_nt_response[24];
1197 fstring name_domain, name_user;
1200 struct netr_SamInfo3 *my_info3 = NULL;
1204 DEBUG(10,("winbindd_dual_pam_auth_samlogon\n"));
1206 /* Parse domain and username */
1208 parse_domain_user(state->request->data.auth.user, name_domain, name_user);
1210 /* do password magic */
1212 generate_random_buffer(chal, sizeof(chal));
1214 if (lp_client_ntlmv2_auth()) {
1215 DATA_BLOB server_chal;
1216 DATA_BLOB names_blob;
1217 DATA_BLOB nt_response;
1218 DATA_BLOB lm_response;
1219 server_chal = data_blob_talloc(state->mem_ctx, chal, 8);
1221 /* note that the 'workgroup' here is a best guess - we don't know
1222 the server's domain at this point. The 'server name' is also
1225 names_blob = NTLMv2_generate_names_blob(state->mem_ctx, global_myname(), lp_workgroup());
1227 if (!SMBNTLMv2encrypt(NULL, name_user, name_domain,
1228 state->request->data.auth.pass,
1231 &lm_response, &nt_response, NULL, NULL)) {
1232 data_blob_free(&names_blob);
1233 data_blob_free(&server_chal);
1234 DEBUG(0, ("winbindd_pam_auth: SMBNTLMv2encrypt() failed!\n"));
1235 result = NT_STATUS_NO_MEMORY;
1238 data_blob_free(&names_blob);
1239 data_blob_free(&server_chal);
1240 lm_resp = data_blob_talloc(state->mem_ctx, lm_response.data,
1241 lm_response.length);
1242 nt_resp = data_blob_talloc(state->mem_ctx, nt_response.data,
1243 nt_response.length);
1244 data_blob_free(&lm_response);
1245 data_blob_free(&nt_response);
1248 if (lp_client_lanman_auth()
1249 && SMBencrypt(state->request->data.auth.pass,
1251 local_lm_response)) {
1252 lm_resp = data_blob_talloc(state->mem_ctx,
1254 sizeof(local_lm_response));
1256 lm_resp = data_blob_null;
1258 SMBNTencrypt(state->request->data.auth.pass,
1262 nt_resp = data_blob_talloc(state->mem_ctx,
1264 sizeof(local_nt_response));
1267 if (strequal(name_domain, get_global_sam_name())) {
1268 DATA_BLOB chal_blob = data_blob_const(chal, sizeof(chal));
1270 result = winbindd_dual_auth_passdb(
1271 state->mem_ctx, name_domain, name_user,
1272 &chal_blob, &lm_resp, &nt_resp, info3);
1276 /* check authentication loop */
1279 netlogon_fn_t logon_fn;
1281 ZERO_STRUCTP(my_info3);
1284 result = cm_connect_netlogon(domain, &netlogon_pipe);
1286 if (!NT_STATUS_IS_OK(result)) {
1287 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
1291 /* It is really important to try SamLogonEx here,
1292 * because in a clustered environment, we want to use
1293 * one machine account from multiple physical
1296 * With a normal SamLogon call, we must keep the
1297 * credentials chain updated and intact between all
1298 * users of the machine account (which would imply
1299 * cross-node communication for every NTLM logon).
1301 * (The credentials chain is not per NETLOGON pipe
1302 * connection, but globally on the server/client pair
1305 * When using SamLogonEx, the credentials are not
1306 * supplied, but the session key is implied by the
1307 * wrapping SamLogon context.
1309 * -- abartlet 21 April 2008
1312 logon_fn = domain->can_do_samlogon_ex
1313 ? rpccli_netlogon_sam_network_logon_ex
1314 : rpccli_netlogon_sam_network_logon;
1316 result = logon_fn(netlogon_pipe,
1319 domain->dcname, /* server name */
1320 name_user, /* user name */
1321 name_domain, /* target domain */
1322 global_myname(), /* workstation */
1329 if ((NT_STATUS_V(result) == DCERPC_FAULT_OP_RNG_ERROR)
1330 && domain->can_do_samlogon_ex) {
1331 DEBUG(3, ("Got a DC that can not do NetSamLogonEx, "
1332 "retrying with NetSamLogon\n"));
1333 domain->can_do_samlogon_ex = false;
1338 /* We have to try a second time as cm_connect_netlogon
1339 might not yet have noticed that the DC has killed
1342 if (!rpccli_is_connected(netlogon_pipe)) {
1347 /* if we get access denied, a possible cause was that we had
1348 and open connection to the DC, but someone changed our
1349 machine account password out from underneath us using 'net
1350 rpc changetrustpw' */
1352 if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
1353 DEBUG(3,("winbindd_pam_auth: sam_logon returned "
1354 "ACCESS_DENIED. Maybe the trust account "
1355 "password was changed and we didn't know it. "
1356 "Killing connections to domain %s\n",
1358 invalidate_cm_connection(&domain->conn);
1362 } while ( (attempts < 2) && retry );
1364 /* handle the case where a NT4 DC does not fill in the acct_flags in
1365 * the samlogon reply info3. When accurate info3 is required by the
1366 * caller, we look up the account flags ourselve - gd */
1368 if ((state->request->flags & WBFLAG_PAM_INFO3_TEXT) &&
1369 NT_STATUS_IS_OK(result) && (my_info3->base.acct_flags == 0)) {
1371 struct rpc_pipe_client *samr_pipe;
1372 struct policy_handle samr_domain_handle, user_pol;
1373 union samr_UserInfo *info = NULL;
1374 NTSTATUS status_tmp;
1377 status_tmp = cm_connect_sam(domain, state->mem_ctx,
1378 &samr_pipe, &samr_domain_handle);
1380 if (!NT_STATUS_IS_OK(status_tmp)) {
1381 DEBUG(3, ("could not open handle to SAMR pipe: %s\n",
1382 nt_errstr(status_tmp)));
1386 status_tmp = rpccli_samr_OpenUser(samr_pipe, state->mem_ctx,
1387 &samr_domain_handle,
1388 MAXIMUM_ALLOWED_ACCESS,
1392 if (!NT_STATUS_IS_OK(status_tmp)) {
1393 DEBUG(3, ("could not open user handle on SAMR pipe: %s\n",
1394 nt_errstr(status_tmp)));
1398 status_tmp = rpccli_samr_QueryUserInfo(samr_pipe, state->mem_ctx,
1403 if (!NT_STATUS_IS_OK(status_tmp)) {
1404 DEBUG(3, ("could not query user info on SAMR pipe: %s\n",
1405 nt_errstr(status_tmp)));
1406 rpccli_samr_Close(samr_pipe, state->mem_ctx, &user_pol);
1410 acct_flags = info->info16.acct_flags;
1412 if (acct_flags == 0) {
1413 rpccli_samr_Close(samr_pipe, state->mem_ctx, &user_pol);
1417 my_info3->base.acct_flags = acct_flags;
1419 DEBUG(10,("successfully retrieved acct_flags 0x%x\n", acct_flags));
1421 rpccli_samr_Close(samr_pipe, state->mem_ctx, &user_pol);
1429 enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain,
1430 struct winbindd_cli_state *state)
1432 NTSTATUS result = NT_STATUS_LOGON_FAILURE;
1433 NTSTATUS krb5_result = NT_STATUS_OK;
1434 fstring name_domain, name_user;
1436 fstring domain_user;
1437 struct netr_SamInfo3 *info3 = NULL;
1438 NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL;
1440 /* Ensure null termination */
1441 state->request->data.auth.user[sizeof(state->request->data.auth.user)-1]='\0';
1443 /* Ensure null termination */
1444 state->request->data.auth.pass[sizeof(state->request->data.auth.pass)-1]='\0';
1446 DEBUG(3, ("[%5lu]: dual pam auth %s\n", (unsigned long)state->pid,
1447 state->request->data.auth.user));
1449 if (!check_request_flags(state->request->flags)) {
1450 result = NT_STATUS_INVALID_PARAMETER_MIX;
1454 /* Parse domain and username */
1456 name_map_status = normalize_name_unmap(state->mem_ctx,
1457 state->request->data.auth.user,
1460 /* If the name normalization didnt' actually do anything,
1461 just use the original name */
1463 if (!NT_STATUS_IS_OK(name_map_status) &&
1464 !NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED))
1466 mapped_user = state->request->data.auth.user;
1469 parse_domain_user(mapped_user, name_domain, name_user);
1471 if ( mapped_user != state->request->data.auth.user ) {
1472 fstr_sprintf( domain_user, "%s%c%s", name_domain,
1473 *lp_winbind_separator(),
1475 safe_strcpy( state->request->data.auth.user, domain_user,
1476 sizeof(state->request->data.auth.user)-1 );
1479 if (domain->online == false) {
1480 result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
1481 if (domain->startup) {
1482 /* Logons are very important to users. If we're offline and
1483 we get a request within the first 30 seconds of startup,
1484 try very hard to find a DC and go online. */
1486 DEBUG(10,("winbindd_dual_pam_auth: domain: %s offline and auth "
1487 "request in startup mode.\n", domain->name ));
1489 winbindd_flush_negative_conn_cache(domain);
1490 result = init_dc_connection(domain);
1494 DEBUG(10,("winbindd_dual_pam_auth: domain: %s last was %s\n", domain->name, domain->online ? "online":"offline"));
1496 /* Check for Kerberos authentication */
1497 if (domain->online && (state->request->flags & WBFLAG_PAM_KRB5)) {
1499 result = winbindd_dual_pam_auth_kerberos(domain, state, &info3);
1500 /* save for later */
1501 krb5_result = result;
1504 if (NT_STATUS_IS_OK(result)) {
1505 DEBUG(10,("winbindd_dual_pam_auth_kerberos succeeded\n"));
1506 goto process_result;
1508 DEBUG(10,("winbindd_dual_pam_auth_kerberos failed: %s\n", nt_errstr(result)));
1511 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
1512 NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
1513 NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1514 DEBUG(10,("winbindd_dual_pam_auth_kerberos setting domain to offline\n"));
1515 set_domain_offline( domain );
1519 /* there are quite some NT_STATUS errors where there is no
1520 * point in retrying with a samlogon, we explictly have to take
1521 * care not to increase the bad logon counter on the DC */
1523 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_DISABLED) ||
1524 NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_EXPIRED) ||
1525 NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_LOCKED_OUT) ||
1526 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_LOGON_HOURS) ||
1527 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_WORKSTATION) ||
1528 NT_STATUS_EQUAL(result, NT_STATUS_LOGON_FAILURE) ||
1529 NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER) ||
1530 NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_EXPIRED) ||
1531 NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_MUST_CHANGE) ||
1532 NT_STATUS_EQUAL(result, NT_STATUS_WRONG_PASSWORD)) {
1536 if (state->request->flags & WBFLAG_PAM_FALLBACK_AFTER_KRB5) {
1537 DEBUG(3,("falling back to samlogon\n"));
1545 /* Check for Samlogon authentication */
1546 if (domain->online) {
1547 result = winbindd_dual_pam_auth_samlogon(domain, state, &info3);
1549 if (NT_STATUS_IS_OK(result)) {
1550 DEBUG(10,("winbindd_dual_pam_auth_samlogon succeeded\n"));
1551 /* add the Krb5 err if we have one */
1552 if ( NT_STATUS_EQUAL(krb5_result, NT_STATUS_TIME_DIFFERENCE_AT_DC ) ) {
1553 info3->base.user_flags |= LOGON_KRB5_FAIL_CLOCK_SKEW;
1555 goto process_result;
1558 DEBUG(10,("winbindd_dual_pam_auth_samlogon failed: %s\n",
1559 nt_errstr(result)));
1561 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
1562 NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
1563 NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND))
1565 DEBUG(10,("winbindd_dual_pam_auth_samlogon setting domain to offline\n"));
1566 set_domain_offline( domain );
1570 if (domain->online) {
1571 /* We're still online - fail. */
1577 /* Check for Cached logons */
1578 if (!domain->online && (state->request->flags & WBFLAG_PAM_CACHED_LOGIN) &&
1579 lp_winbind_offline_logon()) {
1581 result = winbindd_dual_pam_auth_cached(domain, state, &info3);
1583 if (NT_STATUS_IS_OK(result)) {
1584 DEBUG(10,("winbindd_dual_pam_auth_cached succeeded\n"));
1585 goto process_result;
1587 DEBUG(10,("winbindd_dual_pam_auth_cached failed: %s\n", nt_errstr(result)));
1594 if (NT_STATUS_IS_OK(result)) {
1596 struct dom_sid user_sid;
1598 /* In all codepaths where result == NT_STATUS_OK info3 must have
1599 been initialized. */
1601 result = NT_STATUS_INTERNAL_ERROR;
1605 wcache_invalidate_samlogon(find_domain_from_name(name_domain), info3);
1606 netsamlogon_cache_store(name_user, info3);
1608 /* save name_to_sid info as early as possible (only if
1609 this is our primary domain so we don't invalidate
1610 the cache entry by storing the seq_num for the wrong
1612 if ( domain->primary ) {
1613 sid_compose(&user_sid, info3->base.domain_sid,
1615 cache_name2sid(domain, name_domain, name_user,
1616 SID_NAME_USER, &user_sid);
1619 /* Check if the user is in the right group */
1621 result = check_info3_in_group(
1623 state->request->data.auth.require_membership_of_sid);
1624 if (!NT_STATUS_IS_OK(result)) {
1625 DEBUG(3, ("User %s is not in the required group (%s), so plaintext authentication is rejected\n",
1626 state->request->data.auth.user,
1627 state->request->data.auth.require_membership_of_sid));
1631 result = append_auth_data(state, info3, name_domain,
1633 if (!NT_STATUS_IS_OK(result)) {
1637 if ((state->request->flags & WBFLAG_PAM_CACHED_LOGIN)) {
1639 if (lp_winbind_offline_logon()) {
1640 result = winbindd_store_creds(domain,
1642 state->request->data.auth.user,
1643 state->request->data.auth.pass,
1649 if (state->request->flags & WBFLAG_PAM_GET_PWD_POLICY) {
1650 struct winbindd_domain *our_domain = find_our_domain();
1652 /* This is not entirely correct I believe, but it is
1653 consistent. Only apply the password policy settings
1654 too warn users for our own domain. Cannot obtain these
1655 from trusted DCs all the time so don't do it at all.
1658 result = NT_STATUS_NOT_SUPPORTED;
1659 if (our_domain == domain ) {
1660 result = fillup_password_policy(our_domain, state);
1663 if (!NT_STATUS_IS_OK(result)
1664 && !NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED) )
1666 DEBUG(10,("Failed to get password policies for domain %s: %s\n",
1667 domain->name, nt_errstr(result)));
1672 result = NT_STATUS_OK;
1676 /* give us a more useful (more correct?) error code */
1677 if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
1678 (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
1679 result = NT_STATUS_NO_LOGON_SERVERS;
1682 set_auth_errors(state->response, result);
1684 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, ("Plain-text authentication for user %s returned %s (PAM: %d)\n",
1685 state->request->data.auth.user,
1686 state->response->data.auth.nt_status_string,
1687 state->response->data.auth.pam_error));
1689 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
1692 enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain,
1693 struct winbindd_cli_state *state)
1696 struct netr_SamInfo3 *info3 = NULL;
1697 struct rpc_pipe_client *netlogon_pipe;
1698 const char *name_user = NULL;
1699 const char *name_domain = NULL;
1700 const char *workstation;
1704 DATA_BLOB lm_resp, nt_resp;
1706 /* This is child-only, so no check for privileged access is needed
1709 /* Ensure null termination */
1710 state->request->data.auth_crap.user[sizeof(state->request->data.auth_crap.user)-1]=0;
1711 state->request->data.auth_crap.domain[sizeof(state->request->data.auth_crap.domain)-1]=0;
1713 if (!check_request_flags(state->request->flags)) {
1714 result = NT_STATUS_INVALID_PARAMETER_MIX;
1718 name_user = state->request->data.auth_crap.user;
1720 if (*state->request->data.auth_crap.domain) {
1721 name_domain = state->request->data.auth_crap.domain;
1722 } else if (lp_winbind_use_default_domain()) {
1723 name_domain = lp_workgroup();
1725 DEBUG(5,("no domain specified with username (%s) - failing auth\n",
1727 result = NT_STATUS_NO_SUCH_USER;
1731 DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n", (unsigned long)state->pid,
1732 name_domain, name_user));
1734 if (*state->request->data.auth_crap.workstation) {
1735 workstation = state->request->data.auth_crap.workstation;
1737 workstation = global_myname();
1740 if (state->request->data.auth_crap.lm_resp_len > sizeof(state->request->data.auth_crap.lm_resp)
1741 || state->request->data.auth_crap.nt_resp_len > sizeof(state->request->data.auth_crap.nt_resp)) {
1742 if (!(state->request->flags & WBFLAG_BIG_NTLMV2_BLOB) ||
1743 state->request->extra_len != state->request->data.auth_crap.nt_resp_len) {
1744 DEBUG(0, ("winbindd_pam_auth_crap: invalid password length %u/%u\n",
1745 state->request->data.auth_crap.lm_resp_len,
1746 state->request->data.auth_crap.nt_resp_len));
1747 result = NT_STATUS_INVALID_PARAMETER;
1752 lm_resp = data_blob_talloc(state->mem_ctx, state->request->data.auth_crap.lm_resp,
1753 state->request->data.auth_crap.lm_resp_len);
1755 if (state->request->flags & WBFLAG_BIG_NTLMV2_BLOB) {
1756 nt_resp = data_blob_talloc(state->mem_ctx,
1757 state->request->extra_data.data,
1758 state->request->data.auth_crap.nt_resp_len);
1760 nt_resp = data_blob_talloc(state->mem_ctx,
1761 state->request->data.auth_crap.nt_resp,
1762 state->request->data.auth_crap.nt_resp_len);
1765 if (strequal(name_domain, get_global_sam_name())) {
1766 DATA_BLOB chal_blob = data_blob_const(
1767 state->request->data.auth_crap.chal,
1768 sizeof(state->request->data.auth_crap.chal));
1770 result = winbindd_dual_auth_passdb(
1771 state->mem_ctx, name_domain, name_user,
1772 &chal_blob, &lm_resp, &nt_resp, &info3);
1773 goto process_result;
1777 netlogon_fn_t logon_fn;
1781 netlogon_pipe = NULL;
1782 result = cm_connect_netlogon(domain, &netlogon_pipe);
1784 if (!NT_STATUS_IS_OK(result)) {
1785 DEBUG(3, ("could not open handle to NETLOGON pipe (error: %s)\n",
1786 nt_errstr(result)));
1790 logon_fn = domain->can_do_samlogon_ex
1791 ? rpccli_netlogon_sam_network_logon_ex
1792 : rpccli_netlogon_sam_network_logon;
1794 result = logon_fn(netlogon_pipe,
1796 state->request->data.auth_crap.logon_parameters,
1800 /* Bug #3248 - found by Stefan Burkei. */
1801 workstation, /* We carefully set this above so use it... */
1802 state->request->data.auth_crap.chal,
1807 if ((NT_STATUS_V(result) == DCERPC_FAULT_OP_RNG_ERROR)
1808 && domain->can_do_samlogon_ex) {
1809 DEBUG(3, ("Got a DC that can not do NetSamLogonEx, "
1810 "retrying with NetSamLogon\n"));
1811 domain->can_do_samlogon_ex = false;
1818 /* We have to try a second time as cm_connect_netlogon
1819 might not yet have noticed that the DC has killed
1822 if (!rpccli_is_connected(netlogon_pipe)) {
1827 /* if we get access denied, a possible cause was that we had and open
1828 connection to the DC, but someone changed our machine account password
1829 out from underneath us using 'net rpc changetrustpw' */
1831 if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
1832 DEBUG(3,("winbindd_pam_auth: sam_logon returned "
1833 "ACCESS_DENIED. Maybe the trust account "
1834 "password was changed and we didn't know it. "
1835 "Killing connections to domain %s\n",
1837 invalidate_cm_connection(&domain->conn);
1841 } while ( (attempts < 2) && retry );
1845 if (NT_STATUS_IS_OK(result)) {
1847 wcache_invalidate_samlogon(find_domain_from_name(name_domain), info3);
1848 netsamlogon_cache_store(name_user, info3);
1850 /* Check if the user is in the right group */
1852 result = check_info3_in_group(
1854 state->request->data.auth_crap.require_membership_of_sid);
1855 if (!NT_STATUS_IS_OK(result)) {
1856 DEBUG(3, ("User %s is not in the required group (%s), so "
1857 "crap authentication is rejected\n",
1858 state->request->data.auth_crap.user,
1859 state->request->data.auth_crap.require_membership_of_sid));
1863 result = append_auth_data(state, info3, name_domain,
1865 if (!NT_STATUS_IS_OK(result)) {
1872 /* give us a more useful (more correct?) error code */
1873 if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
1874 (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
1875 result = NT_STATUS_NO_LOGON_SERVERS;
1878 if (state->request->flags & WBFLAG_PAM_NT_STATUS_SQUASH) {
1879 result = nt_status_squash(result);
1882 set_auth_errors(state->response, result);
1884 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
1885 ("NTLM CRAP authentication for user [%s]\\[%s] returned %s (PAM: %d)\n",
1888 state->response->data.auth.nt_status_string,
1889 state->response->data.auth.pam_error));
1891 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
1894 enum winbindd_result winbindd_dual_pam_chauthtok(struct winbindd_domain *contact_domain,
1895 struct winbindd_cli_state *state)
1898 char *newpass = NULL;
1899 struct policy_handle dom_pol;
1900 struct rpc_pipe_client *cli = NULL;
1901 bool got_info = false;
1902 struct samr_DomInfo1 *info = NULL;
1903 struct userPwdChangeFailureInformation *reject = NULL;
1904 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1905 fstring domain, user;
1907 ZERO_STRUCT(dom_pol);
1909 DEBUG(3, ("[%5lu]: dual pam chauthtok %s\n", (unsigned long)state->pid,
1910 state->request->data.auth.user));
1912 if (!parse_domain_user(state->request->data.chauthtok.user, domain, user)) {
1916 /* Change password */
1918 oldpass = state->request->data.chauthtok.oldpass;
1919 newpass = state->request->data.chauthtok.newpass;
1921 /* Initialize reject reason */
1922 state->response->data.auth.reject_reason = Undefined;
1924 /* Get sam handle */
1926 result = cm_connect_sam(contact_domain, state->mem_ctx, &cli,
1928 if (!NT_STATUS_IS_OK(result)) {
1929 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
1933 result = rpccli_samr_chgpasswd_user3(cli, state->mem_ctx,
1940 /* Windows 2003 returns NT_STATUS_PASSWORD_RESTRICTION */
1942 if (NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_RESTRICTION) ) {
1944 fill_in_password_policy(state->response, info);
1946 state->response->data.auth.reject_reason =
1947 reject->extendedFailureReason;
1952 /* atm the pidl generated rpccli_samr_ChangePasswordUser3 function will
1953 * return with NT_STATUS_BUFFER_TOO_SMALL for w2k dcs as w2k just
1954 * returns with 4byte error code (NT_STATUS_NOT_SUPPORTED) which is too
1955 * short to comply with the samr_ChangePasswordUser3 idl - gd */
1957 /* only fallback when the chgpasswd_user3 call is not supported */
1958 if ((NT_STATUS_EQUAL(result, NT_STATUS(DCERPC_FAULT_OP_RNG_ERROR))) ||
1959 (NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED)) ||
1960 (NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)) ||
1961 (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED))) {
1963 DEBUG(10,("Password change with chgpasswd_user3 failed with: %s, retrying chgpasswd_user2\n",
1964 nt_errstr(result)));
1966 result = rpccli_samr_chgpasswd_user2(cli, state->mem_ctx, user, newpass, oldpass);
1968 /* Windows 2000 returns NT_STATUS_ACCOUNT_RESTRICTION.
1969 Map to the same status code as Windows 2003. */
1971 if ( NT_STATUS_EQUAL(NT_STATUS_ACCOUNT_RESTRICTION, result ) ) {
1972 result = NT_STATUS_PASSWORD_RESTRICTION;
1978 if (NT_STATUS_IS_OK(result) && (state->request->flags & WBFLAG_PAM_CACHED_LOGIN)) {
1979 if (lp_winbind_offline_logon()) {
1980 result = winbindd_update_creds_by_name(contact_domain,
1981 state->mem_ctx, user,
1983 /* Again, this happens when we login from gdm or xdm
1984 * and the password expires, *BUT* cached crendentials
1985 * doesn't exist. winbindd_update_creds_by_name()
1986 * returns NT_STATUS_NO_SUCH_USER.
1987 * This is not a failure.
1990 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER)) {
1991 result = NT_STATUS_OK;
1994 if (!NT_STATUS_IS_OK(result)) {
1995 DEBUG(10,("Failed to store creds: %s\n", nt_errstr(result)));
1996 goto process_result;
2001 if (!NT_STATUS_IS_OK(result) && !got_info && contact_domain) {
2003 NTSTATUS policy_ret;
2005 policy_ret = fillup_password_policy(contact_domain, state);
2007 /* failure of this is non critical, it will just provide no
2008 * additional information to the client why the change has
2009 * failed - Guenther */
2011 if (!NT_STATUS_IS_OK(policy_ret)) {
2012 DEBUG(10,("Failed to get password policies: %s\n", nt_errstr(policy_ret)));
2013 goto process_result;
2019 if (strequal(contact_domain->name, get_global_sam_name())) {
2020 /* FIXME: internal rpc pipe does not cache handles yet */
2022 if (is_valid_policy_hnd(&dom_pol)) {
2023 rpccli_samr_Close(cli, state->mem_ctx, &dom_pol);
2029 set_auth_errors(state->response, result);
2031 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
2032 ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
2035 state->response->data.auth.nt_status_string,
2036 state->response->data.auth.pam_error));
2038 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2041 enum winbindd_result winbindd_dual_pam_logoff(struct winbindd_domain *domain,
2042 struct winbindd_cli_state *state)
2044 NTSTATUS result = NT_STATUS_NOT_SUPPORTED;
2046 DEBUG(3, ("[%5lu]: pam dual logoff %s\n", (unsigned long)state->pid,
2047 state->request->data.logoff.user));
2049 if (!(state->request->flags & WBFLAG_PAM_KRB5)) {
2050 result = NT_STATUS_OK;
2051 goto process_result;
2054 if (state->request->data.logoff.krb5ccname[0] == '\0') {
2055 result = NT_STATUS_OK;
2056 goto process_result;
2061 if (state->request->data.logoff.uid < 0) {
2062 DEBUG(0,("winbindd_pam_logoff: invalid uid\n"));
2063 goto process_result;
2066 /* what we need here is to find the corresponding krb5 ccache name *we*
2067 * created for a given username and destroy it */
2069 if (!ccache_entry_exists(state->request->data.logoff.user)) {
2070 result = NT_STATUS_OK;
2071 DEBUG(10,("winbindd_pam_logoff: no entry found.\n"));
2072 goto process_result;
2075 if (!ccache_entry_identical(state->request->data.logoff.user,
2076 state->request->data.logoff.uid,
2077 state->request->data.logoff.krb5ccname)) {
2078 DEBUG(0,("winbindd_pam_logoff: cached entry differs.\n"));
2079 goto process_result;
2082 result = remove_ccache(state->request->data.logoff.user);
2083 if (!NT_STATUS_IS_OK(result)) {
2084 DEBUG(0,("winbindd_pam_logoff: failed to remove ccache: %s\n",
2085 nt_errstr(result)));
2086 goto process_result;
2090 result = NT_STATUS_NOT_SUPPORTED;
2096 set_auth_errors(state->response, result);
2098 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2101 /* Change user password with auth crap*/
2103 enum winbindd_result winbindd_dual_pam_chng_pswd_auth_crap(struct winbindd_domain *domainSt, struct winbindd_cli_state *state)
2106 DATA_BLOB new_nt_password;
2107 DATA_BLOB old_nt_hash_enc;
2108 DATA_BLOB new_lm_password;
2109 DATA_BLOB old_lm_hash_enc;
2110 fstring domain,user;
2111 struct policy_handle dom_pol;
2112 struct winbindd_domain *contact_domain = domainSt;
2113 struct rpc_pipe_client *cli = NULL;
2115 ZERO_STRUCT(dom_pol);
2117 /* Ensure null termination */
2118 state->request->data.chng_pswd_auth_crap.user[
2119 sizeof(state->request->data.chng_pswd_auth_crap.user)-1]=0;
2120 state->request->data.chng_pswd_auth_crap.domain[
2121 sizeof(state->request->data.chng_pswd_auth_crap.domain)-1]=0;
2125 DEBUG(3, ("[%5lu]: pam change pswd auth crap domain: %s user: %s\n",
2126 (unsigned long)state->pid,
2127 state->request->data.chng_pswd_auth_crap.domain,
2128 state->request->data.chng_pswd_auth_crap.user));
2130 if (lp_winbind_offline_logon()) {
2131 DEBUG(0,("Refusing password change as winbind offline logons are enabled. "));
2132 DEBUGADD(0,("Changing passwords here would risk inconsistent logons\n"));
2133 result = NT_STATUS_ACCESS_DENIED;
2137 if (*state->request->data.chng_pswd_auth_crap.domain) {
2138 fstrcpy(domain,state->request->data.chng_pswd_auth_crap.domain);
2140 parse_domain_user(state->request->data.chng_pswd_auth_crap.user,
2144 DEBUG(3,("no domain specified with username (%s) - "
2146 state->request->data.chng_pswd_auth_crap.user));
2147 result = NT_STATUS_NO_SUCH_USER;
2152 if (!*domain && lp_winbind_use_default_domain()) {
2153 fstrcpy(domain,(char *)lp_workgroup());
2157 fstrcpy(user, state->request->data.chng_pswd_auth_crap.user);
2160 DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n",
2161 (unsigned long)state->pid, domain, user));
2163 /* Change password */
2164 new_nt_password = data_blob_const(
2165 state->request->data.chng_pswd_auth_crap.new_nt_pswd,
2166 state->request->data.chng_pswd_auth_crap.new_nt_pswd_len);
2168 old_nt_hash_enc = data_blob_const(
2169 state->request->data.chng_pswd_auth_crap.old_nt_hash_enc,
2170 state->request->data.chng_pswd_auth_crap.old_nt_hash_enc_len);
2172 if(state->request->data.chng_pswd_auth_crap.new_lm_pswd_len > 0) {
2173 new_lm_password = data_blob_const(
2174 state->request->data.chng_pswd_auth_crap.new_lm_pswd,
2175 state->request->data.chng_pswd_auth_crap.new_lm_pswd_len);
2177 old_lm_hash_enc = data_blob_const(
2178 state->request->data.chng_pswd_auth_crap.old_lm_hash_enc,
2179 state->request->data.chng_pswd_auth_crap.old_lm_hash_enc_len);
2181 new_lm_password.length = 0;
2182 old_lm_hash_enc.length = 0;
2185 /* Get sam handle */
2187 result = cm_connect_sam(contact_domain, state->mem_ctx, &cli, &dom_pol);
2188 if (!NT_STATUS_IS_OK(result)) {
2189 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
2193 result = rpccli_samr_chng_pswd_auth_crap(
2194 cli, state->mem_ctx, user, new_nt_password, old_nt_hash_enc,
2195 new_lm_password, old_lm_hash_enc);
2199 if (strequal(contact_domain->name, get_global_sam_name())) {
2200 /* FIXME: internal rpc pipe does not cache handles yet */
2202 if (is_valid_policy_hnd(&dom_pol)) {
2203 rpccli_samr_Close(cli, state->mem_ctx, &dom_pol);
2209 set_auth_errors(state->response, result);
2211 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
2212 ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
2214 state->response->data.auth.nt_status_string,
2215 state->response->data.auth.pam_error));
2217 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;