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"
38 #define DBGC_CLASS DBGC_WINBIND
40 #define LOGON_KRB5_FAIL_CLOCK_SKEW 0x02000000
42 static NTSTATUS append_info3_as_txt(TALLOC_CTX *mem_ctx,
43 struct winbindd_cli_state *state,
44 struct netr_SamInfo3 *info3)
49 state->response->data.auth.info3.logon_time =
50 nt_time_to_unix(info3->base.last_logon);
51 state->response->data.auth.info3.logoff_time =
52 nt_time_to_unix(info3->base.last_logoff);
53 state->response->data.auth.info3.kickoff_time =
54 nt_time_to_unix(info3->base.acct_expiry);
55 state->response->data.auth.info3.pass_last_set_time =
56 nt_time_to_unix(info3->base.last_password_change);
57 state->response->data.auth.info3.pass_can_change_time =
58 nt_time_to_unix(info3->base.allow_password_change);
59 state->response->data.auth.info3.pass_must_change_time =
60 nt_time_to_unix(info3->base.force_password_change);
62 state->response->data.auth.info3.logon_count = info3->base.logon_count;
63 state->response->data.auth.info3.bad_pw_count = info3->base.bad_password_count;
65 state->response->data.auth.info3.user_rid = info3->base.rid;
66 state->response->data.auth.info3.group_rid = info3->base.primary_gid;
67 sid_to_fstring(state->response->data.auth.info3.dom_sid, info3->base.domain_sid);
69 state->response->data.auth.info3.num_groups = info3->base.groups.count;
70 state->response->data.auth.info3.user_flgs = info3->base.user_flags;
72 state->response->data.auth.info3.acct_flags = info3->base.acct_flags;
73 state->response->data.auth.info3.num_other_sids = info3->sidcount;
75 fstrcpy(state->response->data.auth.info3.user_name,
76 info3->base.account_name.string);
77 fstrcpy(state->response->data.auth.info3.full_name,
78 info3->base.full_name.string);
79 fstrcpy(state->response->data.auth.info3.logon_script,
80 info3->base.logon_script.string);
81 fstrcpy(state->response->data.auth.info3.profile_path,
82 info3->base.profile_path.string);
83 fstrcpy(state->response->data.auth.info3.home_dir,
84 info3->base.home_directory.string);
85 fstrcpy(state->response->data.auth.info3.dir_drive,
86 info3->base.home_drive.string);
88 fstrcpy(state->response->data.auth.info3.logon_srv,
89 info3->base.logon_server.string);
90 fstrcpy(state->response->data.auth.info3.logon_dom,
91 info3->base.domain.string);
93 ex = talloc_strdup(state->mem_ctx, "");
94 NT_STATUS_HAVE_NO_MEMORY(ex);
96 for (i=0; i < info3->base.groups.count; i++) {
97 ex = talloc_asprintf_append_buffer(ex, "0x%08X:0x%08X\n",
98 info3->base.groups.rids[i].rid,
99 info3->base.groups.rids[i].attributes);
100 NT_STATUS_HAVE_NO_MEMORY(ex);
103 for (i=0; i < info3->sidcount; i++) {
106 sid = dom_sid_string(mem_ctx, info3->sids[i].sid);
107 NT_STATUS_HAVE_NO_MEMORY(sid);
109 ex = talloc_asprintf_append_buffer(ex, "%s:0x%08X\n",
111 info3->sids[i].attributes);
112 NT_STATUS_HAVE_NO_MEMORY(ex);
117 state->response->extra_data.data = ex;
118 state->response->length += talloc_get_size(ex);
123 static NTSTATUS append_info3_as_ndr(TALLOC_CTX *mem_ctx,
124 struct winbindd_cli_state *state,
125 struct netr_SamInfo3 *info3)
128 enum ndr_err_code ndr_err;
130 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, info3,
131 (ndr_push_flags_fn_t)ndr_push_netr_SamInfo3);
132 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
133 DEBUG(0,("append_info3_as_ndr: failed to append\n"));
134 return ndr_map_error2ntstatus(ndr_err);
137 state->response->extra_data.data = blob.data;
138 state->response->length += blob.length;
143 static NTSTATUS append_unix_username(TALLOC_CTX *mem_ctx,
144 struct winbindd_cli_state *state,
145 const struct netr_SamInfo3 *info3,
146 const char *name_domain,
147 const char *name_user)
149 /* We've been asked to return the unix username, per
150 'winbind use default domain' settings and the like */
152 const char *nt_username, *nt_domain;
154 nt_domain = talloc_strdup(mem_ctx, info3->base.domain.string);
156 /* If the server didn't give us one, just use the one
158 nt_domain = name_domain;
161 nt_username = talloc_strdup(mem_ctx, info3->base.account_name.string);
163 /* If the server didn't give us one, just use the one
165 nt_username = name_user;
168 fill_domain_username(state->response->data.auth.unix_username,
169 nt_domain, nt_username, true);
171 DEBUG(5,("Setting unix username to [%s]\n",
172 state->response->data.auth.unix_username));
177 static NTSTATUS append_afs_token(TALLOC_CTX *mem_ctx,
178 struct winbindd_cli_state *state,
179 const struct netr_SamInfo3 *info3,
180 const char *name_domain,
181 const char *name_user)
183 char *afsname = NULL;
187 afsname = talloc_strdup(mem_ctx, lp_afs_username_map());
188 if (afsname == NULL) {
189 return NT_STATUS_NO_MEMORY;
192 afsname = talloc_string_sub(mem_ctx,
193 lp_afs_username_map(),
195 afsname = talloc_string_sub(mem_ctx, afsname,
197 afsname = talloc_string_sub(mem_ctx, afsname,
201 struct dom_sid user_sid;
204 sid_compose(&user_sid, info3->base.domain_sid,
206 sid_to_fstring(sidstr, &user_sid);
207 afsname = talloc_string_sub(mem_ctx, afsname,
211 if (afsname == NULL) {
212 return NT_STATUS_NO_MEMORY;
217 DEBUG(10, ("Generating token for user %s\n", afsname));
219 cell = strchr(afsname, '@');
222 return NT_STATUS_NO_MEMORY;
228 token = afs_createtoken_str(afsname, cell);
232 state->response->extra_data.data = talloc_strdup(state->mem_ctx,
234 if (state->response->extra_data.data == NULL) {
235 return NT_STATUS_NO_MEMORY;
237 state->response->length +=
238 strlen((const char *)state->response->extra_data.data)+1;
243 static NTSTATUS check_info3_in_group(struct netr_SamInfo3 *info3,
244 const char *group_sid)
246 * Check whether a user belongs to a group or list of groups.
248 * @param mem_ctx talloc memory context.
249 * @param info3 user information, including group membership info.
250 * @param group_sid One or more groups , separated by commas.
252 * @return NT_STATUS_OK on success,
253 * NT_STATUS_LOGON_FAILURE if the user does not belong,
254 * or other NT_STATUS_IS_ERR(status) for other kinds of failure.
257 struct dom_sid *require_membership_of_sid;
258 size_t num_require_membership_of_sid;
263 struct nt_user_token *token;
264 TALLOC_CTX *frame = talloc_stackframe();
267 /* Parse the 'required group' SID */
269 if (!group_sid || !group_sid[0]) {
270 /* NO sid supplied, all users may access */
274 token = talloc_zero(talloc_tos(), struct nt_user_token);
276 DEBUG(0, ("talloc failed\n"));
278 return NT_STATUS_NO_MEMORY;
281 num_require_membership_of_sid = 0;
282 require_membership_of_sid = NULL;
286 while (next_token_talloc(talloc_tos(), &p, &req_sid, ",")) {
287 if (!string_to_sid(&sid, req_sid)) {
288 DEBUG(0, ("check_info3_in_group: could not parse %s "
289 "as a SID!", req_sid));
291 return NT_STATUS_INVALID_PARAMETER;
294 status = add_sid_to_array(talloc_tos(), &sid,
295 &require_membership_of_sid,
296 &num_require_membership_of_sid);
297 if (!NT_STATUS_IS_OK(status)) {
298 DEBUG(0, ("add_sid_to_array failed\n"));
304 status = sid_array_from_info3(talloc_tos(), info3,
308 if (!NT_STATUS_IS_OK(status)) {
313 if (!NT_STATUS_IS_OK(status = add_aliases(get_global_sam_sid(),
315 || !NT_STATUS_IS_OK(status = add_aliases(&global_sid_Builtin,
317 DEBUG(3, ("could not add aliases: %s\n",
323 debug_nt_user_token(DBGC_CLASS, 10, token);
325 for (i=0; i<num_require_membership_of_sid; i++) {
326 DEBUG(10, ("Checking SID %s\n", sid_string_dbg(
327 &require_membership_of_sid[i])));
328 if (nt_token_check_sid(&require_membership_of_sid[i],
330 DEBUG(10, ("Access ok\n"));
336 /* Do not distinguish this error from a wrong username/pw */
339 return NT_STATUS_LOGON_FAILURE;
342 struct winbindd_domain *find_auth_domain(uint8_t flags,
343 const char *domain_name)
345 struct winbindd_domain *domain;
348 domain = find_domain_from_name_noinit(domain_name);
349 if (domain == NULL) {
350 DEBUG(3, ("Authentication for domain [%s] refused "
351 "as it is not a trusted domain\n",
357 if (strequal(domain_name, get_global_sam_name())) {
358 return find_domain_from_name_noinit(domain_name);
361 /* we can auth against trusted domains */
362 if (flags & WBFLAG_PAM_CONTACT_TRUSTDOM) {
363 domain = find_domain_from_name_noinit(domain_name);
364 if (domain == NULL) {
365 DEBUG(3, ("Authentication for domain [%s] skipped "
366 "as it is not a trusted domain\n",
373 return find_our_domain();
376 static void fill_in_password_policy(struct winbindd_response *r,
377 const struct samr_DomInfo1 *p)
379 r->data.auth.policy.min_length_password =
380 p->min_password_length;
381 r->data.auth.policy.password_history =
382 p->password_history_length;
383 r->data.auth.policy.password_properties =
384 p->password_properties;
385 r->data.auth.policy.expire =
386 nt_time_to_unix_abs((NTTIME *)&(p->max_password_age));
387 r->data.auth.policy.min_passwordage =
388 nt_time_to_unix_abs((NTTIME *)&(p->min_password_age));
391 static NTSTATUS fillup_password_policy(struct winbindd_domain *domain,
392 struct winbindd_cli_state *state)
394 struct winbindd_methods *methods;
395 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
396 struct samr_DomInfo1 password_policy;
398 if ( !winbindd_can_contact_domain( domain ) ) {
399 DEBUG(5,("fillup_password_policy: No inbound trust to "
400 "contact domain %s\n", domain->name));
401 return NT_STATUS_NOT_SUPPORTED;
404 methods = domain->methods;
406 status = methods->password_policy(domain, state->mem_ctx, &password_policy);
407 if (NT_STATUS_IS_ERR(status)) {
411 fill_in_password_policy(state->response, &password_policy);
416 static NTSTATUS get_max_bad_attempts_from_lockout_policy(struct winbindd_domain *domain,
418 uint16 *lockout_threshold)
420 struct winbindd_methods *methods;
421 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
422 struct samr_DomInfo12 lockout_policy;
424 *lockout_threshold = 0;
426 methods = domain->methods;
428 status = methods->lockout_policy(domain, mem_ctx, &lockout_policy);
429 if (NT_STATUS_IS_ERR(status)) {
433 *lockout_threshold = lockout_policy.lockout_threshold;
438 static NTSTATUS get_pwd_properties(struct winbindd_domain *domain,
440 uint32 *password_properties)
442 struct winbindd_methods *methods;
443 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
444 struct samr_DomInfo1 password_policy;
446 *password_properties = 0;
448 methods = domain->methods;
450 status = methods->password_policy(domain, mem_ctx, &password_policy);
451 if (NT_STATUS_IS_ERR(status)) {
455 *password_properties = password_policy.password_properties;
462 static const char *generate_krb5_ccache(TALLOC_CTX *mem_ctx,
465 bool *internal_ccache)
467 /* accept FILE and WRFILE as krb5_cc_type from the client and then
468 * build the full ccname string based on the user's uid here -
471 const char *gen_cc = NULL;
473 *internal_ccache = true;
479 if (!type || type[0] == '\0') {
483 if (strequal(type, "FILE")) {
484 gen_cc = talloc_asprintf(mem_ctx, "FILE:/tmp/krb5cc_%d", uid);
485 } else if (strequal(type, "WRFILE")) {
486 gen_cc = talloc_asprintf(mem_ctx, "WRFILE:/tmp/krb5cc_%d", uid);
488 DEBUG(10,("we don't allow to set a %s type ccache\n", type));
492 *internal_ccache = false;
496 gen_cc = talloc_strdup(mem_ctx, "MEMORY:winbindd_pam_ccache");
499 if (gen_cc == NULL) {
500 DEBUG(0,("out of memory\n"));
504 DEBUG(10,("using ccache: %s %s\n", gen_cc, *internal_ccache ? "(internal)":""));
509 static void setup_return_cc_name(struct winbindd_cli_state *state, const char *cc)
511 const char *type = state->request->data.auth.krb5_cc_type;
513 state->response->data.auth.krb5ccname[0] = '\0';
515 if (type[0] == '\0') {
519 if (!strequal(type, "FILE") &&
520 !strequal(type, "WRFILE")) {
521 DEBUG(10,("won't return krbccname for a %s type ccache\n",
526 fstrcpy(state->response->data.auth.krb5ccname, cc);
531 uid_t get_uid_from_request(struct winbindd_request *request)
535 uid = request->data.auth.uid;
538 DEBUG(1,("invalid uid: '%u'\n", (unsigned int)uid));
544 static uid_t get_uid_from_state(struct winbindd_cli_state *state)
546 return get_uid_from_request(state->request);
549 /**********************************************************************
550 Authenticate a user with a clear text password using Kerberos and fill up
552 **********************************************************************/
554 static NTSTATUS winbindd_raw_kerberos_login(struct winbindd_domain *domain,
555 struct winbindd_cli_state *state,
556 struct netr_SamInfo3 **info3)
559 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
560 krb5_error_code krb5_ret;
561 const char *cc = NULL;
562 const char *principal_s = NULL;
563 const char *service = NULL;
565 fstring name_domain, name_user;
566 time_t ticket_lifetime = 0;
567 time_t renewal_until = 0;
570 time_t time_offset = 0;
571 bool internal_ccache = true;
572 struct PAC_LOGON_INFO *logon_info = NULL;
577 * prepare a krb5_cc_cache string for the user */
579 uid = get_uid_from_state(state);
581 DEBUG(0,("no valid uid\n"));
584 cc = generate_krb5_ccache(state->mem_ctx,
585 state->request->data.auth.krb5_cc_type,
586 state->request->data.auth.uid,
589 return NT_STATUS_NO_MEMORY;
594 * get kerberos properties */
596 if (domain->private_data) {
597 ads = (ADS_STRUCT *)domain->private_data;
598 time_offset = ads->auth.time_offset;
603 * do kerberos auth and setup ccache as the user */
605 parse_domain_user(state->request->data.auth.user, name_domain, name_user);
607 realm = domain->alt_name;
610 principal_s = talloc_asprintf(state->mem_ctx, "%s@%s", name_user, realm);
611 if (principal_s == NULL) {
612 return NT_STATUS_NO_MEMORY;
615 service = talloc_asprintf(state->mem_ctx, "%s/%s@%s", KRB5_TGS_NAME, realm, realm);
616 if (service == NULL) {
617 return NT_STATUS_NO_MEMORY;
620 /* if this is a user ccache, we need to act as the user to let the krb5
621 * library handle the chown, etc. */
623 /************************ ENTERING NON-ROOT **********************/
625 if (!internal_ccache) {
626 set_effective_uid(uid);
627 DEBUG(10,("winbindd_raw_kerberos_login: uid is %d\n", uid));
630 result = kerberos_return_pac(state->mem_ctx,
632 state->request->data.auth.pass,
639 WINBINDD_PAM_AUTH_KRB5_RENEW_TIME,
642 if (!internal_ccache) {
643 gain_root_privilege();
646 /************************ RETURNED TO ROOT **********************/
648 if (!NT_STATUS_IS_OK(result)) {
652 *info3 = &logon_info->info3;
654 DEBUG(10,("winbindd_raw_kerberos_login: winbindd validated ticket of %s\n",
657 /* if we had a user's ccache then return that string for the pam
660 if (!internal_ccache) {
662 setup_return_cc_name(state, cc);
664 result = add_ccache_to_list(principal_s,
667 state->request->data.auth.user,
675 if (!NT_STATUS_IS_OK(result)) {
676 DEBUG(10,("winbindd_raw_kerberos_login: failed to add ccache to list: %s\n",
681 /* need to delete the memory cred cache, it is not used anymore */
683 krb5_ret = ads_kdestroy(cc);
685 DEBUG(3,("winbindd_raw_kerberos_login: "
686 "could not destroy krb5 credential cache: "
687 "%s\n", error_message(krb5_ret)));
696 /* we could have created a new credential cache with a valid tgt in it
697 * but we werent able to get or verify the service ticket for this
698 * local host and therefor didn't get the PAC, we need to remove that
699 * cache entirely now */
701 krb5_ret = ads_kdestroy(cc);
703 DEBUG(3,("winbindd_raw_kerberos_login: "
704 "could not destroy krb5 credential cache: "
705 "%s\n", error_message(krb5_ret)));
708 if (!NT_STATUS_IS_OK(remove_ccache(state->request->data.auth.user))) {
709 DEBUG(3,("winbindd_raw_kerberos_login: "
710 "could not remove ccache for user %s\n",
711 state->request->data.auth.user));
716 return NT_STATUS_NOT_SUPPORTED;
717 #endif /* HAVE_KRB5 */
720 /****************************************************************
721 ****************************************************************/
723 bool check_request_flags(uint32_t flags)
725 uint32_t flags_edata = WBFLAG_PAM_AFS_TOKEN |
726 WBFLAG_PAM_INFO3_TEXT |
727 WBFLAG_PAM_INFO3_NDR;
729 if ( ( (flags & flags_edata) == WBFLAG_PAM_AFS_TOKEN) ||
730 ( (flags & flags_edata) == WBFLAG_PAM_INFO3_NDR) ||
731 ( (flags & flags_edata) == WBFLAG_PAM_INFO3_TEXT)||
732 !(flags & flags_edata) ) {
736 DEBUG(1, ("check_request_flags: invalid request flags[0x%08X]\n",
742 /****************************************************************
743 ****************************************************************/
745 static NTSTATUS append_auth_data(struct winbindd_cli_state *state,
746 struct netr_SamInfo3 *info3,
747 const char *name_domain,
748 const char *name_user)
751 uint32_t flags = state->request->flags;
753 if (flags & WBFLAG_PAM_USER_SESSION_KEY) {
754 memcpy(state->response->data.auth.user_session_key,
756 sizeof(state->response->data.auth.user_session_key)
760 if (flags & WBFLAG_PAM_LMKEY) {
761 memcpy(state->response->data.auth.first_8_lm_hash,
762 info3->base.LMSessKey.key,
763 sizeof(state->response->data.auth.first_8_lm_hash)
767 if (flags & WBFLAG_PAM_UNIX_NAME) {
768 result = append_unix_username(state->mem_ctx, state, info3,
769 name_domain, name_user);
770 if (!NT_STATUS_IS_OK(result)) {
771 DEBUG(10,("Failed to append Unix Username: %s\n",
777 /* currently, anything from here on potentially overwrites extra_data. */
779 if (flags & WBFLAG_PAM_INFO3_NDR) {
780 result = append_info3_as_ndr(state->mem_ctx, state, info3);
781 if (!NT_STATUS_IS_OK(result)) {
782 DEBUG(10,("Failed to append INFO3 (NDR): %s\n",
788 if (flags & WBFLAG_PAM_INFO3_TEXT) {
789 result = append_info3_as_txt(state->mem_ctx, state, info3);
790 if (!NT_STATUS_IS_OK(result)) {
791 DEBUG(10,("Failed to append INFO3 (TXT): %s\n",
797 if (flags & WBFLAG_PAM_AFS_TOKEN) {
798 result = append_afs_token(state->mem_ctx, state, info3,
799 name_domain, name_user);
800 if (!NT_STATUS_IS_OK(result)) {
801 DEBUG(10,("Failed to append AFS token: %s\n",
810 static NTSTATUS winbindd_dual_pam_auth_cached(struct winbindd_domain *domain,
811 struct winbindd_cli_state *state,
812 struct netr_SamInfo3 **info3)
814 NTSTATUS result = NT_STATUS_LOGON_FAILURE;
815 uint16 max_allowed_bad_attempts;
816 fstring name_domain, name_user;
818 enum lsa_SidType type;
819 uchar new_nt_pass[NT_HASH_LEN];
820 const uint8 *cached_nt_pass;
821 const uint8 *cached_salt;
822 struct netr_SamInfo3 *my_info3;
823 time_t kickoff_time, must_change_time;
824 bool password_good = false;
826 struct winbindd_tdc_domain *tdc_domain = NULL;
833 DEBUG(10,("winbindd_dual_pam_auth_cached\n"));
835 /* Parse domain and username */
837 parse_domain_user(state->request->data.auth.user, name_domain, name_user);
840 if (!lookup_cached_name(state->mem_ctx,
845 DEBUG(10,("winbindd_dual_pam_auth_cached: no such user in the cache\n"));
846 return NT_STATUS_NO_SUCH_USER;
849 if (type != SID_NAME_USER) {
850 DEBUG(10,("winbindd_dual_pam_auth_cached: not a user (%s)\n", sid_type_lookup(type)));
851 return NT_STATUS_LOGON_FAILURE;
854 result = winbindd_get_creds(domain,
860 if (!NT_STATUS_IS_OK(result)) {
861 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get creds: %s\n", nt_errstr(result)));
867 E_md4hash(state->request->data.auth.pass, new_nt_pass);
869 dump_data_pw("new_nt_pass", new_nt_pass, NT_HASH_LEN);
870 dump_data_pw("cached_nt_pass", cached_nt_pass, NT_HASH_LEN);
872 dump_data_pw("cached_salt", cached_salt, NT_HASH_LEN);
876 /* In this case we didn't store the nt_hash itself,
877 but the MD5 combination of salt + nt_hash. */
878 uchar salted_hash[NT_HASH_LEN];
879 E_md5hash(cached_salt, new_nt_pass, salted_hash);
881 password_good = (memcmp(cached_nt_pass, salted_hash,
884 /* Old cached cred - direct store of nt_hash (bad bad bad !). */
885 password_good = (memcmp(cached_nt_pass, new_nt_pass,
891 /* User *DOES* know the password, update logon_time and reset
894 my_info3->base.user_flags |= NETLOGON_CACHED_ACCOUNT;
896 if (my_info3->base.acct_flags & ACB_AUTOLOCK) {
897 return NT_STATUS_ACCOUNT_LOCKED_OUT;
900 if (my_info3->base.acct_flags & ACB_DISABLED) {
901 return NT_STATUS_ACCOUNT_DISABLED;
904 if (my_info3->base.acct_flags & ACB_WSTRUST) {
905 return NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
908 if (my_info3->base.acct_flags & ACB_SVRTRUST) {
909 return NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT;
912 if (my_info3->base.acct_flags & ACB_DOMTRUST) {
913 return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT;
916 if (!(my_info3->base.acct_flags & ACB_NORMAL)) {
917 DEBUG(0,("winbindd_dual_pam_auth_cached: whats wrong with that one?: 0x%08x\n",
918 my_info3->base.acct_flags));
919 return NT_STATUS_LOGON_FAILURE;
922 kickoff_time = nt_time_to_unix(my_info3->base.acct_expiry);
923 if (kickoff_time != 0 && time(NULL) > kickoff_time) {
924 return NT_STATUS_ACCOUNT_EXPIRED;
927 must_change_time = nt_time_to_unix(my_info3->base.force_password_change);
928 if (must_change_time != 0 && must_change_time < time(NULL)) {
929 /* we allow grace logons when the password has expired */
930 my_info3->base.user_flags |= NETLOGON_GRACE_LOGON;
931 /* return NT_STATUS_PASSWORD_EXPIRED; */
936 if ((state->request->flags & WBFLAG_PAM_KRB5) &&
937 ((tdc_domain = wcache_tdc_fetch_domain(state->mem_ctx, name_domain)) != NULL) &&
938 ((tdc_domain->trust_type & NETR_TRUST_TYPE_UPLEVEL) ||
939 /* used to cope with the case winbindd starting without network. */
940 !strequal(tdc_domain->domain_name, tdc_domain->dns_name))) {
943 const char *cc = NULL;
945 const char *principal_s = NULL;
946 const char *service = NULL;
947 bool internal_ccache = false;
949 uid = get_uid_from_state(state);
951 DEBUG(0,("winbindd_dual_pam_auth_cached: invalid uid\n"));
952 return NT_STATUS_INVALID_PARAMETER;
955 cc = generate_krb5_ccache(state->mem_ctx,
956 state->request->data.auth.krb5_cc_type,
957 state->request->data.auth.uid,
960 return NT_STATUS_NO_MEMORY;
963 realm = domain->alt_name;
966 principal_s = talloc_asprintf(state->mem_ctx, "%s@%s", name_user, realm);
967 if (principal_s == NULL) {
968 return NT_STATUS_NO_MEMORY;
971 service = talloc_asprintf(state->mem_ctx, "%s/%s@%s", KRB5_TGS_NAME, realm, realm);
972 if (service == NULL) {
973 return NT_STATUS_NO_MEMORY;
976 if (!internal_ccache) {
978 setup_return_cc_name(state, cc);
980 result = add_ccache_to_list(principal_s,
983 state->request->data.auth.user,
987 time(NULL) + lp_winbind_cache_time(),
988 time(NULL) + WINBINDD_PAM_AUTH_KRB5_RENEW_TIME,
991 if (!NT_STATUS_IS_OK(result)) {
992 DEBUG(10,("winbindd_dual_pam_auth_cached: failed "
993 "to add ccache to list: %s\n",
998 #endif /* HAVE_KRB5 */
1000 /* FIXME: we possibly should handle logon hours as well (does xp when
1001 * offline?) see auth/auth_sam.c:sam_account_ok for details */
1003 unix_to_nt_time(&my_info3->base.last_logon, time(NULL));
1004 my_info3->base.bad_password_count = 0;
1006 result = winbindd_update_creds_by_info3(domain,
1008 state->request->data.auth.user,
1009 state->request->data.auth.pass,
1011 if (!NT_STATUS_IS_OK(result)) {
1012 DEBUG(1,("winbindd_dual_pam_auth_cached: failed to update creds: %s\n",
1013 nt_errstr(result)));
1017 return NT_STATUS_OK;
1021 /* User does *NOT* know the correct password, modify info3 accordingly */
1023 /* failure of this is not critical */
1024 result = get_max_bad_attempts_from_lockout_policy(domain, state->mem_ctx, &max_allowed_bad_attempts);
1025 if (!NT_STATUS_IS_OK(result)) {
1026 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get max_allowed_bad_attempts. "
1027 "Won't be able to honour account lockout policies\n"));
1030 /* increase counter */
1031 my_info3->base.bad_password_count++;
1033 if (max_allowed_bad_attempts == 0) {
1038 if (my_info3->base.bad_password_count >= max_allowed_bad_attempts) {
1040 uint32 password_properties;
1042 result = get_pwd_properties(domain, state->mem_ctx, &password_properties);
1043 if (!NT_STATUS_IS_OK(result)) {
1044 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get password properties.\n"));
1047 if ((my_info3->base.rid != DOMAIN_RID_ADMINISTRATOR) ||
1048 (password_properties & DOMAIN_PASSWORD_LOCKOUT_ADMINS)) {
1049 my_info3->base.acct_flags |= ACB_AUTOLOCK;
1054 result = winbindd_update_creds_by_info3(domain,
1056 state->request->data.auth.user,
1060 if (!NT_STATUS_IS_OK(result)) {
1061 DEBUG(0,("winbindd_dual_pam_auth_cached: failed to update creds %s\n",
1062 nt_errstr(result)));
1065 return NT_STATUS_LOGON_FAILURE;
1068 static NTSTATUS winbindd_dual_pam_auth_kerberos(struct winbindd_domain *domain,
1069 struct winbindd_cli_state *state,
1070 struct netr_SamInfo3 **info3)
1072 struct winbindd_domain *contact_domain;
1073 fstring name_domain, name_user;
1076 DEBUG(10,("winbindd_dual_pam_auth_kerberos\n"));
1078 /* Parse domain and username */
1080 parse_domain_user(state->request->data.auth.user, name_domain, name_user);
1082 /* what domain should we contact? */
1085 if (!(contact_domain = find_domain_from_name(name_domain))) {
1086 DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
1087 state->request->data.auth.user, name_domain, name_user, name_domain));
1088 result = NT_STATUS_NO_SUCH_USER;
1093 if (is_myname(name_domain)) {
1094 DEBUG(3, ("Authentication for domain %s (local domain to this server) not supported at this stage\n", name_domain));
1095 result = NT_STATUS_NO_SUCH_USER;
1099 contact_domain = find_domain_from_name(name_domain);
1100 if (contact_domain == NULL) {
1101 DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
1102 state->request->data.auth.user, name_domain, name_user, name_domain));
1104 contact_domain = find_our_domain();
1108 if (contact_domain->initialized &&
1109 contact_domain->active_directory) {
1113 if (!contact_domain->initialized) {
1114 init_dc_connection(contact_domain);
1117 if (!contact_domain->active_directory) {
1118 DEBUG(3,("krb5 auth requested but domain is not Active Directory\n"));
1119 return NT_STATUS_INVALID_LOGON_TYPE;
1122 result = winbindd_raw_kerberos_login(contact_domain, state, info3);
1127 static NTSTATUS winbindd_dual_auth_passdb(TALLOC_CTX *mem_ctx,
1128 const char *domain, const char *user,
1129 const DATA_BLOB *challenge,
1130 const DATA_BLOB *lm_resp,
1131 const DATA_BLOB *nt_resp,
1132 struct netr_SamInfo3 **pinfo3)
1134 struct auth_usersupplied_info *user_info = NULL;
1135 struct auth_serversupplied_info *server_info = NULL;
1136 struct netr_SamInfo3 *info3;
1139 status = make_user_info(&user_info, user, user, domain, domain,
1140 global_myname(), lm_resp, nt_resp, NULL, NULL,
1142 if (!NT_STATUS_IS_OK(status)) {
1143 DEBUG(10, ("make_user_info failed: %s\n", nt_errstr(status)));
1147 status = check_sam_security(challenge, talloc_tos(), user_info,
1149 free_user_info(&user_info);
1151 if (!NT_STATUS_IS_OK(status)) {
1152 DEBUG(10, ("check_ntlm_password failed: %s\n",
1153 nt_errstr(status)));
1157 info3 = TALLOC_ZERO_P(mem_ctx, struct netr_SamInfo3);
1158 if (info3 == NULL) {
1159 return NT_STATUS_NO_MEMORY;
1162 status = serverinfo_to_SamInfo3(server_info, NULL, 0, info3);
1163 if (!NT_STATUS_IS_OK(status)) {
1164 DEBUG(10, ("serverinfo_to_SamInfo3 failed: %s\n",
1165 nt_errstr(status)));
1169 DEBUG(10, ("Authenticated user %s\\%s successfully\n", domain, user));
1171 return NT_STATUS_OK;
1174 typedef NTSTATUS (*netlogon_fn_t)(struct rpc_pipe_client *cli,
1175 TALLOC_CTX *mem_ctx,
1176 uint32 logon_parameters,
1178 const char *username,
1180 const char *workstation,
1181 const uint8 chal[8],
1182 DATA_BLOB lm_response,
1183 DATA_BLOB nt_response,
1184 struct netr_SamInfo3 **info3);
1186 static NTSTATUS winbindd_dual_pam_auth_samlogon(struct winbindd_domain *domain,
1187 struct winbindd_cli_state *state,
1188 struct netr_SamInfo3 **info3)
1191 struct rpc_pipe_client *netlogon_pipe;
1196 unsigned char local_lm_response[24];
1197 unsigned char local_nt_response[24];
1198 fstring name_domain, name_user;
1201 struct netr_SamInfo3 *my_info3 = NULL;
1205 DEBUG(10,("winbindd_dual_pam_auth_samlogon\n"));
1207 /* Parse domain and username */
1209 parse_domain_user(state->request->data.auth.user, name_domain, name_user);
1211 /* do password magic */
1213 generate_random_buffer(chal, sizeof(chal));
1215 if (lp_client_ntlmv2_auth()) {
1216 DATA_BLOB server_chal;
1217 DATA_BLOB names_blob;
1218 DATA_BLOB nt_response;
1219 DATA_BLOB lm_response;
1220 server_chal = data_blob_talloc(state->mem_ctx, chal, 8);
1222 /* note that the 'workgroup' here is a best guess - we don't know
1223 the server's domain at this point. The 'server name' is also
1226 names_blob = NTLMv2_generate_names_blob(state->mem_ctx, global_myname(), lp_workgroup());
1228 if (!SMBNTLMv2encrypt(NULL, name_user, name_domain,
1229 state->request->data.auth.pass,
1232 &lm_response, &nt_response, NULL, NULL)) {
1233 data_blob_free(&names_blob);
1234 data_blob_free(&server_chal);
1235 DEBUG(0, ("winbindd_pam_auth: SMBNTLMv2encrypt() failed!\n"));
1236 result = NT_STATUS_NO_MEMORY;
1239 data_blob_free(&names_blob);
1240 data_blob_free(&server_chal);
1241 lm_resp = data_blob_talloc(state->mem_ctx, lm_response.data,
1242 lm_response.length);
1243 nt_resp = data_blob_talloc(state->mem_ctx, nt_response.data,
1244 nt_response.length);
1245 data_blob_free(&lm_response);
1246 data_blob_free(&nt_response);
1249 if (lp_client_lanman_auth()
1250 && SMBencrypt(state->request->data.auth.pass,
1252 local_lm_response)) {
1253 lm_resp = data_blob_talloc(state->mem_ctx,
1255 sizeof(local_lm_response));
1257 lm_resp = data_blob_null;
1259 SMBNTencrypt(state->request->data.auth.pass,
1263 nt_resp = data_blob_talloc(state->mem_ctx,
1265 sizeof(local_nt_response));
1268 if (strequal(name_domain, get_global_sam_name())) {
1269 DATA_BLOB chal_blob = data_blob_const(chal, sizeof(chal));
1271 result = winbindd_dual_auth_passdb(
1272 state->mem_ctx, name_domain, name_user,
1273 &chal_blob, &lm_resp, &nt_resp, info3);
1277 /* check authentication loop */
1280 netlogon_fn_t logon_fn;
1282 ZERO_STRUCTP(my_info3);
1285 result = cm_connect_netlogon(domain, &netlogon_pipe);
1287 if (!NT_STATUS_IS_OK(result)) {
1288 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
1292 /* It is really important to try SamLogonEx here,
1293 * because in a clustered environment, we want to use
1294 * one machine account from multiple physical
1297 * With a normal SamLogon call, we must keep the
1298 * credentials chain updated and intact between all
1299 * users of the machine account (which would imply
1300 * cross-node communication for every NTLM logon).
1302 * (The credentials chain is not per NETLOGON pipe
1303 * connection, but globally on the server/client pair
1306 * When using SamLogonEx, the credentials are not
1307 * supplied, but the session key is implied by the
1308 * wrapping SamLogon context.
1310 * -- abartlet 21 April 2008
1313 logon_fn = domain->can_do_samlogon_ex
1314 ? rpccli_netlogon_sam_network_logon_ex
1315 : rpccli_netlogon_sam_network_logon;
1317 result = logon_fn(netlogon_pipe,
1320 domain->dcname, /* server name */
1321 name_user, /* user name */
1322 name_domain, /* target domain */
1323 global_myname(), /* workstation */
1330 if ((NT_STATUS_V(result) == DCERPC_FAULT_OP_RNG_ERROR)
1331 && domain->can_do_samlogon_ex) {
1332 DEBUG(3, ("Got a DC that can not do NetSamLogonEx, "
1333 "retrying with NetSamLogon\n"));
1334 domain->can_do_samlogon_ex = false;
1339 /* We have to try a second time as cm_connect_netlogon
1340 might not yet have noticed that the DC has killed
1343 if (!rpccli_is_connected(netlogon_pipe)) {
1348 /* if we get access denied, a possible cause was that we had
1349 and open connection to the DC, but someone changed our
1350 machine account password out from underneath us using 'net
1351 rpc changetrustpw' */
1353 if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
1354 DEBUG(3,("winbindd_pam_auth: sam_logon returned "
1355 "ACCESS_DENIED. Maybe the trust account "
1356 "password was changed and we didn't know it. "
1357 "Killing connections to domain %s\n",
1359 invalidate_cm_connection(&domain->conn);
1363 } while ( (attempts < 2) && retry );
1365 /* handle the case where a NT4 DC does not fill in the acct_flags in
1366 * the samlogon reply info3. When accurate info3 is required by the
1367 * caller, we look up the account flags ourselve - gd */
1369 if ((state->request->flags & WBFLAG_PAM_INFO3_TEXT) &&
1370 NT_STATUS_IS_OK(result) && (my_info3->base.acct_flags == 0)) {
1372 struct rpc_pipe_client *samr_pipe;
1373 struct policy_handle samr_domain_handle, user_pol;
1374 union samr_UserInfo *info = NULL;
1375 NTSTATUS status_tmp;
1378 status_tmp = cm_connect_sam(domain, state->mem_ctx,
1379 &samr_pipe, &samr_domain_handle);
1381 if (!NT_STATUS_IS_OK(status_tmp)) {
1382 DEBUG(3, ("could not open handle to SAMR pipe: %s\n",
1383 nt_errstr(status_tmp)));
1387 status_tmp = rpccli_samr_OpenUser(samr_pipe, state->mem_ctx,
1388 &samr_domain_handle,
1389 MAXIMUM_ALLOWED_ACCESS,
1393 if (!NT_STATUS_IS_OK(status_tmp)) {
1394 DEBUG(3, ("could not open user handle on SAMR pipe: %s\n",
1395 nt_errstr(status_tmp)));
1399 status_tmp = rpccli_samr_QueryUserInfo(samr_pipe, state->mem_ctx,
1404 if (!NT_STATUS_IS_OK(status_tmp)) {
1405 DEBUG(3, ("could not query user info on SAMR pipe: %s\n",
1406 nt_errstr(status_tmp)));
1407 rpccli_samr_Close(samr_pipe, state->mem_ctx, &user_pol);
1411 acct_flags = info->info16.acct_flags;
1413 if (acct_flags == 0) {
1414 rpccli_samr_Close(samr_pipe, state->mem_ctx, &user_pol);
1418 my_info3->base.acct_flags = acct_flags;
1420 DEBUG(10,("successfully retrieved acct_flags 0x%x\n", acct_flags));
1422 rpccli_samr_Close(samr_pipe, state->mem_ctx, &user_pol);
1430 enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain,
1431 struct winbindd_cli_state *state)
1433 NTSTATUS result = NT_STATUS_LOGON_FAILURE;
1434 NTSTATUS krb5_result = NT_STATUS_OK;
1435 fstring name_domain, name_user;
1437 fstring domain_user;
1438 struct netr_SamInfo3 *info3 = NULL;
1439 NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL;
1441 /* Ensure null termination */
1442 state->request->data.auth.user[sizeof(state->request->data.auth.user)-1]='\0';
1444 /* Ensure null termination */
1445 state->request->data.auth.pass[sizeof(state->request->data.auth.pass)-1]='\0';
1447 DEBUG(3, ("[%5lu]: dual pam auth %s\n", (unsigned long)state->pid,
1448 state->request->data.auth.user));
1450 if (!check_request_flags(state->request->flags)) {
1451 result = NT_STATUS_INVALID_PARAMETER_MIX;
1455 /* Parse domain and username */
1457 name_map_status = normalize_name_unmap(state->mem_ctx,
1458 state->request->data.auth.user,
1461 /* If the name normalization didnt' actually do anything,
1462 just use the original name */
1464 if (!NT_STATUS_IS_OK(name_map_status) &&
1465 !NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED))
1467 mapped_user = state->request->data.auth.user;
1470 parse_domain_user(mapped_user, name_domain, name_user);
1472 if ( mapped_user != state->request->data.auth.user ) {
1473 fstr_sprintf( domain_user, "%s%c%s", name_domain,
1474 *lp_winbind_separator(),
1476 safe_strcpy( state->request->data.auth.user, domain_user,
1477 sizeof(state->request->data.auth.user)-1 );
1480 if (domain->online == false) {
1481 result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
1482 if (domain->startup) {
1483 /* Logons are very important to users. If we're offline and
1484 we get a request within the first 30 seconds of startup,
1485 try very hard to find a DC and go online. */
1487 DEBUG(10,("winbindd_dual_pam_auth: domain: %s offline and auth "
1488 "request in startup mode.\n", domain->name ));
1490 winbindd_flush_negative_conn_cache(domain);
1491 result = init_dc_connection(domain);
1495 DEBUG(10,("winbindd_dual_pam_auth: domain: %s last was %s\n", domain->name, domain->online ? "online":"offline"));
1497 /* Check for Kerberos authentication */
1498 if (domain->online && (state->request->flags & WBFLAG_PAM_KRB5)) {
1500 result = winbindd_dual_pam_auth_kerberos(domain, state, &info3);
1501 /* save for later */
1502 krb5_result = result;
1505 if (NT_STATUS_IS_OK(result)) {
1506 DEBUG(10,("winbindd_dual_pam_auth_kerberos succeeded\n"));
1507 goto process_result;
1509 DEBUG(10,("winbindd_dual_pam_auth_kerberos failed: %s\n", nt_errstr(result)));
1512 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
1513 NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
1514 NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1515 DEBUG(10,("winbindd_dual_pam_auth_kerberos setting domain to offline\n"));
1516 set_domain_offline( domain );
1520 /* there are quite some NT_STATUS errors where there is no
1521 * point in retrying with a samlogon, we explictly have to take
1522 * care not to increase the bad logon counter on the DC */
1524 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_DISABLED) ||
1525 NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_EXPIRED) ||
1526 NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_LOCKED_OUT) ||
1527 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_LOGON_HOURS) ||
1528 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_WORKSTATION) ||
1529 NT_STATUS_EQUAL(result, NT_STATUS_LOGON_FAILURE) ||
1530 NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER) ||
1531 NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_EXPIRED) ||
1532 NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_MUST_CHANGE) ||
1533 NT_STATUS_EQUAL(result, NT_STATUS_WRONG_PASSWORD)) {
1537 if (state->request->flags & WBFLAG_PAM_FALLBACK_AFTER_KRB5) {
1538 DEBUG(3,("falling back to samlogon\n"));
1546 /* Check for Samlogon authentication */
1547 if (domain->online) {
1548 result = winbindd_dual_pam_auth_samlogon(domain, state, &info3);
1550 if (NT_STATUS_IS_OK(result)) {
1551 DEBUG(10,("winbindd_dual_pam_auth_samlogon succeeded\n"));
1552 /* add the Krb5 err if we have one */
1553 if ( NT_STATUS_EQUAL(krb5_result, NT_STATUS_TIME_DIFFERENCE_AT_DC ) ) {
1554 info3->base.user_flags |= LOGON_KRB5_FAIL_CLOCK_SKEW;
1556 goto process_result;
1559 DEBUG(10,("winbindd_dual_pam_auth_samlogon failed: %s\n",
1560 nt_errstr(result)));
1562 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
1563 NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
1564 NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND))
1566 DEBUG(10,("winbindd_dual_pam_auth_samlogon setting domain to offline\n"));
1567 set_domain_offline( domain );
1571 if (domain->online) {
1572 /* We're still online - fail. */
1578 /* Check for Cached logons */
1579 if (!domain->online && (state->request->flags & WBFLAG_PAM_CACHED_LOGIN) &&
1580 lp_winbind_offline_logon()) {
1582 result = winbindd_dual_pam_auth_cached(domain, state, &info3);
1584 if (NT_STATUS_IS_OK(result)) {
1585 DEBUG(10,("winbindd_dual_pam_auth_cached succeeded\n"));
1586 goto process_result;
1588 DEBUG(10,("winbindd_dual_pam_auth_cached failed: %s\n", nt_errstr(result)));
1595 if (NT_STATUS_IS_OK(result)) {
1597 struct dom_sid user_sid;
1599 /* In all codepaths where result == NT_STATUS_OK info3 must have
1600 been initialized. */
1602 result = NT_STATUS_INTERNAL_ERROR;
1606 wcache_invalidate_samlogon(find_domain_from_name(name_domain), info3);
1607 netsamlogon_cache_store(name_user, info3);
1609 /* save name_to_sid info as early as possible (only if
1610 this is our primary domain so we don't invalidate
1611 the cache entry by storing the seq_num for the wrong
1613 if ( domain->primary ) {
1614 sid_compose(&user_sid, info3->base.domain_sid,
1616 cache_name2sid(domain, name_domain, name_user,
1617 SID_NAME_USER, &user_sid);
1620 /* Check if the user is in the right group */
1622 result = check_info3_in_group(
1624 state->request->data.auth.require_membership_of_sid);
1625 if (!NT_STATUS_IS_OK(result)) {
1626 DEBUG(3, ("User %s is not in the required group (%s), so plaintext authentication is rejected\n",
1627 state->request->data.auth.user,
1628 state->request->data.auth.require_membership_of_sid));
1632 result = append_auth_data(state, info3, name_domain,
1634 if (!NT_STATUS_IS_OK(result)) {
1638 if ((state->request->flags & WBFLAG_PAM_CACHED_LOGIN)) {
1640 if (lp_winbind_offline_logon()) {
1641 result = winbindd_store_creds(domain,
1643 state->request->data.auth.user,
1644 state->request->data.auth.pass,
1650 if (state->request->flags & WBFLAG_PAM_GET_PWD_POLICY) {
1651 struct winbindd_domain *our_domain = find_our_domain();
1653 /* This is not entirely correct I believe, but it is
1654 consistent. Only apply the password policy settings
1655 too warn users for our own domain. Cannot obtain these
1656 from trusted DCs all the time so don't do it at all.
1659 result = NT_STATUS_NOT_SUPPORTED;
1660 if (our_domain == domain ) {
1661 result = fillup_password_policy(our_domain, state);
1664 if (!NT_STATUS_IS_OK(result)
1665 && !NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED) )
1667 DEBUG(10,("Failed to get password policies for domain %s: %s\n",
1668 domain->name, nt_errstr(result)));
1673 result = NT_STATUS_OK;
1677 /* give us a more useful (more correct?) error code */
1678 if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
1679 (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
1680 result = NT_STATUS_NO_LOGON_SERVERS;
1683 set_auth_errors(state->response, result);
1685 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, ("Plain-text authentication for user %s returned %s (PAM: %d)\n",
1686 state->request->data.auth.user,
1687 state->response->data.auth.nt_status_string,
1688 state->response->data.auth.pam_error));
1690 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
1693 enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain,
1694 struct winbindd_cli_state *state)
1697 struct netr_SamInfo3 *info3 = NULL;
1698 struct rpc_pipe_client *netlogon_pipe;
1699 const char *name_user = NULL;
1700 const char *name_domain = NULL;
1701 const char *workstation;
1705 DATA_BLOB lm_resp, nt_resp;
1707 /* This is child-only, so no check for privileged access is needed
1710 /* Ensure null termination */
1711 state->request->data.auth_crap.user[sizeof(state->request->data.auth_crap.user)-1]=0;
1712 state->request->data.auth_crap.domain[sizeof(state->request->data.auth_crap.domain)-1]=0;
1714 if (!check_request_flags(state->request->flags)) {
1715 result = NT_STATUS_INVALID_PARAMETER_MIX;
1719 name_user = state->request->data.auth_crap.user;
1721 if (*state->request->data.auth_crap.domain) {
1722 name_domain = state->request->data.auth_crap.domain;
1723 } else if (lp_winbind_use_default_domain()) {
1724 name_domain = lp_workgroup();
1726 DEBUG(5,("no domain specified with username (%s) - failing auth\n",
1728 result = NT_STATUS_NO_SUCH_USER;
1732 DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n", (unsigned long)state->pid,
1733 name_domain, name_user));
1735 if (*state->request->data.auth_crap.workstation) {
1736 workstation = state->request->data.auth_crap.workstation;
1738 workstation = global_myname();
1741 if (state->request->data.auth_crap.lm_resp_len > sizeof(state->request->data.auth_crap.lm_resp)
1742 || state->request->data.auth_crap.nt_resp_len > sizeof(state->request->data.auth_crap.nt_resp)) {
1743 if (!(state->request->flags & WBFLAG_BIG_NTLMV2_BLOB) ||
1744 state->request->extra_len != state->request->data.auth_crap.nt_resp_len) {
1745 DEBUG(0, ("winbindd_pam_auth_crap: invalid password length %u/%u\n",
1746 state->request->data.auth_crap.lm_resp_len,
1747 state->request->data.auth_crap.nt_resp_len));
1748 result = NT_STATUS_INVALID_PARAMETER;
1753 lm_resp = data_blob_talloc(state->mem_ctx, state->request->data.auth_crap.lm_resp,
1754 state->request->data.auth_crap.lm_resp_len);
1756 if (state->request->flags & WBFLAG_BIG_NTLMV2_BLOB) {
1757 nt_resp = data_blob_talloc(state->mem_ctx,
1758 state->request->extra_data.data,
1759 state->request->data.auth_crap.nt_resp_len);
1761 nt_resp = data_blob_talloc(state->mem_ctx,
1762 state->request->data.auth_crap.nt_resp,
1763 state->request->data.auth_crap.nt_resp_len);
1766 if (strequal(name_domain, get_global_sam_name())) {
1767 DATA_BLOB chal_blob = data_blob_const(
1768 state->request->data.auth_crap.chal,
1769 sizeof(state->request->data.auth_crap.chal));
1771 result = winbindd_dual_auth_passdb(
1772 state->mem_ctx, name_domain, name_user,
1773 &chal_blob, &lm_resp, &nt_resp, &info3);
1774 goto process_result;
1778 netlogon_fn_t logon_fn;
1782 netlogon_pipe = NULL;
1783 result = cm_connect_netlogon(domain, &netlogon_pipe);
1785 if (!NT_STATUS_IS_OK(result)) {
1786 DEBUG(3, ("could not open handle to NETLOGON pipe (error: %s)\n",
1787 nt_errstr(result)));
1791 logon_fn = domain->can_do_samlogon_ex
1792 ? rpccli_netlogon_sam_network_logon_ex
1793 : rpccli_netlogon_sam_network_logon;
1795 result = logon_fn(netlogon_pipe,
1797 state->request->data.auth_crap.logon_parameters,
1801 /* Bug #3248 - found by Stefan Burkei. */
1802 workstation, /* We carefully set this above so use it... */
1803 state->request->data.auth_crap.chal,
1808 if ((NT_STATUS_V(result) == DCERPC_FAULT_OP_RNG_ERROR)
1809 && domain->can_do_samlogon_ex) {
1810 DEBUG(3, ("Got a DC that can not do NetSamLogonEx, "
1811 "retrying with NetSamLogon\n"));
1812 domain->can_do_samlogon_ex = false;
1819 /* We have to try a second time as cm_connect_netlogon
1820 might not yet have noticed that the DC has killed
1823 if (!rpccli_is_connected(netlogon_pipe)) {
1828 /* if we get access denied, a possible cause was that we had and open
1829 connection to the DC, but someone changed our machine account password
1830 out from underneath us using 'net rpc changetrustpw' */
1832 if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
1833 DEBUG(3,("winbindd_pam_auth: sam_logon returned "
1834 "ACCESS_DENIED. Maybe the trust account "
1835 "password was changed and we didn't know it. "
1836 "Killing connections to domain %s\n",
1838 invalidate_cm_connection(&domain->conn);
1842 } while ( (attempts < 2) && retry );
1846 if (NT_STATUS_IS_OK(result)) {
1848 wcache_invalidate_samlogon(find_domain_from_name(name_domain), info3);
1849 netsamlogon_cache_store(name_user, info3);
1851 /* Check if the user is in the right group */
1853 result = check_info3_in_group(
1855 state->request->data.auth_crap.require_membership_of_sid);
1856 if (!NT_STATUS_IS_OK(result)) {
1857 DEBUG(3, ("User %s is not in the required group (%s), so "
1858 "crap authentication is rejected\n",
1859 state->request->data.auth_crap.user,
1860 state->request->data.auth_crap.require_membership_of_sid));
1864 result = append_auth_data(state, info3, name_domain,
1866 if (!NT_STATUS_IS_OK(result)) {
1873 /* give us a more useful (more correct?) error code */
1874 if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
1875 (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
1876 result = NT_STATUS_NO_LOGON_SERVERS;
1879 if (state->request->flags & WBFLAG_PAM_NT_STATUS_SQUASH) {
1880 result = nt_status_squash(result);
1883 set_auth_errors(state->response, result);
1885 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
1886 ("NTLM CRAP authentication for user [%s]\\[%s] returned %s (PAM: %d)\n",
1889 state->response->data.auth.nt_status_string,
1890 state->response->data.auth.pam_error));
1892 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
1895 enum winbindd_result winbindd_dual_pam_chauthtok(struct winbindd_domain *contact_domain,
1896 struct winbindd_cli_state *state)
1899 char *newpass = NULL;
1900 struct policy_handle dom_pol;
1901 struct rpc_pipe_client *cli = NULL;
1902 bool got_info = false;
1903 struct samr_DomInfo1 *info = NULL;
1904 struct userPwdChangeFailureInformation *reject = NULL;
1905 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1906 fstring domain, user;
1908 ZERO_STRUCT(dom_pol);
1910 DEBUG(3, ("[%5lu]: dual pam chauthtok %s\n", (unsigned long)state->pid,
1911 state->request->data.auth.user));
1913 if (!parse_domain_user(state->request->data.chauthtok.user, domain, user)) {
1917 /* Change password */
1919 oldpass = state->request->data.chauthtok.oldpass;
1920 newpass = state->request->data.chauthtok.newpass;
1922 /* Initialize reject reason */
1923 state->response->data.auth.reject_reason = Undefined;
1925 /* Get sam handle */
1927 result = cm_connect_sam(contact_domain, state->mem_ctx, &cli,
1929 if (!NT_STATUS_IS_OK(result)) {
1930 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
1934 result = rpccli_samr_chgpasswd_user3(cli, state->mem_ctx,
1941 /* Windows 2003 returns NT_STATUS_PASSWORD_RESTRICTION */
1943 if (NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_RESTRICTION) ) {
1945 fill_in_password_policy(state->response, info);
1947 state->response->data.auth.reject_reason =
1948 reject->extendedFailureReason;
1953 /* atm the pidl generated rpccli_samr_ChangePasswordUser3 function will
1954 * return with NT_STATUS_BUFFER_TOO_SMALL for w2k dcs as w2k just
1955 * returns with 4byte error code (NT_STATUS_NOT_SUPPORTED) which is too
1956 * short to comply with the samr_ChangePasswordUser3 idl - gd */
1958 /* only fallback when the chgpasswd_user3 call is not supported */
1959 if ((NT_STATUS_EQUAL(result, NT_STATUS(DCERPC_FAULT_OP_RNG_ERROR))) ||
1960 (NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED)) ||
1961 (NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)) ||
1962 (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED))) {
1964 DEBUG(10,("Password change with chgpasswd_user3 failed with: %s, retrying chgpasswd_user2\n",
1965 nt_errstr(result)));
1967 result = rpccli_samr_chgpasswd_user2(cli, state->mem_ctx, user, newpass, oldpass);
1969 /* Windows 2000 returns NT_STATUS_ACCOUNT_RESTRICTION.
1970 Map to the same status code as Windows 2003. */
1972 if ( NT_STATUS_EQUAL(NT_STATUS_ACCOUNT_RESTRICTION, result ) ) {
1973 result = NT_STATUS_PASSWORD_RESTRICTION;
1979 if (NT_STATUS_IS_OK(result) && (state->request->flags & WBFLAG_PAM_CACHED_LOGIN)) {
1980 if (lp_winbind_offline_logon()) {
1981 result = winbindd_update_creds_by_name(contact_domain,
1982 state->mem_ctx, user,
1984 /* Again, this happens when we login from gdm or xdm
1985 * and the password expires, *BUT* cached crendentials
1986 * doesn't exist. winbindd_update_creds_by_name()
1987 * returns NT_STATUS_NO_SUCH_USER.
1988 * This is not a failure.
1991 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER)) {
1992 result = NT_STATUS_OK;
1995 if (!NT_STATUS_IS_OK(result)) {
1996 DEBUG(10,("Failed to store creds: %s\n", nt_errstr(result)));
1997 goto process_result;
2002 if (!NT_STATUS_IS_OK(result) && !got_info && contact_domain) {
2004 NTSTATUS policy_ret;
2006 policy_ret = fillup_password_policy(contact_domain, state);
2008 /* failure of this is non critical, it will just provide no
2009 * additional information to the client why the change has
2010 * failed - Guenther */
2012 if (!NT_STATUS_IS_OK(policy_ret)) {
2013 DEBUG(10,("Failed to get password policies: %s\n", nt_errstr(policy_ret)));
2014 goto process_result;
2020 if (strequal(contact_domain->name, get_global_sam_name())) {
2021 /* FIXME: internal rpc pipe does not cache handles yet */
2023 if (is_valid_policy_hnd(&dom_pol)) {
2024 rpccli_samr_Close(cli, state->mem_ctx, &dom_pol);
2030 set_auth_errors(state->response, result);
2032 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
2033 ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
2036 state->response->data.auth.nt_status_string,
2037 state->response->data.auth.pam_error));
2039 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2042 enum winbindd_result winbindd_dual_pam_logoff(struct winbindd_domain *domain,
2043 struct winbindd_cli_state *state)
2045 NTSTATUS result = NT_STATUS_NOT_SUPPORTED;
2047 DEBUG(3, ("[%5lu]: pam dual logoff %s\n", (unsigned long)state->pid,
2048 state->request->data.logoff.user));
2050 if (!(state->request->flags & WBFLAG_PAM_KRB5)) {
2051 result = NT_STATUS_OK;
2052 goto process_result;
2055 if (state->request->data.logoff.krb5ccname[0] == '\0') {
2056 result = NT_STATUS_OK;
2057 goto process_result;
2062 if (state->request->data.logoff.uid < 0) {
2063 DEBUG(0,("winbindd_pam_logoff: invalid uid\n"));
2064 goto process_result;
2067 /* what we need here is to find the corresponding krb5 ccache name *we*
2068 * created for a given username and destroy it */
2070 if (!ccache_entry_exists(state->request->data.logoff.user)) {
2071 result = NT_STATUS_OK;
2072 DEBUG(10,("winbindd_pam_logoff: no entry found.\n"));
2073 goto process_result;
2076 if (!ccache_entry_identical(state->request->data.logoff.user,
2077 state->request->data.logoff.uid,
2078 state->request->data.logoff.krb5ccname)) {
2079 DEBUG(0,("winbindd_pam_logoff: cached entry differs.\n"));
2080 goto process_result;
2083 result = remove_ccache(state->request->data.logoff.user);
2084 if (!NT_STATUS_IS_OK(result)) {
2085 DEBUG(0,("winbindd_pam_logoff: failed to remove ccache: %s\n",
2086 nt_errstr(result)));
2087 goto process_result;
2091 result = NT_STATUS_NOT_SUPPORTED;
2097 set_auth_errors(state->response, result);
2099 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2102 /* Change user password with auth crap*/
2104 enum winbindd_result winbindd_dual_pam_chng_pswd_auth_crap(struct winbindd_domain *domainSt, struct winbindd_cli_state *state)
2107 DATA_BLOB new_nt_password;
2108 DATA_BLOB old_nt_hash_enc;
2109 DATA_BLOB new_lm_password;
2110 DATA_BLOB old_lm_hash_enc;
2111 fstring domain,user;
2112 struct policy_handle dom_pol;
2113 struct winbindd_domain *contact_domain = domainSt;
2114 struct rpc_pipe_client *cli = NULL;
2116 ZERO_STRUCT(dom_pol);
2118 /* Ensure null termination */
2119 state->request->data.chng_pswd_auth_crap.user[
2120 sizeof(state->request->data.chng_pswd_auth_crap.user)-1]=0;
2121 state->request->data.chng_pswd_auth_crap.domain[
2122 sizeof(state->request->data.chng_pswd_auth_crap.domain)-1]=0;
2126 DEBUG(3, ("[%5lu]: pam change pswd auth crap domain: %s user: %s\n",
2127 (unsigned long)state->pid,
2128 state->request->data.chng_pswd_auth_crap.domain,
2129 state->request->data.chng_pswd_auth_crap.user));
2131 if (lp_winbind_offline_logon()) {
2132 DEBUG(0,("Refusing password change as winbind offline logons are enabled. "));
2133 DEBUGADD(0,("Changing passwords here would risk inconsistent logons\n"));
2134 result = NT_STATUS_ACCESS_DENIED;
2138 if (*state->request->data.chng_pswd_auth_crap.domain) {
2139 fstrcpy(domain,state->request->data.chng_pswd_auth_crap.domain);
2141 parse_domain_user(state->request->data.chng_pswd_auth_crap.user,
2145 DEBUG(3,("no domain specified with username (%s) - "
2147 state->request->data.chng_pswd_auth_crap.user));
2148 result = NT_STATUS_NO_SUCH_USER;
2153 if (!*domain && lp_winbind_use_default_domain()) {
2154 fstrcpy(domain,(char *)lp_workgroup());
2158 fstrcpy(user, state->request->data.chng_pswd_auth_crap.user);
2161 DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n",
2162 (unsigned long)state->pid, domain, user));
2164 /* Change password */
2165 new_nt_password = data_blob_const(
2166 state->request->data.chng_pswd_auth_crap.new_nt_pswd,
2167 state->request->data.chng_pswd_auth_crap.new_nt_pswd_len);
2169 old_nt_hash_enc = data_blob_const(
2170 state->request->data.chng_pswd_auth_crap.old_nt_hash_enc,
2171 state->request->data.chng_pswd_auth_crap.old_nt_hash_enc_len);
2173 if(state->request->data.chng_pswd_auth_crap.new_lm_pswd_len > 0) {
2174 new_lm_password = data_blob_const(
2175 state->request->data.chng_pswd_auth_crap.new_lm_pswd,
2176 state->request->data.chng_pswd_auth_crap.new_lm_pswd_len);
2178 old_lm_hash_enc = data_blob_const(
2179 state->request->data.chng_pswd_auth_crap.old_lm_hash_enc,
2180 state->request->data.chng_pswd_auth_crap.old_lm_hash_enc_len);
2182 new_lm_password.length = 0;
2183 old_lm_hash_enc.length = 0;
2186 /* Get sam handle */
2188 result = cm_connect_sam(contact_domain, state->mem_ctx, &cli, &dom_pol);
2189 if (!NT_STATUS_IS_OK(result)) {
2190 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
2194 result = rpccli_samr_chng_pswd_auth_crap(
2195 cli, state->mem_ctx, user, new_nt_password, old_nt_hash_enc,
2196 new_lm_password, old_lm_hash_enc);
2200 if (strequal(contact_domain->name, get_global_sam_name())) {
2201 /* FIXME: internal rpc pipe does not cache handles yet */
2203 if (is_valid_policy_hnd(&dom_pol)) {
2204 rpccli_samr_Close(cli, state->mem_ctx, &dom_pol);
2210 set_auth_errors(state->response, result);
2212 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
2213 ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
2215 state->response->data.auth.nt_status_string,
2216 state->response->data.auth.pam_error));
2218 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;