idl: Merge NETR_TRUST and LSA_TRUST definitions into one set only in lsa.idl
[Samba.git] / source3 / winbindd / winbindd_pam.c
blob51dc2ea4f6692b75da24a55c608b2843290010f8
1 /*
2 Unix SMB/CIFS implementation.
4 Winbind daemon - pam auth funcions
6 Copyright (C) Andrew Tridgell 2000
7 Copyright (C) Tim Potter 2001
8 Copyright (C) Andrew Bartlett 2001-2002
9 Copyright (C) Guenther Deschner 2005
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "includes.h"
26 #include "winbindd.h"
27 #include "../libcli/auth/libcli_auth.h"
28 #include "../librpc/gen_ndr/ndr_samr_c.h"
29 #include "rpc_client/cli_pipe.h"
30 #include "rpc_client/cli_samr.h"
31 #include "../librpc/gen_ndr/ndr_netlogon.h"
32 #include "rpc_client/cli_netlogon.h"
33 #include "smb_krb5.h"
34 #include "../lib/crypto/arcfour.h"
35 #include "../libcli/security/security.h"
36 #include "ads.h"
37 #include "../librpc/gen_ndr/krb5pac.h"
38 #include "passdb/machine_sid.h"
39 #include "auth.h"
40 #include "../lib/tsocket/tsocket.h"
41 #include "auth/kerberos/pac_utils.h"
42 #include "auth/gensec/gensec.h"
43 #include "librpc/crypto/gse_krb5.h"
44 #include "lib/afs/afs_funcs.h"
46 #undef DBGC_CLASS
47 #define DBGC_CLASS DBGC_WINBIND
49 #define LOGON_KRB5_FAIL_CLOCK_SKEW 0x02000000
51 static NTSTATUS append_info3_as_txt(TALLOC_CTX *mem_ctx,
52 struct winbindd_response *resp,
53 struct netr_SamInfo3 *info3)
55 char *ex;
56 uint32_t i;
58 resp->data.auth.info3.logon_time =
59 nt_time_to_unix(info3->base.logon_time);
60 resp->data.auth.info3.logoff_time =
61 nt_time_to_unix(info3->base.logoff_time);
62 resp->data.auth.info3.kickoff_time =
63 nt_time_to_unix(info3->base.kickoff_time);
64 resp->data.auth.info3.pass_last_set_time =
65 nt_time_to_unix(info3->base.last_password_change);
66 resp->data.auth.info3.pass_can_change_time =
67 nt_time_to_unix(info3->base.allow_password_change);
68 resp->data.auth.info3.pass_must_change_time =
69 nt_time_to_unix(info3->base.force_password_change);
71 resp->data.auth.info3.logon_count = info3->base.logon_count;
72 resp->data.auth.info3.bad_pw_count = info3->base.bad_password_count;
74 resp->data.auth.info3.user_rid = info3->base.rid;
75 resp->data.auth.info3.group_rid = info3->base.primary_gid;
76 sid_to_fstring(resp->data.auth.info3.dom_sid, info3->base.domain_sid);
78 resp->data.auth.info3.num_groups = info3->base.groups.count;
79 resp->data.auth.info3.user_flgs = info3->base.user_flags;
81 resp->data.auth.info3.acct_flags = info3->base.acct_flags;
82 resp->data.auth.info3.num_other_sids = info3->sidcount;
84 fstrcpy(resp->data.auth.info3.user_name,
85 info3->base.account_name.string);
86 fstrcpy(resp->data.auth.info3.full_name,
87 info3->base.full_name.string);
88 fstrcpy(resp->data.auth.info3.logon_script,
89 info3->base.logon_script.string);
90 fstrcpy(resp->data.auth.info3.profile_path,
91 info3->base.profile_path.string);
92 fstrcpy(resp->data.auth.info3.home_dir,
93 info3->base.home_directory.string);
94 fstrcpy(resp->data.auth.info3.dir_drive,
95 info3->base.home_drive.string);
97 fstrcpy(resp->data.auth.info3.logon_srv,
98 info3->base.logon_server.string);
99 fstrcpy(resp->data.auth.info3.logon_dom,
100 info3->base.logon_domain.string);
102 ex = talloc_strdup(mem_ctx, "");
103 NT_STATUS_HAVE_NO_MEMORY(ex);
105 for (i=0; i < info3->base.groups.count; i++) {
106 ex = talloc_asprintf_append_buffer(ex, "0x%08X:0x%08X\n",
107 info3->base.groups.rids[i].rid,
108 info3->base.groups.rids[i].attributes);
109 NT_STATUS_HAVE_NO_MEMORY(ex);
112 for (i=0; i < info3->sidcount; i++) {
113 char *sid;
115 sid = dom_sid_string(mem_ctx, info3->sids[i].sid);
116 NT_STATUS_HAVE_NO_MEMORY(sid);
118 ex = talloc_asprintf_append_buffer(ex, "%s:0x%08X\n",
119 sid,
120 info3->sids[i].attributes);
121 NT_STATUS_HAVE_NO_MEMORY(ex);
123 talloc_free(sid);
126 resp->extra_data.data = ex;
127 resp->length += talloc_get_size(ex);
129 return NT_STATUS_OK;
132 static NTSTATUS append_info3_as_ndr(TALLOC_CTX *mem_ctx,
133 struct winbindd_response *resp,
134 struct netr_SamInfo3 *info3)
136 DATA_BLOB blob;
137 enum ndr_err_code ndr_err;
139 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, info3,
140 (ndr_push_flags_fn_t)ndr_push_netr_SamInfo3);
141 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
142 DEBUG(0,("append_info3_as_ndr: failed to append\n"));
143 return ndr_map_error2ntstatus(ndr_err);
146 resp->extra_data.data = blob.data;
147 resp->length += blob.length;
149 return NT_STATUS_OK;
152 static NTSTATUS append_unix_username(TALLOC_CTX *mem_ctx,
153 struct winbindd_response *resp,
154 const struct netr_SamInfo3 *info3,
155 const char *name_domain,
156 const char *name_user)
158 /* We've been asked to return the unix username, per
159 'winbind use default domain' settings and the like */
161 const char *nt_username, *nt_domain;
163 nt_domain = talloc_strdup(mem_ctx, info3->base.logon_domain.string);
164 if (!nt_domain) {
165 /* If the server didn't give us one, just use the one
166 * we sent them */
167 nt_domain = name_domain;
170 nt_username = talloc_strdup(mem_ctx, info3->base.account_name.string);
171 if (!nt_username) {
172 /* If the server didn't give us one, just use the one
173 * we sent them */
174 nt_username = name_user;
177 fill_domain_username(resp->data.auth.unix_username,
178 nt_domain, nt_username, true);
180 DEBUG(5, ("Setting unix username to [%s]\n",
181 resp->data.auth.unix_username));
183 return NT_STATUS_OK;
186 static NTSTATUS append_afs_token(TALLOC_CTX *mem_ctx,
187 struct winbindd_response *resp,
188 const struct netr_SamInfo3 *info3,
189 const char *name_domain,
190 const char *name_user)
192 char *afsname = NULL;
193 char *cell;
194 char *token;
196 afsname = talloc_strdup(mem_ctx, lp_afs_username_map());
197 if (afsname == NULL) {
198 return NT_STATUS_NO_MEMORY;
201 afsname = talloc_string_sub(mem_ctx,
202 lp_afs_username_map(),
203 "%D", name_domain);
204 afsname = talloc_string_sub(mem_ctx, afsname,
205 "%u", name_user);
206 afsname = talloc_string_sub(mem_ctx, afsname,
207 "%U", name_user);
210 struct dom_sid user_sid;
211 fstring sidstr;
213 sid_compose(&user_sid, info3->base.domain_sid,
214 info3->base.rid);
215 sid_to_fstring(sidstr, &user_sid);
216 afsname = talloc_string_sub(mem_ctx, afsname,
217 "%s", sidstr);
220 if (afsname == NULL) {
221 return NT_STATUS_NO_MEMORY;
224 if (!strlower_m(afsname)) {
225 return NT_STATUS_INVALID_PARAMETER;
228 DEBUG(10, ("Generating token for user %s\n", afsname));
230 cell = strchr(afsname, '@');
232 if (cell == NULL) {
233 return NT_STATUS_NO_MEMORY;
236 *cell = '\0';
237 cell += 1;
239 token = afs_createtoken_str(afsname, cell);
240 if (token == NULL) {
241 return NT_STATUS_OK;
243 resp->extra_data.data = talloc_strdup(mem_ctx, token);
244 if (resp->extra_data.data == NULL) {
245 return NT_STATUS_NO_MEMORY;
247 resp->length += strlen((const char *)resp->extra_data.data)+1;
249 return NT_STATUS_OK;
252 static NTSTATUS check_info3_in_group(struct netr_SamInfo3 *info3,
253 const char *group_sid)
255 * Check whether a user belongs to a group or list of groups.
257 * @param mem_ctx talloc memory context.
258 * @param info3 user information, including group membership info.
259 * @param group_sid One or more groups , separated by commas.
261 * @return NT_STATUS_OK on success,
262 * NT_STATUS_LOGON_FAILURE if the user does not belong,
263 * or other NT_STATUS_IS_ERR(status) for other kinds of failure.
266 struct dom_sid *require_membership_of_sid;
267 uint32_t num_require_membership_of_sid;
268 char *req_sid;
269 const char *p;
270 struct dom_sid sid;
271 size_t i;
272 struct security_token *token;
273 TALLOC_CTX *frame = talloc_stackframe();
274 NTSTATUS status;
276 /* Parse the 'required group' SID */
278 if (!group_sid || !group_sid[0]) {
279 /* NO sid supplied, all users may access */
280 TALLOC_FREE(frame);
281 return NT_STATUS_OK;
284 token = talloc_zero(talloc_tos(), struct security_token);
285 if (token == NULL) {
286 DEBUG(0, ("talloc failed\n"));
287 TALLOC_FREE(frame);
288 return NT_STATUS_NO_MEMORY;
291 num_require_membership_of_sid = 0;
292 require_membership_of_sid = NULL;
294 p = group_sid;
296 while (next_token_talloc(talloc_tos(), &p, &req_sid, ",")) {
297 if (!string_to_sid(&sid, req_sid)) {
298 DEBUG(0, ("check_info3_in_group: could not parse %s "
299 "as a SID!", req_sid));
300 TALLOC_FREE(frame);
301 return NT_STATUS_INVALID_PARAMETER;
304 status = add_sid_to_array(talloc_tos(), &sid,
305 &require_membership_of_sid,
306 &num_require_membership_of_sid);
307 if (!NT_STATUS_IS_OK(status)) {
308 DEBUG(0, ("add_sid_to_array failed\n"));
309 TALLOC_FREE(frame);
310 return status;
314 status = sid_array_from_info3(talloc_tos(), info3,
315 &token->sids,
316 &token->num_sids,
317 true);
318 if (!NT_STATUS_IS_OK(status)) {
319 TALLOC_FREE(frame);
320 return status;
323 if (!NT_STATUS_IS_OK(status = add_aliases(get_global_sam_sid(),
324 token))
325 || !NT_STATUS_IS_OK(status = add_aliases(&global_sid_Builtin,
326 token))) {
327 DEBUG(3, ("could not add aliases: %s\n",
328 nt_errstr(status)));
329 TALLOC_FREE(frame);
330 return status;
333 security_token_debug(DBGC_CLASS, 10, token);
335 for (i=0; i<num_require_membership_of_sid; i++) {
336 DEBUG(10, ("Checking SID %s\n", sid_string_dbg(
337 &require_membership_of_sid[i])));
338 if (nt_token_check_sid(&require_membership_of_sid[i],
339 token)) {
340 DEBUG(10, ("Access ok\n"));
341 TALLOC_FREE(frame);
342 return NT_STATUS_OK;
346 /* Do not distinguish this error from a wrong username/pw */
348 TALLOC_FREE(frame);
349 return NT_STATUS_LOGON_FAILURE;
352 struct winbindd_domain *find_auth_domain(uint8_t flags,
353 const char *domain_name)
355 struct winbindd_domain *domain;
357 if (IS_DC) {
358 domain = find_domain_from_name_noinit(domain_name);
359 if (domain == NULL) {
360 DEBUG(3, ("Authentication for domain [%s] refused "
361 "as it is not a trusted domain\n",
362 domain_name));
364 return domain;
367 if (strequal(domain_name, get_global_sam_name())) {
368 return find_domain_from_name_noinit(domain_name);
371 /* we can auth against trusted domains */
372 if (flags & WBFLAG_PAM_CONTACT_TRUSTDOM) {
373 domain = find_domain_from_name_noinit(domain_name);
374 if (domain == NULL) {
375 DEBUG(3, ("Authentication for domain [%s] skipped "
376 "as it is not a trusted domain\n",
377 domain_name));
378 } else {
379 return domain;
383 return find_our_domain();
386 static void fill_in_password_policy(struct winbindd_response *r,
387 const struct samr_DomInfo1 *p)
389 r->data.auth.policy.min_length_password =
390 p->min_password_length;
391 r->data.auth.policy.password_history =
392 p->password_history_length;
393 r->data.auth.policy.password_properties =
394 p->password_properties;
395 r->data.auth.policy.expire =
396 nt_time_to_unix_abs((const NTTIME *)&(p->max_password_age));
397 r->data.auth.policy.min_passwordage =
398 nt_time_to_unix_abs((const NTTIME *)&(p->min_password_age));
401 static NTSTATUS fillup_password_policy(struct winbindd_domain *domain,
402 struct winbindd_response *response)
404 TALLOC_CTX *frame = talloc_stackframe();
405 struct winbindd_methods *methods;
406 NTSTATUS status;
407 struct samr_DomInfo1 password_policy;
409 if ( !winbindd_can_contact_domain( domain ) ) {
410 DEBUG(5,("fillup_password_policy: No inbound trust to "
411 "contact domain %s\n", domain->name));
412 status = NT_STATUS_NOT_SUPPORTED;
413 goto done;
416 methods = domain->methods;
418 status = methods->password_policy(domain, talloc_tos(), &password_policy);
419 if (NT_STATUS_IS_ERR(status)) {
420 goto done;
423 fill_in_password_policy(response, &password_policy);
425 done:
426 TALLOC_FREE(frame);
427 return NT_STATUS_OK;
430 static NTSTATUS get_max_bad_attempts_from_lockout_policy(struct winbindd_domain *domain,
431 TALLOC_CTX *mem_ctx,
432 uint16 *lockout_threshold)
434 struct winbindd_methods *methods;
435 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
436 struct samr_DomInfo12 lockout_policy;
438 *lockout_threshold = 0;
440 methods = domain->methods;
442 status = methods->lockout_policy(domain, mem_ctx, &lockout_policy);
443 if (NT_STATUS_IS_ERR(status)) {
444 return status;
447 *lockout_threshold = lockout_policy.lockout_threshold;
449 return NT_STATUS_OK;
452 static NTSTATUS get_pwd_properties(struct winbindd_domain *domain,
453 TALLOC_CTX *mem_ctx,
454 uint32 *password_properties)
456 struct winbindd_methods *methods;
457 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
458 struct samr_DomInfo1 password_policy;
460 *password_properties = 0;
462 methods = domain->methods;
464 status = methods->password_policy(domain, mem_ctx, &password_policy);
465 if (NT_STATUS_IS_ERR(status)) {
466 return status;
469 *password_properties = password_policy.password_properties;
471 return NT_STATUS_OK;
474 #ifdef HAVE_KRB5
476 static const char *generate_krb5_ccache(TALLOC_CTX *mem_ctx,
477 const char *type,
478 uid_t uid,
479 const char **user_ccache_file)
481 /* accept FILE and WRFILE as krb5_cc_type from the client and then
482 * build the full ccname string based on the user's uid here -
483 * Guenther*/
485 const char *gen_cc = NULL;
487 if (uid != -1) {
488 if (strequal(type, "FILE")) {
489 gen_cc = talloc_asprintf(
490 mem_ctx, "FILE:/tmp/krb5cc_%d", uid);
492 if (strequal(type, "WRFILE")) {
493 gen_cc = talloc_asprintf(
494 mem_ctx, "WRFILE:/tmp/krb5cc_%d", uid);
496 if (strequal(type, "KEYRING")) {
497 gen_cc = talloc_asprintf(
498 mem_ctx, "KEYRING:persistent:%d", uid);
501 if (strnequal(type, "FILE:/", 6) ||
502 strnequal(type, "WRFILE:/", 8) ||
503 strnequal(type, "DIR:/", 5)) {
505 /* we allow only one "%u" substitution */
507 char *p;
509 p = strchr(type, '%');
510 if (p != NULL) {
512 p++;
514 if (p != NULL && *p == 'u' && strchr(p, '%') == NULL) {
515 gen_cc = talloc_asprintf(mem_ctx, type, uid);
521 *user_ccache_file = gen_cc;
523 if (gen_cc == NULL) {
524 gen_cc = talloc_strdup(mem_ctx, "MEMORY:winbindd_pam_ccache");
526 if (gen_cc == NULL) {
527 DEBUG(0,("out of memory\n"));
528 return NULL;
531 DEBUG(10, ("using ccache: %s%s\n", gen_cc,
532 (*user_ccache_file == NULL) ? " (internal)":""));
534 return gen_cc;
537 #endif
539 uid_t get_uid_from_request(struct winbindd_request *request)
541 uid_t uid;
543 uid = request->data.auth.uid;
545 if (uid < 0) {
546 DEBUG(1,("invalid uid: '%u'\n", (unsigned int)uid));
547 return -1;
549 return uid;
552 /**********************************************************************
553 Authenticate a user with a clear text password using Kerberos and fill up
554 ccache if required
555 **********************************************************************/
557 static NTSTATUS winbindd_raw_kerberos_login(TALLOC_CTX *mem_ctx,
558 struct winbindd_domain *domain,
559 const char *user,
560 const char *pass,
561 const char *krb5_cc_type,
562 uid_t uid,
563 struct netr_SamInfo3 **info3,
564 fstring krb5ccname)
566 #ifdef HAVE_KRB5
567 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
568 krb5_error_code krb5_ret;
569 const char *cc = NULL;
570 const char *principal_s = NULL;
571 const char *service = NULL;
572 char *realm = NULL;
573 fstring name_domain, name_user;
574 time_t ticket_lifetime = 0;
575 time_t renewal_until = 0;
576 ADS_STRUCT *ads;
577 time_t time_offset = 0;
578 const char *user_ccache_file;
579 struct PAC_LOGON_INFO *logon_info = NULL;
580 struct PAC_DATA *pac_data = NULL;
581 struct PAC_DATA_CTR *pac_data_ctr = NULL;
582 const char *local_service;
583 int i;
585 *info3 = NULL;
587 if (domain->alt_name == NULL) {
588 return NT_STATUS_INVALID_PARAMETER;
591 /* 1st step:
592 * prepare a krb5_cc_cache string for the user */
594 if (uid == -1) {
595 DEBUG(0,("no valid uid\n"));
598 cc = generate_krb5_ccache(mem_ctx,
599 krb5_cc_type,
600 uid,
601 &user_ccache_file);
602 if (cc == NULL) {
603 return NT_STATUS_NO_MEMORY;
607 /* 2nd step:
608 * get kerberos properties */
610 if (domain->private_data) {
611 ads = (ADS_STRUCT *)domain->private_data;
612 time_offset = ads->auth.time_offset;
616 /* 3rd step:
617 * do kerberos auth and setup ccache as the user */
619 parse_domain_user(user, name_domain, name_user);
621 realm = talloc_strdup(mem_ctx, domain->alt_name);
622 if (realm == NULL) {
623 return NT_STATUS_NO_MEMORY;
626 if (!strupper_m(realm)) {
627 return NT_STATUS_INVALID_PARAMETER;
630 principal_s = talloc_asprintf(mem_ctx, "%s@%s", name_user, realm);
631 if (principal_s == NULL) {
632 return NT_STATUS_NO_MEMORY;
635 service = talloc_asprintf(mem_ctx, "%s/%s@%s", KRB5_TGS_NAME, realm, realm);
636 if (service == NULL) {
637 return NT_STATUS_NO_MEMORY;
640 local_service = talloc_asprintf(mem_ctx, "%s$@%s",
641 lp_netbios_name(), lp_realm());
642 if (local_service == NULL) {
643 return NT_STATUS_NO_MEMORY;
647 /* if this is a user ccache, we need to act as the user to let the krb5
648 * library handle the chown, etc. */
650 /************************ ENTERING NON-ROOT **********************/
652 if (user_ccache_file != NULL) {
653 set_effective_uid(uid);
654 DEBUG(10,("winbindd_raw_kerberos_login: uid is %d\n", uid));
657 result = kerberos_return_pac(mem_ctx,
658 principal_s,
659 pass,
660 time_offset,
661 &ticket_lifetime,
662 &renewal_until,
664 true,
665 true,
666 WINBINDD_PAM_AUTH_KRB5_RENEW_TIME,
667 NULL,
668 local_service,
669 &pac_data_ctr);
670 if (user_ccache_file != NULL) {
671 gain_root_privilege();
674 /************************ RETURNED TO ROOT **********************/
676 if (!NT_STATUS_IS_OK(result)) {
677 goto failed;
680 if (pac_data_ctr == NULL) {
681 goto failed;
684 pac_data = pac_data_ctr->pac_data;
685 if (pac_data == NULL) {
686 goto failed;
689 for (i=0; i < pac_data->num_buffers; i++) {
691 if (pac_data->buffers[i].type != PAC_TYPE_LOGON_INFO) {
692 continue;
695 logon_info = pac_data->buffers[i].info->logon_info.info;
696 if (!logon_info) {
697 return NT_STATUS_INVALID_PARAMETER;
700 break;
703 *info3 = &logon_info->info3;
705 DEBUG(10,("winbindd_raw_kerberos_login: winbindd validated ticket of %s\n",
706 principal_s));
708 /* if we had a user's ccache then return that string for the pam
709 * environment */
711 if (user_ccache_file != NULL) {
713 fstrcpy(krb5ccname, user_ccache_file);
715 result = add_ccache_to_list(principal_s,
717 service,
718 user,
719 pass,
720 realm,
721 uid,
722 time(NULL),
723 ticket_lifetime,
724 renewal_until,
725 false);
727 if (!NT_STATUS_IS_OK(result)) {
728 DEBUG(10,("winbindd_raw_kerberos_login: failed to add ccache to list: %s\n",
729 nt_errstr(result)));
731 } else {
733 /* need to delete the memory cred cache, it is not used anymore */
735 krb5_ret = ads_kdestroy(cc);
736 if (krb5_ret) {
737 DEBUG(3,("winbindd_raw_kerberos_login: "
738 "could not destroy krb5 credential cache: "
739 "%s\n", error_message(krb5_ret)));
744 return NT_STATUS_OK;
746 failed:
748 * Do not delete an existing valid credential cache, if the user
749 * e.g. enters a wrong password
751 if ((strequal(krb5_cc_type, "FILE") || strequal(krb5_cc_type, "WRFILE"))
752 && user_ccache_file != NULL) {
753 return result;
756 /* we could have created a new credential cache with a valid tgt in it
757 * but we werent able to get or verify the service ticket for this
758 * local host and therefor didn't get the PAC, we need to remove that
759 * cache entirely now */
761 krb5_ret = ads_kdestroy(cc);
762 if (krb5_ret) {
763 DEBUG(3,("winbindd_raw_kerberos_login: "
764 "could not destroy krb5 credential cache: "
765 "%s\n", error_message(krb5_ret)));
768 if (!NT_STATUS_IS_OK(remove_ccache(user))) {
769 DEBUG(3,("winbindd_raw_kerberos_login: "
770 "could not remove ccache for user %s\n",
771 user));
774 return result;
775 #else
776 return NT_STATUS_NOT_SUPPORTED;
777 #endif /* HAVE_KRB5 */
780 /****************************************************************
781 ****************************************************************/
783 bool check_request_flags(uint32_t flags)
785 uint32_t flags_edata = WBFLAG_PAM_AFS_TOKEN |
786 WBFLAG_PAM_INFO3_TEXT |
787 WBFLAG_PAM_INFO3_NDR;
789 if ( ( (flags & flags_edata) == WBFLAG_PAM_AFS_TOKEN) ||
790 ( (flags & flags_edata) == WBFLAG_PAM_INFO3_NDR) ||
791 ( (flags & flags_edata) == WBFLAG_PAM_INFO3_TEXT)||
792 !(flags & flags_edata) ) {
793 return true;
796 DEBUG(1, ("check_request_flags: invalid request flags[0x%08X]\n",
797 flags));
799 return false;
802 /****************************************************************
803 ****************************************************************/
805 NTSTATUS append_auth_data(TALLOC_CTX *mem_ctx,
806 struct winbindd_response *resp,
807 uint32_t request_flags,
808 struct netr_SamInfo3 *info3,
809 const char *name_domain,
810 const char *name_user)
812 NTSTATUS result;
814 if (request_flags & WBFLAG_PAM_USER_SESSION_KEY) {
815 memcpy(resp->data.auth.user_session_key,
816 info3->base.key.key,
817 sizeof(resp->data.auth.user_session_key)
818 /* 16 */);
821 if (request_flags & WBFLAG_PAM_LMKEY) {
822 memcpy(resp->data.auth.first_8_lm_hash,
823 info3->base.LMSessKey.key,
824 sizeof(resp->data.auth.first_8_lm_hash)
825 /* 8 */);
828 if (request_flags & WBFLAG_PAM_UNIX_NAME) {
829 result = append_unix_username(mem_ctx, resp,
830 info3, name_domain, name_user);
831 if (!NT_STATUS_IS_OK(result)) {
832 DEBUG(10,("Failed to append Unix Username: %s\n",
833 nt_errstr(result)));
834 return result;
838 /* currently, anything from here on potentially overwrites extra_data. */
840 if (request_flags & WBFLAG_PAM_INFO3_NDR) {
841 result = append_info3_as_ndr(mem_ctx, resp, info3);
842 if (!NT_STATUS_IS_OK(result)) {
843 DEBUG(10,("Failed to append INFO3 (NDR): %s\n",
844 nt_errstr(result)));
845 return result;
849 if (request_flags & WBFLAG_PAM_INFO3_TEXT) {
850 result = append_info3_as_txt(mem_ctx, resp, info3);
851 if (!NT_STATUS_IS_OK(result)) {
852 DEBUG(10,("Failed to append INFO3 (TXT): %s\n",
853 nt_errstr(result)));
854 return result;
858 if (request_flags & WBFLAG_PAM_AFS_TOKEN) {
859 result = append_afs_token(mem_ctx, resp,
860 info3, name_domain, name_user);
861 if (!NT_STATUS_IS_OK(result)) {
862 DEBUG(10,("Failed to append AFS token: %s\n",
863 nt_errstr(result)));
864 return result;
868 return NT_STATUS_OK;
871 static NTSTATUS winbindd_dual_pam_auth_cached(struct winbindd_domain *domain,
872 struct winbindd_cli_state *state,
873 struct netr_SamInfo3 **info3)
875 NTSTATUS result = NT_STATUS_LOGON_FAILURE;
876 uint16 max_allowed_bad_attempts;
877 fstring name_domain, name_user;
878 struct dom_sid sid;
879 enum lsa_SidType type;
880 uchar new_nt_pass[NT_HASH_LEN];
881 const uint8 *cached_nt_pass;
882 const uint8 *cached_salt;
883 struct netr_SamInfo3 *my_info3;
884 time_t kickoff_time, must_change_time;
885 bool password_good = false;
886 #ifdef HAVE_KRB5
887 struct winbindd_tdc_domain *tdc_domain = NULL;
888 #endif
890 *info3 = NULL;
892 ZERO_STRUCTP(info3);
894 DEBUG(10,("winbindd_dual_pam_auth_cached\n"));
896 /* Parse domain and username */
898 parse_domain_user(state->request->data.auth.user, name_domain, name_user);
901 if (!lookup_cached_name(name_domain,
902 name_user,
903 &sid,
904 &type)) {
905 DEBUG(10,("winbindd_dual_pam_auth_cached: no such user in the cache\n"));
906 return NT_STATUS_NO_SUCH_USER;
909 if (type != SID_NAME_USER) {
910 DEBUG(10,("winbindd_dual_pam_auth_cached: not a user (%s)\n", sid_type_lookup(type)));
911 return NT_STATUS_LOGON_FAILURE;
914 result = winbindd_get_creds(domain,
915 state->mem_ctx,
916 &sid,
917 &my_info3,
918 &cached_nt_pass,
919 &cached_salt);
920 if (!NT_STATUS_IS_OK(result)) {
921 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get creds: %s\n", nt_errstr(result)));
922 return result;
925 *info3 = my_info3;
927 E_md4hash(state->request->data.auth.pass, new_nt_pass);
929 dump_data_pw("new_nt_pass", new_nt_pass, NT_HASH_LEN);
930 dump_data_pw("cached_nt_pass", cached_nt_pass, NT_HASH_LEN);
931 if (cached_salt) {
932 dump_data_pw("cached_salt", cached_salt, NT_HASH_LEN);
935 if (cached_salt) {
936 /* In this case we didn't store the nt_hash itself,
937 but the MD5 combination of salt + nt_hash. */
938 uchar salted_hash[NT_HASH_LEN];
939 E_md5hash(cached_salt, new_nt_pass, salted_hash);
941 password_good = (memcmp(cached_nt_pass, salted_hash,
942 NT_HASH_LEN) == 0);
943 } else {
944 /* Old cached cred - direct store of nt_hash (bad bad bad !). */
945 password_good = (memcmp(cached_nt_pass, new_nt_pass,
946 NT_HASH_LEN) == 0);
949 if (password_good) {
951 /* User *DOES* know the password, update logon_time and reset
952 * bad_pw_count */
954 my_info3->base.user_flags |= NETLOGON_CACHED_ACCOUNT;
956 if (my_info3->base.acct_flags & ACB_AUTOLOCK) {
957 return NT_STATUS_ACCOUNT_LOCKED_OUT;
960 if (my_info3->base.acct_flags & ACB_DISABLED) {
961 return NT_STATUS_ACCOUNT_DISABLED;
964 if (my_info3->base.acct_flags & ACB_WSTRUST) {
965 return NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
968 if (my_info3->base.acct_flags & ACB_SVRTRUST) {
969 return NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT;
972 if (my_info3->base.acct_flags & ACB_DOMTRUST) {
973 return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT;
976 if (!(my_info3->base.acct_flags & ACB_NORMAL)) {
977 DEBUG(0,("winbindd_dual_pam_auth_cached: whats wrong with that one?: 0x%08x\n",
978 my_info3->base.acct_flags));
979 return NT_STATUS_LOGON_FAILURE;
982 kickoff_time = nt_time_to_unix(my_info3->base.kickoff_time);
983 if (kickoff_time != 0 && time(NULL) > kickoff_time) {
984 return NT_STATUS_ACCOUNT_EXPIRED;
987 must_change_time = nt_time_to_unix(my_info3->base.force_password_change);
988 if (must_change_time != 0 && must_change_time < time(NULL)) {
989 /* we allow grace logons when the password has expired */
990 my_info3->base.user_flags |= NETLOGON_GRACE_LOGON;
991 /* return NT_STATUS_PASSWORD_EXPIRED; */
992 goto success;
995 #ifdef HAVE_KRB5
996 if ((state->request->flags & WBFLAG_PAM_KRB5) &&
997 ((tdc_domain = wcache_tdc_fetch_domain(state->mem_ctx, name_domain)) != NULL) &&
998 ((tdc_domain->trust_type & LSA_TRUST_TYPE_UPLEVEL) ||
999 /* used to cope with the case winbindd starting without network. */
1000 !strequal(tdc_domain->domain_name, tdc_domain->dns_name))) {
1002 uid_t uid = -1;
1003 const char *cc = NULL;
1004 char *realm = NULL;
1005 const char *principal_s = NULL;
1006 const char *service = NULL;
1007 const char *user_ccache_file;
1009 if (domain->alt_name == NULL) {
1010 return NT_STATUS_INVALID_PARAMETER;
1013 uid = get_uid_from_request(state->request);
1014 if (uid == -1) {
1015 DEBUG(0,("winbindd_dual_pam_auth_cached: invalid uid\n"));
1016 return NT_STATUS_INVALID_PARAMETER;
1019 cc = generate_krb5_ccache(state->mem_ctx,
1020 state->request->data.auth.krb5_cc_type,
1021 state->request->data.auth.uid,
1022 &user_ccache_file);
1023 if (cc == NULL) {
1024 return NT_STATUS_NO_MEMORY;
1027 realm = talloc_strdup(state->mem_ctx, domain->alt_name);
1028 if (realm == NULL) {
1029 return NT_STATUS_NO_MEMORY;
1032 if (!strupper_m(realm)) {
1033 return NT_STATUS_INVALID_PARAMETER;
1036 principal_s = talloc_asprintf(state->mem_ctx, "%s@%s", name_user, realm);
1037 if (principal_s == NULL) {
1038 return NT_STATUS_NO_MEMORY;
1041 service = talloc_asprintf(state->mem_ctx, "%s/%s@%s", KRB5_TGS_NAME, realm, realm);
1042 if (service == NULL) {
1043 return NT_STATUS_NO_MEMORY;
1046 if (user_ccache_file != NULL) {
1048 fstrcpy(state->response->data.auth.krb5ccname,
1049 user_ccache_file);
1051 result = add_ccache_to_list(principal_s,
1053 service,
1054 state->request->data.auth.user,
1055 state->request->data.auth.pass,
1056 realm,
1057 uid,
1058 time(NULL),
1059 time(NULL) + lp_winbind_cache_time(),
1060 time(NULL) + WINBINDD_PAM_AUTH_KRB5_RENEW_TIME,
1061 true);
1063 if (!NT_STATUS_IS_OK(result)) {
1064 DEBUG(10,("winbindd_dual_pam_auth_cached: failed "
1065 "to add ccache to list: %s\n",
1066 nt_errstr(result)));
1070 #endif /* HAVE_KRB5 */
1071 success:
1072 /* FIXME: we possibly should handle logon hours as well (does xp when
1073 * offline?) see auth/auth_sam.c:sam_account_ok for details */
1075 unix_to_nt_time(&my_info3->base.logon_time, time(NULL));
1076 my_info3->base.bad_password_count = 0;
1078 result = winbindd_update_creds_by_info3(domain,
1079 state->request->data.auth.user,
1080 state->request->data.auth.pass,
1081 my_info3);
1082 if (!NT_STATUS_IS_OK(result)) {
1083 DEBUG(1,("winbindd_dual_pam_auth_cached: failed to update creds: %s\n",
1084 nt_errstr(result)));
1085 return result;
1088 return NT_STATUS_OK;
1092 /* User does *NOT* know the correct password, modify info3 accordingly, but only if online */
1093 if (domain->online == false) {
1094 goto failed;
1097 /* failure of this is not critical */
1098 result = get_max_bad_attempts_from_lockout_policy(domain, state->mem_ctx, &max_allowed_bad_attempts);
1099 if (!NT_STATUS_IS_OK(result)) {
1100 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get max_allowed_bad_attempts. "
1101 "Won't be able to honour account lockout policies\n"));
1104 /* increase counter */
1105 my_info3->base.bad_password_count++;
1107 if (max_allowed_bad_attempts == 0) {
1108 goto failed;
1111 /* lockout user */
1112 if (my_info3->base.bad_password_count >= max_allowed_bad_attempts) {
1114 uint32 password_properties;
1116 result = get_pwd_properties(domain, state->mem_ctx, &password_properties);
1117 if (!NT_STATUS_IS_OK(result)) {
1118 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get password properties.\n"));
1121 if ((my_info3->base.rid != DOMAIN_RID_ADMINISTRATOR) ||
1122 (password_properties & DOMAIN_PASSWORD_LOCKOUT_ADMINS)) {
1123 my_info3->base.acct_flags |= ACB_AUTOLOCK;
1127 failed:
1128 result = winbindd_update_creds_by_info3(domain,
1129 state->request->data.auth.user,
1130 NULL,
1131 my_info3);
1133 if (!NT_STATUS_IS_OK(result)) {
1134 DEBUG(0,("winbindd_dual_pam_auth_cached: failed to update creds %s\n",
1135 nt_errstr(result)));
1138 return NT_STATUS_LOGON_FAILURE;
1141 static NTSTATUS winbindd_dual_pam_auth_kerberos(struct winbindd_domain *domain,
1142 struct winbindd_cli_state *state,
1143 struct netr_SamInfo3 **info3)
1145 struct winbindd_domain *contact_domain;
1146 fstring name_domain, name_user;
1147 NTSTATUS result;
1149 DEBUG(10,("winbindd_dual_pam_auth_kerberos\n"));
1151 /* Parse domain and username */
1153 parse_domain_user(state->request->data.auth.user, name_domain, name_user);
1155 /* what domain should we contact? */
1157 if ( IS_DC ) {
1158 if (!(contact_domain = find_domain_from_name(name_domain))) {
1159 DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
1160 state->request->data.auth.user, name_domain, name_user, name_domain));
1161 result = NT_STATUS_NO_SUCH_USER;
1162 goto done;
1165 } else {
1166 if (is_myname(name_domain)) {
1167 DEBUG(3, ("Authentication for domain %s (local domain to this server) not supported at this stage\n", name_domain));
1168 result = NT_STATUS_NO_SUCH_USER;
1169 goto done;
1172 contact_domain = find_domain_from_name(name_domain);
1173 if (contact_domain == NULL) {
1174 DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
1175 state->request->data.auth.user, name_domain, name_user, name_domain));
1177 result = NT_STATUS_NO_SUCH_USER;
1178 goto done;
1182 if (contact_domain->initialized &&
1183 contact_domain->active_directory) {
1184 goto try_login;
1187 if (!contact_domain->initialized) {
1188 init_dc_connection(contact_domain, false);
1191 if (!contact_domain->active_directory) {
1192 DEBUG(3,("krb5 auth requested but domain is not Active Directory\n"));
1193 return NT_STATUS_INVALID_LOGON_TYPE;
1195 try_login:
1196 result = winbindd_raw_kerberos_login(
1197 state->mem_ctx, contact_domain,
1198 state->request->data.auth.user,
1199 state->request->data.auth.pass,
1200 state->request->data.auth.krb5_cc_type,
1201 get_uid_from_request(state->request),
1202 info3, state->response->data.auth.krb5ccname);
1203 done:
1204 return result;
1207 static NTSTATUS winbindd_dual_auth_passdb(TALLOC_CTX *mem_ctx,
1208 uint32_t logon_parameters,
1209 const char *domain, const char *user,
1210 const DATA_BLOB *challenge,
1211 const DATA_BLOB *lm_resp,
1212 const DATA_BLOB *nt_resp,
1213 struct netr_SamInfo3 **pinfo3)
1215 struct auth_context *auth_context;
1216 struct auth_serversupplied_info *server_info;
1217 struct auth_usersupplied_info *user_info = NULL;
1218 struct tsocket_address *local;
1219 struct netr_SamInfo3 *info3;
1220 NTSTATUS status;
1221 int rc;
1222 TALLOC_CTX *frame = talloc_stackframe();
1224 rc = tsocket_address_inet_from_strings(frame,
1225 "ip",
1226 "127.0.0.1",
1228 &local);
1229 if (rc < 0) {
1230 TALLOC_FREE(frame);
1231 return NT_STATUS_NO_MEMORY;
1233 status = make_user_info(frame, &user_info, user, user, domain, domain,
1234 lp_netbios_name(), local, lm_resp, nt_resp, NULL, NULL,
1235 NULL, AUTH_PASSWORD_RESPONSE);
1236 if (!NT_STATUS_IS_OK(status)) {
1237 DEBUG(10, ("make_user_info failed: %s\n", nt_errstr(status)));
1238 TALLOC_FREE(frame);
1239 return status;
1242 user_info->logon_parameters = logon_parameters;
1244 /* We don't want any more mapping of the username */
1245 user_info->mapped_state = True;
1247 /* We don't want to come back to winbindd or to do PAM account checks */
1248 user_info->flags |= USER_INFO_LOCAL_SAM_ONLY | USER_INFO_INFO3_AND_NO_AUTHZ;
1250 status = make_auth_context_fixed(frame, &auth_context, challenge->data);
1252 if (!NT_STATUS_IS_OK(status)) {
1253 DEBUG(0, ("Failed to test authentication with check_sam_security_info3: %s\n", nt_errstr(status)));
1254 TALLOC_FREE(frame);
1255 return status;
1258 status = auth_check_ntlm_password(mem_ctx,
1259 auth_context,
1260 user_info,
1261 &server_info);
1263 if (!NT_STATUS_IS_OK(status)) {
1264 TALLOC_FREE(frame);
1265 return status;
1268 info3 = talloc_zero(mem_ctx, struct netr_SamInfo3);
1269 if (info3 == NULL) {
1270 TALLOC_FREE(frame);
1271 return NT_STATUS_NO_MEMORY;
1274 status = serverinfo_to_SamInfo3(server_info, info3);
1275 if (!NT_STATUS_IS_OK(status)) {
1276 TALLOC_FREE(frame);
1277 TALLOC_FREE(info3);
1278 DEBUG(0, ("serverinfo_to_SamInfo3 failed: %s\n",
1279 nt_errstr(status)));
1280 return status;
1283 *pinfo3 = info3;
1284 DEBUG(10, ("Authenticaticating user %s\\%s returned %s\n", domain,
1285 user, nt_errstr(status)));
1286 TALLOC_FREE(frame);
1287 return status;
1290 static NTSTATUS winbind_samlogon_retry_loop(struct winbindd_domain *domain,
1291 TALLOC_CTX *mem_ctx,
1292 uint32_t logon_parameters,
1293 const char *server,
1294 const char *username,
1295 const char *password,
1296 const char *domainname,
1297 const char *workstation,
1298 const uint8_t chal[8],
1299 DATA_BLOB lm_response,
1300 DATA_BLOB nt_response,
1301 bool interactive,
1302 struct netr_SamInfo3 **info3)
1304 int attempts = 0;
1305 int netr_attempts = 0;
1306 bool retry = false;
1307 NTSTATUS result;
1309 do {
1310 struct rpc_pipe_client *netlogon_pipe;
1311 uint8_t authoritative = 0;
1312 uint32_t flags = 0;
1314 ZERO_STRUCTP(info3);
1315 retry = false;
1317 result = cm_connect_netlogon(domain, &netlogon_pipe);
1319 if (!NT_STATUS_IS_OK(result)) {
1320 DEBUG(3,("Could not open handle to NETLOGON pipe "
1321 "(error: %s, attempts: %d)\n",
1322 nt_errstr(result), netr_attempts));
1324 /* After the first retry always close the connection */
1325 if (netr_attempts > 0) {
1326 DEBUG(3, ("This is again a problem for this "
1327 "particular call, forcing the close "
1328 "of this connection\n"));
1329 invalidate_cm_connection(&domain->conn);
1332 /* After the second retry failover to the next DC */
1333 if (netr_attempts > 1) {
1335 * If the netlogon server is not reachable then
1336 * it is possible that the DC is rebuilding
1337 * sysvol and shutdown netlogon for that time.
1338 * We should failover to the next dc.
1340 DEBUG(3, ("This is the third problem for this "
1341 "particular call, adding DC to the "
1342 "negative cache list\n"));
1343 add_failed_connection_entry(domain->name,
1344 domain->dcname,
1345 result);
1346 saf_delete(domain->name);
1349 /* Only allow 3 retries */
1350 if (netr_attempts < 3) {
1351 DEBUG(3, ("The connection to netlogon "
1352 "failed, retrying\n"));
1353 netr_attempts++;
1354 retry = true;
1355 continue;
1357 return result;
1359 netr_attempts = 0;
1361 if (interactive && username != NULL && password != NULL) {
1362 result = rpccli_netlogon_password_logon(domain->conn.netlogon_creds,
1363 netlogon_pipe->binding_handle,
1364 mem_ctx,
1365 logon_parameters,
1366 domainname,
1367 username,
1368 password,
1369 workstation,
1370 NetlogonInteractiveInformation,
1371 info3);
1372 } else {
1373 result = rpccli_netlogon_network_logon(domain->conn.netlogon_creds,
1374 netlogon_pipe->binding_handle,
1375 mem_ctx,
1376 logon_parameters,
1377 username,
1378 domainname,
1379 workstation,
1380 chal,
1381 lm_response,
1382 nt_response,
1383 &authoritative,
1384 &flags,
1385 info3);
1389 * we increment this after the "feature negotiation"
1390 * for can_do_samlogon_ex and can_do_validation6
1392 attempts += 1;
1394 /* We have to try a second time as cm_connect_netlogon
1395 might not yet have noticed that the DC has killed
1396 our connection. */
1398 if (!rpccli_is_connected(netlogon_pipe)) {
1399 retry = true;
1400 continue;
1403 /* if we get access denied, a possible cause was that we had
1404 and open connection to the DC, but someone changed our
1405 machine account password out from underneath us using 'net
1406 rpc changetrustpw' */
1408 if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
1409 DEBUG(3,("winbind_samlogon_retry_loop: sam_logon returned "
1410 "ACCESS_DENIED. Maybe the trust account "
1411 "password was changed and we didn't know it. "
1412 "Killing connections to domain %s\n",
1413 domainname));
1414 invalidate_cm_connection(&domain->conn);
1415 retry = true;
1418 if (NT_STATUS_EQUAL(result, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1420 * Got DCERPC_FAULT_OP_RNG_ERROR for SamLogon
1421 * (no Ex). This happens against old Samba
1422 * DCs, if LogonSamLogonEx() fails with an error
1423 * e.g. NT_STATUS_NO_SUCH_USER or NT_STATUS_WRONG_PASSWORD.
1425 * The server will log something like this:
1426 * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
1428 * This sets the whole connection into a fault_state mode
1429 * and all following request get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
1431 * This also happens to our retry with LogonSamLogonWithFlags()
1432 * and LogonSamLogon().
1434 * In order to recover from this situation, we need to
1435 * drop the connection.
1437 invalidate_cm_connection(&domain->conn);
1438 result = NT_STATUS_LOGON_FAILURE;
1439 break;
1442 } while ( (attempts < 2) && retry );
1444 if (NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT)) {
1445 DEBUG(3,("winbind_samlogon_retry_loop: sam_network_logon(ex) "
1446 "returned NT_STATUS_IO_TIMEOUT after the retry."
1447 "Killing connections to domain %s\n",
1448 domainname));
1449 invalidate_cm_connection(&domain->conn);
1451 return result;
1454 static NTSTATUS winbindd_dual_pam_auth_samlogon(TALLOC_CTX *mem_ctx,
1455 struct winbindd_domain *domain,
1456 const char *user,
1457 const char *pass,
1458 uint32_t request_flags,
1459 struct netr_SamInfo3 **info3)
1462 uchar chal[8];
1463 DATA_BLOB lm_resp;
1464 DATA_BLOB nt_resp;
1465 unsigned char local_nt_response[24];
1466 fstring name_domain, name_user;
1467 NTSTATUS result;
1468 struct netr_SamInfo3 *my_info3 = NULL;
1470 *info3 = NULL;
1472 DEBUG(10,("winbindd_dual_pam_auth_samlogon\n"));
1474 /* Parse domain and username */
1476 parse_domain_user(user, name_domain, name_user);
1478 /* do password magic */
1480 generate_random_buffer(chal, sizeof(chal));
1482 if (lp_client_ntlmv2_auth()) {
1483 DATA_BLOB server_chal;
1484 DATA_BLOB names_blob;
1485 server_chal = data_blob_const(chal, 8);
1487 /* note that the 'workgroup' here is for the local
1488 machine. The 'server name' must match the
1489 'workstation' passed to the actual SamLogon call.
1491 names_blob = NTLMv2_generate_names_blob(
1492 mem_ctx, lp_netbios_name(), lp_workgroup());
1494 if (!SMBNTLMv2encrypt(mem_ctx, name_user, name_domain,
1495 pass,
1496 &server_chal,
1497 &names_blob,
1498 &lm_resp, &nt_resp, NULL, NULL)) {
1499 data_blob_free(&names_blob);
1500 DEBUG(0, ("winbindd_pam_auth: SMBNTLMv2encrypt() failed!\n"));
1501 result = NT_STATUS_NO_MEMORY;
1502 goto done;
1504 data_blob_free(&names_blob);
1505 } else {
1506 lm_resp = data_blob_null;
1507 SMBNTencrypt(pass, chal, local_nt_response);
1509 nt_resp = data_blob_talloc(mem_ctx, local_nt_response,
1510 sizeof(local_nt_response));
1513 if (strequal(name_domain, get_global_sam_name())) {
1514 DATA_BLOB chal_blob = data_blob_const(chal, sizeof(chal));
1516 result = winbindd_dual_auth_passdb(
1517 mem_ctx, 0, name_domain, name_user,
1518 &chal_blob, &lm_resp, &nt_resp, info3);
1521 * We need to try the remote NETLOGON server if this is NOT_IMPLEMENTED
1523 if (!NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
1524 goto done;
1528 /* check authentication loop */
1530 result = winbind_samlogon_retry_loop(domain,
1531 mem_ctx,
1533 domain->dcname,
1534 name_user,
1535 pass,
1536 name_domain,
1537 lp_netbios_name(),
1538 chal,
1539 lm_resp,
1540 nt_resp,
1541 true, /* interactive */
1542 &my_info3);
1543 if (!NT_STATUS_IS_OK(result)) {
1544 goto done;
1547 /* handle the case where a NT4 DC does not fill in the acct_flags in
1548 * the samlogon reply info3. When accurate info3 is required by the
1549 * caller, we look up the account flags ourselve - gd */
1551 if ((request_flags & WBFLAG_PAM_INFO3_TEXT) &&
1552 NT_STATUS_IS_OK(result) && (my_info3->base.acct_flags == 0)) {
1554 struct rpc_pipe_client *samr_pipe;
1555 struct policy_handle samr_domain_handle, user_pol;
1556 union samr_UserInfo *info = NULL;
1557 NTSTATUS status_tmp, result_tmp;
1558 uint32 acct_flags;
1559 struct dcerpc_binding_handle *b;
1561 status_tmp = cm_connect_sam(domain, mem_ctx, false,
1562 &samr_pipe, &samr_domain_handle);
1564 if (!NT_STATUS_IS_OK(status_tmp)) {
1565 DEBUG(3, ("could not open handle to SAMR pipe: %s\n",
1566 nt_errstr(status_tmp)));
1567 goto done;
1570 b = samr_pipe->binding_handle;
1572 status_tmp = dcerpc_samr_OpenUser(b, mem_ctx,
1573 &samr_domain_handle,
1574 MAXIMUM_ALLOWED_ACCESS,
1575 my_info3->base.rid,
1576 &user_pol,
1577 &result_tmp);
1579 if (!NT_STATUS_IS_OK(status_tmp)) {
1580 DEBUG(3, ("could not open user handle on SAMR pipe: %s\n",
1581 nt_errstr(status_tmp)));
1582 goto done;
1584 if (!NT_STATUS_IS_OK(result_tmp)) {
1585 DEBUG(3, ("could not open user handle on SAMR pipe: %s\n",
1586 nt_errstr(result_tmp)));
1587 goto done;
1590 status_tmp = dcerpc_samr_QueryUserInfo(b, mem_ctx,
1591 &user_pol,
1593 &info,
1594 &result_tmp);
1596 if (!NT_STATUS_IS_OK(status_tmp)) {
1597 DEBUG(3, ("could not query user info on SAMR pipe: %s\n",
1598 nt_errstr(status_tmp)));
1599 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
1600 goto done;
1602 if (!NT_STATUS_IS_OK(result_tmp)) {
1603 DEBUG(3, ("could not query user info on SAMR pipe: %s\n",
1604 nt_errstr(result_tmp)));
1605 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
1606 goto done;
1609 acct_flags = info->info16.acct_flags;
1611 if (acct_flags == 0) {
1612 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
1613 goto done;
1616 my_info3->base.acct_flags = acct_flags;
1618 DEBUG(10,("successfully retrieved acct_flags 0x%x\n", acct_flags));
1620 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
1623 *info3 = my_info3;
1624 done:
1625 return result;
1628 enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain,
1629 struct winbindd_cli_state *state)
1631 NTSTATUS result = NT_STATUS_LOGON_FAILURE;
1632 NTSTATUS krb5_result = NT_STATUS_OK;
1633 fstring name_domain, name_user;
1634 char *mapped_user;
1635 fstring domain_user;
1636 struct netr_SamInfo3 *info3 = NULL;
1637 NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL;
1639 /* Ensure null termination */
1640 state->request->data.auth.user[sizeof(state->request->data.auth.user)-1]='\0';
1642 /* Ensure null termination */
1643 state->request->data.auth.pass[sizeof(state->request->data.auth.pass)-1]='\0';
1645 DEBUG(3, ("[%5lu]: dual pam auth %s\n", (unsigned long)state->pid,
1646 state->request->data.auth.user));
1648 /* Parse domain and username */
1650 name_map_status = normalize_name_unmap(state->mem_ctx,
1651 state->request->data.auth.user,
1652 &mapped_user);
1654 /* If the name normalization didnt' actually do anything,
1655 just use the original name */
1657 if (!NT_STATUS_IS_OK(name_map_status) &&
1658 !NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED))
1660 mapped_user = state->request->data.auth.user;
1663 parse_domain_user(mapped_user, name_domain, name_user);
1665 if ( mapped_user != state->request->data.auth.user ) {
1666 fstr_sprintf( domain_user, "%s%c%s", name_domain,
1667 *lp_winbind_separator(),
1668 name_user );
1669 strlcpy( state->request->data.auth.user, domain_user,
1670 sizeof(state->request->data.auth.user));
1673 if (!domain->online) {
1674 result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
1675 if (domain->startup) {
1676 /* Logons are very important to users. If we're offline and
1677 we get a request within the first 30 seconds of startup,
1678 try very hard to find a DC and go online. */
1680 DEBUG(10,("winbindd_dual_pam_auth: domain: %s offline and auth "
1681 "request in startup mode.\n", domain->name ));
1683 winbindd_flush_negative_conn_cache(domain);
1684 result = init_dc_connection(domain, false);
1688 DEBUG(10,("winbindd_dual_pam_auth: domain: %s last was %s\n", domain->name, domain->online ? "online":"offline"));
1690 /* Check for Kerberos authentication */
1691 if (domain->online && (state->request->flags & WBFLAG_PAM_KRB5)) {
1693 result = winbindd_dual_pam_auth_kerberos(domain, state, &info3);
1694 /* save for later */
1695 krb5_result = result;
1698 if (NT_STATUS_IS_OK(result)) {
1699 DEBUG(10,("winbindd_dual_pam_auth_kerberos succeeded\n"));
1700 goto process_result;
1701 } else {
1702 DEBUG(10,("winbindd_dual_pam_auth_kerberos failed: %s\n", nt_errstr(result)));
1705 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
1706 NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
1707 NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1708 DEBUG(10,("winbindd_dual_pam_auth_kerberos setting domain to offline\n"));
1709 set_domain_offline( domain );
1710 goto cached_logon;
1713 /* there are quite some NT_STATUS errors where there is no
1714 * point in retrying with a samlogon, we explictly have to take
1715 * care not to increase the bad logon counter on the DC */
1717 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_DISABLED) ||
1718 NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_EXPIRED) ||
1719 NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_LOCKED_OUT) ||
1720 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_LOGON_HOURS) ||
1721 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_WORKSTATION) ||
1722 NT_STATUS_EQUAL(result, NT_STATUS_LOGON_FAILURE) ||
1723 NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER) ||
1724 NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_EXPIRED) ||
1725 NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_MUST_CHANGE) ||
1726 NT_STATUS_EQUAL(result, NT_STATUS_WRONG_PASSWORD)) {
1727 goto done;
1730 if (state->request->flags & WBFLAG_PAM_FALLBACK_AFTER_KRB5) {
1731 DEBUG(3,("falling back to samlogon\n"));
1732 goto sam_logon;
1733 } else {
1734 goto cached_logon;
1738 sam_logon:
1739 /* Check for Samlogon authentication */
1740 if (domain->online) {
1741 result = winbindd_dual_pam_auth_samlogon(
1742 state->mem_ctx, domain,
1743 state->request->data.auth.user,
1744 state->request->data.auth.pass,
1745 state->request->flags,
1746 &info3);
1748 if (NT_STATUS_IS_OK(result)) {
1749 DEBUG(10,("winbindd_dual_pam_auth_samlogon succeeded\n"));
1750 /* add the Krb5 err if we have one */
1751 if ( NT_STATUS_EQUAL(krb5_result, NT_STATUS_TIME_DIFFERENCE_AT_DC ) ) {
1752 info3->base.user_flags |= LOGON_KRB5_FAIL_CLOCK_SKEW;
1754 goto process_result;
1757 DEBUG(10,("winbindd_dual_pam_auth_samlogon failed: %s\n",
1758 nt_errstr(result)));
1760 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
1761 NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
1762 NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND))
1764 DEBUG(10,("winbindd_dual_pam_auth_samlogon setting domain to offline\n"));
1765 set_domain_offline( domain );
1766 goto cached_logon;
1769 if (domain->online) {
1770 /* We're still online - fail. */
1771 goto done;
1775 cached_logon:
1776 /* Check for Cached logons */
1777 if (!domain->online && (state->request->flags & WBFLAG_PAM_CACHED_LOGIN) &&
1778 lp_winbind_offline_logon()) {
1780 result = winbindd_dual_pam_auth_cached(domain, state, &info3);
1782 if (NT_STATUS_IS_OK(result)) {
1783 DEBUG(10,("winbindd_dual_pam_auth_cached succeeded\n"));
1784 goto process_result;
1785 } else {
1786 DEBUG(10,("winbindd_dual_pam_auth_cached failed: %s\n", nt_errstr(result)));
1787 goto done;
1791 process_result:
1793 if (NT_STATUS_IS_OK(result)) {
1795 struct dom_sid user_sid;
1797 /* In all codepaths where result == NT_STATUS_OK info3 must have
1798 been initialized. */
1799 if (!info3) {
1800 result = NT_STATUS_INTERNAL_ERROR;
1801 goto done;
1804 sid_compose(&user_sid, info3->base.domain_sid,
1805 info3->base.rid);
1807 if (info3->base.full_name.string == NULL) {
1808 struct netr_SamInfo3 *cached_info3;
1810 cached_info3 = netsamlogon_cache_get(state->mem_ctx,
1811 &user_sid);
1812 if (cached_info3 != NULL &&
1813 cached_info3->base.full_name.string != NULL) {
1814 info3->base.full_name.string =
1815 talloc_strdup(info3,
1816 cached_info3->base.full_name.string);
1817 } else {
1819 /* this might fail so we dont check the return code */
1820 wcache_query_user_fullname(domain,
1821 info3,
1822 &user_sid,
1823 &info3->base.full_name.string);
1827 wcache_invalidate_samlogon(find_domain_from_name(name_domain),
1828 &user_sid);
1829 netsamlogon_cache_store(name_user, info3);
1831 /* save name_to_sid info as early as possible (only if
1832 this is our primary domain so we don't invalidate
1833 the cache entry by storing the seq_num for the wrong
1834 domain). */
1835 if ( domain->primary ) {
1836 cache_name2sid(domain, name_domain, name_user,
1837 SID_NAME_USER, &user_sid);
1840 /* Check if the user is in the right group */
1842 result = check_info3_in_group(
1843 info3,
1844 state->request->data.auth.require_membership_of_sid);
1845 if (!NT_STATUS_IS_OK(result)) {
1846 DEBUG(3, ("User %s is not in the required group (%s), so plaintext authentication is rejected\n",
1847 state->request->data.auth.user,
1848 state->request->data.auth.require_membership_of_sid));
1849 goto done;
1852 result = append_auth_data(state->mem_ctx, state->response,
1853 state->request->flags, info3,
1854 name_domain, name_user);
1855 if (!NT_STATUS_IS_OK(result)) {
1856 goto done;
1859 if ((state->request->flags & WBFLAG_PAM_CACHED_LOGIN)
1860 && lp_winbind_offline_logon()) {
1862 result = winbindd_store_creds(domain,
1863 state->request->data.auth.user,
1864 state->request->data.auth.pass,
1865 info3);
1868 if (state->request->flags & WBFLAG_PAM_GET_PWD_POLICY) {
1869 struct winbindd_domain *our_domain = find_our_domain();
1871 /* This is not entirely correct I believe, but it is
1872 consistent. Only apply the password policy settings
1873 too warn users for our own domain. Cannot obtain these
1874 from trusted DCs all the time so don't do it at all.
1875 -- jerry */
1877 result = NT_STATUS_NOT_SUPPORTED;
1878 if (our_domain == domain ) {
1879 result = fillup_password_policy(
1880 our_domain, state->response);
1883 if (!NT_STATUS_IS_OK(result)
1884 && !NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED) )
1886 DEBUG(10,("Failed to get password policies for domain %s: %s\n",
1887 domain->name, nt_errstr(result)));
1888 goto done;
1892 result = NT_STATUS_OK;
1895 done:
1896 /* give us a more useful (more correct?) error code */
1897 if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
1898 (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
1899 result = NT_STATUS_NO_LOGON_SERVERS;
1902 set_auth_errors(state->response, result);
1904 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, ("Plain-text authentication for user %s returned %s (PAM: %d)\n",
1905 state->request->data.auth.user,
1906 state->response->data.auth.nt_status_string,
1907 state->response->data.auth.pam_error));
1909 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
1912 NTSTATUS winbind_dual_SamLogon(struct winbindd_domain *domain,
1913 TALLOC_CTX *mem_ctx,
1914 uint32_t logon_parameters,
1915 const char *name_user,
1916 const char *name_domain,
1917 const char *workstation,
1918 const uint8_t chal[8],
1919 DATA_BLOB lm_response,
1920 DATA_BLOB nt_response,
1921 struct netr_SamInfo3 **info3)
1923 NTSTATUS result;
1925 if (strequal(name_domain, get_global_sam_name())) {
1926 DATA_BLOB chal_blob = data_blob_const(
1927 chal, 8);
1929 result = winbindd_dual_auth_passdb(
1930 mem_ctx,
1931 logon_parameters,
1932 name_domain, name_user,
1933 &chal_blob, &lm_response, &nt_response, info3);
1936 * We need to try the remote NETLOGON server if this is NOT_IMPLEMENTED
1938 if (!NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
1939 goto process_result;
1943 result = winbind_samlogon_retry_loop(domain,
1944 mem_ctx,
1945 logon_parameters,
1946 domain->dcname,
1947 name_user,
1948 NULL, /* password */
1949 name_domain,
1950 /* Bug #3248 - found by Stefan Burkei. */
1951 workstation, /* We carefully set this above so use it... */
1952 chal,
1953 lm_response,
1954 nt_response,
1955 false, /* interactive */
1956 info3);
1957 if (!NT_STATUS_IS_OK(result)) {
1958 goto done;
1961 process_result:
1963 if (NT_STATUS_IS_OK(result)) {
1964 struct dom_sid user_sid;
1966 sid_compose(&user_sid, (*info3)->base.domain_sid,
1967 (*info3)->base.rid);
1969 if ((*info3)->base.full_name.string == NULL) {
1970 struct netr_SamInfo3 *cached_info3;
1972 cached_info3 = netsamlogon_cache_get(mem_ctx,
1973 &user_sid);
1974 if (cached_info3 != NULL &&
1975 cached_info3->base.full_name.string != NULL) {
1976 (*info3)->base.full_name.string =
1977 talloc_strdup(*info3,
1978 cached_info3->base.full_name.string);
1979 } else {
1981 /* this might fail so we dont check the return code */
1982 wcache_query_user_fullname(domain,
1983 *info3,
1984 &user_sid,
1985 &(*info3)->base.full_name.string);
1989 wcache_invalidate_samlogon(find_domain_from_name(name_domain),
1990 &user_sid);
1991 netsamlogon_cache_store(name_user, *info3);
1994 done:
1996 /* give us a more useful (more correct?) error code */
1997 if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
1998 (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
1999 result = NT_STATUS_NO_LOGON_SERVERS;
2002 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
2003 ("NTLM CRAP authentication for user [%s]\\[%s] returned %s\n",
2004 name_domain,
2005 name_user,
2006 nt_errstr(result)));
2008 return result;
2011 enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain,
2012 struct winbindd_cli_state *state)
2014 NTSTATUS result;
2015 struct netr_SamInfo3 *info3 = NULL;
2016 const char *name_user = NULL;
2017 const char *name_domain = NULL;
2018 const char *workstation;
2020 DATA_BLOB lm_resp, nt_resp;
2022 /* This is child-only, so no check for privileged access is needed
2023 anymore */
2025 /* Ensure null termination */
2026 state->request->data.auth_crap.user[sizeof(state->request->data.auth_crap.user)-1]=0;
2027 state->request->data.auth_crap.domain[sizeof(state->request->data.auth_crap.domain)-1]=0;
2029 name_user = state->request->data.auth_crap.user;
2030 name_domain = state->request->data.auth_crap.domain;
2031 workstation = state->request->data.auth_crap.workstation;
2033 DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n", (unsigned long)state->pid,
2034 name_domain, name_user));
2036 if (state->request->data.auth_crap.lm_resp_len > sizeof(state->request->data.auth_crap.lm_resp)
2037 || state->request->data.auth_crap.nt_resp_len > sizeof(state->request->data.auth_crap.nt_resp)) {
2038 if (!(state->request->flags & WBFLAG_BIG_NTLMV2_BLOB) ||
2039 state->request->extra_len != state->request->data.auth_crap.nt_resp_len) {
2040 DEBUG(0, ("winbindd_pam_auth_crap: invalid password length %u/%u\n",
2041 state->request->data.auth_crap.lm_resp_len,
2042 state->request->data.auth_crap.nt_resp_len));
2043 result = NT_STATUS_INVALID_PARAMETER;
2044 goto done;
2048 lm_resp = data_blob_talloc(state->mem_ctx, state->request->data.auth_crap.lm_resp,
2049 state->request->data.auth_crap.lm_resp_len);
2051 if (state->request->flags & WBFLAG_BIG_NTLMV2_BLOB) {
2052 nt_resp = data_blob_talloc(state->mem_ctx,
2053 state->request->extra_data.data,
2054 state->request->data.auth_crap.nt_resp_len);
2055 } else {
2056 nt_resp = data_blob_talloc(state->mem_ctx,
2057 state->request->data.auth_crap.nt_resp,
2058 state->request->data.auth_crap.nt_resp_len);
2061 result = winbind_dual_SamLogon(domain,
2062 state->mem_ctx,
2063 state->request->data.auth_crap.logon_parameters,
2064 name_user,
2065 name_domain,
2066 /* Bug #3248 - found by Stefan Burkei. */
2067 workstation, /* We carefully set this above so use it... */
2068 state->request->data.auth_crap.chal,
2069 lm_resp,
2070 nt_resp,
2071 &info3);
2072 if (!NT_STATUS_IS_OK(result)) {
2073 goto done;
2076 if (NT_STATUS_IS_OK(result)) {
2077 /* Check if the user is in the right group */
2079 result = check_info3_in_group(
2080 info3,
2081 state->request->data.auth_crap.require_membership_of_sid);
2082 if (!NT_STATUS_IS_OK(result)) {
2083 DEBUG(3, ("User %s is not in the required group (%s), so "
2084 "crap authentication is rejected\n",
2085 state->request->data.auth_crap.user,
2086 state->request->data.auth_crap.require_membership_of_sid));
2087 goto done;
2090 result = append_auth_data(state->mem_ctx, state->response,
2091 state->request->flags, info3,
2092 name_domain, name_user);
2093 if (!NT_STATUS_IS_OK(result)) {
2094 goto done;
2098 done:
2100 if (state->request->flags & WBFLAG_PAM_NT_STATUS_SQUASH) {
2101 result = nt_status_squash(result);
2104 set_auth_errors(state->response, result);
2106 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2109 enum winbindd_result winbindd_dual_pam_chauthtok(struct winbindd_domain *contact_domain,
2110 struct winbindd_cli_state *state)
2112 char *oldpass;
2113 char *newpass = NULL;
2114 struct policy_handle dom_pol;
2115 struct rpc_pipe_client *cli = NULL;
2116 bool got_info = false;
2117 struct samr_DomInfo1 *info = NULL;
2118 struct userPwdChangeFailureInformation *reject = NULL;
2119 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
2120 fstring domain, user;
2121 struct dcerpc_binding_handle *b = NULL;
2123 ZERO_STRUCT(dom_pol);
2125 DEBUG(3, ("[%5lu]: dual pam chauthtok %s\n", (unsigned long)state->pid,
2126 state->request->data.auth.user));
2128 if (!parse_domain_user(state->request->data.chauthtok.user, domain, user)) {
2129 goto done;
2132 /* Change password */
2134 oldpass = state->request->data.chauthtok.oldpass;
2135 newpass = state->request->data.chauthtok.newpass;
2137 /* Initialize reject reason */
2138 state->response->data.auth.reject_reason = Undefined;
2140 /* Get sam handle */
2142 result = cm_connect_sam(contact_domain, state->mem_ctx, true, &cli,
2143 &dom_pol);
2144 if (!NT_STATUS_IS_OK(result)) {
2145 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
2146 goto done;
2149 b = cli->binding_handle;
2151 result = rpccli_samr_chgpasswd_user3(cli, state->mem_ctx,
2152 user,
2153 newpass,
2154 oldpass,
2155 &info,
2156 &reject);
2158 /* Windows 2003 returns NT_STATUS_PASSWORD_RESTRICTION */
2160 if (NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_RESTRICTION) ) {
2162 fill_in_password_policy(state->response, info);
2164 state->response->data.auth.reject_reason =
2165 reject->extendedFailureReason;
2167 got_info = true;
2170 /* atm the pidl generated rpccli_samr_ChangePasswordUser3 function will
2171 * return with NT_STATUS_BUFFER_TOO_SMALL for w2k dcs as w2k just
2172 * returns with 4byte error code (NT_STATUS_NOT_SUPPORTED) which is too
2173 * short to comply with the samr_ChangePasswordUser3 idl - gd */
2175 /* only fallback when the chgpasswd_user3 call is not supported */
2176 if (NT_STATUS_EQUAL(result, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE) ||
2177 NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED) ||
2178 NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL) ||
2179 NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
2181 DEBUG(10,("Password change with chgpasswd_user3 failed with: %s, retrying chgpasswd_user2\n",
2182 nt_errstr(result)));
2184 result = rpccli_samr_chgpasswd_user2(cli, state->mem_ctx, user, newpass, oldpass);
2186 /* Windows 2000 returns NT_STATUS_ACCOUNT_RESTRICTION.
2187 Map to the same status code as Windows 2003. */
2189 if ( NT_STATUS_EQUAL(NT_STATUS_ACCOUNT_RESTRICTION, result ) ) {
2190 result = NT_STATUS_PASSWORD_RESTRICTION;
2194 done:
2196 if (NT_STATUS_IS_OK(result)
2197 && (state->request->flags & WBFLAG_PAM_CACHED_LOGIN)
2198 && lp_winbind_offline_logon()) {
2199 result = winbindd_update_creds_by_name(contact_domain, user,
2200 newpass);
2201 /* Again, this happens when we login from gdm or xdm
2202 * and the password expires, *BUT* cached crendentials
2203 * doesn't exist. winbindd_update_creds_by_name()
2204 * returns NT_STATUS_NO_SUCH_USER.
2205 * This is not a failure.
2206 * --- BoYang
2207 * */
2208 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER)) {
2209 result = NT_STATUS_OK;
2212 if (!NT_STATUS_IS_OK(result)) {
2213 DEBUG(10, ("Failed to store creds: %s\n",
2214 nt_errstr(result)));
2215 goto process_result;
2219 if (!NT_STATUS_IS_OK(result) && !got_info && contact_domain) {
2221 NTSTATUS policy_ret;
2223 policy_ret = fillup_password_policy(
2224 contact_domain, state->response);
2226 /* failure of this is non critical, it will just provide no
2227 * additional information to the client why the change has
2228 * failed - Guenther */
2230 if (!NT_STATUS_IS_OK(policy_ret)) {
2231 DEBUG(10,("Failed to get password policies: %s\n", nt_errstr(policy_ret)));
2232 goto process_result;
2236 process_result:
2238 if (strequal(contact_domain->name, get_global_sam_name())) {
2239 /* FIXME: internal rpc pipe does not cache handles yet */
2240 if (b) {
2241 if (is_valid_policy_hnd(&dom_pol)) {
2242 NTSTATUS _result;
2243 dcerpc_samr_Close(b, state->mem_ctx, &dom_pol, &_result);
2245 TALLOC_FREE(cli);
2249 set_auth_errors(state->response, result);
2251 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
2252 ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
2253 domain,
2254 user,
2255 state->response->data.auth.nt_status_string,
2256 state->response->data.auth.pam_error));
2258 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2261 enum winbindd_result winbindd_dual_pam_logoff(struct winbindd_domain *domain,
2262 struct winbindd_cli_state *state)
2264 NTSTATUS result = NT_STATUS_NOT_SUPPORTED;
2266 DEBUG(3, ("[%5lu]: pam dual logoff %s\n", (unsigned long)state->pid,
2267 state->request->data.logoff.user));
2269 if (!(state->request->flags & WBFLAG_PAM_KRB5)) {
2270 result = NT_STATUS_OK;
2271 goto process_result;
2274 if (state->request->data.logoff.krb5ccname[0] == '\0') {
2275 result = NT_STATUS_OK;
2276 goto process_result;
2279 #ifdef HAVE_KRB5
2281 if (state->request->data.logoff.uid < 0) {
2282 DEBUG(0,("winbindd_pam_logoff: invalid uid\n"));
2283 goto process_result;
2286 /* what we need here is to find the corresponding krb5 ccache name *we*
2287 * created for a given username and destroy it */
2289 if (!ccache_entry_exists(state->request->data.logoff.user)) {
2290 result = NT_STATUS_OK;
2291 DEBUG(10,("winbindd_pam_logoff: no entry found.\n"));
2292 goto process_result;
2295 if (!ccache_entry_identical(state->request->data.logoff.user,
2296 state->request->data.logoff.uid,
2297 state->request->data.logoff.krb5ccname)) {
2298 DEBUG(0,("winbindd_pam_logoff: cached entry differs.\n"));
2299 goto process_result;
2302 result = remove_ccache(state->request->data.logoff.user);
2303 if (!NT_STATUS_IS_OK(result)) {
2304 DEBUG(0,("winbindd_pam_logoff: failed to remove ccache: %s\n",
2305 nt_errstr(result)));
2306 goto process_result;
2310 * Remove any mlock'ed memory creds in the child
2311 * we might be using for krb5 ticket renewal.
2314 winbindd_delete_memory_creds(state->request->data.logoff.user);
2316 #else
2317 result = NT_STATUS_NOT_SUPPORTED;
2318 #endif
2320 process_result:
2323 set_auth_errors(state->response, result);
2325 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2328 /* Change user password with auth crap*/
2330 enum winbindd_result winbindd_dual_pam_chng_pswd_auth_crap(struct winbindd_domain *domainSt, struct winbindd_cli_state *state)
2332 NTSTATUS result;
2333 DATA_BLOB new_nt_password;
2334 DATA_BLOB old_nt_hash_enc;
2335 DATA_BLOB new_lm_password;
2336 DATA_BLOB old_lm_hash_enc;
2337 fstring domain,user;
2338 struct policy_handle dom_pol;
2339 struct winbindd_domain *contact_domain = domainSt;
2340 struct rpc_pipe_client *cli = NULL;
2341 struct dcerpc_binding_handle *b = NULL;
2343 ZERO_STRUCT(dom_pol);
2345 /* Ensure null termination */
2346 state->request->data.chng_pswd_auth_crap.user[
2347 sizeof(state->request->data.chng_pswd_auth_crap.user)-1]=0;
2348 state->request->data.chng_pswd_auth_crap.domain[
2349 sizeof(state->request->data.chng_pswd_auth_crap.domain)-1]=0;
2350 *domain = 0;
2351 *user = 0;
2353 DEBUG(3, ("[%5lu]: pam change pswd auth crap domain: %s user: %s\n",
2354 (unsigned long)state->pid,
2355 state->request->data.chng_pswd_auth_crap.domain,
2356 state->request->data.chng_pswd_auth_crap.user));
2358 if (lp_winbind_offline_logon()) {
2359 DEBUG(0,("Refusing password change as winbind offline logons are enabled. "));
2360 DEBUGADD(0,("Changing passwords here would risk inconsistent logons\n"));
2361 result = NT_STATUS_ACCESS_DENIED;
2362 goto done;
2365 if (*state->request->data.chng_pswd_auth_crap.domain) {
2366 fstrcpy(domain,state->request->data.chng_pswd_auth_crap.domain);
2367 } else {
2368 parse_domain_user(state->request->data.chng_pswd_auth_crap.user,
2369 domain, user);
2371 if(!*domain) {
2372 DEBUG(3,("no domain specified with username (%s) - "
2373 "failing auth\n",
2374 state->request->data.chng_pswd_auth_crap.user));
2375 result = NT_STATUS_NO_SUCH_USER;
2376 goto done;
2380 if (!*domain && lp_winbind_use_default_domain()) {
2381 fstrcpy(domain,lp_workgroup());
2384 if(!*user) {
2385 fstrcpy(user, state->request->data.chng_pswd_auth_crap.user);
2388 DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n",
2389 (unsigned long)state->pid, domain, user));
2391 /* Change password */
2392 new_nt_password = data_blob_const(
2393 state->request->data.chng_pswd_auth_crap.new_nt_pswd,
2394 state->request->data.chng_pswd_auth_crap.new_nt_pswd_len);
2396 old_nt_hash_enc = data_blob_const(
2397 state->request->data.chng_pswd_auth_crap.old_nt_hash_enc,
2398 state->request->data.chng_pswd_auth_crap.old_nt_hash_enc_len);
2400 if(state->request->data.chng_pswd_auth_crap.new_lm_pswd_len > 0) {
2401 new_lm_password = data_blob_const(
2402 state->request->data.chng_pswd_auth_crap.new_lm_pswd,
2403 state->request->data.chng_pswd_auth_crap.new_lm_pswd_len);
2405 old_lm_hash_enc = data_blob_const(
2406 state->request->data.chng_pswd_auth_crap.old_lm_hash_enc,
2407 state->request->data.chng_pswd_auth_crap.old_lm_hash_enc_len);
2408 } else {
2409 new_lm_password = data_blob_null;
2410 old_lm_hash_enc = data_blob_null;
2413 /* Get sam handle */
2415 result = cm_connect_sam(contact_domain, state->mem_ctx, true, &cli, &dom_pol);
2416 if (!NT_STATUS_IS_OK(result)) {
2417 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
2418 goto done;
2421 b = cli->binding_handle;
2423 result = rpccli_samr_chng_pswd_auth_crap(
2424 cli, state->mem_ctx, user, new_nt_password, old_nt_hash_enc,
2425 new_lm_password, old_lm_hash_enc);
2427 done:
2429 if (strequal(contact_domain->name, get_global_sam_name())) {
2430 /* FIXME: internal rpc pipe does not cache handles yet */
2431 if (b) {
2432 if (is_valid_policy_hnd(&dom_pol)) {
2433 NTSTATUS _result;
2434 dcerpc_samr_Close(b, state->mem_ctx, &dom_pol, &_result);
2436 TALLOC_FREE(cli);
2440 set_auth_errors(state->response, result);
2442 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
2443 ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
2444 domain, user,
2445 state->response->data.auth.nt_status_string,
2446 state->response->data.auth.pam_error));
2448 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2451 #ifdef HAVE_KRB5
2452 static NTSTATUS extract_pac_vrfy_sigs(TALLOC_CTX *mem_ctx, DATA_BLOB pac_blob,
2453 struct PAC_LOGON_INFO **logon_info)
2455 krb5_context krbctx = NULL;
2456 krb5_error_code k5ret;
2457 krb5_keytab keytab;
2458 krb5_kt_cursor cursor;
2459 krb5_keytab_entry entry;
2460 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
2462 ZERO_STRUCT(entry);
2463 ZERO_STRUCT(cursor);
2465 k5ret = krb5_init_context(&krbctx);
2466 if (k5ret) {
2467 DEBUG(1, ("Failed to initialize kerberos context: %s\n",
2468 error_message(k5ret)));
2469 status = krb5_to_nt_status(k5ret);
2470 goto out;
2473 k5ret = gse_krb5_get_server_keytab(krbctx, &keytab);
2474 if (k5ret) {
2475 DEBUG(1, ("Failed to get keytab: %s\n",
2476 error_message(k5ret)));
2477 status = krb5_to_nt_status(k5ret);
2478 goto out_free;
2481 k5ret = krb5_kt_start_seq_get(krbctx, keytab, &cursor);
2482 if (k5ret) {
2483 DEBUG(1, ("Failed to start seq: %s\n",
2484 error_message(k5ret)));
2485 status = krb5_to_nt_status(k5ret);
2486 goto out_keytab;
2489 k5ret = krb5_kt_next_entry(krbctx, keytab, &entry, &cursor);
2490 while (k5ret == 0) {
2491 status = kerberos_pac_logon_info(mem_ctx, pac_blob,
2492 krbctx, NULL,
2493 KRB5_KT_KEY(&entry), NULL, 0,
2494 logon_info);
2495 if (NT_STATUS_IS_OK(status)) {
2496 break;
2498 k5ret = smb_krb5_kt_free_entry(krbctx, &entry);
2499 k5ret = krb5_kt_next_entry(krbctx, keytab, &entry, &cursor);
2502 k5ret = krb5_kt_end_seq_get(krbctx, keytab, &cursor);
2503 if (k5ret) {
2504 DEBUG(1, ("Failed to end seq: %s\n",
2505 error_message(k5ret)));
2507 out_keytab:
2508 k5ret = krb5_kt_close(krbctx, keytab);
2509 if (k5ret) {
2510 DEBUG(1, ("Failed to close keytab: %s\n",
2511 error_message(k5ret)));
2513 out_free:
2514 krb5_free_context(krbctx);
2515 out:
2516 return status;
2519 NTSTATUS winbindd_pam_auth_pac_send(struct winbindd_cli_state *state,
2520 struct netr_SamInfo3 **info3)
2522 struct winbindd_request *req = state->request;
2523 DATA_BLOB pac_blob;
2524 struct PAC_LOGON_INFO *logon_info = NULL;
2525 struct netr_SamInfo3 *info3_copy = NULL;
2526 NTSTATUS result;
2528 pac_blob = data_blob_const(req->extra_data.data, req->extra_len);
2529 result = extract_pac_vrfy_sigs(state->mem_ctx, pac_blob, &logon_info);
2530 if (!NT_STATUS_IS_OK(result) &&
2531 !NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
2532 DEBUG(1, ("Error during PAC signature verification: %s\n",
2533 nt_errstr(result)));
2534 return result;
2537 if (logon_info) {
2538 /* Signature verification succeeded, trust the PAC */
2539 result = create_info3_from_pac_logon_info(state->mem_ctx,
2540 logon_info,
2541 &info3_copy);
2542 if (!NT_STATUS_IS_OK(result)) {
2543 return result;
2545 netsamlogon_cache_store(NULL, info3_copy);
2547 } else {
2548 /* Try without signature verification */
2549 result = kerberos_pac_logon_info(state->mem_ctx, pac_blob, NULL,
2550 NULL, NULL, NULL, 0,
2551 &logon_info);
2552 if (!NT_STATUS_IS_OK(result)) {
2553 DEBUG(10, ("Could not extract PAC: %s\n",
2554 nt_errstr(result)));
2555 return result;
2557 if (logon_info) {
2559 * Don't strictly need to copy here,
2560 * but it makes it explicit we're
2561 * returning a copy talloc'ed off
2562 * the state->mem_ctx.
2564 info3_copy = copy_netr_SamInfo3(state->mem_ctx,
2565 &logon_info->info3);
2566 if (info3_copy == NULL) {
2567 return NT_STATUS_NO_MEMORY;
2572 *info3 = info3_copy;
2574 return NT_STATUS_OK;
2576 #else /* HAVE_KRB5 */
2577 NTSTATUS winbindd_pam_auth_pac_send(struct winbindd_cli_state *state,
2578 struct netr_SamInfo3 **info3)
2580 return NT_STATUS_NO_SUCH_USER;
2582 #endif /* HAVE_KRB5 */