s3:libads: make use of talloc_stackframe() in ads_setup_tls_wrapping()
[Samba.git] / source3 / winbindd / winbindd_pam.c
blob9764c874f77627a714ca3f370da7eea82d3333e6
1 /*
2 Unix SMB/CIFS implementation.
4 Winbind daemon - pam auth functions
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/>.
25 #include "includes.h"
26 #include "ntdomain.h"
27 #include "winbindd.h"
28 #include "libsmb/namequery.h"
29 #include "../libcli/auth/libcli_auth.h"
30 #include "libcli/auth/pam_errors.h"
31 #include "../librpc/gen_ndr/ndr_samr_c.h"
32 #include "librpc/rpc/dcesrv_core.h"
33 #include "librpc/gen_ndr/ndr_winbind.h"
34 #include "rpc_client/cli_pipe.h"
35 #include "rpc_client/cli_samr.h"
36 #include "../librpc/gen_ndr/ndr_netlogon.h"
37 #include "rpc_client/cli_netlogon.h"
38 #include "smb_krb5.h"
39 #include "../libcli/security/security.h"
40 #include "ads.h"
41 #include "../librpc/gen_ndr/krb5pac.h"
42 #include "passdb/machine_sid.h"
43 #include "auth.h"
44 #include "../lib/tsocket/tsocket.h"
45 #include "auth/kerberos/pac_utils.h"
46 #include "auth/gensec/gensec.h"
47 #include "librpc/crypto/gse_krb5.h"
48 #include "lib/afs/afs_funcs.h"
49 #include "libsmb/samlogon_cache.h"
50 #include "rpc_client/util_netlogon.h"
51 #include "param/param.h"
52 #include "messaging/messaging.h"
53 #include "lib/util/string_wrappers.h"
54 #include "lib/crypto/gnutls_helpers.h"
56 #include "lib/crypto/gnutls_helpers.h"
57 #include <gnutls/crypto.h>
58 #include "lib/global_contexts.h"
60 #undef DBGC_CLASS
61 #define DBGC_CLASS DBGC_WINBIND
63 #define LOGON_KRB5_FAIL_CLOCK_SKEW 0x02000000
65 static NTSTATUS append_info3_as_txt(TALLOC_CTX *mem_ctx,
66 struct winbindd_response *resp,
67 uint16_t validation_level,
68 union netr_Validation *validation)
70 struct netr_SamInfo3 *info3 = NULL;
71 char *ex = NULL;
72 uint32_t i;
73 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
74 TALLOC_CTX *frame = talloc_stackframe();
76 status = map_validation_to_info3(frame,
77 validation_level,
78 validation,
79 &info3);
80 if (!NT_STATUS_IS_OK(status)) {
81 goto out;
84 resp->data.auth.info3.logon_time =
85 nt_time_to_unix(info3->base.logon_time);
86 resp->data.auth.info3.logoff_time =
87 nt_time_to_unix(info3->base.logoff_time);
88 resp->data.auth.info3.kickoff_time =
89 nt_time_to_unix(info3->base.kickoff_time);
90 resp->data.auth.info3.pass_last_set_time =
91 nt_time_to_unix(info3->base.last_password_change);
92 resp->data.auth.info3.pass_can_change_time =
93 nt_time_to_unix(info3->base.allow_password_change);
94 resp->data.auth.info3.pass_must_change_time =
95 nt_time_to_unix(info3->base.force_password_change);
97 resp->data.auth.info3.logon_count = info3->base.logon_count;
98 resp->data.auth.info3.bad_pw_count = info3->base.bad_password_count;
100 resp->data.auth.info3.user_rid = info3->base.rid;
101 resp->data.auth.info3.group_rid = info3->base.primary_gid;
102 sid_to_fstring(resp->data.auth.info3.dom_sid, info3->base.domain_sid);
104 resp->data.auth.info3.num_groups = info3->base.groups.count;
105 resp->data.auth.info3.user_flgs = info3->base.user_flags;
107 resp->data.auth.info3.acct_flags = info3->base.acct_flags;
108 resp->data.auth.info3.num_other_sids = info3->sidcount;
110 fstrcpy(resp->data.auth.info3.user_name,
111 info3->base.account_name.string);
112 fstrcpy(resp->data.auth.info3.full_name,
113 info3->base.full_name.string);
114 fstrcpy(resp->data.auth.info3.logon_script,
115 info3->base.logon_script.string);
116 fstrcpy(resp->data.auth.info3.profile_path,
117 info3->base.profile_path.string);
118 fstrcpy(resp->data.auth.info3.home_dir,
119 info3->base.home_directory.string);
120 fstrcpy(resp->data.auth.info3.dir_drive,
121 info3->base.home_drive.string);
123 fstrcpy(resp->data.auth.info3.logon_srv,
124 info3->base.logon_server.string);
125 fstrcpy(resp->data.auth.info3.logon_dom,
126 info3->base.logon_domain.string);
128 resp->data.auth.validation_level = validation_level;
129 if (validation_level == 6) {
130 fstrcpy(resp->data.auth.info6.dns_domainname,
131 validation->sam6->dns_domainname.string);
132 fstrcpy(resp->data.auth.info6.principal_name,
133 validation->sam6->principal_name.string);
136 ex = talloc_strdup(frame, "");
137 if (ex == NULL) {
138 status = NT_STATUS_NO_MEMORY;
139 goto out;
142 for (i=0; i < info3->base.groups.count; i++) {
143 ex = talloc_asprintf_append_buffer(ex, "0x%08X:0x%08X\n",
144 info3->base.groups.rids[i].rid,
145 info3->base.groups.rids[i].attributes);
146 if (ex == NULL) {
147 status = NT_STATUS_NO_MEMORY;
148 goto out;
152 for (i=0; i < info3->sidcount; i++) {
153 struct dom_sid_buf sidbuf;
155 ex = talloc_asprintf_append_buffer(
157 "%s:0x%08X\n",
158 dom_sid_str_buf(info3->sids[i].sid, &sidbuf),
159 info3->sids[i].attributes);
160 if (ex == NULL) {
161 status = NT_STATUS_NO_MEMORY;
162 goto out;
166 resp->length += talloc_get_size(ex);
167 resp->extra_data.data = talloc_move(mem_ctx, &ex);
169 status = NT_STATUS_OK;
170 out:
171 TALLOC_FREE(frame);
172 return status;
175 static NTSTATUS append_info3_as_ndr(TALLOC_CTX *mem_ctx,
176 struct winbindd_response *resp,
177 struct netr_SamInfo3 *info3)
179 DATA_BLOB blob;
180 enum ndr_err_code ndr_err;
182 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, info3,
183 (ndr_push_flags_fn_t)ndr_push_netr_SamInfo3);
184 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
185 DEBUG(0,("append_info3_as_ndr: failed to append\n"));
186 return ndr_map_error2ntstatus(ndr_err);
189 resp->extra_data.data = blob.data;
190 resp->length += blob.length;
192 return NT_STATUS_OK;
195 static NTSTATUS append_unix_username(uint16_t validation_level,
196 union netr_Validation *validation,
197 const char *name_domain,
198 const char *name_user,
199 TALLOC_CTX *mem_ctx,
200 char **_unix_username)
202 TALLOC_CTX *tmp_ctx = NULL;
203 const char *nt_username = NULL;
204 const char *nt_domain = NULL;
205 char *unix_username = NULL;
206 struct netr_SamBaseInfo *base_info = NULL;
207 NTSTATUS status;
209 tmp_ctx = talloc_new(mem_ctx);
210 if (tmp_ctx == NULL) {
211 return NT_STATUS_NO_MEMORY;
214 /* We've been asked to return the unix username, per
215 'winbind use default domain' settings and the like */
217 switch (validation_level) {
218 case 3:
219 base_info = &validation->sam3->base;
220 break;
221 case 6:
222 base_info = &validation->sam6->base;
223 break;
224 default:
225 DBG_ERR("Invalid validation level %d\n", validation_level);
226 status = NT_STATUS_INTERNAL_ERROR;
227 goto out;
230 nt_domain = talloc_strdup(tmp_ctx, base_info->logon_domain.string);
231 if (!nt_domain) {
232 /* If the server didn't give us one, just use the one
233 * we sent them */
234 nt_domain = name_domain;
237 nt_username = talloc_strdup(tmp_ctx, base_info->account_name.string);
238 if (!nt_username) {
239 /* If the server didn't give us one, just use the one
240 * we sent them */
241 nt_username = name_user;
244 unix_username = fill_domain_username_talloc(tmp_ctx,
245 nt_domain,
246 nt_username,
247 true);
248 if (unix_username == NULL) {
249 status = NT_STATUS_NO_MEMORY;
250 goto out;
253 DBG_INFO("Setting unix username to [%s]\n", unix_username);
255 *_unix_username = talloc_move(mem_ctx, &unix_username);
257 status = NT_STATUS_OK;
258 out:
259 TALLOC_FREE(tmp_ctx);
261 return status;
264 static NTSTATUS append_afs_token(uint16_t validation_level,
265 union netr_Validation *validation,
266 const char *name_domain,
267 const char *name_user,
268 TALLOC_CTX *mem_ctx,
269 DATA_BLOB *_blob)
271 TALLOC_CTX *tmp_ctx = NULL;
272 char *afsname = NULL;
273 char *cell;
274 char *token;
275 struct netr_SamBaseInfo *base_info = NULL;
276 NTSTATUS status;
278 tmp_ctx = talloc_new(mem_ctx);
279 if (tmp_ctx == NULL) {
280 return NT_STATUS_NO_MEMORY;
283 switch (validation_level) {
284 case 3:
285 base_info = &validation->sam3->base;
286 break;
287 case 6:
288 base_info = &validation->sam6->base;
289 break;
290 default:
291 DBG_ERR("Invalid validation level %d\n", validation_level);
292 status = NT_STATUS_INTERNAL_ERROR;
293 goto out;
296 afsname = talloc_strdup(tmp_ctx, lp_afs_username_map());
297 if (afsname == NULL) {
298 status = NT_STATUS_NO_MEMORY;
299 goto out;
302 afsname = talloc_string_sub(tmp_ctx,
303 lp_afs_username_map(),
304 "%D", name_domain);
305 afsname = talloc_string_sub(tmp_ctx, afsname,
306 "%u", name_user);
307 afsname = talloc_string_sub(tmp_ctx, afsname,
308 "%U", name_user);
311 struct dom_sid user_sid;
312 struct dom_sid_buf sidstr;
314 sid_compose(&user_sid, base_info->domain_sid, base_info->rid);
315 afsname = talloc_string_sub(
316 tmp_ctx,
317 afsname,
318 "%s",
319 dom_sid_str_buf(&user_sid, &sidstr));
322 if (afsname == NULL) {
323 status = NT_STATUS_NO_MEMORY;
324 goto out;
327 if (!strlower_m(afsname)) {
328 status = NT_STATUS_INVALID_PARAMETER;
329 goto out;
332 DEBUG(10, ("Generating token for user %s\n", afsname));
334 cell = strchr(afsname, '@');
336 if (cell == NULL) {
337 status = NT_STATUS_NO_MEMORY;
338 goto out;
341 *cell = '\0';
342 cell += 1;
344 token = afs_createtoken_str(afsname, cell);
345 if (token == NULL) {
346 status = NT_STATUS_OK;
347 goto out;
350 talloc_steal(mem_ctx, token);
351 *_blob = data_blob_string_const_null(token);
353 status = NT_STATUS_OK;
354 out:
355 TALLOC_FREE(tmp_ctx);
357 return status;
360 NTSTATUS extra_data_to_sid_array(const char *group_sid,
361 TALLOC_CTX *mem_ctx,
362 struct wbint_SidArray **_sid_array)
364 TALLOC_CTX *tmp_ctx = NULL;
365 struct wbint_SidArray *sid_array = NULL;
366 struct dom_sid *require_membership_of_sid = NULL;
367 uint32_t num_require_membership_of_sid = 0;
368 char *req_sid = NULL;
369 const char *p = NULL;
370 NTSTATUS status;
372 if (_sid_array == NULL) {
373 return NT_STATUS_INVALID_PARAMETER;
376 *_sid_array = NULL;
378 tmp_ctx = talloc_new(mem_ctx);
379 if (tmp_ctx == NULL) {
380 return NT_STATUS_NO_MEMORY;
383 sid_array = talloc_zero(tmp_ctx, struct wbint_SidArray);
384 if (sid_array == NULL) {
385 status = NT_STATUS_NO_MEMORY;
386 goto fail;
389 if (!group_sid || !group_sid[0]) {
390 /* NO sid supplied, all users may access */
391 status = NT_STATUS_OK;
393 * Always return an allocated wbint_SidArray,
394 * even if the array is empty.
396 goto out;
399 num_require_membership_of_sid = 0;
400 require_membership_of_sid = NULL;
401 p = group_sid;
403 while (next_token_talloc(tmp_ctx, &p, &req_sid, ",")) {
404 struct dom_sid sid;
406 if (!string_to_sid(&sid, req_sid)) {
407 DBG_ERR("check_info3_in_group: could not parse %s "
408 "as a SID!\n", req_sid);
409 status = NT_STATUS_INVALID_PARAMETER;
410 goto fail;
413 status = add_sid_to_array(tmp_ctx, &sid,
414 &require_membership_of_sid,
415 &num_require_membership_of_sid);
416 if (!NT_STATUS_IS_OK(status)) {
417 DBG_ERR("add_sid_to_array failed\n");
418 goto fail;
422 sid_array->num_sids = num_require_membership_of_sid;
423 sid_array->sids = talloc_move(sid_array, &require_membership_of_sid);
425 status = NT_STATUS_OK;
426 out:
427 *_sid_array = talloc_move(mem_ctx, &sid_array);
429 fail:
430 TALLOC_FREE(tmp_ctx);
432 return status;
435 static NTSTATUS check_info3_in_group(struct netr_SamInfo3 *info3,
436 struct wbint_SidArray *sid_array)
438 * Check whether a user belongs to a group or list of groups.
440 * @param mem_ctx talloc memory context.
441 * @param info3 user information, including group membership info.
442 * @param group_sid One or more groups , separated by commas.
444 * @return NT_STATUS_OK on success,
445 * NT_STATUS_LOGON_FAILURE if the user does not belong,
446 * or other NT_STATUS_IS_ERR(status) for other kinds of failure.
449 size_t i;
450 struct security_token *token;
451 NTSTATUS status;
453 /* Parse the 'required group' SID */
455 if (sid_array == NULL || sid_array->num_sids == 0) {
456 /* NO sid supplied, all users may access */
457 return NT_STATUS_OK;
461 * This is a limited-use security_token for the purpose of
462 * checking the SID list below, so no claims need to be added
463 * and se_access_check() will never run.
465 token = security_token_initialise(talloc_tos(),
466 CLAIMS_EVALUATION_INVALID_STATE);
467 if (token == NULL) {
468 DEBUG(0, ("talloc failed\n"));
469 return NT_STATUS_NO_MEMORY;
472 status = sid_array_from_info3(token, info3,
473 &token->sids,
474 &token->num_sids,
475 true);
476 if (!NT_STATUS_IS_OK(status)) {
477 return status;
480 if (!NT_STATUS_IS_OK(status = add_aliases(get_global_sam_sid(),
481 token))
482 || !NT_STATUS_IS_OK(status = add_aliases(&global_sid_Builtin,
483 token))) {
484 DEBUG(3, ("could not add aliases: %s\n",
485 nt_errstr(status)));
486 return status;
489 security_token_debug(DBGC_CLASS, 10, token);
491 for (i=0; i<sid_array->num_sids; i++) {
492 struct dom_sid_buf buf;
493 DEBUG(10, ("Checking SID %s\n",
494 dom_sid_str_buf(&sid_array->sids[i],
495 &buf)));
496 if (nt_token_check_sid(&sid_array->sids[i],
497 token)) {
498 DEBUG(10, ("Access ok\n"));
499 return NT_STATUS_OK;
503 /* Do not distinguish this error from a wrong username/pw */
505 return NT_STATUS_LOGON_FAILURE;
508 struct winbindd_domain *find_auth_domain(uint8_t flags,
509 const char *domain_name)
511 struct winbindd_domain *domain;
513 if (IS_DC) {
514 domain = find_domain_from_name_noinit(domain_name);
515 if (domain == NULL) {
516 DEBUG(3, ("Authentication for domain [%s] refused "
517 "as it is not a trusted domain\n",
518 domain_name));
519 return NULL;
522 if (domain->secure_channel_type != SEC_CHAN_NULL) {
523 return domain;
526 return domain->routing_domain;
529 if (strequal(domain_name, get_global_sam_name())) {
530 return find_domain_from_name_noinit(domain_name);
533 if (lp_winbind_use_krb5_enterprise_principals()) {
535 * If we use enterprise principals
536 * we always go through our primary domain
537 * and follow the WRONG_REALM replies.
539 flags &= ~WBFLAG_PAM_CONTACT_TRUSTDOM;
542 /* we can auth against trusted domains */
543 if (flags & WBFLAG_PAM_CONTACT_TRUSTDOM) {
544 domain = find_domain_from_name_noinit(domain_name);
545 if (domain == NULL) {
546 DEBUG(3, ("Authentication for domain [%s] skipped "
547 "as it is not a trusted domain\n",
548 domain_name));
549 } else {
550 return domain;
554 return find_our_domain();
557 static NTSTATUS get_password_policy(struct winbindd_domain *domain,
558 TALLOC_CTX *mem_ctx,
559 struct samr_DomInfo1 **_policy)
561 NTSTATUS status;
562 struct samr_DomInfo1 *policy = NULL;
564 if ( !winbindd_can_contact_domain( domain ) ) {
565 DBG_INFO("No inbound trust to contact domain %s\n",
566 domain->name);
567 return NT_STATUS_NOT_SUPPORTED;
570 policy = talloc_zero(mem_ctx, struct samr_DomInfo1);
571 if (policy == NULL) {
572 return NT_STATUS_NO_MEMORY;
575 status = wb_cache_password_policy(domain, mem_ctx, policy);
576 if (NT_STATUS_IS_ERR(status)) {
577 TALLOC_FREE(policy);
578 return status;
581 *_policy = talloc_move(mem_ctx, &policy);
583 return NT_STATUS_OK;
586 static NTSTATUS get_max_bad_attempts_from_lockout_policy(struct winbindd_domain *domain,
587 TALLOC_CTX *mem_ctx,
588 uint16_t *lockout_threshold)
590 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
591 struct samr_DomInfo12 lockout_policy;
593 *lockout_threshold = 0;
595 status = wb_cache_lockout_policy(domain, mem_ctx, &lockout_policy);
596 if (NT_STATUS_IS_ERR(status)) {
597 return status;
600 *lockout_threshold = lockout_policy.lockout_threshold;
602 return NT_STATUS_OK;
605 static NTSTATUS get_pwd_properties(struct winbindd_domain *domain,
606 TALLOC_CTX *mem_ctx,
607 uint32_t *password_properties)
609 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
610 struct samr_DomInfo1 password_policy;
612 *password_properties = 0;
614 status = wb_cache_password_policy(domain, mem_ctx, &password_policy);
615 if (NT_STATUS_IS_ERR(status)) {
616 return status;
619 *password_properties = password_policy.password_properties;
621 return NT_STATUS_OK;
624 #ifdef HAVE_KRB5
626 static bool generate_krb5_ccache(TALLOC_CTX *mem_ctx,
627 const char *type,
628 uid_t uid,
629 const char **user_ccache_file)
631 /* accept FILE and WRFILE as krb5_cc_type from the client and then
632 * build the full ccname string based on the user's uid here -
633 * Guenther*/
635 const char *gen_cc = NULL;
637 if (uid != -1) {
638 if (strequal(type, "FILE")) {
639 gen_cc = talloc_asprintf(
640 mem_ctx, "FILE:/tmp/krb5cc_%d", uid);
641 if (gen_cc == NULL) {
642 return false;
645 if (strequal(type, "WRFILE")) {
646 gen_cc = talloc_asprintf(
647 mem_ctx, "WRFILE:/tmp/krb5cc_%d", uid);
648 if (gen_cc == NULL) {
649 return false;
652 if (strequal(type, "KEYRING")) {
653 gen_cc = talloc_asprintf(
654 mem_ctx, "KEYRING:persistent:%d", uid);
655 if (gen_cc == NULL) {
656 return false;
659 if (strequal(type, "KCM")) {
660 gen_cc = talloc_asprintf(mem_ctx,
661 "KCM:%d",
662 uid);
663 if (gen_cc == NULL) {
664 return false;
668 if (strnequal(type, "FILE:/", 6) ||
669 strnequal(type, "WRFILE:/", 8) ||
670 strnequal(type, "DIR:/", 5)) {
672 /* we allow only one "%u" substitution */
674 char *p;
676 p = strchr(type, '%');
677 if (p != NULL) {
679 p++;
681 if (p != NULL && *p == 'u' && strchr(p, '%') == NULL) {
682 char uid_str[sizeof("18446744073709551615")];
684 snprintf(uid_str, sizeof(uid_str), "%u", uid);
686 gen_cc = talloc_string_sub2(mem_ctx,
687 type,
688 "%u",
689 uid_str,
690 /* remove_unsafe_characters */
691 false,
692 /* replace_once */
693 true,
694 /* allow_trailing_dollar */
695 false);
696 if (gen_cc == NULL) {
697 return false;
704 *user_ccache_file = gen_cc;
706 DBG_DEBUG("using ccache: %s\n", gen_cc != NULL ? gen_cc : "(internal)");
708 return true;
711 #endif
713 uid_t get_uid_from_request(struct winbindd_request *request)
715 uid_t uid;
717 uid = request->data.auth.uid;
719 if (uid == (uid_t)-1) {
720 DEBUG(1,("invalid uid: '%u'\n", (unsigned int)uid));
721 return -1;
723 return uid;
726 /**********************************************************************
727 Authenticate a user with a clear text password using Kerberos and fill up
728 ccache if required
729 **********************************************************************/
731 static NTSTATUS winbindd_raw_kerberos_login(TALLOC_CTX *mem_ctx,
732 struct winbindd_domain *domain,
733 const char *user,
734 const char *pass,
735 const char *krb5_cc_type,
736 uid_t uid,
737 struct netr_SamInfo6 **info6,
738 const char **_krb5ccname)
740 #ifdef HAVE_KRB5
741 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
742 const char *cc = NULL;
743 const char *principal_s = NULL;
744 char *realm = NULL;
745 char *name_namespace = NULL;
746 char *name_domain = NULL;
747 char *name_user = NULL;
748 time_t ticket_lifetime = 0;
749 time_t renewal_until = 0;
750 time_t time_offset = 0;
751 const char *user_ccache_file;
752 struct PAC_LOGON_INFO *logon_info = NULL;
753 struct PAC_UPN_DNS_INFO *upn_dns_info = NULL;
754 struct PAC_DATA *pac_data = NULL;
755 struct PAC_DATA_CTR *pac_data_ctr = NULL;
756 const char *local_service;
757 uint32_t i;
758 struct netr_SamInfo6 *info6_copy = NULL;
759 char *canon_principal = NULL;
760 char *canon_realm = NULL;
761 bool ok;
763 *info6 = NULL;
765 if (domain->alt_name == NULL) {
766 return NT_STATUS_INVALID_PARAMETER;
769 if (_krb5ccname != NULL) {
770 *_krb5ccname = NULL;
773 /* 1st step:
774 * prepare a krb5_cc_cache string for the user */
776 if (uid == -1) {
777 DEBUG(0,("no valid uid\n"));
780 ok = generate_krb5_ccache(mem_ctx,
781 krb5_cc_type,
782 uid,
783 &user_ccache_file);
784 if (!ok) {
785 return NT_STATUS_NO_MEMORY;
787 cc = user_ccache_file;
789 /* 2nd step:
790 * get kerberos properties */
792 if (domain->backend_data.ads_conn != NULL) {
793 time_offset = domain->backend_data.ads_conn->auth.time_offset;
797 /* 3rd step:
798 * do kerberos auth and setup ccache as the user */
800 ok = parse_domain_user(mem_ctx,
801 user,
802 &name_namespace,
803 &name_domain,
804 &name_user);
805 if (!ok) {
806 return NT_STATUS_INVALID_PARAMETER;
809 realm = talloc_strdup(mem_ctx, domain->alt_name);
810 if (realm == NULL) {
811 return NT_STATUS_NO_MEMORY;
814 if (!strupper_m(realm)) {
815 return NT_STATUS_INVALID_PARAMETER;
818 if (lp_winbind_use_krb5_enterprise_principals() &&
819 name_namespace[0] != '\0')
821 principal_s = talloc_asprintf(mem_ctx,
822 "%s@%s@%s",
823 name_user,
824 name_namespace,
825 realm);
826 } else {
827 principal_s = talloc_asprintf(mem_ctx,
828 "%s@%s",
829 name_user,
830 realm);
832 if (principal_s == NULL) {
833 return NT_STATUS_NO_MEMORY;
836 local_service = talloc_asprintf(mem_ctx, "%s$@%s",
837 lp_netbios_name(), lp_realm());
838 if (local_service == NULL) {
839 return NT_STATUS_NO_MEMORY;
843 /* if this is a user ccache, we need to act as the user to let the krb5
844 * library handle the chown, etc. */
846 /************************ ENTERING NON-ROOT **********************/
848 if (user_ccache_file != NULL) {
849 set_effective_uid(uid);
850 DEBUG(10,("winbindd_raw_kerberos_login: uid is %d\n", uid));
854 * Note cc can be NULL, it means
855 * kerberos_return_pac() will use
856 * a temporary krb5 ccache internally.
858 result = kerberos_return_pac(mem_ctx,
859 principal_s,
860 pass,
861 time_offset,
862 &ticket_lifetime,
863 &renewal_until,
865 true,
866 true,
867 WINBINDD_PAM_AUTH_KRB5_RENEW_TIME,
868 NULL,
869 local_service,
870 &canon_principal,
871 &canon_realm,
872 &pac_data_ctr);
873 if (user_ccache_file != NULL) {
874 gain_root_privilege();
877 /************************ RETURNED TO ROOT **********************/
879 if (!NT_STATUS_IS_OK(result)) {
880 goto failed;
883 if (pac_data_ctr == NULL) {
884 goto failed;
887 pac_data = pac_data_ctr->pac_data;
888 if (pac_data == NULL) {
889 goto failed;
892 for (i=0; i < pac_data->num_buffers; i++) {
894 if (pac_data->buffers[i].type == PAC_TYPE_LOGON_INFO) {
895 logon_info = pac_data->buffers[i].info->logon_info.info;
896 continue;
899 if (pac_data->buffers[i].type == PAC_TYPE_UPN_DNS_INFO) {
900 upn_dns_info = &pac_data->buffers[i].info->upn_dns_info;
901 continue;
905 if (logon_info == NULL) {
906 DEBUG(10,("Missing logon_info in ticket of %s\n",
907 principal_s));
908 return NT_STATUS_INVALID_PARAMETER;
911 DEBUG(10,("winbindd_raw_kerberos_login: winbindd validated ticket of %s\n",
912 principal_s));
914 result = create_info6_from_pac(mem_ctx, logon_info,
915 upn_dns_info, &info6_copy);
916 if (!NT_STATUS_IS_OK(result)) {
917 goto failed;
920 /* if we had a user's ccache then return that string for the pam
921 * environment */
923 if (user_ccache_file != NULL) {
925 if (_krb5ccname != NULL) {
926 *_krb5ccname = talloc_steal(mem_ctx, user_ccache_file);
929 result = add_ccache_to_list(principal_s,
931 user,
932 pass,
933 realm,
934 uid,
935 time(NULL),
936 ticket_lifetime,
937 renewal_until,
938 false,
939 canon_principal,
940 canon_realm);
942 if (!NT_STATUS_IS_OK(result)) {
943 DEBUG(10,("winbindd_raw_kerberos_login: failed to add ccache to list: %s\n",
944 nt_errstr(result)));
948 *info6 = info6_copy;
949 return NT_STATUS_OK;
951 failed:
953 * Do not delete an existing valid credential cache, if the user
954 * e.g. enters a wrong password
956 if ((strequal(krb5_cc_type, "FILE") || strequal(krb5_cc_type, "WRFILE"))
957 && user_ccache_file != NULL) {
958 return result;
961 /* we could have created a new credential cache with a valid tgt in it
962 * but we weren't able to get or verify the service ticket for this
963 * local host and therefore didn't get the PAC, we need to remove that
964 * cache entirely now */
966 if (!NT_STATUS_IS_OK(remove_ccache(user))) {
967 DEBUG(3,("winbindd_raw_kerberos_login: "
968 "could not remove ccache for user %s\n",
969 user));
972 return result;
973 #else
974 return NT_STATUS_NOT_SUPPORTED;
975 #endif /* HAVE_KRB5 */
978 /****************************************************************
979 ****************************************************************/
981 bool check_request_flags(uint32_t flags)
983 uint32_t flags_edata = WBFLAG_PAM_AFS_TOKEN |
984 WBFLAG_PAM_INFO3_TEXT |
985 WBFLAG_PAM_INFO3_NDR;
987 if ( ( (flags & flags_edata) == WBFLAG_PAM_AFS_TOKEN) ||
988 ( (flags & flags_edata) == WBFLAG_PAM_INFO3_NDR) ||
989 ( (flags & flags_edata) == WBFLAG_PAM_INFO3_TEXT)||
990 !(flags & flags_edata) ) {
991 return true;
994 DEBUG(1, ("check_request_flags: invalid request flags[0x%08X]\n",
995 flags));
997 return false;
1000 /****************************************************************
1001 ****************************************************************/
1003 NTSTATUS append_auth_data(TALLOC_CTX *mem_ctx,
1004 struct winbindd_response *resp,
1005 uint32_t request_flags,
1006 uint16_t validation_level,
1007 union netr_Validation *validation,
1008 const char *name_domain,
1009 const char *name_user)
1011 struct netr_SamInfo3 *info3 = NULL;
1012 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1014 result = map_validation_to_info3(talloc_tos(),
1015 validation_level,
1016 validation,
1017 &info3);
1018 if (!NT_STATUS_IS_OK(result)) {
1019 goto out;
1022 if (request_flags & WBFLAG_PAM_USER_SESSION_KEY) {
1023 memcpy(resp->data.auth.user_session_key,
1024 info3->base.key.key,
1025 sizeof(resp->data.auth.user_session_key)
1026 /* 16 */);
1029 if (request_flags & WBFLAG_PAM_LMKEY) {
1030 memcpy(resp->data.auth.first_8_lm_hash,
1031 info3->base.LMSessKey.key,
1032 sizeof(resp->data.auth.first_8_lm_hash)
1033 /* 8 */);
1036 if (request_flags & WBFLAG_PAM_UNIX_NAME) {
1037 char *unix_username = NULL;
1038 result = append_unix_username(validation_level,
1039 validation,
1040 name_domain,
1041 name_user,
1042 mem_ctx,
1043 &unix_username);
1044 if (!NT_STATUS_IS_OK(result)) {
1045 DEBUG(10,("Failed to append Unix Username: %s\n",
1046 nt_errstr(result)));
1047 goto out;
1049 fstrcpy(resp->data.auth.unix_username, unix_username);
1050 TALLOC_FREE(unix_username);
1053 /* currently, anything from here on potentially overwrites extra_data. */
1055 if (request_flags & WBFLAG_PAM_INFO3_NDR) {
1056 result = append_info3_as_ndr(mem_ctx, resp, info3);
1057 if (!NT_STATUS_IS_OK(result)) {
1058 DEBUG(10,("Failed to append INFO3 (NDR): %s\n",
1059 nt_errstr(result)));
1060 goto out;
1064 if (request_flags & WBFLAG_PAM_INFO3_TEXT) {
1065 result = append_info3_as_txt(mem_ctx, resp,
1066 validation_level,
1067 validation);
1068 if (!NT_STATUS_IS_OK(result)) {
1069 DEBUG(10,("Failed to append INFO3 (TXT): %s\n",
1070 nt_errstr(result)));
1071 goto out;
1075 if (request_flags & WBFLAG_PAM_AFS_TOKEN) {
1076 DATA_BLOB blob = data_blob_null;
1077 result = append_afs_token(validation_level,
1078 validation,
1079 name_domain,
1080 name_user,
1081 mem_ctx,
1082 &blob);
1083 if (!NT_STATUS_IS_OK(result)) {
1084 DEBUG(10,("Failed to append AFS token: %s\n",
1085 nt_errstr(result)));
1086 goto out;
1088 resp->extra_data.data = blob.data;
1089 resp->length += blob.length;
1092 result = NT_STATUS_OK;
1093 out:
1094 TALLOC_FREE(info3);
1095 return result;
1098 static NTSTATUS winbindd_dual_pam_auth_cached(struct winbindd_domain *domain,
1099 bool krb5_auth,
1100 const char *user,
1101 const char *pass,
1102 const char *krb5_cc_type,
1103 uid_t uid,
1104 TALLOC_CTX *mem_ctx,
1105 uint16_t *_validation_level,
1106 union netr_Validation **_validation,
1107 const char **_krb5ccname)
1109 TALLOC_CTX *tmp_ctx = NULL;
1110 NTSTATUS result = NT_STATUS_LOGON_FAILURE;
1111 uint16_t max_allowed_bad_attempts;
1112 char *name_namespace = NULL;
1113 char *name_domain = NULL;
1114 char *name_user = NULL;
1115 struct dom_sid sid;
1116 enum lsa_SidType type;
1117 uchar new_nt_pass[NT_HASH_LEN];
1118 const uint8_t *cached_nt_pass;
1119 const uint8_t *cached_salt;
1120 struct netr_SamInfo3 *my_info3;
1121 time_t kickoff_time, must_change_time;
1122 bool password_good = false;
1123 bool ok;
1124 #ifdef HAVE_KRB5
1125 struct winbindd_tdc_domain *tdc_domain = NULL;
1126 #endif
1128 if (_validation == NULL) {
1129 return NT_STATUS_INVALID_PARAMETER;
1131 *_validation = NULL;
1133 if (_krb5ccname != NULL) {
1134 *_krb5ccname = NULL;
1137 DEBUG(10,("winbindd_dual_pam_auth_cached\n"));
1139 tmp_ctx = talloc_new(mem_ctx);
1140 if (tmp_ctx == NULL) {
1141 return NT_STATUS_NO_MEMORY;
1144 /* Parse domain and username */
1146 ok = parse_domain_user(tmp_ctx,
1147 user,
1148 &name_namespace,
1149 &name_domain,
1150 &name_user);
1151 if (!ok) {
1152 DBG_DEBUG("parse_domain_user failed\n");
1153 result = NT_STATUS_NO_SUCH_USER;
1154 goto out;
1157 if (!lookup_cached_name(name_namespace,
1158 name_domain,
1159 name_user,
1160 &sid,
1161 &type)) {
1162 DEBUG(10,("winbindd_dual_pam_auth_cached: no such user in the cache\n"));
1163 result = NT_STATUS_NO_SUCH_USER;
1164 goto out;
1167 if (type != SID_NAME_USER) {
1168 DEBUG(10,("winbindd_dual_pam_auth_cached: not a user (%s)\n", sid_type_lookup(type)));
1169 result = NT_STATUS_LOGON_FAILURE;
1170 goto out;
1173 result = winbindd_get_creds(domain,
1174 tmp_ctx,
1175 &sid,
1176 &my_info3,
1177 &cached_nt_pass,
1178 &cached_salt);
1179 if (!NT_STATUS_IS_OK(result)) {
1180 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get creds: %s\n", nt_errstr(result)));
1181 goto out;
1184 E_md4hash(pass, new_nt_pass);
1186 dump_data_pw("new_nt_pass", new_nt_pass, NT_HASH_LEN);
1187 dump_data_pw("cached_nt_pass", cached_nt_pass, NT_HASH_LEN);
1188 if (cached_salt) {
1189 dump_data_pw("cached_salt", cached_salt, NT_HASH_LEN);
1192 if (cached_salt) {
1193 /* In this case we didn't store the nt_hash itself,
1194 but the MD5 combination of salt + nt_hash. */
1195 uchar salted_hash[NT_HASH_LEN];
1196 gnutls_hash_hd_t hash_hnd = NULL;
1197 int rc;
1199 rc = gnutls_hash_init(&hash_hnd, GNUTLS_DIG_MD5);
1200 if (rc < 0) {
1201 result = gnutls_error_to_ntstatus(
1202 rc, NT_STATUS_HASH_NOT_SUPPORTED);
1203 goto out;
1206 rc = gnutls_hash(hash_hnd, cached_salt, 16);
1207 if (rc < 0) {
1208 gnutls_hash_deinit(hash_hnd, NULL);
1209 result = gnutls_error_to_ntstatus(
1210 rc, NT_STATUS_HASH_NOT_SUPPORTED);
1211 goto out;
1213 rc = gnutls_hash(hash_hnd, new_nt_pass, 16);
1214 if (rc < 0) {
1215 gnutls_hash_deinit(hash_hnd, NULL);
1216 result = gnutls_error_to_ntstatus(
1217 rc, NT_STATUS_HASH_NOT_SUPPORTED);
1218 goto out;
1220 gnutls_hash_deinit(hash_hnd, salted_hash);
1222 password_good = mem_equal_const_time(cached_nt_pass, salted_hash,
1223 NT_HASH_LEN);
1224 } else {
1225 /* Old cached cred - direct store of nt_hash (bad bad bad !). */
1226 password_good = mem_equal_const_time(cached_nt_pass, new_nt_pass,
1227 NT_HASH_LEN);
1230 if (password_good) {
1232 /* User *DOES* know the password, update logon_time and reset
1233 * bad_pw_count */
1235 my_info3->base.user_flags |= NETLOGON_CACHED_ACCOUNT;
1237 if (my_info3->base.acct_flags & ACB_AUTOLOCK) {
1238 result = NT_STATUS_ACCOUNT_LOCKED_OUT;
1239 goto out;
1242 if (my_info3->base.acct_flags & ACB_DISABLED) {
1243 result = NT_STATUS_ACCOUNT_DISABLED;
1244 goto out;
1247 if (my_info3->base.acct_flags & ACB_WSTRUST) {
1248 result = NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
1249 goto out;
1252 if (my_info3->base.acct_flags & ACB_SVRTRUST) {
1253 result = NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT;
1254 goto out;
1257 if (my_info3->base.acct_flags & ACB_DOMTRUST) {
1258 result = NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT;
1259 goto out;
1262 if (!(my_info3->base.acct_flags & ACB_NORMAL)) {
1263 DEBUG(0,("winbindd_dual_pam_auth_cached: what's wrong with that one?: 0x%08x\n",
1264 my_info3->base.acct_flags));
1265 result = NT_STATUS_LOGON_FAILURE;
1266 goto out;
1269 kickoff_time = nt_time_to_unix(my_info3->base.kickoff_time);
1270 if (kickoff_time != 0 && time(NULL) > kickoff_time) {
1271 result = NT_STATUS_ACCOUNT_EXPIRED;
1272 goto out;
1275 must_change_time = nt_time_to_unix(my_info3->base.force_password_change);
1276 if (must_change_time != 0 && must_change_time < time(NULL)) {
1277 /* we allow grace logons when the password has expired */
1278 my_info3->base.user_flags |= NETLOGON_GRACE_LOGON;
1279 /* return NT_STATUS_PASSWORD_EXPIRED; */
1280 goto success;
1283 #ifdef HAVE_KRB5
1284 if ((krb5_auth) &&
1285 ((tdc_domain = wcache_tdc_fetch_domain(tmp_ctx, name_domain)) != NULL) &&
1286 ((tdc_domain->trust_type & LSA_TRUST_TYPE_UPLEVEL) ||
1287 /* used to cope with the case winbindd starting without network. */
1288 !strequal(tdc_domain->domain_name, tdc_domain->dns_name))) {
1289 const char *cc = NULL;
1290 char *realm = NULL;
1291 const char *principal_s = NULL;
1292 const char *user_ccache_file;
1294 if (domain->alt_name == NULL) {
1295 result = NT_STATUS_INVALID_PARAMETER;
1296 goto out;
1299 if (uid == -1) {
1300 DEBUG(0,("winbindd_dual_pam_auth_cached: invalid uid\n"));
1301 result = NT_STATUS_INVALID_PARAMETER;
1302 goto out;
1305 ok = generate_krb5_ccache(tmp_ctx,
1306 krb5_cc_type,
1307 uid,
1308 &user_ccache_file);
1309 if (!ok) {
1310 result = NT_STATUS_NO_MEMORY;
1311 goto out;
1313 cc = user_ccache_file;
1315 realm = talloc_strdup(tmp_ctx, domain->alt_name);
1316 if (realm == NULL) {
1317 result = NT_STATUS_NO_MEMORY;
1318 goto out;
1321 if (!strupper_m(realm)) {
1322 result = NT_STATUS_INVALID_PARAMETER;
1323 goto out;
1326 principal_s = talloc_asprintf(tmp_ctx, "%s@%s", name_user, realm);
1327 if (principal_s == NULL) {
1328 result = NT_STATUS_NO_MEMORY;
1329 goto out;
1332 if (user_ccache_file != NULL) {
1334 if (_krb5ccname != NULL) {
1335 *_krb5ccname = talloc_move(mem_ctx,
1336 &user_ccache_file);
1339 result = add_ccache_to_list(principal_s,
1341 user,
1342 pass,
1343 realm,
1344 uid,
1345 time(NULL),
1346 time(NULL) + lp_winbind_cache_time(),
1347 time(NULL) + WINBINDD_PAM_AUTH_KRB5_RENEW_TIME,
1348 true,
1349 principal_s,
1350 realm);
1352 if (!NT_STATUS_IS_OK(result)) {
1353 DEBUG(10,("winbindd_dual_pam_auth_cached: failed "
1354 "to add ccache to list: %s\n",
1355 nt_errstr(result)));
1359 #endif /* HAVE_KRB5 */
1360 success:
1361 /* FIXME: we possibly should handle logon hours as well (does xp when
1362 * offline?) see auth/auth_sam.c:sam_account_ok for details */
1364 unix_to_nt_time(&my_info3->base.logon_time, time(NULL));
1365 my_info3->base.bad_password_count = 0;
1367 result = winbindd_update_creds_by_info3(domain,
1368 user,
1369 pass,
1370 my_info3);
1371 if (!NT_STATUS_IS_OK(result)) {
1372 DEBUG(1,("winbindd_dual_pam_auth_cached: failed to update creds: %s\n",
1373 nt_errstr(result)));
1374 goto out;
1377 result = map_info3_to_validation(mem_ctx,
1378 my_info3,
1379 _validation_level,
1380 _validation);
1381 if (!NT_STATUS_IS_OK(result)) {
1382 DBG_ERR("map_info3_to_validation failed: %s\n",
1383 nt_errstr(result));
1384 goto out;
1387 result = NT_STATUS_OK;
1388 goto out;
1391 /* User does *NOT* know the correct password, modify info3 accordingly, but only if online */
1392 if (domain->online == false) {
1393 goto failed;
1396 /* failure of this is not critical */
1397 result = get_max_bad_attempts_from_lockout_policy(domain, tmp_ctx, &max_allowed_bad_attempts);
1398 if (!NT_STATUS_IS_OK(result)) {
1399 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get max_allowed_bad_attempts. "
1400 "Won't be able to honour account lockout policies\n"));
1403 /* increase counter */
1404 my_info3->base.bad_password_count++;
1406 if (max_allowed_bad_attempts == 0) {
1407 goto failed;
1410 /* lockout user */
1411 if (my_info3->base.bad_password_count >= max_allowed_bad_attempts) {
1413 uint32_t password_properties;
1415 result = get_pwd_properties(domain, tmp_ctx, &password_properties);
1416 if (!NT_STATUS_IS_OK(result)) {
1417 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get password properties.\n"));
1420 if ((my_info3->base.rid != DOMAIN_RID_ADMINISTRATOR) ||
1421 (password_properties & DOMAIN_PASSWORD_LOCKOUT_ADMINS)) {
1422 my_info3->base.acct_flags |= ACB_AUTOLOCK;
1426 failed:
1427 result = winbindd_update_creds_by_info3(domain, user, NULL, my_info3);
1428 if (!NT_STATUS_IS_OK(result)) {
1429 DEBUG(0,("winbindd_dual_pam_auth_cached: failed to update creds %s\n",
1430 nt_errstr(result)));
1433 result = NT_STATUS_LOGON_FAILURE;
1435 out:
1436 TALLOC_FREE(tmp_ctx);
1438 return result;
1441 static NTSTATUS winbindd_dual_pam_auth_kerberos(struct winbindd_domain *domain,
1442 const char *user,
1443 const char *pass,
1444 const char *krb5_cc_type,
1445 uid_t uid,
1446 TALLOC_CTX *mem_ctx,
1447 uint16_t *_validation_level,
1448 union netr_Validation **_validation,
1449 const char **_krb5ccname)
1451 struct netr_SamInfo6 *info6 = NULL;
1452 struct winbindd_domain *contact_domain;
1453 char *name_namespace = NULL;
1454 char *name_domain = NULL;
1455 char *name_user = NULL;
1456 NTSTATUS result;
1457 bool ok;
1459 DEBUG(10,("winbindd_dual_pam_auth_kerberos\n"));
1461 /* Parse domain and username */
1463 ok = parse_domain_user(mem_ctx,
1464 user,
1465 &name_namespace,
1466 &name_domain,
1467 &name_user);
1468 if (!ok) {
1469 result = NT_STATUS_INVALID_PARAMETER;
1470 goto done;
1473 /* what domain should we contact? */
1475 if (lp_winbind_use_krb5_enterprise_principals()) {
1476 contact_domain = find_auth_domain(0, name_namespace);
1477 } else {
1478 contact_domain = find_domain_from_name(name_namespace);
1480 if (contact_domain == NULL) {
1481 DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
1482 user, name_domain, name_user, name_namespace));
1483 result = NT_STATUS_NO_SUCH_USER;
1484 goto done;
1487 if (contact_domain->initialized &&
1488 contact_domain->active_directory) {
1489 goto try_login;
1492 if (!contact_domain->initialized) {
1493 init_dc_connection(contact_domain, false);
1496 if (!contact_domain->active_directory) {
1497 DEBUG(3,("krb5 auth requested but domain (%s) is not Active Directory\n",
1498 contact_domain->name));
1499 return NT_STATUS_INVALID_LOGON_TYPE;
1501 try_login:
1502 result = winbindd_raw_kerberos_login(
1503 mem_ctx,
1504 contact_domain,
1505 user,
1506 pass,
1507 krb5_cc_type,
1508 uid,
1509 &info6,
1510 _krb5ccname);
1511 if (!NT_STATUS_IS_OK(result)) {
1512 goto done;
1515 result = map_info6_to_validation(mem_ctx,
1516 info6,
1517 _validation_level,
1518 _validation);
1519 TALLOC_FREE(info6);
1520 if (!NT_STATUS_IS_OK(result)) {
1521 DBG_ERR("map_info6_to_validation failed: %s\n",
1522 nt_errstr(result));
1525 done:
1526 return result;
1529 static NTSTATUS winbindd_dual_auth_passdb(TALLOC_CTX *mem_ctx,
1530 uint32_t logon_parameters,
1531 const char *domain,
1532 const char *user,
1533 const uint64_t logon_id,
1534 const char *client_name,
1535 const int client_pid,
1536 const DATA_BLOB *challenge,
1537 const DATA_BLOB *lm_resp,
1538 const DATA_BLOB *nt_resp,
1539 const struct tsocket_address *remote,
1540 const struct tsocket_address *local,
1541 bool interactive,
1542 uint8_t *pauthoritative,
1543 struct netr_SamInfo3 **pinfo3)
1545 struct auth_context *auth_context;
1546 struct auth_serversupplied_info *server_info;
1547 struct auth_usersupplied_info *user_info = NULL;
1548 struct netr_SamInfo3 *info3;
1549 NTSTATUS status;
1550 bool ok;
1551 TALLOC_CTX *frame = talloc_stackframe();
1554 * We are authoritative by default
1556 *pauthoritative = 1;
1558 status = make_user_info(frame, &user_info, user, user, domain, domain,
1559 lp_netbios_name(), remote, local,
1560 "winbind",
1561 lm_resp, nt_resp, NULL, NULL,
1562 NULL, AUTH_PASSWORD_RESPONSE);
1563 if (!NT_STATUS_IS_OK(status)) {
1564 DEBUG(10, ("make_user_info failed: %s\n", nt_errstr(status)));
1565 TALLOC_FREE(frame);
1566 return status;
1569 user_info->logon_parameters = logon_parameters;
1570 user_info->logon_id = logon_id;
1571 user_info->auth_description = talloc_asprintf(
1572 frame, "PASSDB, %s, %d", client_name, client_pid);
1573 if (user_info->auth_description == NULL) {
1574 TALLOC_FREE(frame);
1575 return NT_STATUS_NO_MEMORY;
1578 /* We don't want to come back to winbindd or to do PAM account checks */
1579 user_info->flags |= USER_INFO_INFO3_AND_NO_AUTHZ;
1581 if (interactive) {
1582 user_info->flags |= USER_INFO_INTERACTIVE_LOGON;
1585 status = make_auth3_context_for_winbind(frame, &auth_context);
1586 if (!NT_STATUS_IS_OK(status)) {
1587 DBG_ERR("make_auth3_context_for_winbind failed: %s\n",
1588 nt_errstr(status));
1589 TALLOC_FREE(frame);
1590 return status;
1593 ok = auth3_context_set_challenge(auth_context,
1594 challenge->data, "fixed");
1595 if (!ok) {
1596 TALLOC_FREE(frame);
1597 return NT_STATUS_NO_MEMORY;
1600 status = auth_check_ntlm_password(mem_ctx,
1601 auth_context,
1602 user_info,
1603 &server_info,
1604 pauthoritative);
1605 if (!NT_STATUS_IS_OK(status)) {
1606 TALLOC_FREE(frame);
1607 return status;
1610 info3 = talloc_zero(mem_ctx, struct netr_SamInfo3);
1611 if (info3 == NULL) {
1612 TALLOC_FREE(frame);
1613 return NT_STATUS_NO_MEMORY;
1616 status = serverinfo_to_SamInfo3(server_info, info3);
1617 if (!NT_STATUS_IS_OK(status)) {
1618 TALLOC_FREE(frame);
1619 TALLOC_FREE(info3);
1620 DEBUG(0, ("serverinfo_to_SamInfo3 failed: %s\n",
1621 nt_errstr(status)));
1622 return status;
1625 *pinfo3 = info3;
1626 DBG_DEBUG("Authenticating user %s\\%s returned %s\n",
1627 domain,
1628 user,
1629 nt_errstr(status));
1630 TALLOC_FREE(frame);
1631 return status;
1634 static NTSTATUS winbind_samlogon_retry_loop(struct winbindd_domain *domain,
1635 TALLOC_CTX *mem_ctx,
1636 uint32_t logon_parameters,
1637 const char *username,
1638 const char *password,
1639 const char *domainname,
1640 const char *workstation,
1641 const uint64_t logon_id,
1642 bool plaintext_given,
1643 DATA_BLOB chal,
1644 DATA_BLOB lm_response,
1645 DATA_BLOB nt_response,
1646 bool interactive,
1647 uint8_t *authoritative,
1648 uint32_t *flags,
1649 uint16_t *_validation_level,
1650 union netr_Validation **_validation)
1652 int attempts = 0;
1653 int netr_attempts = 0;
1654 bool retry = false;
1655 bool valid_result = false;
1656 NTSTATUS result;
1657 enum netr_LogonInfoClass logon_type_i;
1658 enum netr_LogonInfoClass logon_type_n;
1659 uint16_t validation_level = UINT16_MAX;
1660 union netr_Validation *validation = NULL;
1661 TALLOC_CTX *base_ctx = NULL;
1662 struct netr_SamBaseInfo *base_info = NULL;
1664 do {
1665 struct rpc_pipe_client *netlogon_pipe;
1666 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1669 * We should always reset authoritative to 1
1670 * before calling a server again.
1672 * Otherwise we could treat a local problem as
1673 * non-authoritative.
1675 *authoritative = 1;
1677 retry = false;
1679 D_DEBUG("Creating a DCERPC netlogon connection for SAM logon. "
1680 "netlogon attempt: %d, samlogon attempt: %d.\n",
1681 netr_attempts,
1682 attempts);
1683 result = cm_connect_netlogon_secure(domain, &netlogon_pipe,
1684 &netlogon_creds_ctx);
1686 if (NT_STATUS_EQUAL(result,
1687 NT_STATUS_CANT_ACCESS_DOMAIN_INFO)) {
1689 * This means we don't have a trust account.
1691 *authoritative = 0;
1692 result = NT_STATUS_NO_SUCH_USER;
1693 break;
1696 if (!NT_STATUS_IS_OK(result)) {
1697 DEBUG(3,("Could not open handle to NETLOGON pipe "
1698 "(error: %s, attempts: %d)\n",
1699 nt_errstr(result), netr_attempts));
1701 reset_cm_connection_on_error(domain, NULL, result);
1703 /* After the first retry always close the connection */
1704 if (netr_attempts > 0) {
1705 DEBUG(3, ("This is again a problem for this "
1706 "particular call, forcing the close "
1707 "of this connection\n"));
1708 invalidate_cm_connection(domain);
1711 /* After the second retry failover to the next DC */
1712 if (netr_attempts > 1) {
1714 * If the netlogon server is not reachable then
1715 * it is possible that the DC is rebuilding
1716 * sysvol and shutdown netlogon for that time.
1717 * We should failover to the next dc.
1719 DEBUG(3, ("This is the third problem for this "
1720 "particular call, adding DC to the "
1721 "negative cache list: %s %s\n", domain->name, domain->dcname));
1722 add_failed_connection_entry(domain->name,
1723 domain->dcname,
1724 result);
1725 saf_delete(domain->name);
1728 /* Only allow 3 retries */
1729 if (netr_attempts < 3) {
1730 DEBUG(3, ("The connection to netlogon "
1731 "failed, retrying\n"));
1732 netr_attempts++;
1733 retry = true;
1734 continue;
1736 return result;
1739 logon_type_i = NetlogonInteractiveInformation;
1740 logon_type_n = NetlogonNetworkInformation;
1741 if (domain->domain_trust_attribs & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
1742 logon_type_i = NetlogonInteractiveTransitiveInformation;
1743 logon_type_n = NetlogonNetworkTransitiveInformation;
1746 if (domain->domain_trust_attribs & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1747 logon_type_i = NetlogonInteractiveTransitiveInformation;
1748 logon_type_n = NetlogonNetworkTransitiveInformation;
1751 if (domain->domain_trust_attribs & LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE) {
1752 logon_type_i = NetlogonInteractiveInformation;
1753 logon_type_n = NetlogonNetworkInformation;
1756 if (domain->domain_trust_attribs & LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) {
1757 logon_type_i = NetlogonInteractiveInformation;
1758 logon_type_n = NetlogonNetworkInformation;
1761 netr_attempts = 0;
1762 if (plaintext_given) {
1763 result = rpccli_netlogon_password_logon(
1764 netlogon_creds_ctx,
1765 netlogon_pipe->binding_handle,
1766 mem_ctx,
1767 logon_parameters,
1768 domainname,
1769 username,
1770 password,
1771 workstation,
1772 logon_id,
1773 logon_type_i,
1774 authoritative,
1775 flags,
1776 &validation_level,
1777 &validation);
1778 } else if (interactive) {
1779 result = rpccli_netlogon_interactive_logon(
1780 netlogon_creds_ctx,
1781 netlogon_pipe->binding_handle,
1782 mem_ctx,
1783 logon_parameters,
1784 username,
1785 domainname,
1786 workstation,
1787 logon_id,
1788 lm_response,
1789 nt_response,
1790 logon_type_i,
1791 authoritative,
1792 flags,
1793 &validation_level,
1794 &validation);
1795 } else {
1796 result = rpccli_netlogon_network_logon(
1797 netlogon_creds_ctx,
1798 netlogon_pipe->binding_handle,
1799 mem_ctx,
1800 logon_parameters,
1801 username,
1802 domainname,
1803 workstation,
1804 logon_id,
1805 chal,
1806 lm_response,
1807 nt_response,
1808 logon_type_n,
1809 authoritative,
1810 flags,
1811 &validation_level,
1812 &validation);
1816 * we increment this after the "feature negotiation"
1817 * for can_do_samlogon_ex and can_do_validation6
1819 attempts += 1;
1821 /* We have to try a second time as cm_connect_netlogon
1822 might not yet have noticed that the DC has killed
1823 our connection. */
1825 retry = reset_cm_connection_on_error(domain,
1826 netlogon_pipe->binding_handle,
1827 result);
1828 if (retry) {
1829 DBG_PREFIX(attempts > 1 ? DBGLVL_NOTICE : DBGLVL_INFO, (
1830 "This is problem %d for this "
1831 "particular call,"
1832 "DOMAIN[%s] DC[%s] - %s\n",
1833 attempts,
1834 domain->name,
1835 domain->dcname,
1836 nt_errstr(result)));
1837 continue;
1840 valid_result = true;
1842 if (NT_STATUS_EQUAL(result, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1844 * Got DCERPC_FAULT_OP_RNG_ERROR for SamLogon
1845 * (no Ex). This happens against old Samba
1846 * DCs, if LogonSamLogonEx() fails with an error
1847 * e.g. NT_STATUS_NO_SUCH_USER or NT_STATUS_WRONG_PASSWORD.
1849 * The server will log something like this:
1850 * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
1852 * This sets the whole connection into a fault_state mode
1853 * and all following request get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
1855 * This also happens to our retry with LogonSamLogonWithFlags()
1856 * and LogonSamLogon().
1858 * In order to recover from this situation, we need to
1859 * drop the connection.
1861 invalidate_cm_connection(domain);
1862 result = NT_STATUS_LOGON_FAILURE;
1863 break;
1866 } while ( (attempts < 3) && retry );
1868 if (!valid_result) {
1870 * This matches what windows does. In a chain of transitive
1871 * trusts the ACCESS_DENIED/authoritative=0 is not propagated
1872 * instead of NT_STATUS_NO_LOGON_SERVERS/authoritative=1 is
1873 * passed along the chain if there's no other DC is available.
1875 DBG_WARNING("Mapping %s/authoritative=%u to "
1876 "NT_STATUS_NO_LOGON_SERVERS/authoritative=1 for"
1877 "USERNAME[%s] USERDOMAIN[%s] REMOTE-DOMAIN[%s] \n",
1878 nt_errstr(result),
1879 *authoritative,
1880 username,
1881 domainname,
1882 domain->name);
1883 *authoritative = 1;
1884 return NT_STATUS_NO_LOGON_SERVERS;
1887 if (!NT_STATUS_IS_OK(result)) {
1888 return result;
1891 switch (validation_level) {
1892 case 3:
1893 base_ctx = validation->sam3;
1894 base_info = &validation->sam3->base;
1895 break;
1896 case 6:
1897 base_ctx = validation->sam6;
1898 base_info = &validation->sam6->base;
1899 break;
1900 default:
1901 smb_panic(__location__);
1904 if (base_info->acct_flags == 0 || base_info->account_name.string == NULL) {
1905 struct dom_sid user_sid;
1906 struct dom_sid_buf sid_buf;
1907 const char *acct_flags_src = "server";
1908 const char *acct_name_src = "server";
1911 * Handle the case where a NT4 DC does not fill in the acct_flags in
1912 * the samlogon reply info3. Yes, in 2021, there are still admins
1913 * around with real NT4 DCs.
1915 * We used to call dcerpc_samr_QueryUserInfo(level=16) to fetch
1916 * acct_flags, but as NT4 DCs reject authentication with workstation
1917 * accounts with NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT, even if
1918 * MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT is specified, we only ever got
1919 * ACB_NORMAL back (maybe with ACB_PWNOEXP in addition).
1921 * For network logons NT4 DCs also skip the
1922 * account_name, so we have to fallback to the
1923 * one given by the client.
1926 if (base_info->acct_flags == 0) {
1927 base_info->acct_flags = ACB_NORMAL;
1928 if (base_info->force_password_change == NTTIME_MAX) {
1929 base_info->acct_flags |= ACB_PWNOEXP;
1931 acct_flags_src = "calculated";
1934 if (base_info->account_name.string == NULL) {
1935 base_info->account_name.string = talloc_strdup(base_ctx,
1936 username);
1937 if (base_info->account_name.string == NULL) {
1938 TALLOC_FREE(validation);
1939 return NT_STATUS_NO_MEMORY;
1941 acct_name_src = "client";
1944 sid_compose(&user_sid, base_info->domain_sid, base_info->rid);
1946 DBG_DEBUG("Fallback to %s_acct_flags[0x%x] %s_acct_name[%s] for %s\n",
1947 acct_flags_src,
1948 base_info->acct_flags,
1949 acct_name_src,
1950 base_info->account_name.string,
1951 dom_sid_str_buf(&user_sid, &sid_buf));
1954 *_validation_level = validation_level;
1955 *_validation = validation;
1956 return NT_STATUS_OK;
1959 static NTSTATUS nt_dual_auth_passdb(TALLOC_CTX *mem_ctx,
1960 fstring name_user,
1961 fstring name_domain,
1962 const char *pass,
1963 uint64_t logon_id,
1964 const char *client_name,
1965 const int client_pid,
1966 const struct tsocket_address *remote,
1967 const struct tsocket_address *local,
1968 uint8_t *authoritative,
1969 struct netr_SamInfo3 **info3)
1971 unsigned char local_nt_response[24];
1972 uchar chal[8];
1973 DATA_BLOB chal_blob;
1974 DATA_BLOB lm_resp;
1975 DATA_BLOB nt_resp;
1977 /* do password magic */
1979 generate_random_buffer(chal, sizeof(chal));
1980 chal_blob = data_blob_const(chal, sizeof(chal));
1982 if (lp_client_ntlmv2_auth()) {
1983 DATA_BLOB server_chal;
1984 DATA_BLOB names_blob;
1985 server_chal = data_blob_const(chal, 8);
1987 /* note that the 'workgroup' here is for the local
1988 machine. The 'server name' must match the
1989 'workstation' passed to the actual SamLogon call.
1991 names_blob = NTLMv2_generate_names_blob(mem_ctx,
1992 lp_netbios_name(),
1993 lp_workgroup());
1995 if (!SMBNTLMv2encrypt(mem_ctx, name_user, name_domain,
1996 pass, &server_chal, &names_blob,
1997 &lm_resp, &nt_resp, NULL, NULL)) {
1998 data_blob_free(&names_blob);
1999 DEBUG(0, ("SMBNTLMv2encrypt() failed!\n"));
2000 return NT_STATUS_NO_MEMORY;
2002 data_blob_free(&names_blob);
2003 } else {
2004 int rc;
2005 lm_resp = data_blob_null;
2007 rc = SMBNTencrypt(pass, chal, local_nt_response);
2008 if (rc != 0) {
2009 DEBUG(0, ("SMBNTencrypt() failed!\n"));
2010 return gnutls_error_to_ntstatus(rc,
2011 NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
2014 nt_resp = data_blob_talloc(mem_ctx, local_nt_response,
2015 sizeof(local_nt_response));
2018 return winbindd_dual_auth_passdb(talloc_tos(), 0, name_domain,
2019 name_user, logon_id, client_name,
2020 client_pid, &chal_blob, &lm_resp,
2021 &nt_resp, remote, local,
2022 true, /* interactive */
2023 authoritative, info3);
2026 static NTSTATUS winbindd_dual_pam_auth_samlogon(
2027 TALLOC_CTX *mem_ctx,
2028 struct winbindd_domain *domain,
2029 const char *user,
2030 const char *pass,
2031 uint64_t logon_id,
2032 const char *client_name,
2033 const int client_pid,
2034 uint32_t request_flags,
2035 const struct tsocket_address *remote,
2036 const struct tsocket_address *local,
2037 uint16_t *_validation_level,
2038 union netr_Validation **_validation)
2040 char *name_namespace = NULL;
2041 char *name_domain = NULL;
2042 char *name_user = NULL;
2043 NTSTATUS result;
2044 uint8_t authoritative = 1;
2045 uint32_t flags = 0;
2046 uint16_t validation_level = 0;
2047 union netr_Validation *validation = NULL;
2048 bool ok;
2050 DEBUG(10,("winbindd_dual_pam_auth_samlogon\n"));
2052 /* Parse domain and username */
2054 ok = parse_domain_user(mem_ctx,
2055 user,
2056 &name_namespace,
2057 &name_domain,
2058 &name_user);
2059 if (!ok) {
2060 return NT_STATUS_INVALID_PARAMETER;
2064 * We check against domain->name instead of
2065 * name_domain, as find_auth_domain() ->
2066 * find_domain_from_name_noinit() already decided
2067 * that we are in a child for the correct domain.
2069 * name_domain can also be lp_realm()
2070 * we need to check against domain->name.
2072 if (strequal(domain->name, get_global_sam_name())) {
2073 struct netr_SamInfo3 *info3 = NULL;
2075 result = nt_dual_auth_passdb(mem_ctx, name_user, name_domain,
2076 pass, logon_id, client_name,
2077 client_pid, remote, local,
2078 &authoritative, &info3);
2081 * We need to try the remote NETLOGON server if this is
2082 * not authoritative (for example on the RODC).
2084 if (authoritative != 0) {
2085 if (!NT_STATUS_IS_OK(result)) {
2086 return result;
2088 result = map_info3_to_validation(mem_ctx,
2089 info3,
2090 &validation_level,
2091 &validation);
2092 TALLOC_FREE(info3);
2093 if (!NT_STATUS_IS_OK(result)) {
2094 return result;
2097 goto done;
2101 /* check authentication loop */
2103 result = winbind_samlogon_retry_loop(domain,
2104 mem_ctx,
2106 name_user,
2107 pass,
2108 name_domain,
2109 lp_netbios_name(),
2110 logon_id,
2111 true, /* plaintext_given */
2112 data_blob_null,
2113 data_blob_null, data_blob_null,
2114 true, /* interactive */
2115 &authoritative,
2116 &flags,
2117 &validation_level,
2118 &validation);
2119 if (!NT_STATUS_IS_OK(result)) {
2120 return result;
2123 done:
2124 *_validation_level = validation_level;
2125 *_validation = validation;
2127 return NT_STATUS_OK;
2131 * @brief generate an authentication message in the logs.
2134 static void log_authentication(
2135 TALLOC_CTX *mem_ctx,
2136 const struct winbindd_domain *domain,
2137 const char *client_name,
2138 pid_t client_pid,
2139 uint16_t validation_level,
2140 union netr_Validation *validation,
2141 const struct timeval start_time,
2142 const uint64_t logon_id,
2143 const char *command,
2144 const char *user_name,
2145 const char *domain_name,
2146 const char *workstation,
2147 const DATA_BLOB lm_resp,
2148 const DATA_BLOB nt_resp,
2149 const struct tsocket_address *remote,
2150 const struct tsocket_address *local,
2151 NTSTATUS result)
2153 struct auth_usersupplied_info *ui = NULL;
2154 struct dom_sid *sid = NULL;
2155 struct loadparm_context *lp_ctx = NULL;
2156 struct imessaging_context *msg_ctx = NULL;
2157 struct netr_SamBaseInfo *base_info = NULL;
2159 if (validation != NULL) {
2160 switch (validation_level) {
2161 case 3:
2162 base_info = &validation->sam3->base;
2163 break;
2164 case 6:
2165 base_info = &validation->sam6->base;
2166 break;
2167 default:
2168 DBG_WARNING("Unexpected validation level '%d'\n",
2169 validation_level);
2170 break;
2174 ui = talloc_zero(mem_ctx, struct auth_usersupplied_info);
2175 ui->logon_id = logon_id;
2176 ui->service_description = "winbind";
2177 ui->password.response.nt.length = nt_resp.length;
2178 ui->password.response.nt.data = nt_resp.data;
2179 ui->password.response.lanman.length = lm_resp.length;
2180 ui->password.response.lanman.data = lm_resp.data;
2181 if (nt_resp.length == 0 && lm_resp.length == 0) {
2182 ui->password_state = AUTH_PASSWORD_PLAIN;
2183 } else {
2184 ui->password_state = AUTH_PASSWORD_RESPONSE;
2187 * In the event of a failure ui->auth_description will be null,
2188 * the logging code handles this correctly so it can be ignored.
2190 ui->auth_description = talloc_asprintf(
2192 "%s, %s, %d",
2193 command,
2194 client_name,
2195 client_pid);
2196 if (ui->auth_description == NULL) {
2197 DBG_ERR("OOM Unable to create auth_description\n");
2199 ui->client.account_name = user_name;
2200 ui->client.domain_name = domain_name;
2201 ui->workstation_name = workstation;
2202 ui->remote_host = remote;
2203 ui->local_host = local;
2205 if (base_info != NULL) {
2206 sid = dom_sid_dup(ui, base_info->domain_sid);
2207 if (sid != NULL) {
2208 sid_append_rid(sid, base_info->rid);
2212 if (lp_auth_event_notification()) {
2213 lp_ctx = loadparm_init_s3(ui, loadparm_s3_helpers());
2214 msg_ctx = imessaging_client_init(
2215 ui, lp_ctx, global_event_context());
2217 log_authentication_event(
2218 msg_ctx,
2219 lp_ctx,
2220 &start_time,
2222 result,
2223 base_info != NULL ? base_info->logon_domain.string : "",
2224 base_info != NULL ? base_info->account_name.string : "",
2225 sid,
2226 NULL /* client_audit_info */,
2227 NULL /* server_audit_info */);
2228 TALLOC_FREE(ui);
2231 NTSTATUS _wbint_PamAuth(struct pipes_struct *p,
2232 struct wbint_PamAuth *r)
2234 struct winbindd_domain *domain = wb_child_domain();
2235 NTSTATUS result = NT_STATUS_LOGON_FAILURE;
2236 NTSTATUS krb5_result = NT_STATUS_OK;
2237 char *name_namespace = NULL;
2238 char *name_domain = NULL;
2239 char *name_user = NULL;
2240 char *mapped_user = NULL;
2241 const char *domain_user = NULL;
2242 uint16_t validation_level = UINT16_MAX;
2243 union netr_Validation *validation = NULL;
2244 struct netr_SamBaseInfo *base_info = NULL;
2245 NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL;
2246 bool ok;
2247 uint64_t logon_id = 0;
2248 const struct timeval start_time = timeval_current();
2249 const struct tsocket_address *remote = NULL;
2250 const struct tsocket_address *local = NULL;
2251 const char *krb5ccname = NULL;
2252 uid_t uid;
2253 pid_t client_pid;
2255 if (domain == NULL) {
2256 return NT_STATUS_REQUEST_NOT_ACCEPTED;
2259 /* Cut client_pid to 32bit */
2260 client_pid = r->in.client_pid;
2261 if ((uint64_t)client_pid != r->in.client_pid) {
2262 DBG_DEBUG("pid out of range\n");
2263 return NT_STATUS_INVALID_PARAMETER;
2266 /* Cut uid to 32bit */
2267 uid = r->in.info->uid;
2268 if ((uint64_t)uid != r->in.info->uid) {
2269 DBG_DEBUG("uid out of range\n");
2270 return NT_STATUS_INVALID_PARAMETER;
2274 * Generate a logon_id for this session.
2276 logon_id = generate_random_u64();
2277 remote = dcesrv_connection_get_remote_address(p->dce_call->conn);
2278 local = dcesrv_connection_get_local_address(p->dce_call->conn);
2279 DEBUG(3, ("[%"PRIu32"]: dual pam auth %s\n", client_pid,
2280 r->in.info->username));
2282 /* Parse domain and username */
2284 name_map_status = normalize_name_unmap(p->mem_ctx,
2285 r->in.info->username,
2286 &mapped_user);
2288 /* If the name normalization didn't actually do anything,
2289 just use the original name */
2291 if (!NT_STATUS_IS_OK(name_map_status) &&
2292 !NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED))
2294 mapped_user = discard_const(r->in.info->username);
2297 ok = parse_domain_user(p->mem_ctx,
2298 mapped_user,
2299 &name_namespace,
2300 &name_domain,
2301 &name_user);
2302 if (!ok) {
2303 result = NT_STATUS_INVALID_PARAMETER;
2304 goto done;
2307 if (mapped_user != r->in.info->username) {
2308 domain_user = talloc_asprintf(talloc_tos(),
2309 "%s%c%s",
2310 name_domain,
2311 *lp_winbind_separator(),
2312 name_user);
2313 if (domain_user == NULL) {
2314 result = NT_STATUS_NO_MEMORY;
2315 goto done;
2317 r->in.info->username = domain_user;
2320 if (!domain->online) {
2321 result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
2322 if (domain->startup) {
2323 /* Logons are very important to users. If we're offline and
2324 we get a request within the first 30 seconds of startup,
2325 try very hard to find a DC and go online. */
2327 DEBUG(10,("winbindd_dual_pam_auth: domain: %s offline and auth "
2328 "request in startup mode.\n", domain->name ));
2330 winbindd_flush_negative_conn_cache(domain);
2331 result = init_dc_connection(domain, false);
2335 DEBUG(10,("winbindd_dual_pam_auth: domain: %s last was %s\n", domain->name, domain->online ? "online":"offline"));
2337 /* Check for Kerberos authentication */
2338 if (domain->online && (r->in.flags & WBFLAG_PAM_KRB5)) {
2339 result = winbindd_dual_pam_auth_kerberos(
2340 domain,
2341 r->in.info->username,
2342 r->in.info->password,
2343 r->in.info->krb5_cc_type,
2344 uid,
2345 p->mem_ctx,
2346 &validation_level,
2347 &validation,
2348 &krb5ccname);
2350 /* save for later */
2351 krb5_result = result;
2353 if (NT_STATUS_IS_OK(result)) {
2354 DEBUG(10,("winbindd_dual_pam_auth_kerberos succeeded\n"));
2355 goto process_result;
2358 DBG_DEBUG("winbindd_dual_pam_auth_kerberos failed: %s\n",
2359 nt_errstr(result));
2361 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
2362 NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
2363 NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2364 DEBUG(10,("winbindd_dual_pam_auth_kerberos setting domain to offline\n"));
2365 set_domain_offline( domain );
2366 goto cached_logon;
2369 /* there are quite some NT_STATUS errors where there is no
2370 * point in retrying with a samlogon, we explicitly have to take
2371 * care not to increase the bad logon counter on the DC */
2373 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_DISABLED) ||
2374 NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_EXPIRED) ||
2375 NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_LOCKED_OUT) ||
2376 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_LOGON_HOURS) ||
2377 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_WORKSTATION) ||
2378 NT_STATUS_EQUAL(result, NT_STATUS_LOGON_FAILURE) ||
2379 NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER) ||
2380 NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_EXPIRED) ||
2381 NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_MUST_CHANGE) ||
2382 NT_STATUS_EQUAL(result, NT_STATUS_WRONG_PASSWORD)) {
2383 goto done;
2386 if (r->in.flags & WBFLAG_PAM_FALLBACK_AFTER_KRB5) {
2387 DEBUG(3,("falling back to samlogon\n"));
2388 goto sam_logon;
2389 } else {
2390 goto cached_logon;
2394 sam_logon:
2395 /* Check for Samlogon authentication */
2396 if (domain->online) {
2397 result = winbindd_dual_pam_auth_samlogon(
2398 p->mem_ctx,
2399 domain,
2400 r->in.info->username,
2401 r->in.info->password,
2402 logon_id,
2403 r->in.client_name,
2404 client_pid,
2405 r->in.flags,
2406 remote,
2407 local,
2408 &validation_level,
2409 &validation);
2411 if (NT_STATUS_IS_OK(result)) {
2412 DEBUG(10,("winbindd_dual_pam_auth_samlogon succeeded\n"));
2414 switch (validation_level) {
2415 case 3:
2416 base_info = &validation->sam3->base;
2417 break;
2418 case 6:
2419 base_info = &validation->sam6->base;
2420 break;
2421 default:
2422 DBG_ERR("Bad validation level %d\n",
2423 validation_level);
2424 result = NT_STATUS_INTERNAL_ERROR;
2425 goto done;
2428 /* add the Krb5 err if we have one */
2429 if ( NT_STATUS_EQUAL(krb5_result, NT_STATUS_TIME_DIFFERENCE_AT_DC ) ) {
2430 base_info->user_flags |= LOGON_KRB5_FAIL_CLOCK_SKEW;
2433 goto process_result;
2436 DEBUG(10,("winbindd_dual_pam_auth_samlogon failed: %s\n",
2437 nt_errstr(result)));
2439 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
2440 NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
2441 NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND))
2443 DEBUG(10,("winbindd_dual_pam_auth_samlogon setting domain to offline\n"));
2444 set_domain_offline( domain );
2445 goto cached_logon;
2448 if (domain->online) {
2449 /* We're still online - fail. */
2450 goto done;
2454 cached_logon:
2455 /* Check for Cached logons */
2456 if (!domain->online && (r->in.flags & WBFLAG_PAM_CACHED_LOGIN) &&
2457 lp_winbind_offline_logon()) {
2458 result = winbindd_dual_pam_auth_cached(domain,
2459 (r->in.flags & WBFLAG_PAM_KRB5),
2460 r->in.info->username,
2461 r->in.info->password,
2462 r->in.info->krb5_cc_type,
2463 uid,
2464 p->mem_ctx,
2465 &validation_level,
2466 &validation,
2467 &krb5ccname);
2469 if (!NT_STATUS_IS_OK(result)) {
2470 DEBUG(10,("winbindd_dual_pam_auth_cached failed: %s\n", nt_errstr(result)));
2471 goto done;
2473 DEBUG(10,("winbindd_dual_pam_auth_cached succeeded\n"));
2476 process_result:
2478 if (NT_STATUS_IS_OK(result)) {
2479 struct dom_sid user_sid;
2480 TALLOC_CTX *base_ctx = NULL;
2481 struct netr_SamInfo3 *info3 = NULL;
2483 switch (validation_level) {
2484 case 3:
2485 base_ctx = validation->sam3;
2486 base_info = &validation->sam3->base;
2487 break;
2488 case 6:
2489 base_ctx = validation->sam6;
2490 base_info = &validation->sam6->base;
2491 break;
2492 default:
2493 DBG_ERR("Bad validation level %d\n", validation_level);
2494 result = NT_STATUS_INTERNAL_ERROR;
2495 goto done;
2498 sid_compose(&user_sid, base_info->domain_sid, base_info->rid);
2500 if (base_info->full_name.string == NULL) {
2501 struct netr_SamInfo3 *cached_info3;
2503 cached_info3 = netsamlogon_cache_get(p->mem_ctx,
2504 &user_sid);
2505 if (cached_info3 != NULL &&
2506 cached_info3->base.full_name.string != NULL) {
2507 base_info->full_name.string = talloc_strdup(
2508 base_ctx,
2509 cached_info3->base.full_name.string);
2510 if (base_info->full_name.string == NULL) {
2511 result = NT_STATUS_NO_MEMORY;
2512 goto done;
2514 } else {
2516 /* this might fail so we don't check the return code */
2517 wcache_query_user_fullname(domain,
2518 base_ctx,
2519 &user_sid,
2520 &base_info->full_name.string);
2524 result = map_validation_to_info3(talloc_tos(),
2525 validation_level,
2526 validation,
2527 &info3);
2528 if (!NT_STATUS_IS_OK(result)) {
2529 goto done;
2532 wcache_invalidate_samlogon(find_domain_from_name(name_domain),
2533 &user_sid);
2534 netsamlogon_cache_store(name_user, info3);
2536 /* save name_to_sid info as early as possible (only if
2537 this is our primary domain so we don't invalidate
2538 the cache entry by storing the seq_num for the wrong
2539 domain). */
2540 if ( domain->primary ) {
2541 cache_name2sid(domain, name_domain, name_user,
2542 SID_NAME_USER, &user_sid);
2545 /* Check if the user is in the right group */
2547 result = check_info3_in_group(info3,
2548 r->in.require_membership_of_sid);
2549 if (!NT_STATUS_IS_OK(result)) {
2550 char *s = NDR_PRINT_STRUCT_STRING(p->mem_ctx,
2551 wbint_SidArray,
2552 r->in.require_membership_of_sid);
2553 DBG_NOTICE("User %s is not in the required groups:\n",
2554 r->in.info->username);
2555 DEBUGADD(DBGLVL_NOTICE, ("%s", s));
2556 DEBUGADD(DBGLVL_NOTICE,
2557 ("Plaintext authentication is rejected\n"));
2558 goto done;
2561 if (!is_allowed_domain(info3->base.logon_domain.string)) {
2562 DBG_NOTICE("Authentication failed for user [%s] "
2563 "from firewalled domain [%s]\n",
2564 info3->base.account_name.string,
2565 info3->base.logon_domain.string);
2566 result = NT_STATUS_AUTHENTICATION_FIREWALL_FAILED;
2567 goto done;
2570 r->out.validation = talloc_zero(p->mem_ctx,
2571 struct wbint_Validation);
2572 if (r->out.validation == NULL) {
2573 result = NT_STATUS_NO_MEMORY;
2574 goto done;
2577 r->out.validation->level = validation_level;
2578 r->out.validation->validation = talloc_steal(r->out.validation,
2579 validation);
2580 r->out.validation->krb5ccname = talloc_steal(r->out.validation,
2581 krb5ccname);
2582 if ((r->in.flags & WBFLAG_PAM_CACHED_LOGIN)
2583 && lp_winbind_offline_logon()) {
2585 result = winbindd_store_creds(domain,
2586 r->in.info->username,
2587 r->in.info->password,
2588 info3);
2591 result = NT_STATUS_OK;
2594 done:
2595 /* give us a more useful (more correct?) error code */
2596 if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
2597 (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
2598 result = NT_STATUS_NO_LOGON_SERVERS;
2601 DBG_PREFIX(NT_STATUS_IS_OK(result) ? 5 : 2,
2602 ("Plain-text authentication for user %s returned %s"
2603 " (PAM: %d)\n",
2604 r->in.info->username,
2605 nt_errstr(result),
2606 nt_status_to_pam(result)));
2609 * Log the winbind pam authentication, the logon_id will tie this to
2610 * any of the logons invoked from this request.
2613 log_authentication(
2614 p->mem_ctx,
2615 domain,
2616 r->in.client_name,
2617 client_pid,
2618 validation_level,
2619 validation,
2620 start_time,
2621 logon_id,
2622 "PAM_AUTH",
2623 name_user,
2624 name_domain,
2625 NULL,
2626 data_blob_null,
2627 data_blob_null,
2628 remote,
2629 local,
2630 result);
2632 if (NT_STATUS_IS_OK(result)) {
2633 gpupdate_user_init(r->in.info->username);
2636 return result;
2639 NTSTATUS winbind_dual_SamLogon(struct winbindd_domain *domain,
2640 TALLOC_CTX *mem_ctx,
2641 bool interactive,
2642 uint32_t logon_parameters,
2643 const char *name_user,
2644 const char *name_domain,
2645 const char *workstation,
2646 const uint64_t logon_id,
2647 const char* client_name,
2648 const int client_pid,
2649 DATA_BLOB chal_blob,
2650 DATA_BLOB lm_response,
2651 DATA_BLOB nt_response,
2652 const struct tsocket_address *remote,
2653 const struct tsocket_address *local,
2654 uint8_t *authoritative,
2655 bool skip_sam,
2656 uint32_t *flags,
2657 uint16_t *_validation_level,
2658 union netr_Validation **_validation)
2660 uint16_t validation_level = 0;
2661 union netr_Validation *validation = NULL;
2662 NTSTATUS result;
2665 * We check against domain->name instead of
2666 * name_domain, as find_auth_domain() ->
2667 * find_domain_from_name_noinit() already decided
2668 * that we are in a child for the correct domain.
2670 * name_domain can also be lp_realm()
2671 * we need to check against domain->name.
2673 if (!skip_sam && strequal(domain->name, get_global_sam_name())) {
2674 struct netr_SamInfo3 *info3 = NULL;
2676 result = winbindd_dual_auth_passdb(
2677 talloc_tos(),
2678 logon_parameters,
2679 name_domain, name_user,
2680 logon_id,
2681 client_name,
2682 client_pid,
2683 &chal_blob, &lm_response, &nt_response,
2684 remote,
2685 local,
2686 interactive,
2687 authoritative,
2688 &info3);
2689 if (NT_STATUS_IS_OK(result)) {
2690 result = map_info3_to_validation(mem_ctx,
2691 info3,
2692 &validation_level,
2693 &validation);
2694 TALLOC_FREE(info3);
2695 if (!NT_STATUS_IS_OK(result)) {
2696 goto done;
2701 * We need to try the remote NETLOGON server if this is
2702 * not authoritative.
2704 if (*authoritative != 0) {
2705 *flags = 0;
2706 goto process_result;
2710 result = winbind_samlogon_retry_loop(domain,
2711 mem_ctx,
2712 logon_parameters,
2713 name_user,
2714 NULL, /* password */
2715 name_domain,
2716 /* Bug #3248 - found by Stefan Burkei. */
2717 workstation, /* We carefully set this above so use it... */
2718 logon_id,
2719 false, /* plaintext_given */
2720 chal_blob,
2721 lm_response,
2722 nt_response,
2723 interactive,
2724 authoritative,
2725 flags,
2726 &validation_level,
2727 &validation);
2728 if (!NT_STATUS_IS_OK(result)) {
2729 goto done;
2732 process_result:
2734 if (NT_STATUS_IS_OK(result)) {
2735 struct dom_sid user_sid;
2736 TALLOC_CTX *base_ctx = NULL;
2737 struct netr_SamBaseInfo *base_info = NULL;
2738 struct netr_SamInfo3 *info3 = NULL;
2740 switch (validation_level) {
2741 case 3:
2742 base_ctx = validation->sam3;
2743 base_info = &validation->sam3->base;
2744 break;
2745 case 6:
2746 base_ctx = validation->sam6;
2747 base_info = &validation->sam6->base;
2748 break;
2749 default:
2750 result = NT_STATUS_INTERNAL_ERROR;
2751 goto done;
2754 sid_compose(&user_sid, base_info->domain_sid, base_info->rid);
2756 if (base_info->full_name.string == NULL) {
2757 struct netr_SamInfo3 *cached_info3;
2759 cached_info3 = netsamlogon_cache_get(mem_ctx,
2760 &user_sid);
2761 if (cached_info3 != NULL &&
2762 cached_info3->base.full_name.string != NULL)
2764 base_info->full_name.string = talloc_strdup(
2765 base_ctx,
2766 cached_info3->base.full_name.string);
2767 } else {
2769 /* this might fail so we don't check the return code */
2770 wcache_query_user_fullname(domain,
2771 base_ctx,
2772 &user_sid,
2773 &base_info->full_name.string);
2777 result = map_validation_to_info3(talloc_tos(),
2778 validation_level,
2779 validation,
2780 &info3);
2781 if (!NT_STATUS_IS_OK(result)) {
2782 goto done;
2784 wcache_invalidate_samlogon(find_domain_from_name(name_domain),
2785 &user_sid);
2786 netsamlogon_cache_store(name_user, info3);
2787 TALLOC_FREE(info3);
2790 done:
2792 /* give us a more useful (more correct?) error code */
2793 if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
2794 (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
2795 result = NT_STATUS_NO_LOGON_SERVERS;
2798 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
2799 ("NTLM CRAP authentication for user [%s]\\[%s] returned %s\n",
2800 name_domain,
2801 name_user,
2802 nt_errstr(result)));
2804 if (!NT_STATUS_IS_OK(result)) {
2805 return result;
2808 *_validation_level = validation_level;
2809 *_validation = validation;
2810 return NT_STATUS_OK;
2813 NTSTATUS _wbint_PamAuthCrap(struct pipes_struct *p, struct wbint_PamAuthCrap *r)
2815 struct winbindd_domain *domain = wb_child_domain();
2816 NTSTATUS result;
2817 uint64_t logon_id = 0;
2818 uint8_t authoritative = 1;
2819 uint32_t flags = 0;
2820 uint16_t validation_level = UINT16_MAX;
2821 union netr_Validation *validation = NULL;
2822 const struct timeval start_time = timeval_current();
2823 const struct tsocket_address *remote = NULL;
2824 const struct tsocket_address *local = NULL;
2825 struct netr_SamInfo3 *info3 = NULL;
2826 pid_t client_pid;
2828 if (domain == NULL) {
2829 return NT_STATUS_REQUEST_NOT_ACCEPTED;
2832 /* Cut client_pid to 32bit */
2833 client_pid = r->in.client_pid;
2834 if ((uint64_t)client_pid != r->in.client_pid) {
2835 DBG_DEBUG("pid out of range\n");
2836 return NT_STATUS_INVALID_PARAMETER;
2839 logon_id = generate_random_u64();
2840 remote = dcesrv_connection_get_remote_address(p->dce_call->conn);
2841 local = dcesrv_connection_get_local_address(p->dce_call->conn);
2843 DBG_NOTICE("[%"PRIu32"]: pam auth crap domain: %s user: %s\n",
2844 client_pid, r->in.domain, r->in.user);
2846 result = winbind_dual_SamLogon(domain,
2847 p->mem_ctx,
2848 false, /* interactive */
2849 r->in.logon_parameters,
2850 r->in.user,
2851 r->in.domain,
2852 r->in.workstation,
2853 logon_id,
2854 r->in.client_name,
2855 client_pid,
2856 r->in.chal,
2857 r->in.lm_resp,
2858 r->in.nt_resp,
2859 remote,
2860 local,
2861 &authoritative,
2862 false,
2863 &flags,
2864 &validation_level,
2865 &validation);
2866 if (!NT_STATUS_IS_OK(result)) {
2867 goto done;
2870 result = map_validation_to_info3(p->mem_ctx,
2871 validation_level,
2872 validation,
2873 &info3);
2874 if (!NT_STATUS_IS_OK(result)) {
2875 goto done;
2878 /* Check if the user is in the right group */
2879 result = check_info3_in_group(info3, r->in.require_membership_of_sid);
2880 if (!NT_STATUS_IS_OK(result)) {
2881 char *s = NDR_PRINT_STRUCT_STRING(p->mem_ctx,
2882 wbint_SidArray,
2883 r->in.require_membership_of_sid);
2884 DBG_NOTICE("User %s is not in the required groups:\n",
2885 r->in.user);
2886 DEBUGADD(DBGLVL_NOTICE, ("%s", s));
2887 DEBUGADD(DBGLVL_NOTICE,
2888 ("CRAP authentication is rejected\n"));
2889 goto done;
2892 if (!is_allowed_domain(info3->base.logon_domain.string)) {
2893 DBG_NOTICE("Authentication failed for user [%s] "
2894 "from firewalled domain [%s]\n",
2895 info3->base.account_name.string,
2896 info3->base.logon_domain.string);
2897 result = NT_STATUS_AUTHENTICATION_FIREWALL_FAILED;
2898 goto done;
2901 r->out.validation = talloc_zero(p->mem_ctx,
2902 struct wbint_PamAuthCrapValidation);
2903 if (r->out.validation == NULL) {
2904 result = NT_STATUS_NO_MEMORY;
2905 goto done;
2908 r->out.validation->level = validation_level;
2909 r->out.validation->validation = talloc_move(r->out.validation,
2910 &validation);
2911 done:
2913 if (r->in.flags & WBFLAG_PAM_NT_STATUS_SQUASH) {
2914 result = nt_status_squash(result);
2917 *r->out.authoritative = authoritative;
2920 * Log the winbind pam authentication, the logon_id will tie this to
2921 * any of the logons invoked from this request.
2923 log_authentication(
2924 p->mem_ctx,
2925 domain,
2926 r->in.client_name,
2927 client_pid,
2928 r->out.validation->level,
2929 r->out.validation->validation,
2930 start_time,
2931 logon_id,
2932 "NTLM_AUTH",
2933 r->in.user,
2934 r->in.domain,
2935 r->in.workstation,
2936 r->in.lm_resp,
2937 r->in.nt_resp,
2938 remote,
2939 local,
2940 result);
2942 return result;
2945 NTSTATUS _wbint_PamAuthChangePassword(struct pipes_struct *p,
2946 struct wbint_PamAuthChangePassword *r)
2948 struct winbindd_domain *contact_domain = wb_child_domain();
2949 struct policy_handle dom_pol;
2950 struct rpc_pipe_client *cli = NULL;
2951 bool got_info = false;
2952 struct samr_DomInfo1 *info = NULL;
2953 struct userPwdChangeFailureInformation *reject = NULL;
2954 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
2955 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
2956 char *namespace = NULL;
2957 char *domain = NULL;
2958 char *user = NULL;
2959 struct dcerpc_binding_handle *b = NULL;
2960 bool ok;
2961 pid_t client_pid;
2963 ZERO_STRUCT(dom_pol);
2965 if (contact_domain == NULL) {
2966 return NT_STATUS_REQUEST_NOT_ACCEPTED;
2969 /* Cut client_pid to 32bit */
2970 client_pid = r->in.client_pid;
2971 if ((uint64_t)client_pid != r->in.client_pid) {
2972 DBG_DEBUG("pid out of range\n");
2973 return NT_STATUS_INVALID_PARAMETER;
2976 DBG_NOTICE("[%"PRIu32"]: dual pam chauthtok %s\n",
2977 client_pid, r->in.user);
2979 ok = parse_domain_user(p->mem_ctx,
2980 r->in.user,
2981 &namespace,
2982 &domain,
2983 &user);
2984 if (!ok) {
2985 goto done;
2988 if (!is_allowed_domain(domain)) {
2989 DBG_NOTICE("Authentication failed for user [%s] "
2990 "from firewalled domain [%s]\n",
2991 user, domain);
2992 result = NT_STATUS_AUTHENTICATION_FIREWALL_FAILED;
2993 goto done;
2996 /* Initialize reject reason */
2997 *r->out.reject_reason = Undefined;
2999 /* Get sam handle */
3001 result = cm_connect_sam(contact_domain,
3002 p->mem_ctx,
3003 true,
3004 &cli,
3005 &dom_pol);
3006 if (!NT_STATUS_IS_OK(result)) {
3007 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
3008 goto done;
3011 b = cli->binding_handle;
3013 status = dcerpc_samr_chgpasswd_user4(cli->binding_handle,
3014 p->mem_ctx,
3015 cli->srv_name_slash,
3016 user,
3017 r->in.old_password,
3018 r->in.new_password,
3019 &result);
3020 if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(result)) {
3021 /* Password successfully changed. */
3022 goto done;
3024 if (!NT_STATUS_IS_OK(status)) {
3025 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE) ||
3026 NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED) ||
3027 NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
3028 /* DO NOT FALLBACK TO RC4 */
3029 if (lp_weak_crypto() == SAMBA_WEAK_CRYPTO_DISALLOWED) {
3030 result = NT_STATUS_STRONG_CRYPTO_NOT_SUPPORTED;
3031 goto process_result;
3034 } else {
3035 /* Password change was unsuccessful. */
3036 if (!NT_STATUS_IS_OK(result)) {
3037 goto done;
3041 result = rpccli_samr_chgpasswd_user3(cli,
3042 p->mem_ctx,
3043 user,
3044 r->in.new_password,
3045 r->in.old_password,
3046 &info,
3047 &reject);
3049 /* Windows 2003 returns NT_STATUS_PASSWORD_RESTRICTION */
3051 if (NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_RESTRICTION) ) {
3053 *r->out.dominfo = talloc_steal(p->mem_ctx, info);
3054 *r->out.reject_reason = reject->extendedFailureReason;
3056 got_info = true;
3059 /* atm the pidl generated rpccli_samr_ChangePasswordUser3 function will
3060 * return with NT_STATUS_BUFFER_TOO_SMALL for w2k dcs as w2k just
3061 * returns with 4byte error code (NT_STATUS_NOT_SUPPORTED) which is too
3062 * short to comply with the samr_ChangePasswordUser3 idl - gd */
3064 /* only fallback when the chgpasswd_user3 call is not supported */
3065 if (NT_STATUS_EQUAL(result, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE) ||
3066 NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED) ||
3067 NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL) ||
3068 NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
3070 DEBUG(10,("Password change with chgpasswd_user3 failed with: %s, retrying chgpasswd_user2\n",
3071 nt_errstr(result)));
3073 result = rpccli_samr_chgpasswd_user2(cli,
3074 p->mem_ctx,
3075 user,
3076 r->in.new_password,
3077 r->in.old_password);
3079 /* Windows 2000 returns NT_STATUS_ACCOUNT_RESTRICTION.
3080 Map to the same status code as Windows 2003. */
3082 if ( NT_STATUS_EQUAL(NT_STATUS_ACCOUNT_RESTRICTION, result ) ) {
3083 result = NT_STATUS_PASSWORD_RESTRICTION;
3087 done:
3089 if (NT_STATUS_IS_OK(result)
3090 && (r->in.flags & WBFLAG_PAM_CACHED_LOGIN)
3091 && lp_winbind_offline_logon()) {
3092 result = winbindd_update_creds_by_name(contact_domain, user,
3093 r->in.new_password);
3094 /* Again, this happens when we login from gdm or xdm
3095 * and the password expires, *BUT* cached credentials
3096 * don't exist. winbindd_update_creds_by_name()
3097 * returns NT_STATUS_NO_SUCH_USER.
3098 * This is not a failure.
3099 * --- BoYang
3100 * */
3101 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER)) {
3102 result = NT_STATUS_OK;
3105 if (!NT_STATUS_IS_OK(result)) {
3106 DEBUG(10, ("Failed to store creds: %s\n",
3107 nt_errstr(result)));
3108 goto process_result;
3112 if (!NT_STATUS_IS_OK(result) && !got_info && contact_domain) {
3114 NTSTATUS policy_ret;
3116 policy_ret = get_password_policy(contact_domain,
3117 p->mem_ctx,
3118 &info);
3120 /* failure of this is non critical, it will just provide no
3121 * additional information to the client why the change has
3122 * failed - Guenther */
3124 if (!NT_STATUS_IS_OK(policy_ret)) {
3125 DEBUG(10,("Failed to get password policies: %s\n", nt_errstr(policy_ret)));
3126 goto process_result;
3129 *r->out.dominfo = talloc_steal(p->mem_ctx, info);
3132 process_result:
3134 if (strequal(contact_domain->name, get_global_sam_name())) {
3135 /* FIXME: internal rpc pipe does not cache handles yet */
3136 if (b) {
3137 if (is_valid_policy_hnd(&dom_pol)) {
3138 NTSTATUS _result;
3139 dcerpc_samr_Close(b,
3140 p->mem_ctx,
3141 &dom_pol,
3142 &_result);
3144 TALLOC_FREE(cli);
3148 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
3149 ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
3150 domain,
3151 user,
3152 nt_errstr(result),
3153 nt_status_to_pam(result)));
3155 return result;
3158 NTSTATUS _wbint_PamLogOff(struct pipes_struct *p, struct wbint_PamLogOff *r)
3160 struct winbindd_domain *domain = wb_child_domain();
3161 NTSTATUS result = NT_STATUS_NOT_SUPPORTED;
3162 pid_t client_pid;
3163 uid_t user_uid;
3165 if (domain == NULL) {
3166 return NT_STATUS_REQUEST_NOT_ACCEPTED;
3169 /* Cut client_pid to 32bit */
3170 client_pid = r->in.client_pid;
3171 if ((uint64_t)client_pid != r->in.client_pid) {
3172 DBG_DEBUG("pid out of range\n");
3173 return NT_STATUS_INVALID_PARAMETER;
3176 /* Cut uid to 32bit */
3177 user_uid = r->in.uid;
3178 if ((uint64_t)user_uid != r->in.uid) {
3179 DBG_DEBUG("uid out of range\n");
3180 return NT_STATUS_INVALID_PARAMETER;
3183 DBG_NOTICE("[%"PRIu32"]: pam dual logoff %s\n", client_pid, r->in.user);
3185 if (!(r->in.flags & WBFLAG_PAM_KRB5)) {
3186 result = NT_STATUS_OK;
3187 goto process_result;
3190 if ((r->in.krb5ccname == NULL) || (strlen(r->in.krb5ccname) == 0)) {
3191 result = NT_STATUS_OK;
3192 goto process_result;
3195 #ifdef HAVE_KRB5
3197 if (user_uid == (uid_t)-1) {
3198 DBG_DEBUG("Invalid uid for user '%s'\n", r->in.user);
3199 goto process_result;
3202 /* what we need here is to find the corresponding krb5 ccache name *we*
3203 * created for a given username and destroy it */
3205 if (!ccache_entry_exists(r->in.user)) {
3206 result = NT_STATUS_OK;
3207 DBG_DEBUG("No entry found for user '%s'.\n", r->in.user);
3208 goto process_result;
3211 if (!ccache_entry_identical(r->in.user, user_uid, r->in.krb5ccname)) {
3212 DBG_DEBUG("Cached entry differs for user '%s'\n", r->in.user);
3213 goto process_result;
3216 result = remove_ccache(r->in.user);
3217 if (!NT_STATUS_IS_OK(result)) {
3218 DBG_DEBUG("Failed to remove ccache for user '%s': %s\n",
3219 r->in.user, nt_errstr(result));
3220 goto process_result;
3224 * Remove any mlock'ed memory creds in the child
3225 * we might be using for krb5 ticket renewal.
3228 winbindd_delete_memory_creds(r->in.user);
3230 #else
3231 result = NT_STATUS_NOT_SUPPORTED;
3232 #endif
3234 process_result:
3236 return result;
3239 /* Change user password with auth crap*/
3241 NTSTATUS _wbint_PamAuthCrapChangePassword(struct pipes_struct *p,
3242 struct wbint_PamAuthCrapChangePassword *r)
3244 NTSTATUS result;
3245 char *namespace = NULL;
3246 char *domain = NULL;
3247 char *user = NULL;
3248 struct policy_handle dom_pol;
3249 struct winbindd_domain *contact_domain = wb_child_domain();
3250 struct rpc_pipe_client *cli = NULL;
3251 struct dcerpc_binding_handle *b = NULL;
3252 TALLOC_CTX *frame = talloc_stackframe();
3253 pid_t client_pid;
3255 ZERO_STRUCT(dom_pol);
3257 if (contact_domain == NULL) {
3258 return NT_STATUS_REQUEST_NOT_ACCEPTED;
3261 /* Cut client_pid to 32bit */
3262 client_pid = r->in.client_pid;
3263 if ((uint64_t)client_pid != r->in.client_pid) {
3264 DBG_DEBUG("pid out of range\n");
3265 return NT_STATUS_INVALID_PARAMETER;
3268 DBG_NOTICE("[%"PRIu32"]: pam change pswd auth crap domain: %s "
3269 "user: %s\n", client_pid, r->in.domain, r->in.user);
3271 if (lp_winbind_offline_logon()) {
3272 DEBUG(0,("Refusing password change as winbind offline logons are enabled. "));
3273 DEBUGADD(0,("Changing passwords here would risk inconsistent logons\n"));
3274 result = NT_STATUS_ACCESS_DENIED;
3275 goto done;
3278 if (r->in.domain != NULL && strlen(r->in.domain) > 0) {
3279 user = talloc_strdup(frame, "");
3280 namespace = talloc_strdup(frame, "");
3281 domain = talloc_strdup(frame, r->in.domain);
3282 if (domain == NULL || user == NULL || namespace == NULL) {
3283 result = NT_STATUS_NO_MEMORY;
3284 goto done;
3287 } else {
3288 bool ok;
3290 ok = parse_domain_user(frame,
3291 r->in.user,
3292 &namespace,
3293 &domain,
3294 &user);
3295 if (!ok) {
3296 result = NT_STATUS_INVALID_PARAMETER;
3297 goto done;
3300 if (strlen(domain) == 0) {
3301 DBG_NOTICE("no domain specified with username (%s) - "
3302 "failing auth\n", r->in.user);
3303 result = NT_STATUS_NO_SUCH_USER;
3304 goto done;
3308 if (!*domain && lp_winbind_use_default_domain()) {
3309 TALLOC_FREE(domain);
3310 domain = talloc_strdup(frame, lp_workgroup());
3311 if (domain == NULL) {
3312 result = NT_STATUS_NO_MEMORY;
3313 goto done;
3317 if (!is_allowed_domain(domain)) {
3318 DBG_NOTICE("Authentication failed for user [%s] "
3319 "from firewalled domain [%s]\n",
3320 r->in.user,
3321 domain);
3322 result = NT_STATUS_AUTHENTICATION_FIREWALL_FAILED;
3323 goto done;
3326 if(!*user) {
3327 TALLOC_FREE(user);
3328 user = talloc_strdup(frame, r->in.user);
3329 if (user == NULL) {
3330 result = NT_STATUS_NO_SUCH_USER;
3331 goto done;
3335 /* Get sam handle */
3337 result = cm_connect_sam(contact_domain,
3338 p->mem_ctx,
3339 true,
3340 &cli,
3341 &dom_pol);
3342 if (!NT_STATUS_IS_OK(result)) {
3343 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
3344 goto done;
3347 b = cli->binding_handle;
3349 result = rpccli_samr_chng_pswd_auth_crap(cli,
3350 p->mem_ctx,
3351 user,
3352 r->in.new_nt_pswd,
3353 r->in.old_nt_hash_enc,
3354 r->in.new_lm_pswd,
3355 r->in.old_lm_hash_enc);
3357 done:
3359 if (strequal(contact_domain->name, get_global_sam_name())) {
3360 /* FIXME: internal rpc pipe does not cache handles yet */
3361 if (b) {
3362 if (is_valid_policy_hnd(&dom_pol)) {
3363 NTSTATUS _result;
3364 dcerpc_samr_Close(b,
3365 p->mem_ctx,
3366 &dom_pol,
3367 &_result);
3369 TALLOC_FREE(cli);
3373 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
3374 ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
3375 domain, user,
3376 nt_errstr(result),
3377 nt_status_to_pam(result)));
3378 TALLOC_FREE(frame);
3379 return result;
3382 #ifdef HAVE_KRB5
3383 static NTSTATUS extract_pac_vrfy_sigs(TALLOC_CTX *mem_ctx, DATA_BLOB pac_blob,
3384 struct PAC_DATA **p_pac_data)
3386 krb5_context krbctx = NULL;
3387 krb5_error_code k5ret;
3388 krb5_keytab keytab;
3389 krb5_kt_cursor cursor;
3390 krb5_keytab_entry entry;
3391 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
3393 ZERO_STRUCT(entry);
3394 ZERO_STRUCT(cursor);
3396 k5ret = smb_krb5_init_context_common(&krbctx);
3397 if (k5ret) {
3398 DBG_ERR("kerberos init context failed (%s)\n",
3399 error_message(k5ret));
3400 status = krb5_to_nt_status(k5ret);
3401 goto out;
3404 k5ret = gse_krb5_get_server_keytab(krbctx, &keytab);
3405 if (k5ret) {
3406 DEBUG(1, ("Failed to get keytab: %s\n",
3407 error_message(k5ret)));
3408 status = krb5_to_nt_status(k5ret);
3409 goto out_free;
3412 k5ret = krb5_kt_start_seq_get(krbctx, keytab, &cursor);
3413 if (k5ret) {
3414 DEBUG(1, ("Failed to start seq: %s\n",
3415 error_message(k5ret)));
3416 status = krb5_to_nt_status(k5ret);
3417 goto out_keytab;
3420 k5ret = krb5_kt_next_entry(krbctx, keytab, &entry, &cursor);
3421 while (k5ret == 0) {
3422 status = kerberos_decode_pac(mem_ctx,
3423 pac_blob,
3424 krbctx,
3425 NULL, /* krbtgt_keyblock */
3426 KRB5_KT_KEY(&entry), /* service_keyblock */
3427 NULL, /* client_principal */
3428 0, /* tgs_authtime */
3429 p_pac_data);
3430 (void)smb_krb5_kt_free_entry(krbctx, &entry);
3431 if (NT_STATUS_IS_OK(status)) {
3432 break;
3434 k5ret = krb5_kt_next_entry(krbctx, keytab, &entry, &cursor);
3436 if (k5ret != 0 && k5ret != KRB5_KT_END) {
3437 DEBUG(1, ("Failed to get next entry: %s\n",
3438 error_message(k5ret)));
3439 (void)smb_krb5_kt_free_entry(krbctx, &entry);
3442 k5ret = krb5_kt_end_seq_get(krbctx, keytab, &cursor);
3443 if (k5ret) {
3444 DEBUG(1, ("Failed to end seq: %s\n",
3445 error_message(k5ret)));
3447 out_keytab:
3448 k5ret = krb5_kt_close(krbctx, keytab);
3449 if (k5ret) {
3450 DEBUG(1, ("Failed to close keytab: %s\n",
3451 error_message(k5ret)));
3453 out_free:
3454 krb5_free_context(krbctx);
3455 out:
3456 return status;
3459 NTSTATUS winbindd_pam_auth_pac_verify(struct winbindd_cli_state *state,
3460 TALLOC_CTX *mem_ctx,
3461 bool *p_is_trusted,
3462 uint16_t *p_validation_level,
3463 union netr_Validation **p_validation)
3465 struct winbindd_request *req = state->request;
3466 DATA_BLOB pac_blob;
3467 struct PAC_DATA *pac_data = NULL;
3468 struct PAC_LOGON_INFO *logon_info = NULL;
3469 struct PAC_UPN_DNS_INFO *upn_dns_info = NULL;
3470 struct netr_SamInfo6 *info6 = NULL;
3471 uint16_t validation_level = 0;
3472 union netr_Validation *validation = NULL;
3473 struct netr_SamInfo3 *info3_copy = NULL;
3474 NTSTATUS result;
3475 bool is_trusted = false;
3476 uint32_t i;
3477 TALLOC_CTX *tmp_ctx = NULL;
3479 tmp_ctx = talloc_new(mem_ctx);
3480 if (tmp_ctx == NULL) {
3481 return NT_STATUS_NO_MEMORY;
3484 *p_is_trusted = false;
3485 *p_validation_level = 0;
3486 *p_validation = NULL;
3488 pac_blob = data_blob_const(req->extra_data.data, req->extra_len);
3489 result = extract_pac_vrfy_sigs(tmp_ctx, pac_blob, &pac_data);
3490 if (NT_STATUS_IS_OK(result)) {
3491 is_trusted = true;
3493 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
3494 /* Try without signature verification */
3495 result = kerberos_decode_pac(tmp_ctx,
3496 pac_blob,
3497 NULL, /* krb5_context */
3498 NULL, /* krbtgt_keyblock */
3499 NULL, /* service_keyblock */
3500 NULL, /* client_principal */
3501 0, /* tgs_authtime */
3502 &pac_data);
3504 if (!NT_STATUS_IS_OK(result)) {
3505 DEBUG(1, ("Error during PAC signature verification: %s\n",
3506 nt_errstr(result)));
3507 goto out;
3510 for (i=0; i < pac_data->num_buffers; i++) {
3511 if (pac_data->buffers[i].type == PAC_TYPE_LOGON_INFO) {
3512 logon_info = pac_data->buffers[i].info->logon_info.info;
3513 continue;
3515 if (pac_data->buffers[i].type == PAC_TYPE_UPN_DNS_INFO) {
3516 upn_dns_info = &pac_data->buffers[i].info->upn_dns_info;
3517 continue;
3521 result = create_info6_from_pac(tmp_ctx,
3522 logon_info,
3523 upn_dns_info,
3524 &info6);
3525 if (!NT_STATUS_IS_OK(result)) {
3526 goto out;
3529 if (!is_allowed_domain(info6->base.logon_domain.string)) {
3530 DBG_NOTICE("Authentication failed for user [%s] "
3531 "from firewalled domain [%s]\n",
3532 info6->base.account_name.string,
3533 info6->base.logon_domain.string);
3534 result = NT_STATUS_AUTHENTICATION_FIREWALL_FAILED;
3535 goto out;
3538 result = map_info6_to_validation(tmp_ctx,
3539 info6,
3540 &validation_level,
3541 &validation);
3542 if (!NT_STATUS_IS_OK(result)) {
3543 goto out;
3546 result = map_validation_to_info3(tmp_ctx,
3547 validation_level,
3548 validation,
3549 &info3_copy);
3550 if (!NT_STATUS_IS_OK(result)) {
3551 goto out;
3554 if (is_trusted) {
3556 * Signature verification succeeded, we can
3557 * trust the PAC and prime the netsamlogon
3558 * and name2sid caches. DO NOT DO THIS
3559 * in the signature verification failed
3560 * code path.
3562 struct winbindd_domain *domain = NULL;
3564 netsamlogon_cache_store(NULL, info3_copy);
3567 * We're in the parent here, so find the child
3568 * pointer from the PAC domain name.
3570 domain = find_lookup_domain_from_name(
3571 info3_copy->base.logon_domain.string);
3572 if (domain && domain->primary ) {
3573 struct dom_sid user_sid;
3574 struct dom_sid_buf buf;
3576 sid_compose(&user_sid,
3577 info3_copy->base.domain_sid,
3578 info3_copy->base.rid);
3580 cache_name2sid_trusted(domain,
3581 info3_copy->base.logon_domain.string,
3582 info3_copy->base.account_name.string,
3583 SID_NAME_USER,
3584 &user_sid);
3586 DBG_INFO("PAC for user %s\\%s SID %s primed cache\n",
3587 info3_copy->base.logon_domain.string,
3588 info3_copy->base.account_name.string,
3589 dom_sid_str_buf(&user_sid, &buf));
3593 *p_is_trusted = is_trusted;
3594 *p_validation_level = validation_level;
3595 *p_validation = talloc_move(mem_ctx, &validation);
3597 result = NT_STATUS_OK;
3598 out:
3599 TALLOC_FREE(tmp_ctx);
3600 return result;
3602 #else /* HAVE_KRB5 */
3603 NTSTATUS winbindd_pam_auth_pac_verify(struct winbindd_cli_state *state,
3604 TALLOC_CTX *mem_ctx,
3605 bool *p_is_trusted,
3606 uint16_t *p_validation_level,
3607 union netr_Validation **p_validation);
3610 *p_is_trusted = false;
3611 *p_validation_level = 0;
3612 *p_validation = NULL;
3613 return NT_STATUS_NO_SUCH_USER;
3615 #endif /* HAVE_KRB5 */