2 Unix SMB/CIFS implementation.
4 Winbind daemon - pam auth funcions
6 Copyright (C) Andrew Tridgell 2000
7 Copyright (C) Tim Potter 2001
8 Copyright (C) Andrew Bartlett 2001-2002
9 Copyright (C) Guenther Deschner 2005
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 #include "../libcli/auth/libcli_auth.h"
28 #include "../librpc/gen_ndr/ndr_samr_c.h"
29 #include "rpc_client/cli_pipe.h"
30 #include "rpc_client/cli_samr.h"
31 #include "../librpc/gen_ndr/ndr_netlogon.h"
32 #include "rpc_client/cli_netlogon.h"
34 #include "../lib/crypto/arcfour.h"
35 #include "../libcli/security/security.h"
37 #include "../librpc/gen_ndr/krb5pac.h"
38 #include "passdb/machine_sid.h"
42 #define DBGC_CLASS DBGC_WINBIND
44 #define LOGON_KRB5_FAIL_CLOCK_SKEW 0x02000000
46 static NTSTATUS append_info3_as_txt(TALLOC_CTX *mem_ctx,
47 struct winbindd_response *resp,
48 struct netr_SamInfo3 *info3)
53 resp->data.auth.info3.logon_time =
54 nt_time_to_unix(info3->base.last_logon);
55 resp->data.auth.info3.logoff_time =
56 nt_time_to_unix(info3->base.last_logoff);
57 resp->data.auth.info3.kickoff_time =
58 nt_time_to_unix(info3->base.acct_expiry);
59 resp->data.auth.info3.pass_last_set_time =
60 nt_time_to_unix(info3->base.last_password_change);
61 resp->data.auth.info3.pass_can_change_time =
62 nt_time_to_unix(info3->base.allow_password_change);
63 resp->data.auth.info3.pass_must_change_time =
64 nt_time_to_unix(info3->base.force_password_change);
66 resp->data.auth.info3.logon_count = info3->base.logon_count;
67 resp->data.auth.info3.bad_pw_count = info3->base.bad_password_count;
69 resp->data.auth.info3.user_rid = info3->base.rid;
70 resp->data.auth.info3.group_rid = info3->base.primary_gid;
71 sid_to_fstring(resp->data.auth.info3.dom_sid, info3->base.domain_sid);
73 resp->data.auth.info3.num_groups = info3->base.groups.count;
74 resp->data.auth.info3.user_flgs = info3->base.user_flags;
76 resp->data.auth.info3.acct_flags = info3->base.acct_flags;
77 resp->data.auth.info3.num_other_sids = info3->sidcount;
79 fstrcpy(resp->data.auth.info3.user_name,
80 info3->base.account_name.string);
81 fstrcpy(resp->data.auth.info3.full_name,
82 info3->base.full_name.string);
83 fstrcpy(resp->data.auth.info3.logon_script,
84 info3->base.logon_script.string);
85 fstrcpy(resp->data.auth.info3.profile_path,
86 info3->base.profile_path.string);
87 fstrcpy(resp->data.auth.info3.home_dir,
88 info3->base.home_directory.string);
89 fstrcpy(resp->data.auth.info3.dir_drive,
90 info3->base.home_drive.string);
92 fstrcpy(resp->data.auth.info3.logon_srv,
93 info3->base.logon_server.string);
94 fstrcpy(resp->data.auth.info3.logon_dom,
95 info3->base.domain.string);
97 ex = talloc_strdup(mem_ctx, "");
98 NT_STATUS_HAVE_NO_MEMORY(ex);
100 for (i=0; i < info3->base.groups.count; i++) {
101 ex = talloc_asprintf_append_buffer(ex, "0x%08X:0x%08X\n",
102 info3->base.groups.rids[i].rid,
103 info3->base.groups.rids[i].attributes);
104 NT_STATUS_HAVE_NO_MEMORY(ex);
107 for (i=0; i < info3->sidcount; i++) {
110 sid = dom_sid_string(mem_ctx, info3->sids[i].sid);
111 NT_STATUS_HAVE_NO_MEMORY(sid);
113 ex = talloc_asprintf_append_buffer(ex, "%s:0x%08X\n",
115 info3->sids[i].attributes);
116 NT_STATUS_HAVE_NO_MEMORY(ex);
121 resp->extra_data.data = ex;
122 resp->length += talloc_get_size(ex);
127 static NTSTATUS append_info3_as_ndr(TALLOC_CTX *mem_ctx,
128 struct winbindd_response *resp,
129 struct netr_SamInfo3 *info3)
132 enum ndr_err_code ndr_err;
134 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, info3,
135 (ndr_push_flags_fn_t)ndr_push_netr_SamInfo3);
136 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
137 DEBUG(0,("append_info3_as_ndr: failed to append\n"));
138 return ndr_map_error2ntstatus(ndr_err);
141 resp->extra_data.data = blob.data;
142 resp->length += blob.length;
147 static NTSTATUS append_unix_username(TALLOC_CTX *mem_ctx,
148 struct winbindd_response *resp,
149 const struct netr_SamInfo3 *info3,
150 const char *name_domain,
151 const char *name_user)
153 /* We've been asked to return the unix username, per
154 'winbind use default domain' settings and the like */
156 const char *nt_username, *nt_domain;
158 nt_domain = talloc_strdup(mem_ctx, info3->base.domain.string);
160 /* If the server didn't give us one, just use the one
162 nt_domain = name_domain;
165 nt_username = talloc_strdup(mem_ctx, info3->base.account_name.string);
167 /* If the server didn't give us one, just use the one
169 nt_username = name_user;
172 fill_domain_username(resp->data.auth.unix_username,
173 nt_domain, nt_username, true);
175 DEBUG(5, ("Setting unix username to [%s]\n",
176 resp->data.auth.unix_username));
181 static NTSTATUS append_afs_token(TALLOC_CTX *mem_ctx,
182 struct winbindd_response *resp,
183 const struct netr_SamInfo3 *info3,
184 const char *name_domain,
185 const char *name_user)
187 char *afsname = NULL;
191 afsname = talloc_strdup(mem_ctx, lp_afs_username_map());
192 if (afsname == NULL) {
193 return NT_STATUS_NO_MEMORY;
196 afsname = talloc_string_sub(mem_ctx,
197 lp_afs_username_map(),
199 afsname = talloc_string_sub(mem_ctx, afsname,
201 afsname = talloc_string_sub(mem_ctx, afsname,
205 struct dom_sid user_sid;
208 sid_compose(&user_sid, info3->base.domain_sid,
210 sid_to_fstring(sidstr, &user_sid);
211 afsname = talloc_string_sub(mem_ctx, afsname,
215 if (afsname == NULL) {
216 return NT_STATUS_NO_MEMORY;
221 DEBUG(10, ("Generating token for user %s\n", afsname));
223 cell = strchr(afsname, '@');
226 return NT_STATUS_NO_MEMORY;
232 token = afs_createtoken_str(afsname, cell);
236 resp->extra_data.data = talloc_strdup(mem_ctx, token);
237 if (resp->extra_data.data == NULL) {
238 return NT_STATUS_NO_MEMORY;
240 resp->length += strlen((const char *)resp->extra_data.data)+1;
245 static NTSTATUS check_info3_in_group(struct netr_SamInfo3 *info3,
246 const char *group_sid)
248 * Check whether a user belongs to a group or list of groups.
250 * @param mem_ctx talloc memory context.
251 * @param info3 user information, including group membership info.
252 * @param group_sid One or more groups , separated by commas.
254 * @return NT_STATUS_OK on success,
255 * NT_STATUS_LOGON_FAILURE if the user does not belong,
256 * or other NT_STATUS_IS_ERR(status) for other kinds of failure.
259 struct dom_sid *require_membership_of_sid;
260 uint32_t num_require_membership_of_sid;
265 struct security_token *token;
266 TALLOC_CTX *frame = talloc_stackframe();
269 /* Parse the 'required group' SID */
271 if (!group_sid || !group_sid[0]) {
272 /* NO sid supplied, all users may access */
276 token = talloc_zero(talloc_tos(), struct security_token);
278 DEBUG(0, ("talloc failed\n"));
280 return NT_STATUS_NO_MEMORY;
283 num_require_membership_of_sid = 0;
284 require_membership_of_sid = NULL;
288 while (next_token_talloc(talloc_tos(), &p, &req_sid, ",")) {
289 if (!string_to_sid(&sid, req_sid)) {
290 DEBUG(0, ("check_info3_in_group: could not parse %s "
291 "as a SID!", req_sid));
293 return NT_STATUS_INVALID_PARAMETER;
296 status = add_sid_to_array(talloc_tos(), &sid,
297 &require_membership_of_sid,
298 &num_require_membership_of_sid);
299 if (!NT_STATUS_IS_OK(status)) {
300 DEBUG(0, ("add_sid_to_array failed\n"));
306 status = sid_array_from_info3(talloc_tos(), info3,
310 if (!NT_STATUS_IS_OK(status)) {
315 if (!NT_STATUS_IS_OK(status = add_aliases(get_global_sam_sid(),
317 || !NT_STATUS_IS_OK(status = add_aliases(&global_sid_Builtin,
319 DEBUG(3, ("could not add aliases: %s\n",
325 security_token_debug(DBGC_CLASS, 10, token);
327 for (i=0; i<num_require_membership_of_sid; i++) {
328 DEBUG(10, ("Checking SID %s\n", sid_string_dbg(
329 &require_membership_of_sid[i])));
330 if (nt_token_check_sid(&require_membership_of_sid[i],
332 DEBUG(10, ("Access ok\n"));
338 /* Do not distinguish this error from a wrong username/pw */
341 return NT_STATUS_LOGON_FAILURE;
344 struct winbindd_domain *find_auth_domain(uint8_t flags,
345 const char *domain_name)
347 struct winbindd_domain *domain;
350 domain = find_domain_from_name_noinit(domain_name);
351 if (domain == NULL) {
352 DEBUG(3, ("Authentication for domain [%s] refused "
353 "as it is not a trusted domain\n",
359 if (strequal(domain_name, get_global_sam_name())) {
360 return find_domain_from_name_noinit(domain_name);
363 /* we can auth against trusted domains */
364 if (flags & WBFLAG_PAM_CONTACT_TRUSTDOM) {
365 domain = find_domain_from_name_noinit(domain_name);
366 if (domain == NULL) {
367 DEBUG(3, ("Authentication for domain [%s] skipped "
368 "as it is not a trusted domain\n",
375 return find_our_domain();
378 static void fill_in_password_policy(struct winbindd_response *r,
379 const struct samr_DomInfo1 *p)
381 r->data.auth.policy.min_length_password =
382 p->min_password_length;
383 r->data.auth.policy.password_history =
384 p->password_history_length;
385 r->data.auth.policy.password_properties =
386 p->password_properties;
387 r->data.auth.policy.expire =
388 nt_time_to_unix_abs((const NTTIME *)&(p->max_password_age));
389 r->data.auth.policy.min_passwordage =
390 nt_time_to_unix_abs((const NTTIME *)&(p->min_password_age));
393 static NTSTATUS fillup_password_policy(struct winbindd_domain *domain,
394 struct winbindd_response *response)
396 TALLOC_CTX *frame = talloc_stackframe();
397 struct winbindd_methods *methods;
399 struct samr_DomInfo1 password_policy;
401 if ( !winbindd_can_contact_domain( domain ) ) {
402 DEBUG(5,("fillup_password_policy: No inbound trust to "
403 "contact domain %s\n", domain->name));
404 status = NT_STATUS_NOT_SUPPORTED;
408 methods = domain->methods;
410 status = methods->password_policy(domain, talloc_tos(), &password_policy);
411 if (NT_STATUS_IS_ERR(status)) {
415 fill_in_password_policy(response, &password_policy);
422 static NTSTATUS get_max_bad_attempts_from_lockout_policy(struct winbindd_domain *domain,
424 uint16 *lockout_threshold)
426 struct winbindd_methods *methods;
427 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
428 struct samr_DomInfo12 lockout_policy;
430 *lockout_threshold = 0;
432 methods = domain->methods;
434 status = methods->lockout_policy(domain, mem_ctx, &lockout_policy);
435 if (NT_STATUS_IS_ERR(status)) {
439 *lockout_threshold = lockout_policy.lockout_threshold;
444 static NTSTATUS get_pwd_properties(struct winbindd_domain *domain,
446 uint32 *password_properties)
448 struct winbindd_methods *methods;
449 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
450 struct samr_DomInfo1 password_policy;
452 *password_properties = 0;
454 methods = domain->methods;
456 status = methods->password_policy(domain, mem_ctx, &password_policy);
457 if (NT_STATUS_IS_ERR(status)) {
461 *password_properties = password_policy.password_properties;
468 static const char *generate_krb5_ccache(TALLOC_CTX *mem_ctx,
471 const char **user_ccache_file)
473 /* accept FILE and WRFILE as krb5_cc_type from the client and then
474 * build the full ccname string based on the user's uid here -
477 const char *gen_cc = NULL;
480 if (strequal(type, "FILE")) {
481 gen_cc = talloc_asprintf(
482 mem_ctx, "FILE:/tmp/krb5cc_%d", uid);
484 if (strequal(type, "WRFILE")) {
485 gen_cc = talloc_asprintf(
486 mem_ctx, "WRFILE:/tmp/krb5cc_%d", uid);
490 *user_ccache_file = gen_cc;
492 if (gen_cc == NULL) {
493 gen_cc = talloc_strdup(mem_ctx, "MEMORY:winbindd_pam_ccache");
495 if (gen_cc == NULL) {
496 DEBUG(0,("out of memory\n"));
500 DEBUG(10, ("using ccache: %s%s\n", gen_cc,
501 (*user_ccache_file == NULL) ? " (internal)":""));
508 uid_t get_uid_from_request(struct winbindd_request *request)
512 uid = request->data.auth.uid;
515 DEBUG(1,("invalid uid: '%u'\n", (unsigned int)uid));
521 /**********************************************************************
522 Authenticate a user with a clear text password using Kerberos and fill up
524 **********************************************************************/
526 static NTSTATUS winbindd_raw_kerberos_login(TALLOC_CTX *mem_ctx,
527 struct winbindd_domain *domain,
530 const char *krb5_cc_type,
532 struct netr_SamInfo3 **info3,
536 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
537 krb5_error_code krb5_ret;
538 const char *cc = NULL;
539 const char *principal_s = NULL;
540 const char *service = NULL;
542 fstring name_domain, name_user;
543 time_t ticket_lifetime = 0;
544 time_t renewal_until = 0;
546 time_t time_offset = 0;
547 const char *user_ccache_file;
548 struct PAC_LOGON_INFO *logon_info = NULL;
553 * prepare a krb5_cc_cache string for the user */
556 DEBUG(0,("no valid uid\n"));
559 cc = generate_krb5_ccache(mem_ctx,
564 return NT_STATUS_NO_MEMORY;
569 * get kerberos properties */
571 if (domain->private_data) {
572 ads = (ADS_STRUCT *)domain->private_data;
573 time_offset = ads->auth.time_offset;
578 * do kerberos auth and setup ccache as the user */
580 parse_domain_user(user, name_domain, name_user);
582 realm = domain->alt_name;
585 principal_s = talloc_asprintf(mem_ctx, "%s@%s", name_user, realm);
586 if (principal_s == NULL) {
587 return NT_STATUS_NO_MEMORY;
590 service = talloc_asprintf(mem_ctx, "%s/%s@%s", KRB5_TGS_NAME, realm, realm);
591 if (service == NULL) {
592 return NT_STATUS_NO_MEMORY;
595 /* if this is a user ccache, we need to act as the user to let the krb5
596 * library handle the chown, etc. */
598 /************************ ENTERING NON-ROOT **********************/
600 if (user_ccache_file != NULL) {
601 set_effective_uid(uid);
602 DEBUG(10,("winbindd_raw_kerberos_login: uid is %d\n", uid));
605 result = kerberos_return_pac(mem_ctx,
614 WINBINDD_PAM_AUTH_KRB5_RENEW_TIME,
617 if (user_ccache_file != NULL) {
618 gain_root_privilege();
621 /************************ RETURNED TO ROOT **********************/
623 if (!NT_STATUS_IS_OK(result)) {
627 *info3 = &logon_info->info3;
629 DEBUG(10,("winbindd_raw_kerberos_login: winbindd validated ticket of %s\n",
632 /* if we had a user's ccache then return that string for the pam
635 if (user_ccache_file != NULL) {
637 fstrcpy(krb5ccname, user_ccache_file);
639 result = add_ccache_to_list(principal_s,
650 if (!NT_STATUS_IS_OK(result)) {
651 DEBUG(10,("winbindd_raw_kerberos_login: failed to add ccache to list: %s\n",
656 /* need to delete the memory cred cache, it is not used anymore */
658 krb5_ret = ads_kdestroy(cc);
660 DEBUG(3,("winbindd_raw_kerberos_login: "
661 "could not destroy krb5 credential cache: "
662 "%s\n", error_message(krb5_ret)));
671 /* we could have created a new credential cache with a valid tgt in it
672 * but we werent able to get or verify the service ticket for this
673 * local host and therefor didn't get the PAC, we need to remove that
674 * cache entirely now */
676 krb5_ret = ads_kdestroy(cc);
678 DEBUG(3,("winbindd_raw_kerberos_login: "
679 "could not destroy krb5 credential cache: "
680 "%s\n", error_message(krb5_ret)));
683 if (!NT_STATUS_IS_OK(remove_ccache(user))) {
684 DEBUG(3,("winbindd_raw_kerberos_login: "
685 "could not remove ccache for user %s\n",
691 return NT_STATUS_NOT_SUPPORTED;
692 #endif /* HAVE_KRB5 */
695 /****************************************************************
696 ****************************************************************/
698 bool check_request_flags(uint32_t flags)
700 uint32_t flags_edata = WBFLAG_PAM_AFS_TOKEN |
701 WBFLAG_PAM_INFO3_TEXT |
702 WBFLAG_PAM_INFO3_NDR;
704 if ( ( (flags & flags_edata) == WBFLAG_PAM_AFS_TOKEN) ||
705 ( (flags & flags_edata) == WBFLAG_PAM_INFO3_NDR) ||
706 ( (flags & flags_edata) == WBFLAG_PAM_INFO3_TEXT)||
707 !(flags & flags_edata) ) {
711 DEBUG(1, ("check_request_flags: invalid request flags[0x%08X]\n",
717 /****************************************************************
718 ****************************************************************/
720 static NTSTATUS append_auth_data(TALLOC_CTX *mem_ctx,
721 struct winbindd_response *resp,
722 uint32_t request_flags,
723 struct netr_SamInfo3 *info3,
724 const char *name_domain,
725 const char *name_user)
729 if (request_flags & WBFLAG_PAM_USER_SESSION_KEY) {
730 memcpy(resp->data.auth.user_session_key,
732 sizeof(resp->data.auth.user_session_key)
736 if (request_flags & WBFLAG_PAM_LMKEY) {
737 memcpy(resp->data.auth.first_8_lm_hash,
738 info3->base.LMSessKey.key,
739 sizeof(resp->data.auth.first_8_lm_hash)
743 if (request_flags & WBFLAG_PAM_UNIX_NAME) {
744 result = append_unix_username(mem_ctx, resp,
745 info3, name_domain, name_user);
746 if (!NT_STATUS_IS_OK(result)) {
747 DEBUG(10,("Failed to append Unix Username: %s\n",
753 /* currently, anything from here on potentially overwrites extra_data. */
755 if (request_flags & WBFLAG_PAM_INFO3_NDR) {
756 result = append_info3_as_ndr(mem_ctx, resp, info3);
757 if (!NT_STATUS_IS_OK(result)) {
758 DEBUG(10,("Failed to append INFO3 (NDR): %s\n",
764 if (request_flags & WBFLAG_PAM_INFO3_TEXT) {
765 result = append_info3_as_txt(mem_ctx, resp, info3);
766 if (!NT_STATUS_IS_OK(result)) {
767 DEBUG(10,("Failed to append INFO3 (TXT): %s\n",
773 if (request_flags & WBFLAG_PAM_AFS_TOKEN) {
774 result = append_afs_token(mem_ctx, resp,
775 info3, name_domain, name_user);
776 if (!NT_STATUS_IS_OK(result)) {
777 DEBUG(10,("Failed to append AFS token: %s\n",
786 static NTSTATUS winbindd_dual_pam_auth_cached(struct winbindd_domain *domain,
787 struct winbindd_cli_state *state,
788 struct netr_SamInfo3 **info3)
790 NTSTATUS result = NT_STATUS_LOGON_FAILURE;
791 uint16 max_allowed_bad_attempts;
792 fstring name_domain, name_user;
794 enum lsa_SidType type;
795 uchar new_nt_pass[NT_HASH_LEN];
796 const uint8 *cached_nt_pass;
797 const uint8 *cached_salt;
798 struct netr_SamInfo3 *my_info3;
799 time_t kickoff_time, must_change_time;
800 bool password_good = false;
802 struct winbindd_tdc_domain *tdc_domain = NULL;
809 DEBUG(10,("winbindd_dual_pam_auth_cached\n"));
811 /* Parse domain and username */
813 parse_domain_user(state->request->data.auth.user, name_domain, name_user);
816 if (!lookup_cached_name(name_domain,
820 DEBUG(10,("winbindd_dual_pam_auth_cached: no such user in the cache\n"));
821 return NT_STATUS_NO_SUCH_USER;
824 if (type != SID_NAME_USER) {
825 DEBUG(10,("winbindd_dual_pam_auth_cached: not a user (%s)\n", sid_type_lookup(type)));
826 return NT_STATUS_LOGON_FAILURE;
829 result = winbindd_get_creds(domain,
835 if (!NT_STATUS_IS_OK(result)) {
836 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get creds: %s\n", nt_errstr(result)));
842 E_md4hash(state->request->data.auth.pass, new_nt_pass);
844 dump_data_pw("new_nt_pass", new_nt_pass, NT_HASH_LEN);
845 dump_data_pw("cached_nt_pass", cached_nt_pass, NT_HASH_LEN);
847 dump_data_pw("cached_salt", cached_salt, NT_HASH_LEN);
851 /* In this case we didn't store the nt_hash itself,
852 but the MD5 combination of salt + nt_hash. */
853 uchar salted_hash[NT_HASH_LEN];
854 E_md5hash(cached_salt, new_nt_pass, salted_hash);
856 password_good = (memcmp(cached_nt_pass, salted_hash,
859 /* Old cached cred - direct store of nt_hash (bad bad bad !). */
860 password_good = (memcmp(cached_nt_pass, new_nt_pass,
866 /* User *DOES* know the password, update logon_time and reset
869 my_info3->base.user_flags |= NETLOGON_CACHED_ACCOUNT;
871 if (my_info3->base.acct_flags & ACB_AUTOLOCK) {
872 return NT_STATUS_ACCOUNT_LOCKED_OUT;
875 if (my_info3->base.acct_flags & ACB_DISABLED) {
876 return NT_STATUS_ACCOUNT_DISABLED;
879 if (my_info3->base.acct_flags & ACB_WSTRUST) {
880 return NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
883 if (my_info3->base.acct_flags & ACB_SVRTRUST) {
884 return NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT;
887 if (my_info3->base.acct_flags & ACB_DOMTRUST) {
888 return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT;
891 if (!(my_info3->base.acct_flags & ACB_NORMAL)) {
892 DEBUG(0,("winbindd_dual_pam_auth_cached: whats wrong with that one?: 0x%08x\n",
893 my_info3->base.acct_flags));
894 return NT_STATUS_LOGON_FAILURE;
897 kickoff_time = nt_time_to_unix(my_info3->base.acct_expiry);
898 if (kickoff_time != 0 && time(NULL) > kickoff_time) {
899 return NT_STATUS_ACCOUNT_EXPIRED;
902 must_change_time = nt_time_to_unix(my_info3->base.force_password_change);
903 if (must_change_time != 0 && must_change_time < time(NULL)) {
904 /* we allow grace logons when the password has expired */
905 my_info3->base.user_flags |= NETLOGON_GRACE_LOGON;
906 /* return NT_STATUS_PASSWORD_EXPIRED; */
911 if ((state->request->flags & WBFLAG_PAM_KRB5) &&
912 ((tdc_domain = wcache_tdc_fetch_domain(state->mem_ctx, name_domain)) != NULL) &&
913 ((tdc_domain->trust_type & NETR_TRUST_TYPE_UPLEVEL) ||
914 /* used to cope with the case winbindd starting without network. */
915 !strequal(tdc_domain->domain_name, tdc_domain->dns_name))) {
918 const char *cc = NULL;
920 const char *principal_s = NULL;
921 const char *service = NULL;
922 const char *user_ccache_file;
924 uid = get_uid_from_request(state->request);
926 DEBUG(0,("winbindd_dual_pam_auth_cached: invalid uid\n"));
927 return NT_STATUS_INVALID_PARAMETER;
930 cc = generate_krb5_ccache(state->mem_ctx,
931 state->request->data.auth.krb5_cc_type,
932 state->request->data.auth.uid,
935 return NT_STATUS_NO_MEMORY;
938 realm = domain->alt_name;
941 principal_s = talloc_asprintf(state->mem_ctx, "%s@%s", name_user, realm);
942 if (principal_s == NULL) {
943 return NT_STATUS_NO_MEMORY;
946 service = talloc_asprintf(state->mem_ctx, "%s/%s@%s", KRB5_TGS_NAME, realm, realm);
947 if (service == NULL) {
948 return NT_STATUS_NO_MEMORY;
951 if (user_ccache_file != NULL) {
953 fstrcpy(state->response->data.auth.krb5ccname,
956 result = add_ccache_to_list(principal_s,
959 state->request->data.auth.user,
963 time(NULL) + lp_winbind_cache_time(),
964 time(NULL) + WINBINDD_PAM_AUTH_KRB5_RENEW_TIME,
967 if (!NT_STATUS_IS_OK(result)) {
968 DEBUG(10,("winbindd_dual_pam_auth_cached: failed "
969 "to add ccache to list: %s\n",
974 #endif /* HAVE_KRB5 */
976 /* FIXME: we possibly should handle logon hours as well (does xp when
977 * offline?) see auth/auth_sam.c:sam_account_ok for details */
979 unix_to_nt_time(&my_info3->base.last_logon, time(NULL));
980 my_info3->base.bad_password_count = 0;
982 result = winbindd_update_creds_by_info3(domain,
983 state->request->data.auth.user,
984 state->request->data.auth.pass,
986 if (!NT_STATUS_IS_OK(result)) {
987 DEBUG(1,("winbindd_dual_pam_auth_cached: failed to update creds: %s\n",
996 /* User does *NOT* know the correct password, modify info3 accordingly */
998 /* failure of this is not critical */
999 result = get_max_bad_attempts_from_lockout_policy(domain, state->mem_ctx, &max_allowed_bad_attempts);
1000 if (!NT_STATUS_IS_OK(result)) {
1001 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get max_allowed_bad_attempts. "
1002 "Won't be able to honour account lockout policies\n"));
1005 /* increase counter */
1006 my_info3->base.bad_password_count++;
1008 if (max_allowed_bad_attempts == 0) {
1013 if (my_info3->base.bad_password_count >= max_allowed_bad_attempts) {
1015 uint32 password_properties;
1017 result = get_pwd_properties(domain, state->mem_ctx, &password_properties);
1018 if (!NT_STATUS_IS_OK(result)) {
1019 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get password properties.\n"));
1022 if ((my_info3->base.rid != DOMAIN_RID_ADMINISTRATOR) ||
1023 (password_properties & DOMAIN_PASSWORD_LOCKOUT_ADMINS)) {
1024 my_info3->base.acct_flags |= ACB_AUTOLOCK;
1029 result = winbindd_update_creds_by_info3(domain,
1030 state->request->data.auth.user,
1034 if (!NT_STATUS_IS_OK(result)) {
1035 DEBUG(0,("winbindd_dual_pam_auth_cached: failed to update creds %s\n",
1036 nt_errstr(result)));
1039 return NT_STATUS_LOGON_FAILURE;
1042 static NTSTATUS winbindd_dual_pam_auth_kerberos(struct winbindd_domain *domain,
1043 struct winbindd_cli_state *state,
1044 struct netr_SamInfo3 **info3)
1046 struct winbindd_domain *contact_domain;
1047 fstring name_domain, name_user;
1050 DEBUG(10,("winbindd_dual_pam_auth_kerberos\n"));
1052 /* Parse domain and username */
1054 parse_domain_user(state->request->data.auth.user, name_domain, name_user);
1056 /* what domain should we contact? */
1059 if (!(contact_domain = find_domain_from_name(name_domain))) {
1060 DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
1061 state->request->data.auth.user, name_domain, name_user, name_domain));
1062 result = NT_STATUS_NO_SUCH_USER;
1067 if (is_myname(name_domain)) {
1068 DEBUG(3, ("Authentication for domain %s (local domain to this server) not supported at this stage\n", name_domain));
1069 result = NT_STATUS_NO_SUCH_USER;
1073 contact_domain = find_domain_from_name(name_domain);
1074 if (contact_domain == NULL) {
1075 DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
1076 state->request->data.auth.user, name_domain, name_user, name_domain));
1078 contact_domain = find_our_domain();
1082 if (contact_domain->initialized &&
1083 contact_domain->active_directory) {
1087 if (!contact_domain->initialized) {
1088 init_dc_connection(contact_domain);
1091 if (!contact_domain->active_directory) {
1092 DEBUG(3,("krb5 auth requested but domain is not Active Directory\n"));
1093 return NT_STATUS_INVALID_LOGON_TYPE;
1096 result = winbindd_raw_kerberos_login(
1097 state->mem_ctx, contact_domain,
1098 state->request->data.auth.user,
1099 state->request->data.auth.pass,
1100 state->request->data.auth.krb5_cc_type,
1101 get_uid_from_request(state->request),
1102 info3, state->response->data.auth.krb5ccname);
1107 static NTSTATUS winbindd_dual_auth_passdb(TALLOC_CTX *mem_ctx,
1108 const char *domain, const char *user,
1109 const DATA_BLOB *challenge,
1110 const DATA_BLOB *lm_resp,
1111 const DATA_BLOB *nt_resp,
1112 struct netr_SamInfo3 **pinfo3)
1114 struct auth_usersupplied_info *user_info = NULL;
1117 status = make_user_info(&user_info, user, user, domain, domain,
1118 global_myname(), lm_resp, nt_resp, NULL, NULL,
1119 NULL, AUTH_PASSWORD_RESPONSE);
1120 if (!NT_STATUS_IS_OK(status)) {
1121 DEBUG(10, ("make_user_info failed: %s\n", nt_errstr(status)));
1125 /* We don't want any more mapping of the username */
1126 user_info->mapped_state = True;
1128 status = check_sam_security_info3(challenge, talloc_tos(), user_info,
1130 free_user_info(&user_info);
1131 DEBUG(10, ("Authenticaticating user %s\\%s returned %s\n", domain,
1132 user, nt_errstr(status)));
1136 static NTSTATUS winbind_samlogon_retry_loop(struct winbindd_domain *domain,
1137 TALLOC_CTX *mem_ctx,
1138 uint32_t logon_parameters,
1140 const char *username,
1141 const char *domainname,
1142 const char *workstation,
1143 const uint8_t chal[8],
1144 DATA_BLOB lm_response,
1145 DATA_BLOB nt_response,
1146 struct netr_SamInfo3 **info3)
1153 struct rpc_pipe_client *netlogon_pipe;
1154 const struct pipe_auth_data *auth;
1155 uint32_t neg_flags = 0;
1157 ZERO_STRUCTP(info3);
1160 result = cm_connect_netlogon(domain, &netlogon_pipe);
1162 if (!NT_STATUS_IS_OK(result)) {
1163 DEBUG(3,("could not open handle to NETLOGON pipe (error: %s)\n",
1164 nt_errstr(result)));
1167 auth = netlogon_pipe->auth;
1168 if (netlogon_pipe->dc) {
1169 neg_flags = netlogon_pipe->dc->negotiate_flags;
1172 /* It is really important to try SamLogonEx here,
1173 * because in a clustered environment, we want to use
1174 * one machine account from multiple physical
1177 * With a normal SamLogon call, we must keep the
1178 * credentials chain updated and intact between all
1179 * users of the machine account (which would imply
1180 * cross-node communication for every NTLM logon).
1182 * (The credentials chain is not per NETLOGON pipe
1183 * connection, but globally on the server/client pair
1186 * When using SamLogonEx, the credentials are not
1187 * supplied, but the session key is implied by the
1188 * wrapping SamLogon context.
1190 * -- abartlet 21 April 2008
1192 * It's also important to use NetlogonValidationSamInfo4 (6),
1193 * because it relies on the rpc transport encryption
1194 * and avoids using the global netlogon schannel
1195 * session key to en/decrypt secret information
1196 * like the user_session_key for network logons.
1198 * [MS-APDS] 3.1.5.2 NTLM Network Logon
1199 * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
1200 * NETLOGON_NEG_AUTHENTICATED_RPC set together
1201 * are the indication that the server supports
1202 * NetlogonValidationSamInfo4 (6). And it must only
1203 * be used if "SealSecureChannel" is used.
1205 * -- metze 4 February 2011
1209 domain->can_do_validation6 = false;
1210 } else if (auth->auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
1211 domain->can_do_validation6 = false;
1212 } else if (auth->auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
1213 domain->can_do_validation6 = false;
1214 } else if (!(neg_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
1215 domain->can_do_validation6 = false;
1216 } else if (!(neg_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
1217 domain->can_do_validation6 = false;
1220 if (domain->can_do_samlogon_ex) {
1221 result = rpccli_netlogon_sam_network_logon_ex(
1225 server, /* server name */
1226 username, /* user name */
1227 domainname, /* target domain */
1228 workstation, /* workstation */
1230 domain->can_do_validation6 ? 6 : 3,
1235 result = rpccli_netlogon_sam_network_logon(
1239 server, /* server name */
1240 username, /* user name */
1241 domainname, /* target domain */
1242 workstation, /* workstation */
1244 domain->can_do_validation6 ? 6 : 3,
1250 if (NT_STATUS_EQUAL(result, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)
1251 && domain->can_do_samlogon_ex) {
1252 DEBUG(3, ("Got a DC that can not do NetSamLogonEx, "
1253 "retrying with NetSamLogon\n"));
1254 domain->can_do_samlogon_ex = false;
1256 * It's likely that the server also does not support
1257 * validation level 6
1259 domain->can_do_validation6 = false;
1264 if (domain->can_do_validation6 &&
1265 (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
1266 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
1267 NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL))) {
1268 DEBUG(3,("Got a DC that can not do validation level 6, "
1269 "retrying with level 3\n"));
1270 domain->can_do_validation6 = false;
1276 * we increment this after the "feature negotiation"
1277 * for can_do_samlogon_ex and can_do_validation6
1281 /* We have to try a second time as cm_connect_netlogon
1282 might not yet have noticed that the DC has killed
1285 if (!rpccli_is_connected(netlogon_pipe)) {
1290 /* if we get access denied, a possible cause was that we had
1291 and open connection to the DC, but someone changed our
1292 machine account password out from underneath us using 'net
1293 rpc changetrustpw' */
1295 if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
1296 DEBUG(3,("winbindd_pam_auth: sam_logon returned "
1297 "ACCESS_DENIED. Maybe the trust account "
1298 "password was changed and we didn't know it. "
1299 "Killing connections to domain %s\n",
1301 invalidate_cm_connection(&domain->conn);
1305 } while ( (attempts < 2) && retry );
1310 static NTSTATUS winbindd_dual_pam_auth_samlogon(TALLOC_CTX *mem_ctx,
1311 struct winbindd_domain *domain,
1314 uint32_t request_flags,
1315 struct netr_SamInfo3 **info3)
1321 unsigned char local_nt_response[24];
1322 fstring name_domain, name_user;
1324 struct netr_SamInfo3 *my_info3 = NULL;
1328 DEBUG(10,("winbindd_dual_pam_auth_samlogon\n"));
1330 /* Parse domain and username */
1332 parse_domain_user(user, name_domain, name_user);
1334 /* do password magic */
1336 generate_random_buffer(chal, sizeof(chal));
1338 if (lp_client_ntlmv2_auth()) {
1339 DATA_BLOB server_chal;
1340 DATA_BLOB names_blob;
1341 server_chal = data_blob_const(chal, 8);
1343 /* note that the 'workgroup' here is for the local
1344 machine. The 'server name' must match the
1345 'workstation' passed to the actual SamLogon call.
1347 names_blob = NTLMv2_generate_names_blob(
1348 mem_ctx, global_myname(), lp_workgroup());
1350 if (!SMBNTLMv2encrypt(mem_ctx, name_user, name_domain,
1354 &lm_resp, &nt_resp, NULL, NULL)) {
1355 data_blob_free(&names_blob);
1356 DEBUG(0, ("winbindd_pam_auth: SMBNTLMv2encrypt() failed!\n"));
1357 result = NT_STATUS_NO_MEMORY;
1360 data_blob_free(&names_blob);
1362 lm_resp = data_blob_null;
1363 SMBNTencrypt(pass, chal, local_nt_response);
1365 nt_resp = data_blob_talloc(mem_ctx, local_nt_response,
1366 sizeof(local_nt_response));
1369 if (strequal(name_domain, get_global_sam_name())) {
1370 DATA_BLOB chal_blob = data_blob_const(chal, sizeof(chal));
1372 result = winbindd_dual_auth_passdb(
1373 mem_ctx, name_domain, name_user,
1374 &chal_blob, &lm_resp, &nt_resp, info3);
1378 /* check authentication loop */
1380 result = winbind_samlogon_retry_loop(domain,
1391 if (!NT_STATUS_IS_OK(result)) {
1395 /* handle the case where a NT4 DC does not fill in the acct_flags in
1396 * the samlogon reply info3. When accurate info3 is required by the
1397 * caller, we look up the account flags ourselve - gd */
1399 if ((request_flags & WBFLAG_PAM_INFO3_TEXT) &&
1400 NT_STATUS_IS_OK(result) && (my_info3->base.acct_flags == 0)) {
1402 struct rpc_pipe_client *samr_pipe;
1403 struct policy_handle samr_domain_handle, user_pol;
1404 union samr_UserInfo *info = NULL;
1405 NTSTATUS status_tmp, result_tmp;
1407 struct dcerpc_binding_handle *b;
1409 status_tmp = cm_connect_sam(domain, mem_ctx,
1410 &samr_pipe, &samr_domain_handle);
1412 if (!NT_STATUS_IS_OK(status_tmp)) {
1413 DEBUG(3, ("could not open handle to SAMR pipe: %s\n",
1414 nt_errstr(status_tmp)));
1418 b = samr_pipe->binding_handle;
1420 status_tmp = dcerpc_samr_OpenUser(b, mem_ctx,
1421 &samr_domain_handle,
1422 MAXIMUM_ALLOWED_ACCESS,
1427 if (!NT_STATUS_IS_OK(status_tmp)) {
1428 DEBUG(3, ("could not open user handle on SAMR pipe: %s\n",
1429 nt_errstr(status_tmp)));
1432 if (!NT_STATUS_IS_OK(result_tmp)) {
1433 DEBUG(3, ("could not open user handle on SAMR pipe: %s\n",
1434 nt_errstr(result_tmp)));
1438 status_tmp = dcerpc_samr_QueryUserInfo(b, mem_ctx,
1444 if (!NT_STATUS_IS_OK(status_tmp)) {
1445 DEBUG(3, ("could not query user info on SAMR pipe: %s\n",
1446 nt_errstr(status_tmp)));
1447 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
1450 if (!NT_STATUS_IS_OK(result_tmp)) {
1451 DEBUG(3, ("could not query user info on SAMR pipe: %s\n",
1452 nt_errstr(result_tmp)));
1453 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
1457 acct_flags = info->info16.acct_flags;
1459 if (acct_flags == 0) {
1460 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
1464 my_info3->base.acct_flags = acct_flags;
1466 DEBUG(10,("successfully retrieved acct_flags 0x%x\n", acct_flags));
1468 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
1476 enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain,
1477 struct winbindd_cli_state *state)
1479 NTSTATUS result = NT_STATUS_LOGON_FAILURE;
1480 NTSTATUS krb5_result = NT_STATUS_OK;
1481 fstring name_domain, name_user;
1483 fstring domain_user;
1484 struct netr_SamInfo3 *info3 = NULL;
1485 NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL;
1487 /* Ensure null termination */
1488 state->request->data.auth.user[sizeof(state->request->data.auth.user)-1]='\0';
1490 /* Ensure null termination */
1491 state->request->data.auth.pass[sizeof(state->request->data.auth.pass)-1]='\0';
1493 DEBUG(3, ("[%5lu]: dual pam auth %s\n", (unsigned long)state->pid,
1494 state->request->data.auth.user));
1496 /* Parse domain and username */
1498 name_map_status = normalize_name_unmap(state->mem_ctx,
1499 state->request->data.auth.user,
1502 /* If the name normalization didnt' actually do anything,
1503 just use the original name */
1505 if (!NT_STATUS_IS_OK(name_map_status) &&
1506 !NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED))
1508 mapped_user = state->request->data.auth.user;
1511 parse_domain_user(mapped_user, name_domain, name_user);
1513 if ( mapped_user != state->request->data.auth.user ) {
1514 fstr_sprintf( domain_user, "%s%c%s", name_domain,
1515 *lp_winbind_separator(),
1517 strlcpy( state->request->data.auth.user, domain_user,
1518 sizeof(state->request->data.auth.user));
1521 if (!domain->online) {
1522 result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
1523 if (domain->startup) {
1524 /* Logons are very important to users. If we're offline and
1525 we get a request within the first 30 seconds of startup,
1526 try very hard to find a DC and go online. */
1528 DEBUG(10,("winbindd_dual_pam_auth: domain: %s offline and auth "
1529 "request in startup mode.\n", domain->name ));
1531 winbindd_flush_negative_conn_cache(domain);
1532 result = init_dc_connection(domain);
1536 DEBUG(10,("winbindd_dual_pam_auth: domain: %s last was %s\n", domain->name, domain->online ? "online":"offline"));
1538 /* Check for Kerberos authentication */
1539 if (domain->online && (state->request->flags & WBFLAG_PAM_KRB5)) {
1541 result = winbindd_dual_pam_auth_kerberos(domain, state, &info3);
1542 /* save for later */
1543 krb5_result = result;
1546 if (NT_STATUS_IS_OK(result)) {
1547 DEBUG(10,("winbindd_dual_pam_auth_kerberos succeeded\n"));
1548 goto process_result;
1550 DEBUG(10,("winbindd_dual_pam_auth_kerberos failed: %s\n", nt_errstr(result)));
1553 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
1554 NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
1555 NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1556 DEBUG(10,("winbindd_dual_pam_auth_kerberos setting domain to offline\n"));
1557 set_domain_offline( domain );
1561 /* there are quite some NT_STATUS errors where there is no
1562 * point in retrying with a samlogon, we explictly have to take
1563 * care not to increase the bad logon counter on the DC */
1565 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_DISABLED) ||
1566 NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_EXPIRED) ||
1567 NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_LOCKED_OUT) ||
1568 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_LOGON_HOURS) ||
1569 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_WORKSTATION) ||
1570 NT_STATUS_EQUAL(result, NT_STATUS_LOGON_FAILURE) ||
1571 NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER) ||
1572 NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_EXPIRED) ||
1573 NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_MUST_CHANGE) ||
1574 NT_STATUS_EQUAL(result, NT_STATUS_WRONG_PASSWORD)) {
1578 if (state->request->flags & WBFLAG_PAM_FALLBACK_AFTER_KRB5) {
1579 DEBUG(3,("falling back to samlogon\n"));
1587 /* Check for Samlogon authentication */
1588 if (domain->online) {
1589 result = winbindd_dual_pam_auth_samlogon(
1590 state->mem_ctx, domain,
1591 state->request->data.auth.user,
1592 state->request->data.auth.pass,
1593 state->request->flags,
1596 if (NT_STATUS_IS_OK(result)) {
1597 DEBUG(10,("winbindd_dual_pam_auth_samlogon succeeded\n"));
1598 /* add the Krb5 err if we have one */
1599 if ( NT_STATUS_EQUAL(krb5_result, NT_STATUS_TIME_DIFFERENCE_AT_DC ) ) {
1600 info3->base.user_flags |= LOGON_KRB5_FAIL_CLOCK_SKEW;
1602 goto process_result;
1605 DEBUG(10,("winbindd_dual_pam_auth_samlogon failed: %s\n",
1606 nt_errstr(result)));
1608 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
1609 NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
1610 NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND))
1612 DEBUG(10,("winbindd_dual_pam_auth_samlogon setting domain to offline\n"));
1613 set_domain_offline( domain );
1617 if (domain->online) {
1618 /* We're still online - fail. */
1624 /* Check for Cached logons */
1625 if (!domain->online && (state->request->flags & WBFLAG_PAM_CACHED_LOGIN) &&
1626 lp_winbind_offline_logon()) {
1628 result = winbindd_dual_pam_auth_cached(domain, state, &info3);
1630 if (NT_STATUS_IS_OK(result)) {
1631 DEBUG(10,("winbindd_dual_pam_auth_cached succeeded\n"));
1632 goto process_result;
1634 DEBUG(10,("winbindd_dual_pam_auth_cached failed: %s\n", nt_errstr(result)));
1641 if (NT_STATUS_IS_OK(result)) {
1643 struct dom_sid user_sid;
1645 /* In all codepaths where result == NT_STATUS_OK info3 must have
1646 been initialized. */
1648 result = NT_STATUS_INTERNAL_ERROR;
1652 sid_compose(&user_sid, info3->base.domain_sid,
1655 wcache_invalidate_samlogon(find_domain_from_name(name_domain),
1657 netsamlogon_cache_store(name_user, info3);
1659 /* save name_to_sid info as early as possible (only if
1660 this is our primary domain so we don't invalidate
1661 the cache entry by storing the seq_num for the wrong
1663 if ( domain->primary ) {
1664 cache_name2sid(domain, name_domain, name_user,
1665 SID_NAME_USER, &user_sid);
1668 /* Check if the user is in the right group */
1670 result = check_info3_in_group(
1672 state->request->data.auth.require_membership_of_sid);
1673 if (!NT_STATUS_IS_OK(result)) {
1674 DEBUG(3, ("User %s is not in the required group (%s), so plaintext authentication is rejected\n",
1675 state->request->data.auth.user,
1676 state->request->data.auth.require_membership_of_sid));
1680 result = append_auth_data(state->mem_ctx, state->response,
1681 state->request->flags, info3,
1682 name_domain, name_user);
1683 if (!NT_STATUS_IS_OK(result)) {
1687 if ((state->request->flags & WBFLAG_PAM_CACHED_LOGIN)
1688 && lp_winbind_offline_logon()) {
1690 result = winbindd_store_creds(domain,
1691 state->request->data.auth.user,
1692 state->request->data.auth.pass,
1696 if (state->request->flags & WBFLAG_PAM_GET_PWD_POLICY) {
1697 struct winbindd_domain *our_domain = find_our_domain();
1699 /* This is not entirely correct I believe, but it is
1700 consistent. Only apply the password policy settings
1701 too warn users for our own domain. Cannot obtain these
1702 from trusted DCs all the time so don't do it at all.
1705 result = NT_STATUS_NOT_SUPPORTED;
1706 if (our_domain == domain ) {
1707 result = fillup_password_policy(
1708 our_domain, state->response);
1711 if (!NT_STATUS_IS_OK(result)
1712 && !NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED) )
1714 DEBUG(10,("Failed to get password policies for domain %s: %s\n",
1715 domain->name, nt_errstr(result)));
1720 result = NT_STATUS_OK;
1724 /* give us a more useful (more correct?) error code */
1725 if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
1726 (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
1727 result = NT_STATUS_NO_LOGON_SERVERS;
1730 set_auth_errors(state->response, result);
1732 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, ("Plain-text authentication for user %s returned %s (PAM: %d)\n",
1733 state->request->data.auth.user,
1734 state->response->data.auth.nt_status_string,
1735 state->response->data.auth.pam_error));
1737 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
1740 enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain,
1741 struct winbindd_cli_state *state)
1744 struct netr_SamInfo3 *info3 = NULL;
1745 const char *name_user = NULL;
1746 const char *name_domain = NULL;
1747 const char *workstation;
1749 DATA_BLOB lm_resp, nt_resp;
1751 /* This is child-only, so no check for privileged access is needed
1754 /* Ensure null termination */
1755 state->request->data.auth_crap.user[sizeof(state->request->data.auth_crap.user)-1]=0;
1756 state->request->data.auth_crap.domain[sizeof(state->request->data.auth_crap.domain)-1]=0;
1758 name_user = state->request->data.auth_crap.user;
1759 name_domain = state->request->data.auth_crap.domain;
1760 workstation = state->request->data.auth_crap.workstation;
1762 DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n", (unsigned long)state->pid,
1763 name_domain, name_user));
1765 if (state->request->data.auth_crap.lm_resp_len > sizeof(state->request->data.auth_crap.lm_resp)
1766 || state->request->data.auth_crap.nt_resp_len > sizeof(state->request->data.auth_crap.nt_resp)) {
1767 if (!(state->request->flags & WBFLAG_BIG_NTLMV2_BLOB) ||
1768 state->request->extra_len != state->request->data.auth_crap.nt_resp_len) {
1769 DEBUG(0, ("winbindd_pam_auth_crap: invalid password length %u/%u\n",
1770 state->request->data.auth_crap.lm_resp_len,
1771 state->request->data.auth_crap.nt_resp_len));
1772 result = NT_STATUS_INVALID_PARAMETER;
1777 lm_resp = data_blob_talloc(state->mem_ctx, state->request->data.auth_crap.lm_resp,
1778 state->request->data.auth_crap.lm_resp_len);
1780 if (state->request->flags & WBFLAG_BIG_NTLMV2_BLOB) {
1781 nt_resp = data_blob_talloc(state->mem_ctx,
1782 state->request->extra_data.data,
1783 state->request->data.auth_crap.nt_resp_len);
1785 nt_resp = data_blob_talloc(state->mem_ctx,
1786 state->request->data.auth_crap.nt_resp,
1787 state->request->data.auth_crap.nt_resp_len);
1790 if (strequal(name_domain, get_global_sam_name())) {
1791 DATA_BLOB chal_blob = data_blob_const(
1792 state->request->data.auth_crap.chal,
1793 sizeof(state->request->data.auth_crap.chal));
1795 result = winbindd_dual_auth_passdb(
1796 state->mem_ctx, name_domain, name_user,
1797 &chal_blob, &lm_resp, &nt_resp, &info3);
1798 goto process_result;
1801 result = winbind_samlogon_retry_loop(domain,
1803 state->request->data.auth_crap.logon_parameters,
1807 /* Bug #3248 - found by Stefan Burkei. */
1808 workstation, /* We carefully set this above so use it... */
1809 state->request->data.auth_crap.chal,
1813 if (!NT_STATUS_IS_OK(result)) {
1819 if (NT_STATUS_IS_OK(result)) {
1820 struct dom_sid user_sid;
1822 sid_compose(&user_sid, info3->base.domain_sid,
1824 wcache_invalidate_samlogon(find_domain_from_name(name_domain),
1826 netsamlogon_cache_store(name_user, info3);
1828 /* Check if the user is in the right group */
1830 result = check_info3_in_group(
1832 state->request->data.auth_crap.require_membership_of_sid);
1833 if (!NT_STATUS_IS_OK(result)) {
1834 DEBUG(3, ("User %s is not in the required group (%s), so "
1835 "crap authentication is rejected\n",
1836 state->request->data.auth_crap.user,
1837 state->request->data.auth_crap.require_membership_of_sid));
1841 result = append_auth_data(state->mem_ctx, state->response,
1842 state->request->flags, info3,
1843 name_domain, name_user);
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;
1885 struct dcerpc_binding_handle *b = NULL;
1887 ZERO_STRUCT(dom_pol);
1889 DEBUG(3, ("[%5lu]: dual pam chauthtok %s\n", (unsigned long)state->pid,
1890 state->request->data.auth.user));
1892 if (!parse_domain_user(state->request->data.chauthtok.user, domain, user)) {
1896 /* Change password */
1898 oldpass = state->request->data.chauthtok.oldpass;
1899 newpass = state->request->data.chauthtok.newpass;
1901 /* Initialize reject reason */
1902 state->response->data.auth.reject_reason = Undefined;
1904 /* Get sam handle */
1906 result = cm_connect_sam(contact_domain, state->mem_ctx, &cli,
1908 if (!NT_STATUS_IS_OK(result)) {
1909 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
1913 b = cli->binding_handle;
1915 result = rpccli_samr_chgpasswd_user3(cli, state->mem_ctx,
1922 /* Windows 2003 returns NT_STATUS_PASSWORD_RESTRICTION */
1924 if (NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_RESTRICTION) ) {
1926 fill_in_password_policy(state->response, info);
1928 state->response->data.auth.reject_reason =
1929 reject->extendedFailureReason;
1934 /* atm the pidl generated rpccli_samr_ChangePasswordUser3 function will
1935 * return with NT_STATUS_BUFFER_TOO_SMALL for w2k dcs as w2k just
1936 * returns with 4byte error code (NT_STATUS_NOT_SUPPORTED) which is too
1937 * short to comply with the samr_ChangePasswordUser3 idl - gd */
1939 /* only fallback when the chgpasswd_user3 call is not supported */
1940 if (NT_STATUS_EQUAL(result, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE) ||
1941 NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED) ||
1942 NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL) ||
1943 NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
1945 DEBUG(10,("Password change with chgpasswd_user3 failed with: %s, retrying chgpasswd_user2\n",
1946 nt_errstr(result)));
1948 result = rpccli_samr_chgpasswd_user2(cli, state->mem_ctx, user, newpass, oldpass);
1950 /* Windows 2000 returns NT_STATUS_ACCOUNT_RESTRICTION.
1951 Map to the same status code as Windows 2003. */
1953 if ( NT_STATUS_EQUAL(NT_STATUS_ACCOUNT_RESTRICTION, result ) ) {
1954 result = NT_STATUS_PASSWORD_RESTRICTION;
1960 if (NT_STATUS_IS_OK(result)
1961 && (state->request->flags & WBFLAG_PAM_CACHED_LOGIN)
1962 && lp_winbind_offline_logon()) {
1963 result = winbindd_update_creds_by_name(contact_domain, user,
1965 /* Again, this happens when we login from gdm or xdm
1966 * and the password expires, *BUT* cached crendentials
1967 * doesn't exist. winbindd_update_creds_by_name()
1968 * returns NT_STATUS_NO_SUCH_USER.
1969 * This is not a failure.
1972 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER)) {
1973 result = NT_STATUS_OK;
1976 if (!NT_STATUS_IS_OK(result)) {
1977 DEBUG(10, ("Failed to store creds: %s\n",
1978 nt_errstr(result)));
1979 goto process_result;
1983 if (!NT_STATUS_IS_OK(result) && !got_info && contact_domain) {
1985 NTSTATUS policy_ret;
1987 policy_ret = fillup_password_policy(
1988 contact_domain, state->response);
1990 /* failure of this is non critical, it will just provide no
1991 * additional information to the client why the change has
1992 * failed - Guenther */
1994 if (!NT_STATUS_IS_OK(policy_ret)) {
1995 DEBUG(10,("Failed to get password policies: %s\n", nt_errstr(policy_ret)));
1996 goto process_result;
2002 if (strequal(contact_domain->name, get_global_sam_name())) {
2003 /* FIXME: internal rpc pipe does not cache handles yet */
2005 if (is_valid_policy_hnd(&dom_pol)) {
2007 dcerpc_samr_Close(b, state->mem_ctx, &dom_pol, &_result);
2013 set_auth_errors(state->response, result);
2015 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
2016 ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
2019 state->response->data.auth.nt_status_string,
2020 state->response->data.auth.pam_error));
2022 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2025 enum winbindd_result winbindd_dual_pam_logoff(struct winbindd_domain *domain,
2026 struct winbindd_cli_state *state)
2028 NTSTATUS result = NT_STATUS_NOT_SUPPORTED;
2030 DEBUG(3, ("[%5lu]: pam dual logoff %s\n", (unsigned long)state->pid,
2031 state->request->data.logoff.user));
2033 if (!(state->request->flags & WBFLAG_PAM_KRB5)) {
2034 result = NT_STATUS_OK;
2035 goto process_result;
2038 if (state->request->data.logoff.krb5ccname[0] == '\0') {
2039 result = NT_STATUS_OK;
2040 goto process_result;
2045 if (state->request->data.logoff.uid < 0) {
2046 DEBUG(0,("winbindd_pam_logoff: invalid uid\n"));
2047 goto process_result;
2050 /* what we need here is to find the corresponding krb5 ccache name *we*
2051 * created for a given username and destroy it */
2053 if (!ccache_entry_exists(state->request->data.logoff.user)) {
2054 result = NT_STATUS_OK;
2055 DEBUG(10,("winbindd_pam_logoff: no entry found.\n"));
2056 goto process_result;
2059 if (!ccache_entry_identical(state->request->data.logoff.user,
2060 state->request->data.logoff.uid,
2061 state->request->data.logoff.krb5ccname)) {
2062 DEBUG(0,("winbindd_pam_logoff: cached entry differs.\n"));
2063 goto process_result;
2066 result = remove_ccache(state->request->data.logoff.user);
2067 if (!NT_STATUS_IS_OK(result)) {
2068 DEBUG(0,("winbindd_pam_logoff: failed to remove ccache: %s\n",
2069 nt_errstr(result)));
2070 goto process_result;
2074 result = NT_STATUS_NOT_SUPPORTED;
2080 set_auth_errors(state->response, result);
2082 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2085 /* Change user password with auth crap*/
2087 enum winbindd_result winbindd_dual_pam_chng_pswd_auth_crap(struct winbindd_domain *domainSt, struct winbindd_cli_state *state)
2090 DATA_BLOB new_nt_password;
2091 DATA_BLOB old_nt_hash_enc;
2092 DATA_BLOB new_lm_password;
2093 DATA_BLOB old_lm_hash_enc;
2094 fstring domain,user;
2095 struct policy_handle dom_pol;
2096 struct winbindd_domain *contact_domain = domainSt;
2097 struct rpc_pipe_client *cli = NULL;
2098 struct dcerpc_binding_handle *b = NULL;
2100 ZERO_STRUCT(dom_pol);
2102 /* Ensure null termination */
2103 state->request->data.chng_pswd_auth_crap.user[
2104 sizeof(state->request->data.chng_pswd_auth_crap.user)-1]=0;
2105 state->request->data.chng_pswd_auth_crap.domain[
2106 sizeof(state->request->data.chng_pswd_auth_crap.domain)-1]=0;
2110 DEBUG(3, ("[%5lu]: pam change pswd auth crap domain: %s user: %s\n",
2111 (unsigned long)state->pid,
2112 state->request->data.chng_pswd_auth_crap.domain,
2113 state->request->data.chng_pswd_auth_crap.user));
2115 if (lp_winbind_offline_logon()) {
2116 DEBUG(0,("Refusing password change as winbind offline logons are enabled. "));
2117 DEBUGADD(0,("Changing passwords here would risk inconsistent logons\n"));
2118 result = NT_STATUS_ACCESS_DENIED;
2122 if (*state->request->data.chng_pswd_auth_crap.domain) {
2123 fstrcpy(domain,state->request->data.chng_pswd_auth_crap.domain);
2125 parse_domain_user(state->request->data.chng_pswd_auth_crap.user,
2129 DEBUG(3,("no domain specified with username (%s) - "
2131 state->request->data.chng_pswd_auth_crap.user));
2132 result = NT_STATUS_NO_SUCH_USER;
2137 if (!*domain && lp_winbind_use_default_domain()) {
2138 fstrcpy(domain,lp_workgroup());
2142 fstrcpy(user, state->request->data.chng_pswd_auth_crap.user);
2145 DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n",
2146 (unsigned long)state->pid, domain, user));
2148 /* Change password */
2149 new_nt_password = data_blob_const(
2150 state->request->data.chng_pswd_auth_crap.new_nt_pswd,
2151 state->request->data.chng_pswd_auth_crap.new_nt_pswd_len);
2153 old_nt_hash_enc = data_blob_const(
2154 state->request->data.chng_pswd_auth_crap.old_nt_hash_enc,
2155 state->request->data.chng_pswd_auth_crap.old_nt_hash_enc_len);
2157 if(state->request->data.chng_pswd_auth_crap.new_lm_pswd_len > 0) {
2158 new_lm_password = data_blob_const(
2159 state->request->data.chng_pswd_auth_crap.new_lm_pswd,
2160 state->request->data.chng_pswd_auth_crap.new_lm_pswd_len);
2162 old_lm_hash_enc = data_blob_const(
2163 state->request->data.chng_pswd_auth_crap.old_lm_hash_enc,
2164 state->request->data.chng_pswd_auth_crap.old_lm_hash_enc_len);
2166 new_lm_password.length = 0;
2167 old_lm_hash_enc.length = 0;
2170 /* Get sam handle */
2172 result = cm_connect_sam(contact_domain, state->mem_ctx, &cli, &dom_pol);
2173 if (!NT_STATUS_IS_OK(result)) {
2174 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
2178 b = cli->binding_handle;
2180 result = rpccli_samr_chng_pswd_auth_crap(
2181 cli, state->mem_ctx, user, new_nt_password, old_nt_hash_enc,
2182 new_lm_password, old_lm_hash_enc);
2186 if (strequal(contact_domain->name, get_global_sam_name())) {
2187 /* FIXME: internal rpc pipe does not cache handles yet */
2189 if (is_valid_policy_hnd(&dom_pol)) {
2191 dcerpc_samr_Close(b, state->mem_ctx, &dom_pol, &_result);
2197 set_auth_errors(state->response, result);
2199 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
2200 ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
2202 state->response->data.auth.nt_status_string,
2203 state->response->data.auth.pam_error));
2205 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;