source: vendor/current/source3/winbindd/winbindd_pam.c

Last change on this file was 989, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.7

File size: 71.3 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3
4 Winbind daemon - pam auth funcions
5
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
10
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.
15
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.
20
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/>.
23*/
24
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"
45
46#undef DBGC_CLASS
47#define DBGC_CLASS DBGC_WINBIND
48
49#define LOGON_KRB5_FAIL_CLOCK_SKEW 0x02000000
50
51static NTSTATUS append_info3_as_txt(TALLOC_CTX *mem_ctx,
52 struct winbindd_response *resp,
53 struct netr_SamInfo3 *info3)
54{
55 char *ex;
56 uint32_t i;
57
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);
70
71 resp->data.auth.info3.logon_count = info3->base.logon_count;
72 resp->data.auth.info3.bad_pw_count = info3->base.bad_password_count;
73
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);
77
78 resp->data.auth.info3.num_groups = info3->base.groups.count;
79 resp->data.auth.info3.user_flgs = info3->base.user_flags;
80
81 resp->data.auth.info3.acct_flags = info3->base.acct_flags;
82 resp->data.auth.info3.num_other_sids = info3->sidcount;
83
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);
96
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);
101
102 ex = talloc_strdup(mem_ctx, "");
103 NT_STATUS_HAVE_NO_MEMORY(ex);
104
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);
110 }
111
112 for (i=0; i < info3->sidcount; i++) {
113 char *sid;
114
115 sid = dom_sid_string(mem_ctx, info3->sids[i].sid);
116 NT_STATUS_HAVE_NO_MEMORY(sid);
117
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);
122
123 talloc_free(sid);
124 }
125
126 resp->extra_data.data = ex;
127 resp->length += talloc_get_size(ex);
128
129 return NT_STATUS_OK;
130}
131
132static NTSTATUS append_info3_as_ndr(TALLOC_CTX *mem_ctx,
133 struct winbindd_response *resp,
134 struct netr_SamInfo3 *info3)
135{
136 DATA_BLOB blob;
137 enum ndr_err_code ndr_err;
138
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);
144 }
145
146 resp->extra_data.data = blob.data;
147 resp->length += blob.length;
148
149 return NT_STATUS_OK;
150}
151
152static 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)
157{
158 /* We've been asked to return the unix username, per
159 'winbind use default domain' settings and the like */
160
161 const char *nt_username, *nt_domain;
162
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;
168 }
169
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;
175 }
176
177 fill_domain_username(resp->data.auth.unix_username,
178 nt_domain, nt_username, true);
179
180 DEBUG(5, ("Setting unix username to [%s]\n",
181 resp->data.auth.unix_username));
182
183 return NT_STATUS_OK;
184}
185
186static 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)
191{
192 char *afsname = NULL;
193 char *cell;
194 char *token;
195
196 afsname = talloc_strdup(mem_ctx, lp_afs_username_map());
197 if (afsname == NULL) {
198 return NT_STATUS_NO_MEMORY;
199 }
200
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);
208
209 {
210 struct dom_sid user_sid;
211 fstring sidstr;
212
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);
218 }
219
220 if (afsname == NULL) {
221 return NT_STATUS_NO_MEMORY;
222 }
223
224 if (!strlower_m(afsname)) {
225 return NT_STATUS_INVALID_PARAMETER;
226 }
227
228 DEBUG(10, ("Generating token for user %s\n", afsname));
229
230 cell = strchr(afsname, '@');
231
232 if (cell == NULL) {
233 return NT_STATUS_NO_MEMORY;
234 }
235
236 *cell = '\0';
237 cell += 1;
238
239 token = afs_createtoken_str(afsname, cell);
240 if (token == NULL) {
241 return NT_STATUS_OK;
242 }
243 resp->extra_data.data = talloc_strdup(mem_ctx, token);
244 if (resp->extra_data.data == NULL) {
245 return NT_STATUS_NO_MEMORY;
246 }
247 resp->length += strlen((const char *)resp->extra_data.data)+1;
248
249 return NT_STATUS_OK;
250}
251
252static NTSTATUS check_info3_in_group(struct netr_SamInfo3 *info3,
253 const char *group_sid)
254/**
255 * Check whether a user belongs to a group or list of groups.
256 *
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.
260 *
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.
264 */
265{
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;
275
276 /* Parse the 'required group' SID */
277
278 if (!group_sid || !group_sid[0]) {
279 /* NO sid supplied, all users may access */
280 TALLOC_FREE(frame);
281 return NT_STATUS_OK;
282 }
283
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;
289 }
290
291 num_require_membership_of_sid = 0;
292 require_membership_of_sid = NULL;
293
294 p = group_sid;
295
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;
302 }
303
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;
311 }
312 }
313
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;
321 }
322
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;
331 }
332
333 security_token_debug(DBGC_CLASS, 10, token);
334
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;
343 }
344 }
345
346 /* Do not distinguish this error from a wrong username/pw */
347
348 TALLOC_FREE(frame);
349 return NT_STATUS_LOGON_FAILURE;
350}
351
352struct winbindd_domain *find_auth_domain(uint8_t flags,
353 const char *domain_name)
354{
355 struct winbindd_domain *domain;
356
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));
363 }
364 return domain;
365 }
366
367 if (strequal(domain_name, get_global_sam_name())) {
368 return find_domain_from_name_noinit(domain_name);
369 }
370
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;
380 }
381 }
382
383 return find_our_domain();
384}
385
386static void fill_in_password_policy(struct winbindd_response *r,
387 const struct samr_DomInfo1 *p)
388{
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));
399}
400
401static NTSTATUS fillup_password_policy(struct winbindd_domain *domain,
402 struct winbindd_response *response)
403{
404 TALLOC_CTX *frame = talloc_stackframe();
405 struct winbindd_methods *methods;
406 NTSTATUS status;
407 struct samr_DomInfo1 password_policy;
408
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;
414 }
415
416 methods = domain->methods;
417
418 status = methods->password_policy(domain, talloc_tos(), &password_policy);
419 if (NT_STATUS_IS_ERR(status)) {
420 goto done;
421 }
422
423 fill_in_password_policy(response, &password_policy);
424
425done:
426 TALLOC_FREE(frame);
427 return NT_STATUS_OK;
428}
429
430static NTSTATUS get_max_bad_attempts_from_lockout_policy(struct winbindd_domain *domain,
431 TALLOC_CTX *mem_ctx,
432 uint16_t *lockout_threshold)
433{
434 struct winbindd_methods *methods;
435 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
436 struct samr_DomInfo12 lockout_policy;
437
438 *lockout_threshold = 0;
439
440 methods = domain->methods;
441
442 status = methods->lockout_policy(domain, mem_ctx, &lockout_policy);
443 if (NT_STATUS_IS_ERR(status)) {
444 return status;
445 }
446
447 *lockout_threshold = lockout_policy.lockout_threshold;
448
449 return NT_STATUS_OK;
450}
451
452static NTSTATUS get_pwd_properties(struct winbindd_domain *domain,
453 TALLOC_CTX *mem_ctx,
454 uint32_t *password_properties)
455{
456 struct winbindd_methods *methods;
457 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
458 struct samr_DomInfo1 password_policy;
459
460 *password_properties = 0;
461
462 methods = domain->methods;
463
464 status = methods->password_policy(domain, mem_ctx, &password_policy);
465 if (NT_STATUS_IS_ERR(status)) {
466 return status;
467 }
468
469 *password_properties = password_policy.password_properties;
470
471 return NT_STATUS_OK;
472}
473
474#ifdef HAVE_KRB5
475
476static const char *generate_krb5_ccache(TALLOC_CTX *mem_ctx,
477 const char *type,
478 uid_t uid,
479 const char **user_ccache_file)
480{
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*/
484
485 const char *gen_cc = NULL;
486
487 if (uid != -1) {
488 if (strequal(type, "FILE")) {
489 gen_cc = talloc_asprintf(
490 mem_ctx, "FILE:/tmp/krb5cc_%d", uid);
491 }
492 if (strequal(type, "WRFILE")) {
493 gen_cc = talloc_asprintf(
494 mem_ctx, "WRFILE:/tmp/krb5cc_%d", uid);
495 }
496 if (strequal(type, "KEYRING")) {
497 gen_cc = talloc_asprintf(
498 mem_ctx, "KEYRING:persistent:%d", uid);
499 }
500
501 if (strnequal(type, "FILE:/", 6) ||
502 strnequal(type, "WRFILE:/", 8) ||
503 strnequal(type, "DIR:/", 5)) {
504
505 /* we allow only one "%u" substitution */
506
507 char *p;
508
509 p = strchr(type, '%');
510 if (p != NULL) {
511
512 p++;
513
514 if (p != NULL && *p == 'u' && strchr(p, '%') == NULL) {
515 char uid_str[sizeof("18446744073709551615")];
516
517 snprintf(uid_str, sizeof(uid_str), "%u", uid);
518
519 gen_cc = talloc_string_sub2(mem_ctx,
520 type,
521 "%u",
522 uid_str,
523 /* remove_unsafe_characters */
524 false,
525 /* replace_once */
526 true,
527 /* allow_trailing_dollar */
528 false);
529 }
530 }
531 }
532 }
533
534 *user_ccache_file = gen_cc;
535
536 if (gen_cc == NULL) {
537 gen_cc = talloc_strdup(mem_ctx, "MEMORY:winbindd_pam_ccache");
538 }
539 if (gen_cc == NULL) {
540 DEBUG(0,("out of memory\n"));
541 return NULL;
542 }
543
544 DEBUG(10, ("using ccache: %s%s\n", gen_cc,
545 (*user_ccache_file == NULL) ? " (internal)":""));
546
547 return gen_cc;
548}
549
550#endif
551
552uid_t get_uid_from_request(struct winbindd_request *request)
553{
554 uid_t uid;
555
556 uid = request->data.auth.uid;
557
558 if (uid < 0) {
559 DEBUG(1,("invalid uid: '%u'\n", (unsigned int)uid));
560 return -1;
561 }
562 return uid;
563}
564
565/**********************************************************************
566 Authenticate a user with a clear text password using Kerberos and fill up
567 ccache if required
568 **********************************************************************/
569
570static NTSTATUS winbindd_raw_kerberos_login(TALLOC_CTX *mem_ctx,
571 struct winbindd_domain *domain,
572 const char *user,
573 const char *pass,
574 const char *krb5_cc_type,
575 uid_t uid,
576 struct netr_SamInfo3 **info3,
577 fstring krb5ccname)
578{
579#ifdef HAVE_KRB5
580 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
581 krb5_error_code krb5_ret;
582 const char *cc = NULL;
583 const char *principal_s = NULL;
584 const char *service = NULL;
585 char *realm = NULL;
586 fstring name_domain, name_user;
587 time_t ticket_lifetime = 0;
588 time_t renewal_until = 0;
589 ADS_STRUCT *ads;
590 time_t time_offset = 0;
591 const char *user_ccache_file;
592 struct PAC_LOGON_INFO *logon_info = NULL;
593 struct PAC_DATA *pac_data = NULL;
594 struct PAC_DATA_CTR *pac_data_ctr = NULL;
595 const char *local_service;
596 int i;
597 struct netr_SamInfo3 *info3_copy = NULL;
598
599 *info3 = NULL;
600
601 if (domain->alt_name == NULL) {
602 return NT_STATUS_INVALID_PARAMETER;
603 }
604
605 /* 1st step:
606 * prepare a krb5_cc_cache string for the user */
607
608 if (uid == -1) {
609 DEBUG(0,("no valid uid\n"));
610 }
611
612 cc = generate_krb5_ccache(mem_ctx,
613 krb5_cc_type,
614 uid,
615 &user_ccache_file);
616 if (cc == NULL) {
617 return NT_STATUS_NO_MEMORY;
618 }
619
620
621 /* 2nd step:
622 * get kerberos properties */
623
624 if (domain->private_data) {
625 ads = (ADS_STRUCT *)domain->private_data;
626 time_offset = ads->auth.time_offset;
627 }
628
629
630 /* 3rd step:
631 * do kerberos auth and setup ccache as the user */
632
633 parse_domain_user(user, name_domain, name_user);
634
635 realm = talloc_strdup(mem_ctx, domain->alt_name);
636 if (realm == NULL) {
637 return NT_STATUS_NO_MEMORY;
638 }
639
640 if (!strupper_m(realm)) {
641 return NT_STATUS_INVALID_PARAMETER;
642 }
643
644 principal_s = talloc_asprintf(mem_ctx, "%s@%s", name_user, realm);
645 if (principal_s == NULL) {
646 return NT_STATUS_NO_MEMORY;
647 }
648
649 service = talloc_asprintf(mem_ctx, "%s/%s@%s", KRB5_TGS_NAME, realm, realm);
650 if (service == NULL) {
651 return NT_STATUS_NO_MEMORY;
652 }
653
654 local_service = talloc_asprintf(mem_ctx, "%s$@%s",
655 lp_netbios_name(), lp_realm());
656 if (local_service == NULL) {
657 return NT_STATUS_NO_MEMORY;
658 }
659
660
661 /* if this is a user ccache, we need to act as the user to let the krb5
662 * library handle the chown, etc. */
663
664 /************************ ENTERING NON-ROOT **********************/
665
666 if (user_ccache_file != NULL) {
667 set_effective_uid(uid);
668 DEBUG(10,("winbindd_raw_kerberos_login: uid is %d\n", uid));
669 }
670
671 result = kerberos_return_pac(mem_ctx,
672 principal_s,
673 pass,
674 time_offset,
675 &ticket_lifetime,
676 &renewal_until,
677 cc,
678 true,
679 true,
680 WINBINDD_PAM_AUTH_KRB5_RENEW_TIME,
681 NULL,
682 local_service,
683 &pac_data_ctr);
684 if (user_ccache_file != NULL) {
685 gain_root_privilege();
686 }
687
688 /************************ RETURNED TO ROOT **********************/
689
690 if (!NT_STATUS_IS_OK(result)) {
691 goto failed;
692 }
693
694 if (pac_data_ctr == NULL) {
695 goto failed;
696 }
697
698 pac_data = pac_data_ctr->pac_data;
699 if (pac_data == NULL) {
700 goto failed;
701 }
702
703 for (i=0; i < pac_data->num_buffers; i++) {
704
705 if (pac_data->buffers[i].type != PAC_TYPE_LOGON_INFO) {
706 continue;
707 }
708
709 logon_info = pac_data->buffers[i].info->logon_info.info;
710 if (!logon_info) {
711 return NT_STATUS_INVALID_PARAMETER;
712 }
713
714 break;
715 }
716
717 if (logon_info == NULL) {
718 DEBUG(10,("Missing logon_info in ticket of %s\n",
719 principal_s));
720 return NT_STATUS_INVALID_PARAMETER;
721 }
722
723 DEBUG(10,("winbindd_raw_kerberos_login: winbindd validated ticket of %s\n",
724 principal_s));
725
726 result = create_info3_from_pac_logon_info(mem_ctx, logon_info, &info3_copy);
727 if (!NT_STATUS_IS_OK(result)) {
728 goto failed;
729 }
730
731 /* if we had a user's ccache then return that string for the pam
732 * environment */
733
734 if (user_ccache_file != NULL) {
735
736 fstrcpy(krb5ccname, user_ccache_file);
737
738 result = add_ccache_to_list(principal_s,
739 cc,
740 service,
741 user,
742 pass,
743 realm,
744 uid,
745 time(NULL),
746 ticket_lifetime,
747 renewal_until,
748 false);
749
750 if (!NT_STATUS_IS_OK(result)) {
751 DEBUG(10,("winbindd_raw_kerberos_login: failed to add ccache to list: %s\n",
752 nt_errstr(result)));
753 }
754 } else {
755
756 /* need to delete the memory cred cache, it is not used anymore */
757
758 krb5_ret = ads_kdestroy(cc);
759 if (krb5_ret) {
760 DEBUG(3,("winbindd_raw_kerberos_login: "
761 "could not destroy krb5 credential cache: "
762 "%s\n", error_message(krb5_ret)));
763 }
764
765 }
766 *info3 = info3_copy;
767 return NT_STATUS_OK;
768
769failed:
770 /*
771 * Do not delete an existing valid credential cache, if the user
772 * e.g. enters a wrong password
773 */
774 if ((strequal(krb5_cc_type, "FILE") || strequal(krb5_cc_type, "WRFILE"))
775 && user_ccache_file != NULL) {
776 return result;
777 }
778
779 /* we could have created a new credential cache with a valid tgt in it
780 * but we werent able to get or verify the service ticket for this
781 * local host and therefor didn't get the PAC, we need to remove that
782 * cache entirely now */
783
784 krb5_ret = ads_kdestroy(cc);
785 if (krb5_ret) {
786 DEBUG(3,("winbindd_raw_kerberos_login: "
787 "could not destroy krb5 credential cache: "
788 "%s\n", error_message(krb5_ret)));
789 }
790
791 if (!NT_STATUS_IS_OK(remove_ccache(user))) {
792 DEBUG(3,("winbindd_raw_kerberos_login: "
793 "could not remove ccache for user %s\n",
794 user));
795 }
796
797 return result;
798#else
799 return NT_STATUS_NOT_SUPPORTED;
800#endif /* HAVE_KRB5 */
801}
802
803/****************************************************************
804****************************************************************/
805
806bool check_request_flags(uint32_t flags)
807{
808 uint32_t flags_edata = WBFLAG_PAM_AFS_TOKEN |
809 WBFLAG_PAM_INFO3_TEXT |
810 WBFLAG_PAM_INFO3_NDR;
811
812 if ( ( (flags & flags_edata) == WBFLAG_PAM_AFS_TOKEN) ||
813 ( (flags & flags_edata) == WBFLAG_PAM_INFO3_NDR) ||
814 ( (flags & flags_edata) == WBFLAG_PAM_INFO3_TEXT)||
815 !(flags & flags_edata) ) {
816 return true;
817 }
818
819 DEBUG(1, ("check_request_flags: invalid request flags[0x%08X]\n",
820 flags));
821
822 return false;
823}
824
825/****************************************************************
826****************************************************************/
827
828NTSTATUS append_auth_data(TALLOC_CTX *mem_ctx,
829 struct winbindd_response *resp,
830 uint32_t request_flags,
831 struct netr_SamInfo3 *info3,
832 const char *name_domain,
833 const char *name_user)
834{
835 NTSTATUS result;
836
837 if (request_flags & WBFLAG_PAM_USER_SESSION_KEY) {
838 memcpy(resp->data.auth.user_session_key,
839 info3->base.key.key,
840 sizeof(resp->data.auth.user_session_key)
841 /* 16 */);
842 }
843
844 if (request_flags & WBFLAG_PAM_LMKEY) {
845 memcpy(resp->data.auth.first_8_lm_hash,
846 info3->base.LMSessKey.key,
847 sizeof(resp->data.auth.first_8_lm_hash)
848 /* 8 */);
849 }
850
851 if (request_flags & WBFLAG_PAM_UNIX_NAME) {
852 result = append_unix_username(mem_ctx, resp,
853 info3, name_domain, name_user);
854 if (!NT_STATUS_IS_OK(result)) {
855 DEBUG(10,("Failed to append Unix Username: %s\n",
856 nt_errstr(result)));
857 return result;
858 }
859 }
860
861 /* currently, anything from here on potentially overwrites extra_data. */
862
863 if (request_flags & WBFLAG_PAM_INFO3_NDR) {
864 result = append_info3_as_ndr(mem_ctx, resp, info3);
865 if (!NT_STATUS_IS_OK(result)) {
866 DEBUG(10,("Failed to append INFO3 (NDR): %s\n",
867 nt_errstr(result)));
868 return result;
869 }
870 }
871
872 if (request_flags & WBFLAG_PAM_INFO3_TEXT) {
873 result = append_info3_as_txt(mem_ctx, resp, info3);
874 if (!NT_STATUS_IS_OK(result)) {
875 DEBUG(10,("Failed to append INFO3 (TXT): %s\n",
876 nt_errstr(result)));
877 return result;
878 }
879 }
880
881 if (request_flags & WBFLAG_PAM_AFS_TOKEN) {
882 result = append_afs_token(mem_ctx, resp,
883 info3, name_domain, name_user);
884 if (!NT_STATUS_IS_OK(result)) {
885 DEBUG(10,("Failed to append AFS token: %s\n",
886 nt_errstr(result)));
887 return result;
888 }
889 }
890
891 return NT_STATUS_OK;
892}
893
894static NTSTATUS winbindd_dual_pam_auth_cached(struct winbindd_domain *domain,
895 struct winbindd_cli_state *state,
896 struct netr_SamInfo3 **info3)
897{
898 NTSTATUS result = NT_STATUS_LOGON_FAILURE;
899 uint16_t max_allowed_bad_attempts;
900 fstring name_domain, name_user;
901 struct dom_sid sid;
902 enum lsa_SidType type;
903 uchar new_nt_pass[NT_HASH_LEN];
904 const uint8_t *cached_nt_pass;
905 const uint8_t *cached_salt;
906 struct netr_SamInfo3 *my_info3;
907 time_t kickoff_time, must_change_time;
908 bool password_good = false;
909#ifdef HAVE_KRB5
910 struct winbindd_tdc_domain *tdc_domain = NULL;
911#endif
912
913 *info3 = NULL;
914
915 ZERO_STRUCTP(info3);
916
917 DEBUG(10,("winbindd_dual_pam_auth_cached\n"));
918
919 /* Parse domain and username */
920
921 parse_domain_user(state->request->data.auth.user, name_domain, name_user);
922
923
924 if (!lookup_cached_name(name_domain,
925 name_user,
926 &sid,
927 &type)) {
928 DEBUG(10,("winbindd_dual_pam_auth_cached: no such user in the cache\n"));
929 return NT_STATUS_NO_SUCH_USER;
930 }
931
932 if (type != SID_NAME_USER) {
933 DEBUG(10,("winbindd_dual_pam_auth_cached: not a user (%s)\n", sid_type_lookup(type)));
934 return NT_STATUS_LOGON_FAILURE;
935 }
936
937 result = winbindd_get_creds(domain,
938 state->mem_ctx,
939 &sid,
940 &my_info3,
941 &cached_nt_pass,
942 &cached_salt);
943 if (!NT_STATUS_IS_OK(result)) {
944 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get creds: %s\n", nt_errstr(result)));
945 return result;
946 }
947
948 *info3 = my_info3;
949
950 E_md4hash(state->request->data.auth.pass, new_nt_pass);
951
952 dump_data_pw("new_nt_pass", new_nt_pass, NT_HASH_LEN);
953 dump_data_pw("cached_nt_pass", cached_nt_pass, NT_HASH_LEN);
954 if (cached_salt) {
955 dump_data_pw("cached_salt", cached_salt, NT_HASH_LEN);
956 }
957
958 if (cached_salt) {
959 /* In this case we didn't store the nt_hash itself,
960 but the MD5 combination of salt + nt_hash. */
961 uchar salted_hash[NT_HASH_LEN];
962 E_md5hash(cached_salt, new_nt_pass, salted_hash);
963
964 password_good = (memcmp(cached_nt_pass, salted_hash,
965 NT_HASH_LEN) == 0);
966 } else {
967 /* Old cached cred - direct store of nt_hash (bad bad bad !). */
968 password_good = (memcmp(cached_nt_pass, new_nt_pass,
969 NT_HASH_LEN) == 0);
970 }
971
972 if (password_good) {
973
974 /* User *DOES* know the password, update logon_time and reset
975 * bad_pw_count */
976
977 my_info3->base.user_flags |= NETLOGON_CACHED_ACCOUNT;
978
979 if (my_info3->base.acct_flags & ACB_AUTOLOCK) {
980 return NT_STATUS_ACCOUNT_LOCKED_OUT;
981 }
982
983 if (my_info3->base.acct_flags & ACB_DISABLED) {
984 return NT_STATUS_ACCOUNT_DISABLED;
985 }
986
987 if (my_info3->base.acct_flags & ACB_WSTRUST) {
988 return NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
989 }
990
991 if (my_info3->base.acct_flags & ACB_SVRTRUST) {
992 return NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT;
993 }
994
995 if (my_info3->base.acct_flags & ACB_DOMTRUST) {
996 return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT;
997 }
998
999 if (!(my_info3->base.acct_flags & ACB_NORMAL)) {
1000 DEBUG(0,("winbindd_dual_pam_auth_cached: whats wrong with that one?: 0x%08x\n",
1001 my_info3->base.acct_flags));
1002 return NT_STATUS_LOGON_FAILURE;
1003 }
1004
1005 kickoff_time = nt_time_to_unix(my_info3->base.kickoff_time);
1006 if (kickoff_time != 0 && time(NULL) > kickoff_time) {
1007 return NT_STATUS_ACCOUNT_EXPIRED;
1008 }
1009
1010 must_change_time = nt_time_to_unix(my_info3->base.force_password_change);
1011 if (must_change_time != 0 && must_change_time < time(NULL)) {
1012 /* we allow grace logons when the password has expired */
1013 my_info3->base.user_flags |= NETLOGON_GRACE_LOGON;
1014 /* return NT_STATUS_PASSWORD_EXPIRED; */
1015 goto success;
1016 }
1017
1018#ifdef HAVE_KRB5
1019 if ((state->request->flags & WBFLAG_PAM_KRB5) &&
1020 ((tdc_domain = wcache_tdc_fetch_domain(state->mem_ctx, name_domain)) != NULL) &&
1021 ((tdc_domain->trust_type & LSA_TRUST_TYPE_UPLEVEL) ||
1022 /* used to cope with the case winbindd starting without network. */
1023 !strequal(tdc_domain->domain_name, tdc_domain->dns_name))) {
1024
1025 uid_t uid = -1;
1026 const char *cc = NULL;
1027 char *realm = NULL;
1028 const char *principal_s = NULL;
1029 const char *service = NULL;
1030 const char *user_ccache_file;
1031
1032 if (domain->alt_name == NULL) {
1033 return NT_STATUS_INVALID_PARAMETER;
1034 }
1035
1036 uid = get_uid_from_request(state->request);
1037 if (uid == -1) {
1038 DEBUG(0,("winbindd_dual_pam_auth_cached: invalid uid\n"));
1039 return NT_STATUS_INVALID_PARAMETER;
1040 }
1041
1042 cc = generate_krb5_ccache(state->mem_ctx,
1043 state->request->data.auth.krb5_cc_type,
1044 state->request->data.auth.uid,
1045 &user_ccache_file);
1046 if (cc == NULL) {
1047 return NT_STATUS_NO_MEMORY;
1048 }
1049
1050 realm = talloc_strdup(state->mem_ctx, domain->alt_name);
1051 if (realm == NULL) {
1052 return NT_STATUS_NO_MEMORY;
1053 }
1054
1055 if (!strupper_m(realm)) {
1056 return NT_STATUS_INVALID_PARAMETER;
1057 }
1058
1059 principal_s = talloc_asprintf(state->mem_ctx, "%s@%s", name_user, realm);
1060 if (principal_s == NULL) {
1061 return NT_STATUS_NO_MEMORY;
1062 }
1063
1064 service = talloc_asprintf(state->mem_ctx, "%s/%s@%s", KRB5_TGS_NAME, realm, realm);
1065 if (service == NULL) {
1066 return NT_STATUS_NO_MEMORY;
1067 }
1068
1069 if (user_ccache_file != NULL) {
1070
1071 fstrcpy(state->response->data.auth.krb5ccname,
1072 user_ccache_file);
1073
1074 result = add_ccache_to_list(principal_s,
1075 cc,
1076 service,
1077 state->request->data.auth.user,
1078 state->request->data.auth.pass,
1079 realm,
1080 uid,
1081 time(NULL),
1082 time(NULL) + lp_winbind_cache_time(),
1083 time(NULL) + WINBINDD_PAM_AUTH_KRB5_RENEW_TIME,
1084 true);
1085
1086 if (!NT_STATUS_IS_OK(result)) {
1087 DEBUG(10,("winbindd_dual_pam_auth_cached: failed "
1088 "to add ccache to list: %s\n",
1089 nt_errstr(result)));
1090 }
1091 }
1092 }
1093#endif /* HAVE_KRB5 */
1094 success:
1095 /* FIXME: we possibly should handle logon hours as well (does xp when
1096 * offline?) see auth/auth_sam.c:sam_account_ok for details */
1097
1098 unix_to_nt_time(&my_info3->base.logon_time, time(NULL));
1099 my_info3->base.bad_password_count = 0;
1100
1101 result = winbindd_update_creds_by_info3(domain,
1102 state->request->data.auth.user,
1103 state->request->data.auth.pass,
1104 my_info3);
1105 if (!NT_STATUS_IS_OK(result)) {
1106 DEBUG(1,("winbindd_dual_pam_auth_cached: failed to update creds: %s\n",
1107 nt_errstr(result)));
1108 return result;
1109 }
1110
1111 return NT_STATUS_OK;
1112
1113 }
1114
1115 /* User does *NOT* know the correct password, modify info3 accordingly, but only if online */
1116 if (domain->online == false) {
1117 goto failed;
1118 }
1119
1120 /* failure of this is not critical */
1121 result = get_max_bad_attempts_from_lockout_policy(domain, state->mem_ctx, &max_allowed_bad_attempts);
1122 if (!NT_STATUS_IS_OK(result)) {
1123 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get max_allowed_bad_attempts. "
1124 "Won't be able to honour account lockout policies\n"));
1125 }
1126
1127 /* increase counter */
1128 my_info3->base.bad_password_count++;
1129
1130 if (max_allowed_bad_attempts == 0) {
1131 goto failed;
1132 }
1133
1134 /* lockout user */
1135 if (my_info3->base.bad_password_count >= max_allowed_bad_attempts) {
1136
1137 uint32_t password_properties;
1138
1139 result = get_pwd_properties(domain, state->mem_ctx, &password_properties);
1140 if (!NT_STATUS_IS_OK(result)) {
1141 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get password properties.\n"));
1142 }
1143
1144 if ((my_info3->base.rid != DOMAIN_RID_ADMINISTRATOR) ||
1145 (password_properties & DOMAIN_PASSWORD_LOCKOUT_ADMINS)) {
1146 my_info3->base.acct_flags |= ACB_AUTOLOCK;
1147 }
1148 }
1149
1150failed:
1151 result = winbindd_update_creds_by_info3(domain,
1152 state->request->data.auth.user,
1153 NULL,
1154 my_info3);
1155
1156 if (!NT_STATUS_IS_OK(result)) {
1157 DEBUG(0,("winbindd_dual_pam_auth_cached: failed to update creds %s\n",
1158 nt_errstr(result)));
1159 }
1160
1161 return NT_STATUS_LOGON_FAILURE;
1162}
1163
1164static NTSTATUS winbindd_dual_pam_auth_kerberos(struct winbindd_domain *domain,
1165 struct winbindd_cli_state *state,
1166 struct netr_SamInfo3 **info3)
1167{
1168 struct winbindd_domain *contact_domain;
1169 fstring name_domain, name_user;
1170 NTSTATUS result;
1171
1172 DEBUG(10,("winbindd_dual_pam_auth_kerberos\n"));
1173
1174 /* Parse domain and username */
1175
1176 parse_domain_user(state->request->data.auth.user, name_domain, name_user);
1177
1178 /* what domain should we contact? */
1179
1180 if ( IS_DC ) {
1181 if (!(contact_domain = find_domain_from_name(name_domain))) {
1182 DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
1183 state->request->data.auth.user, name_domain, name_user, name_domain));
1184 result = NT_STATUS_NO_SUCH_USER;
1185 goto done;
1186 }
1187
1188 } else {
1189 if (is_myname(name_domain)) {
1190 DEBUG(3, ("Authentication for domain %s (local domain to this server) not supported at this stage\n", name_domain));
1191 result = NT_STATUS_NO_SUCH_USER;
1192 goto done;
1193 }
1194
1195 contact_domain = find_domain_from_name(name_domain);
1196 if (contact_domain == NULL) {
1197 DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
1198 state->request->data.auth.user, name_domain, name_user, name_domain));
1199
1200 result = NT_STATUS_NO_SUCH_USER;
1201 goto done;
1202 }
1203 }
1204
1205 if (contact_domain->initialized &&
1206 contact_domain->active_directory) {
1207 goto try_login;
1208 }
1209
1210 if (!contact_domain->initialized) {
1211 init_dc_connection(contact_domain, false);
1212 }
1213
1214 if (!contact_domain->active_directory) {
1215 DEBUG(3,("krb5 auth requested but domain is not Active Directory\n"));
1216 return NT_STATUS_INVALID_LOGON_TYPE;
1217 }
1218try_login:
1219 result = winbindd_raw_kerberos_login(
1220 state->mem_ctx, contact_domain,
1221 state->request->data.auth.user,
1222 state->request->data.auth.pass,
1223 state->request->data.auth.krb5_cc_type,
1224 get_uid_from_request(state->request),
1225 info3, state->response->data.auth.krb5ccname);
1226done:
1227 return result;
1228}
1229
1230static NTSTATUS winbindd_dual_auth_passdb(TALLOC_CTX *mem_ctx,
1231 uint32_t logon_parameters,
1232 const char *domain, const char *user,
1233 const DATA_BLOB *challenge,
1234 const DATA_BLOB *lm_resp,
1235 const DATA_BLOB *nt_resp,
1236 struct netr_SamInfo3 **pinfo3)
1237{
1238 struct auth_context *auth_context;
1239 struct auth_serversupplied_info *server_info;
1240 struct auth_usersupplied_info *user_info = NULL;
1241 struct tsocket_address *local;
1242 struct netr_SamInfo3 *info3;
1243 NTSTATUS status;
1244 int rc;
1245 TALLOC_CTX *frame = talloc_stackframe();
1246
1247 rc = tsocket_address_inet_from_strings(frame,
1248 "ip",
1249 "127.0.0.1",
1250 0,
1251 &local);
1252 if (rc < 0) {
1253 TALLOC_FREE(frame);
1254 return NT_STATUS_NO_MEMORY;
1255 }
1256 status = make_user_info(frame, &user_info, user, user, domain, domain,
1257 lp_netbios_name(), local, lm_resp, nt_resp, NULL, NULL,
1258 NULL, AUTH_PASSWORD_RESPONSE);
1259 if (!NT_STATUS_IS_OK(status)) {
1260 DEBUG(10, ("make_user_info failed: %s\n", nt_errstr(status)));
1261 TALLOC_FREE(frame);
1262 return status;
1263 }
1264
1265 user_info->logon_parameters = logon_parameters;
1266
1267 /* We don't want any more mapping of the username */
1268 user_info->mapped_state = True;
1269
1270 /* We don't want to come back to winbindd or to do PAM account checks */
1271 user_info->flags |= USER_INFO_LOCAL_SAM_ONLY | USER_INFO_INFO3_AND_NO_AUTHZ;
1272
1273 status = make_auth_context_fixed(frame, &auth_context, challenge->data);
1274
1275 if (!NT_STATUS_IS_OK(status)) {
1276 DEBUG(0, ("Failed to test authentication with check_sam_security_info3: %s\n", nt_errstr(status)));
1277 TALLOC_FREE(frame);
1278 return status;
1279 }
1280
1281 status = auth_check_ntlm_password(mem_ctx,
1282 auth_context,
1283 user_info,
1284 &server_info);
1285
1286 if (!NT_STATUS_IS_OK(status)) {
1287 TALLOC_FREE(frame);
1288 return status;
1289 }
1290
1291 info3 = talloc_zero(mem_ctx, struct netr_SamInfo3);
1292 if (info3 == NULL) {
1293 TALLOC_FREE(frame);
1294 return NT_STATUS_NO_MEMORY;
1295 }
1296
1297 status = serverinfo_to_SamInfo3(server_info, info3);
1298 if (!NT_STATUS_IS_OK(status)) {
1299 TALLOC_FREE(frame);
1300 TALLOC_FREE(info3);
1301 DEBUG(0, ("serverinfo_to_SamInfo3 failed: %s\n",
1302 nt_errstr(status)));
1303 return status;
1304 }
1305
1306 *pinfo3 = info3;
1307 DEBUG(10, ("Authenticaticating user %s\\%s returned %s\n", domain,
1308 user, nt_errstr(status)));
1309 TALLOC_FREE(frame);
1310 return status;
1311}
1312
1313static NTSTATUS winbind_samlogon_retry_loop(struct winbindd_domain *domain,
1314 TALLOC_CTX *mem_ctx,
1315 uint32_t logon_parameters,
1316 const char *username,
1317 const char *password,
1318 const char *domainname,
1319 const char *workstation,
1320 const uint8_t chal[8],
1321 DATA_BLOB lm_response,
1322 DATA_BLOB nt_response,
1323 bool interactive,
1324 struct netr_SamInfo3 **info3)
1325{
1326 int attempts = 0;
1327 int netr_attempts = 0;
1328 bool retry = false;
1329 NTSTATUS result;
1330
1331 do {
1332 struct rpc_pipe_client *netlogon_pipe;
1333 uint8_t authoritative = 0;
1334 uint32_t flags = 0;
1335
1336 ZERO_STRUCTP(info3);
1337 retry = false;
1338
1339 result = cm_connect_netlogon(domain, &netlogon_pipe);
1340
1341 if (!NT_STATUS_IS_OK(result)) {
1342 DEBUG(3,("Could not open handle to NETLOGON pipe "
1343 "(error: %s, attempts: %d)\n",
1344 nt_errstr(result), netr_attempts));
1345
1346 /* After the first retry always close the connection */
1347 if (netr_attempts > 0) {
1348 DEBUG(3, ("This is again a problem for this "
1349 "particular call, forcing the close "
1350 "of this connection\n"));
1351 invalidate_cm_connection(domain);
1352 }
1353
1354 /* After the second retry failover to the next DC */
1355 if (netr_attempts > 1) {
1356 /*
1357 * If the netlogon server is not reachable then
1358 * it is possible that the DC is rebuilding
1359 * sysvol and shutdown netlogon for that time.
1360 * We should failover to the next dc.
1361 */
1362 DEBUG(3, ("This is the third problem for this "
1363 "particular call, adding DC to the "
1364 "negative cache list\n"));
1365 add_failed_connection_entry(domain->name,
1366 domain->dcname,
1367 result);
1368 saf_delete(domain->name);
1369 }
1370
1371 /* Only allow 3 retries */
1372 if (netr_attempts < 3) {
1373 DEBUG(3, ("The connection to netlogon "
1374 "failed, retrying\n"));
1375 netr_attempts++;
1376 retry = true;
1377 continue;
1378 }
1379 return result;
1380 }
1381 netr_attempts = 0;
1382 if (domain->conn.netlogon_creds == NULL) {
1383 DBG_NOTICE("No security credentials available for "
1384 "domain [%s]\n", domainname);
1385 result = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1386 } else if (interactive && username != NULL && password != NULL) {
1387 result = rpccli_netlogon_password_logon(domain->conn.netlogon_creds,
1388 netlogon_pipe->binding_handle,
1389 mem_ctx,
1390 logon_parameters,
1391 domainname,
1392 username,
1393 password,
1394 workstation,
1395 NetlogonInteractiveInformation,
1396 info3);
1397 } else {
1398 result = rpccli_netlogon_network_logon(domain->conn.netlogon_creds,
1399 netlogon_pipe->binding_handle,
1400 mem_ctx,
1401 logon_parameters,
1402 username,
1403 domainname,
1404 workstation,
1405 chal,
1406 lm_response,
1407 nt_response,
1408 &authoritative,
1409 &flags,
1410 info3);
1411 }
1412
1413 /*
1414 * we increment this after the "feature negotiation"
1415 * for can_do_samlogon_ex and can_do_validation6
1416 */
1417 attempts += 1;
1418
1419 /* We have to try a second time as cm_connect_netlogon
1420 might not yet have noticed that the DC has killed
1421 our connection. */
1422
1423 if (!rpccli_is_connected(netlogon_pipe)) {
1424 retry = true;
1425 continue;
1426 }
1427
1428 /* if we get access denied, a possible cause was that we had
1429 and open connection to the DC, but someone changed our
1430 machine account password out from underneath us using 'net
1431 rpc changetrustpw' */
1432
1433 if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
1434 DEBUG(1,("winbind_samlogon_retry_loop: sam_logon returned "
1435 "ACCESS_DENIED. Maybe the DC has Restrict "
1436 "NTLM set or the trust account "
1437 "password was changed and we didn't know it. "
1438 "Killing connections to domain %s\n",
1439 domainname));
1440 invalidate_cm_connection(domain);
1441 retry = true;
1442 }
1443
1444 if (NT_STATUS_EQUAL(result, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1445 /*
1446 * Got DCERPC_FAULT_OP_RNG_ERROR for SamLogon
1447 * (no Ex). This happens against old Samba
1448 * DCs, if LogonSamLogonEx() fails with an error
1449 * e.g. NT_STATUS_NO_SUCH_USER or NT_STATUS_WRONG_PASSWORD.
1450 *
1451 * The server will log something like this:
1452 * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
1453 *
1454 * This sets the whole connection into a fault_state mode
1455 * and all following request get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
1456 *
1457 * This also happens to our retry with LogonSamLogonWithFlags()
1458 * and LogonSamLogon().
1459 *
1460 * In order to recover from this situation, we need to
1461 * drop the connection.
1462 */
1463 invalidate_cm_connection(domain);
1464 result = NT_STATUS_LOGON_FAILURE;
1465 break;
1466 }
1467
1468 } while ( (attempts < 2) && retry );
1469
1470 if (NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT)) {
1471 DEBUG(3,("winbind_samlogon_retry_loop: sam_network_logon(ex) "
1472 "returned NT_STATUS_IO_TIMEOUT after the retry."
1473 "Killing connections to domain %s\n",
1474 domainname));
1475 invalidate_cm_connection(domain);
1476 }
1477 return result;
1478}
1479
1480static NTSTATUS winbindd_dual_pam_auth_samlogon(TALLOC_CTX *mem_ctx,
1481 struct winbindd_domain *domain,
1482 const char *user,
1483 const char *pass,
1484 uint32_t request_flags,
1485 struct netr_SamInfo3 **info3)
1486{
1487
1488 uchar chal[8];
1489 DATA_BLOB lm_resp;
1490 DATA_BLOB nt_resp;
1491 unsigned char local_nt_response[24];
1492 fstring name_domain, name_user;
1493 NTSTATUS result;
1494 struct netr_SamInfo3 *my_info3 = NULL;
1495
1496 *info3 = NULL;
1497
1498 DEBUG(10,("winbindd_dual_pam_auth_samlogon\n"));
1499
1500 /* Parse domain and username */
1501
1502 parse_domain_user(user, name_domain, name_user);
1503
1504 /* do password magic */
1505
1506 generate_random_buffer(chal, sizeof(chal));
1507
1508 if (lp_client_ntlmv2_auth()) {
1509 DATA_BLOB server_chal;
1510 DATA_BLOB names_blob;
1511 server_chal = data_blob_const(chal, 8);
1512
1513 /* note that the 'workgroup' here is for the local
1514 machine. The 'server name' must match the
1515 'workstation' passed to the actual SamLogon call.
1516 */
1517 names_blob = NTLMv2_generate_names_blob(
1518 mem_ctx, lp_netbios_name(), lp_workgroup());
1519
1520 if (!SMBNTLMv2encrypt(mem_ctx, name_user, name_domain,
1521 pass,
1522 &server_chal,
1523 &names_blob,
1524 &lm_resp, &nt_resp, NULL, NULL)) {
1525 data_blob_free(&names_blob);
1526 DEBUG(0, ("winbindd_pam_auth: SMBNTLMv2encrypt() failed!\n"));
1527 result = NT_STATUS_NO_MEMORY;
1528 goto done;
1529 }
1530 data_blob_free(&names_blob);
1531 } else {
1532 lm_resp = data_blob_null;
1533 SMBNTencrypt(pass, chal, local_nt_response);
1534
1535 nt_resp = data_blob_talloc(mem_ctx, local_nt_response,
1536 sizeof(local_nt_response));
1537 }
1538
1539 if (strequal(name_domain, get_global_sam_name())) {
1540 DATA_BLOB chal_blob = data_blob_const(chal, sizeof(chal));
1541
1542 result = winbindd_dual_auth_passdb(
1543 mem_ctx, 0, name_domain, name_user,
1544 &chal_blob, &lm_resp, &nt_resp, info3);
1545
1546 /*
1547 * We need to try the remote NETLOGON server if this is NOT_IMPLEMENTED
1548 */
1549 if (!NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
1550 goto done;
1551 }
1552 }
1553
1554 /* check authentication loop */
1555
1556 result = winbind_samlogon_retry_loop(domain,
1557 mem_ctx,
1558 0,
1559 name_user,
1560 pass,
1561 name_domain,
1562 lp_netbios_name(),
1563 chal,
1564 lm_resp,
1565 nt_resp,
1566 true, /* interactive */
1567 &my_info3);
1568 if (!NT_STATUS_IS_OK(result)) {
1569 goto done;
1570 }
1571
1572 /* handle the case where a NT4 DC does not fill in the acct_flags in
1573 * the samlogon reply info3. When accurate info3 is required by the
1574 * caller, we look up the account flags ourselve - gd */
1575
1576 if ((request_flags & WBFLAG_PAM_INFO3_TEXT) &&
1577 NT_STATUS_IS_OK(result) && (my_info3->base.acct_flags == 0)) {
1578
1579 struct rpc_pipe_client *samr_pipe;
1580 struct policy_handle samr_domain_handle, user_pol;
1581 union samr_UserInfo *info = NULL;
1582 NTSTATUS status_tmp, result_tmp;
1583 uint32_t acct_flags;
1584 struct dcerpc_binding_handle *b;
1585
1586 status_tmp = cm_connect_sam(domain, mem_ctx, false,
1587 &samr_pipe, &samr_domain_handle);
1588
1589 if (!NT_STATUS_IS_OK(status_tmp)) {
1590 DEBUG(3, ("could not open handle to SAMR pipe: %s\n",
1591 nt_errstr(status_tmp)));
1592 goto done;
1593 }
1594
1595 b = samr_pipe->binding_handle;
1596
1597 status_tmp = dcerpc_samr_OpenUser(b, mem_ctx,
1598 &samr_domain_handle,
1599 MAXIMUM_ALLOWED_ACCESS,
1600 my_info3->base.rid,
1601 &user_pol,
1602 &result_tmp);
1603
1604 if (!NT_STATUS_IS_OK(status_tmp)) {
1605 DEBUG(3, ("could not open user handle on SAMR pipe: %s\n",
1606 nt_errstr(status_tmp)));
1607 goto done;
1608 }
1609 if (!NT_STATUS_IS_OK(result_tmp)) {
1610 DEBUG(3, ("could not open user handle on SAMR pipe: %s\n",
1611 nt_errstr(result_tmp)));
1612 goto done;
1613 }
1614
1615 status_tmp = dcerpc_samr_QueryUserInfo(b, mem_ctx,
1616 &user_pol,
1617 16,
1618 &info,
1619 &result_tmp);
1620
1621 if (!NT_STATUS_IS_OK(status_tmp)) {
1622 DEBUG(3, ("could not query user info on SAMR pipe: %s\n",
1623 nt_errstr(status_tmp)));
1624 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
1625 goto done;
1626 }
1627 if (!NT_STATUS_IS_OK(result_tmp)) {
1628 DEBUG(3, ("could not query user info on SAMR pipe: %s\n",
1629 nt_errstr(result_tmp)));
1630 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
1631 goto done;
1632 }
1633
1634 acct_flags = info->info16.acct_flags;
1635
1636 if (acct_flags == 0) {
1637 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
1638 goto done;
1639 }
1640
1641 my_info3->base.acct_flags = acct_flags;
1642
1643 DEBUG(10,("successfully retrieved acct_flags 0x%x\n", acct_flags));
1644
1645 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
1646 }
1647
1648 *info3 = my_info3;
1649done:
1650 return result;
1651}
1652
1653enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain,
1654 struct winbindd_cli_state *state)
1655{
1656 NTSTATUS result = NT_STATUS_LOGON_FAILURE;
1657 NTSTATUS krb5_result = NT_STATUS_OK;
1658 fstring name_domain, name_user;
1659 char *mapped_user;
1660 fstring domain_user;
1661 struct netr_SamInfo3 *info3 = NULL;
1662 NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL;
1663
1664 /* Ensure null termination */
1665 state->request->data.auth.user[sizeof(state->request->data.auth.user)-1]='\0';
1666
1667 /* Ensure null termination */
1668 state->request->data.auth.pass[sizeof(state->request->data.auth.pass)-1]='\0';
1669
1670 DEBUG(3, ("[%5lu]: dual pam auth %s\n", (unsigned long)state->pid,
1671 state->request->data.auth.user));
1672
1673 /* Parse domain and username */
1674
1675 name_map_status = normalize_name_unmap(state->mem_ctx,
1676 state->request->data.auth.user,
1677 &mapped_user);
1678
1679 /* If the name normalization didnt' actually do anything,
1680 just use the original name */
1681
1682 if (!NT_STATUS_IS_OK(name_map_status) &&
1683 !NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED))
1684 {
1685 mapped_user = state->request->data.auth.user;
1686 }
1687
1688 parse_domain_user(mapped_user, name_domain, name_user);
1689
1690 if ( mapped_user != state->request->data.auth.user ) {
1691 fstr_sprintf( domain_user, "%s%c%s", name_domain,
1692 *lp_winbind_separator(),
1693 name_user );
1694 strlcpy( state->request->data.auth.user, domain_user,
1695 sizeof(state->request->data.auth.user));
1696 }
1697
1698 if (!domain->online) {
1699 result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
1700 if (domain->startup) {
1701 /* Logons are very important to users. If we're offline and
1702 we get a request within the first 30 seconds of startup,
1703 try very hard to find a DC and go online. */
1704
1705 DEBUG(10,("winbindd_dual_pam_auth: domain: %s offline and auth "
1706 "request in startup mode.\n", domain->name ));
1707
1708 winbindd_flush_negative_conn_cache(domain);
1709 result = init_dc_connection(domain, false);
1710 }
1711 }
1712
1713 DEBUG(10,("winbindd_dual_pam_auth: domain: %s last was %s\n", domain->name, domain->online ? "online":"offline"));
1714
1715 /* Check for Kerberos authentication */
1716 if (domain->online && (state->request->flags & WBFLAG_PAM_KRB5)) {
1717
1718 result = winbindd_dual_pam_auth_kerberos(domain, state, &info3);
1719 /* save for later */
1720 krb5_result = result;
1721
1722
1723 if (NT_STATUS_IS_OK(result)) {
1724 DEBUG(10,("winbindd_dual_pam_auth_kerberos succeeded\n"));
1725 goto process_result;
1726 } else {
1727 DEBUG(10,("winbindd_dual_pam_auth_kerberos failed: %s\n", nt_errstr(result)));
1728 }
1729
1730 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
1731 NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
1732 NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1733 DEBUG(10,("winbindd_dual_pam_auth_kerberos setting domain to offline\n"));
1734 set_domain_offline( domain );
1735 goto cached_logon;
1736 }
1737
1738 /* there are quite some NT_STATUS errors where there is no
1739 * point in retrying with a samlogon, we explictly have to take
1740 * care not to increase the bad logon counter on the DC */
1741
1742 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_DISABLED) ||
1743 NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_EXPIRED) ||
1744 NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_LOCKED_OUT) ||
1745 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_LOGON_HOURS) ||
1746 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_WORKSTATION) ||
1747 NT_STATUS_EQUAL(result, NT_STATUS_LOGON_FAILURE) ||
1748 NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER) ||
1749 NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_EXPIRED) ||
1750 NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_MUST_CHANGE) ||
1751 NT_STATUS_EQUAL(result, NT_STATUS_WRONG_PASSWORD)) {
1752 goto done;
1753 }
1754
1755 if (state->request->flags & WBFLAG_PAM_FALLBACK_AFTER_KRB5) {
1756 DEBUG(3,("falling back to samlogon\n"));
1757 goto sam_logon;
1758 } else {
1759 goto cached_logon;
1760 }
1761 }
1762
1763sam_logon:
1764 /* Check for Samlogon authentication */
1765 if (domain->online) {
1766 result = winbindd_dual_pam_auth_samlogon(
1767 state->mem_ctx, domain,
1768 state->request->data.auth.user,
1769 state->request->data.auth.pass,
1770 state->request->flags,
1771 &info3);
1772
1773 if (NT_STATUS_IS_OK(result)) {
1774 DEBUG(10,("winbindd_dual_pam_auth_samlogon succeeded\n"));
1775 /* add the Krb5 err if we have one */
1776 if ( NT_STATUS_EQUAL(krb5_result, NT_STATUS_TIME_DIFFERENCE_AT_DC ) ) {
1777 info3->base.user_flags |= LOGON_KRB5_FAIL_CLOCK_SKEW;
1778 }
1779 goto process_result;
1780 }
1781
1782 DEBUG(10,("winbindd_dual_pam_auth_samlogon failed: %s\n",
1783 nt_errstr(result)));
1784
1785 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
1786 NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
1787 NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND))
1788 {
1789 DEBUG(10,("winbindd_dual_pam_auth_samlogon setting domain to offline\n"));
1790 set_domain_offline( domain );
1791 goto cached_logon;
1792 }
1793
1794 if (domain->online) {
1795 /* We're still online - fail. */
1796 goto done;
1797 }
1798 }
1799
1800cached_logon:
1801 /* Check for Cached logons */
1802 if (!domain->online && (state->request->flags & WBFLAG_PAM_CACHED_LOGIN) &&
1803 lp_winbind_offline_logon()) {
1804
1805 result = winbindd_dual_pam_auth_cached(domain, state, &info3);
1806
1807 if (NT_STATUS_IS_OK(result)) {
1808 DEBUG(10,("winbindd_dual_pam_auth_cached succeeded\n"));
1809 goto process_result;
1810 } else {
1811 DEBUG(10,("winbindd_dual_pam_auth_cached failed: %s\n", nt_errstr(result)));
1812 goto done;
1813 }
1814 }
1815
1816process_result:
1817
1818 if (NT_STATUS_IS_OK(result)) {
1819
1820 struct dom_sid user_sid;
1821
1822 /* In all codepaths where result == NT_STATUS_OK info3 must have
1823 been initialized. */
1824 if (!info3) {
1825 result = NT_STATUS_INTERNAL_ERROR;
1826 goto done;
1827 }
1828
1829 sid_compose(&user_sid, info3->base.domain_sid,
1830 info3->base.rid);
1831
1832 if (info3->base.full_name.string == NULL) {
1833 struct netr_SamInfo3 *cached_info3;
1834
1835 cached_info3 = netsamlogon_cache_get(state->mem_ctx,
1836 &user_sid);
1837 if (cached_info3 != NULL &&
1838 cached_info3->base.full_name.string != NULL) {
1839 info3->base.full_name.string =
1840 talloc_strdup(info3,
1841 cached_info3->base.full_name.string);
1842 } else {
1843
1844 /* this might fail so we don't check the return code */
1845 wcache_query_user_fullname(domain,
1846 info3,
1847 &user_sid,
1848 &info3->base.full_name.string);
1849 }
1850 }
1851
1852 wcache_invalidate_samlogon(find_domain_from_name(name_domain),
1853 &user_sid);
1854 netsamlogon_cache_store(name_user, info3);
1855
1856 /* save name_to_sid info as early as possible (only if
1857 this is our primary domain so we don't invalidate
1858 the cache entry by storing the seq_num for the wrong
1859 domain). */
1860 if ( domain->primary ) {
1861 cache_name2sid(domain, name_domain, name_user,
1862 SID_NAME_USER, &user_sid);
1863 }
1864
1865 /* Check if the user is in the right group */
1866
1867 result = check_info3_in_group(
1868 info3,
1869 state->request->data.auth.require_membership_of_sid);
1870 if (!NT_STATUS_IS_OK(result)) {
1871 DEBUG(3, ("User %s is not in the required group (%s), so plaintext authentication is rejected\n",
1872 state->request->data.auth.user,
1873 state->request->data.auth.require_membership_of_sid));
1874 goto done;
1875 }
1876
1877 result = append_auth_data(state->mem_ctx, state->response,
1878 state->request->flags, info3,
1879 name_domain, name_user);
1880 if (!NT_STATUS_IS_OK(result)) {
1881 goto done;
1882 }
1883
1884 if ((state->request->flags & WBFLAG_PAM_CACHED_LOGIN)
1885 && lp_winbind_offline_logon()) {
1886
1887 result = winbindd_store_creds(domain,
1888 state->request->data.auth.user,
1889 state->request->data.auth.pass,
1890 info3);
1891 }
1892
1893 if (state->request->flags & WBFLAG_PAM_GET_PWD_POLICY) {
1894 struct winbindd_domain *our_domain = find_our_domain();
1895
1896 /* This is not entirely correct I believe, but it is
1897 consistent. Only apply the password policy settings
1898 too warn users for our own domain. Cannot obtain these
1899 from trusted DCs all the time so don't do it at all.
1900 -- jerry */
1901
1902 result = NT_STATUS_NOT_SUPPORTED;
1903 if (our_domain == domain ) {
1904 result = fillup_password_policy(
1905 our_domain, state->response);
1906 }
1907
1908 if (!NT_STATUS_IS_OK(result)
1909 && !NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED) )
1910 {
1911 DEBUG(10,("Failed to get password policies for domain %s: %s\n",
1912 domain->name, nt_errstr(result)));
1913 goto done;
1914 }
1915 }
1916
1917 result = NT_STATUS_OK;
1918 }
1919
1920done:
1921 /* give us a more useful (more correct?) error code */
1922 if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
1923 (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
1924 result = NT_STATUS_NO_LOGON_SERVERS;
1925 }
1926
1927 set_auth_errors(state->response, result);
1928
1929 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, ("Plain-text authentication for user %s returned %s (PAM: %d)\n",
1930 state->request->data.auth.user,
1931 state->response->data.auth.nt_status_string,
1932 state->response->data.auth.pam_error));
1933
1934 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
1935}
1936
1937NTSTATUS winbind_dual_SamLogon(struct winbindd_domain *domain,
1938 TALLOC_CTX *mem_ctx,
1939 uint32_t logon_parameters,
1940 const char *name_user,
1941 const char *name_domain,
1942 const char *workstation,
1943 const uint8_t chal[8],
1944 DATA_BLOB lm_response,
1945 DATA_BLOB nt_response,
1946 struct netr_SamInfo3 **info3)
1947{
1948 NTSTATUS result;
1949
1950 if (strequal(name_domain, get_global_sam_name())) {
1951 DATA_BLOB chal_blob = data_blob_const(
1952 chal, 8);
1953
1954 result = winbindd_dual_auth_passdb(
1955 mem_ctx,
1956 logon_parameters,
1957 name_domain, name_user,
1958 &chal_blob, &lm_response, &nt_response, info3);
1959
1960 /*
1961 * We need to try the remote NETLOGON server if this is NOT_IMPLEMENTED
1962 */
1963 if (!NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
1964 goto process_result;
1965 }
1966 }
1967
1968 result = winbind_samlogon_retry_loop(domain,
1969 mem_ctx,
1970 logon_parameters,
1971 name_user,
1972 NULL, /* password */
1973 name_domain,
1974 /* Bug #3248 - found by Stefan Burkei. */
1975 workstation, /* We carefully set this above so use it... */
1976 chal,
1977 lm_response,
1978 nt_response,
1979 false, /* interactive */
1980 info3);
1981 if (!NT_STATUS_IS_OK(result)) {
1982 goto done;
1983 }
1984
1985process_result:
1986
1987 if (NT_STATUS_IS_OK(result)) {
1988 struct dom_sid user_sid;
1989
1990 sid_compose(&user_sid, (*info3)->base.domain_sid,
1991 (*info3)->base.rid);
1992
1993 if ((*info3)->base.full_name.string == NULL) {
1994 struct netr_SamInfo3 *cached_info3;
1995
1996 cached_info3 = netsamlogon_cache_get(mem_ctx,
1997 &user_sid);
1998 if (cached_info3 != NULL &&
1999 cached_info3->base.full_name.string != NULL) {
2000 (*info3)->base.full_name.string =
2001 talloc_strdup(*info3,
2002 cached_info3->base.full_name.string);
2003 } else {
2004
2005 /* this might fail so we don't check the return code */
2006 wcache_query_user_fullname(domain,
2007 *info3,
2008 &user_sid,
2009 &(*info3)->base.full_name.string);
2010 }
2011 }
2012
2013 wcache_invalidate_samlogon(find_domain_from_name(name_domain),
2014 &user_sid);
2015 netsamlogon_cache_store(name_user, *info3);
2016 }
2017
2018done:
2019
2020 /* give us a more useful (more correct?) error code */
2021 if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
2022 (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
2023 result = NT_STATUS_NO_LOGON_SERVERS;
2024 }
2025
2026 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
2027 ("NTLM CRAP authentication for user [%s]\\[%s] returned %s\n",
2028 name_domain,
2029 name_user,
2030 nt_errstr(result)));
2031
2032 return result;
2033}
2034
2035enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain,
2036 struct winbindd_cli_state *state)
2037{
2038 NTSTATUS result;
2039 struct netr_SamInfo3 *info3 = NULL;
2040 const char *name_user = NULL;
2041 const char *name_domain = NULL;
2042 const char *workstation;
2043
2044 DATA_BLOB lm_resp, nt_resp;
2045
2046 /* This is child-only, so no check for privileged access is needed
2047 anymore */
2048
2049 /* Ensure null termination */
2050 state->request->data.auth_crap.user[sizeof(state->request->data.auth_crap.user)-1]=0;
2051 state->request->data.auth_crap.domain[sizeof(state->request->data.auth_crap.domain)-1]=0;
2052
2053 name_user = state->request->data.auth_crap.user;
2054 name_domain = state->request->data.auth_crap.domain;
2055 workstation = state->request->data.auth_crap.workstation;
2056
2057 DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n", (unsigned long)state->pid,
2058 name_domain, name_user));
2059
2060 if (state->request->data.auth_crap.lm_resp_len > sizeof(state->request->data.auth_crap.lm_resp)
2061 || state->request->data.auth_crap.nt_resp_len > sizeof(state->request->data.auth_crap.nt_resp)) {
2062 if (!(state->request->flags & WBFLAG_BIG_NTLMV2_BLOB) ||
2063 state->request->extra_len != state->request->data.auth_crap.nt_resp_len) {
2064 DEBUG(0, ("winbindd_pam_auth_crap: invalid password length %u/%u\n",
2065 state->request->data.auth_crap.lm_resp_len,
2066 state->request->data.auth_crap.nt_resp_len));
2067 result = NT_STATUS_INVALID_PARAMETER;
2068 goto done;
2069 }
2070 }
2071
2072 lm_resp = data_blob_talloc(state->mem_ctx, state->request->data.auth_crap.lm_resp,
2073 state->request->data.auth_crap.lm_resp_len);
2074
2075 if (state->request->flags & WBFLAG_BIG_NTLMV2_BLOB) {
2076 nt_resp = data_blob_talloc(state->mem_ctx,
2077 state->request->extra_data.data,
2078 state->request->data.auth_crap.nt_resp_len);
2079 } else {
2080 nt_resp = data_blob_talloc(state->mem_ctx,
2081 state->request->data.auth_crap.nt_resp,
2082 state->request->data.auth_crap.nt_resp_len);
2083 }
2084
2085 result = winbind_dual_SamLogon(domain,
2086 state->mem_ctx,
2087 state->request->data.auth_crap.logon_parameters,
2088 name_user,
2089 name_domain,
2090 /* Bug #3248 - found by Stefan Burkei. */
2091 workstation, /* We carefully set this above so use it... */
2092 state->request->data.auth_crap.chal,
2093 lm_resp,
2094 nt_resp,
2095 &info3);
2096 if (!NT_STATUS_IS_OK(result)) {
2097 goto done;
2098 }
2099
2100 if (NT_STATUS_IS_OK(result)) {
2101 /* Check if the user is in the right group */
2102
2103 result = check_info3_in_group(
2104 info3,
2105 state->request->data.auth_crap.require_membership_of_sid);
2106 if (!NT_STATUS_IS_OK(result)) {
2107 DEBUG(3, ("User %s is not in the required group (%s), so "
2108 "crap authentication is rejected\n",
2109 state->request->data.auth_crap.user,
2110 state->request->data.auth_crap.require_membership_of_sid));
2111 goto done;
2112 }
2113
2114 result = append_auth_data(state->mem_ctx, state->response,
2115 state->request->flags, info3,
2116 name_domain, name_user);
2117 if (!NT_STATUS_IS_OK(result)) {
2118 goto done;
2119 }
2120 }
2121
2122done:
2123
2124 if (state->request->flags & WBFLAG_PAM_NT_STATUS_SQUASH) {
2125 result = nt_status_squash(result);
2126 }
2127
2128 set_auth_errors(state->response, result);
2129
2130 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2131}
2132
2133enum winbindd_result winbindd_dual_pam_chauthtok(struct winbindd_domain *contact_domain,
2134 struct winbindd_cli_state *state)
2135{
2136 char *oldpass;
2137 char *newpass = NULL;
2138 struct policy_handle dom_pol;
2139 struct rpc_pipe_client *cli = NULL;
2140 bool got_info = false;
2141 struct samr_DomInfo1 *info = NULL;
2142 struct userPwdChangeFailureInformation *reject = NULL;
2143 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
2144 fstring domain, user;
2145 struct dcerpc_binding_handle *b = NULL;
2146
2147 ZERO_STRUCT(dom_pol);
2148
2149 DEBUG(3, ("[%5lu]: dual pam chauthtok %s\n", (unsigned long)state->pid,
2150 state->request->data.auth.user));
2151
2152 if (!parse_domain_user(state->request->data.chauthtok.user, domain, user)) {
2153 goto done;
2154 }
2155
2156 /* Change password */
2157
2158 oldpass = state->request->data.chauthtok.oldpass;
2159 newpass = state->request->data.chauthtok.newpass;
2160
2161 /* Initialize reject reason */
2162 state->response->data.auth.reject_reason = Undefined;
2163
2164 /* Get sam handle */
2165
2166 result = cm_connect_sam(contact_domain, state->mem_ctx, true, &cli,
2167 &dom_pol);
2168 if (!NT_STATUS_IS_OK(result)) {
2169 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
2170 goto done;
2171 }
2172
2173 b = cli->binding_handle;
2174
2175 result = rpccli_samr_chgpasswd_user3(cli, state->mem_ctx,
2176 user,
2177 newpass,
2178 oldpass,
2179 &info,
2180 &reject);
2181
2182 /* Windows 2003 returns NT_STATUS_PASSWORD_RESTRICTION */
2183
2184 if (NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_RESTRICTION) ) {
2185
2186 fill_in_password_policy(state->response, info);
2187
2188 state->response->data.auth.reject_reason =
2189 reject->extendedFailureReason;
2190
2191 got_info = true;
2192 }
2193
2194 /* atm the pidl generated rpccli_samr_ChangePasswordUser3 function will
2195 * return with NT_STATUS_BUFFER_TOO_SMALL for w2k dcs as w2k just
2196 * returns with 4byte error code (NT_STATUS_NOT_SUPPORTED) which is too
2197 * short to comply with the samr_ChangePasswordUser3 idl - gd */
2198
2199 /* only fallback when the chgpasswd_user3 call is not supported */
2200 if (NT_STATUS_EQUAL(result, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE) ||
2201 NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED) ||
2202 NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL) ||
2203 NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
2204
2205 DEBUG(10,("Password change with chgpasswd_user3 failed with: %s, retrying chgpasswd_user2\n",
2206 nt_errstr(result)));
2207
2208 result = rpccli_samr_chgpasswd_user2(cli, state->mem_ctx, user, newpass, oldpass);
2209
2210 /* Windows 2000 returns NT_STATUS_ACCOUNT_RESTRICTION.
2211 Map to the same status code as Windows 2003. */
2212
2213 if ( NT_STATUS_EQUAL(NT_STATUS_ACCOUNT_RESTRICTION, result ) ) {
2214 result = NT_STATUS_PASSWORD_RESTRICTION;
2215 }
2216 }
2217
2218done:
2219
2220 if (NT_STATUS_IS_OK(result)
2221 && (state->request->flags & WBFLAG_PAM_CACHED_LOGIN)
2222 && lp_winbind_offline_logon()) {
2223 result = winbindd_update_creds_by_name(contact_domain, user,
2224 newpass);
2225 /* Again, this happens when we login from gdm or xdm
2226 * and the password expires, *BUT* cached crendentials
2227 * doesn't exist. winbindd_update_creds_by_name()
2228 * returns NT_STATUS_NO_SUCH_USER.
2229 * This is not a failure.
2230 * --- BoYang
2231 * */
2232 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER)) {
2233 result = NT_STATUS_OK;
2234 }
2235
2236 if (!NT_STATUS_IS_OK(result)) {
2237 DEBUG(10, ("Failed to store creds: %s\n",
2238 nt_errstr(result)));
2239 goto process_result;
2240 }
2241 }
2242
2243 if (!NT_STATUS_IS_OK(result) && !got_info && contact_domain) {
2244
2245 NTSTATUS policy_ret;
2246
2247 policy_ret = fillup_password_policy(
2248 contact_domain, state->response);
2249
2250 /* failure of this is non critical, it will just provide no
2251 * additional information to the client why the change has
2252 * failed - Guenther */
2253
2254 if (!NT_STATUS_IS_OK(policy_ret)) {
2255 DEBUG(10,("Failed to get password policies: %s\n", nt_errstr(policy_ret)));
2256 goto process_result;
2257 }
2258 }
2259
2260process_result:
2261
2262 if (strequal(contact_domain->name, get_global_sam_name())) {
2263 /* FIXME: internal rpc pipe does not cache handles yet */
2264 if (b) {
2265 if (is_valid_policy_hnd(&dom_pol)) {
2266 NTSTATUS _result;
2267 dcerpc_samr_Close(b, state->mem_ctx, &dom_pol, &_result);
2268 }
2269 TALLOC_FREE(cli);
2270 }
2271 }
2272
2273 set_auth_errors(state->response, result);
2274
2275 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
2276 ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
2277 domain,
2278 user,
2279 state->response->data.auth.nt_status_string,
2280 state->response->data.auth.pam_error));
2281
2282 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2283}
2284
2285enum winbindd_result winbindd_dual_pam_logoff(struct winbindd_domain *domain,
2286 struct winbindd_cli_state *state)
2287{
2288 NTSTATUS result = NT_STATUS_NOT_SUPPORTED;
2289
2290 DEBUG(3, ("[%5lu]: pam dual logoff %s\n", (unsigned long)state->pid,
2291 state->request->data.logoff.user));
2292
2293 if (!(state->request->flags & WBFLAG_PAM_KRB5)) {
2294 result = NT_STATUS_OK;
2295 goto process_result;
2296 }
2297
2298 if (state->request->data.logoff.krb5ccname[0] == '\0') {
2299 result = NT_STATUS_OK;
2300 goto process_result;
2301 }
2302
2303#ifdef HAVE_KRB5
2304
2305 if (state->request->data.logoff.uid < 0) {
2306 DEBUG(0,("winbindd_pam_logoff: invalid uid\n"));
2307 goto process_result;
2308 }
2309
2310 /* what we need here is to find the corresponding krb5 ccache name *we*
2311 * created for a given username and destroy it */
2312
2313 if (!ccache_entry_exists(state->request->data.logoff.user)) {
2314 result = NT_STATUS_OK;
2315 DEBUG(10,("winbindd_pam_logoff: no entry found.\n"));
2316 goto process_result;
2317 }
2318
2319 if (!ccache_entry_identical(state->request->data.logoff.user,
2320 state->request->data.logoff.uid,
2321 state->request->data.logoff.krb5ccname)) {
2322 DEBUG(0,("winbindd_pam_logoff: cached entry differs.\n"));
2323 goto process_result;
2324 }
2325
2326 result = remove_ccache(state->request->data.logoff.user);
2327 if (!NT_STATUS_IS_OK(result)) {
2328 DEBUG(0,("winbindd_pam_logoff: failed to remove ccache: %s\n",
2329 nt_errstr(result)));
2330 goto process_result;
2331 }
2332
2333 /*
2334 * Remove any mlock'ed memory creds in the child
2335 * we might be using for krb5 ticket renewal.
2336 */
2337
2338 winbindd_delete_memory_creds(state->request->data.logoff.user);
2339
2340#else
2341 result = NT_STATUS_NOT_SUPPORTED;
2342#endif
2343
2344process_result:
2345
2346
2347 set_auth_errors(state->response, result);
2348
2349 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2350}
2351
2352/* Change user password with auth crap*/
2353
2354enum winbindd_result winbindd_dual_pam_chng_pswd_auth_crap(struct winbindd_domain *domainSt, struct winbindd_cli_state *state)
2355{
2356 NTSTATUS result;
2357 DATA_BLOB new_nt_password;
2358 DATA_BLOB old_nt_hash_enc;
2359 DATA_BLOB new_lm_password;
2360 DATA_BLOB old_lm_hash_enc;
2361 fstring domain,user;
2362 struct policy_handle dom_pol;
2363 struct winbindd_domain *contact_domain = domainSt;
2364 struct rpc_pipe_client *cli = NULL;
2365 struct dcerpc_binding_handle *b = NULL;
2366
2367 ZERO_STRUCT(dom_pol);
2368
2369 /* Ensure null termination */
2370 state->request->data.chng_pswd_auth_crap.user[
2371 sizeof(state->request->data.chng_pswd_auth_crap.user)-1]=0;
2372 state->request->data.chng_pswd_auth_crap.domain[
2373 sizeof(state->request->data.chng_pswd_auth_crap.domain)-1]=0;
2374 *domain = 0;
2375 *user = 0;
2376
2377 DEBUG(3, ("[%5lu]: pam change pswd auth crap domain: %s user: %s\n",
2378 (unsigned long)state->pid,
2379 state->request->data.chng_pswd_auth_crap.domain,
2380 state->request->data.chng_pswd_auth_crap.user));
2381
2382 if (lp_winbind_offline_logon()) {
2383 DEBUG(0,("Refusing password change as winbind offline logons are enabled. "));
2384 DEBUGADD(0,("Changing passwords here would risk inconsistent logons\n"));
2385 result = NT_STATUS_ACCESS_DENIED;
2386 goto done;
2387 }
2388
2389 if (*state->request->data.chng_pswd_auth_crap.domain) {
2390 fstrcpy(domain,state->request->data.chng_pswd_auth_crap.domain);
2391 } else {
2392 parse_domain_user(state->request->data.chng_pswd_auth_crap.user,
2393 domain, user);
2394
2395 if(!*domain) {
2396 DEBUG(3,("no domain specified with username (%s) - "
2397 "failing auth\n",
2398 state->request->data.chng_pswd_auth_crap.user));
2399 result = NT_STATUS_NO_SUCH_USER;
2400 goto done;
2401 }
2402 }
2403
2404 if (!*domain && lp_winbind_use_default_domain()) {
2405 fstrcpy(domain,lp_workgroup());
2406 }
2407
2408 if(!*user) {
2409 fstrcpy(user, state->request->data.chng_pswd_auth_crap.user);
2410 }
2411
2412 DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n",
2413 (unsigned long)state->pid, domain, user));
2414
2415 /* Change password */
2416 new_nt_password = data_blob_const(
2417 state->request->data.chng_pswd_auth_crap.new_nt_pswd,
2418 state->request->data.chng_pswd_auth_crap.new_nt_pswd_len);
2419
2420 old_nt_hash_enc = data_blob_const(
2421 state->request->data.chng_pswd_auth_crap.old_nt_hash_enc,
2422 state->request->data.chng_pswd_auth_crap.old_nt_hash_enc_len);
2423
2424 if(state->request->data.chng_pswd_auth_crap.new_lm_pswd_len > 0) {
2425 new_lm_password = data_blob_const(
2426 state->request->data.chng_pswd_auth_crap.new_lm_pswd,
2427 state->request->data.chng_pswd_auth_crap.new_lm_pswd_len);
2428
2429 old_lm_hash_enc = data_blob_const(
2430 state->request->data.chng_pswd_auth_crap.old_lm_hash_enc,
2431 state->request->data.chng_pswd_auth_crap.old_lm_hash_enc_len);
2432 } else {
2433 new_lm_password = data_blob_null;
2434 old_lm_hash_enc = data_blob_null;
2435 }
2436
2437 /* Get sam handle */
2438
2439 result = cm_connect_sam(contact_domain, state->mem_ctx, true, &cli, &dom_pol);
2440 if (!NT_STATUS_IS_OK(result)) {
2441 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
2442 goto done;
2443 }
2444
2445 b = cli->binding_handle;
2446
2447 result = rpccli_samr_chng_pswd_auth_crap(
2448 cli, state->mem_ctx, user, new_nt_password, old_nt_hash_enc,
2449 new_lm_password, old_lm_hash_enc);
2450
2451 done:
2452
2453 if (strequal(contact_domain->name, get_global_sam_name())) {
2454 /* FIXME: internal rpc pipe does not cache handles yet */
2455 if (b) {
2456 if (is_valid_policy_hnd(&dom_pol)) {
2457 NTSTATUS _result;
2458 dcerpc_samr_Close(b, state->mem_ctx, &dom_pol, &_result);
2459 }
2460 TALLOC_FREE(cli);
2461 }
2462 }
2463
2464 set_auth_errors(state->response, result);
2465
2466 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
2467 ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
2468 domain, user,
2469 state->response->data.auth.nt_status_string,
2470 state->response->data.auth.pam_error));
2471
2472 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2473}
2474
2475#ifdef HAVE_KRB5
2476static NTSTATUS extract_pac_vrfy_sigs(TALLOC_CTX *mem_ctx, DATA_BLOB pac_blob,
2477 struct PAC_LOGON_INFO **logon_info)
2478{
2479 krb5_context krbctx = NULL;
2480 krb5_error_code k5ret;
2481 krb5_keytab keytab;
2482 krb5_kt_cursor cursor;
2483 krb5_keytab_entry entry;
2484 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
2485
2486 ZERO_STRUCT(entry);
2487 ZERO_STRUCT(cursor);
2488
2489 k5ret = krb5_init_context(&krbctx);
2490 if (k5ret) {
2491 DEBUG(1, ("Failed to initialize kerberos context: %s\n",
2492 error_message(k5ret)));
2493 status = krb5_to_nt_status(k5ret);
2494 goto out;
2495 }
2496
2497 k5ret = gse_krb5_get_server_keytab(krbctx, &keytab);
2498 if (k5ret) {
2499 DEBUG(1, ("Failed to get keytab: %s\n",
2500 error_message(k5ret)));
2501 status = krb5_to_nt_status(k5ret);
2502 goto out_free;
2503 }
2504
2505 k5ret = krb5_kt_start_seq_get(krbctx, keytab, &cursor);
2506 if (k5ret) {
2507 DEBUG(1, ("Failed to start seq: %s\n",
2508 error_message(k5ret)));
2509 status = krb5_to_nt_status(k5ret);
2510 goto out_keytab;
2511 }
2512
2513 k5ret = krb5_kt_next_entry(krbctx, keytab, &entry, &cursor);
2514 while (k5ret == 0) {
2515 status = kerberos_pac_logon_info(mem_ctx, pac_blob,
2516 krbctx, NULL,
2517 KRB5_KT_KEY(&entry), NULL, 0,
2518 logon_info);
2519 if (NT_STATUS_IS_OK(status)) {
2520 break;
2521 }
2522 k5ret = smb_krb5_kt_free_entry(krbctx, &entry);
2523 k5ret = krb5_kt_next_entry(krbctx, keytab, &entry, &cursor);
2524 }
2525
2526 k5ret = krb5_kt_end_seq_get(krbctx, keytab, &cursor);
2527 if (k5ret) {
2528 DEBUG(1, ("Failed to end seq: %s\n",
2529 error_message(k5ret)));
2530 }
2531out_keytab:
2532 k5ret = krb5_kt_close(krbctx, keytab);
2533 if (k5ret) {
2534 DEBUG(1, ("Failed to close keytab: %s\n",
2535 error_message(k5ret)));
2536 }
2537out_free:
2538 krb5_free_context(krbctx);
2539out:
2540 return status;
2541}
2542
2543NTSTATUS winbindd_pam_auth_pac_send(struct winbindd_cli_state *state,
2544 struct netr_SamInfo3 **info3)
2545{
2546 struct winbindd_request *req = state->request;
2547 DATA_BLOB pac_blob;
2548 struct PAC_LOGON_INFO *logon_info = NULL;
2549 struct netr_SamInfo3 *info3_copy = NULL;
2550 NTSTATUS result;
2551
2552 pac_blob = data_blob_const(req->extra_data.data, req->extra_len);
2553 result = extract_pac_vrfy_sigs(state->mem_ctx, pac_blob, &logon_info);
2554 if (!NT_STATUS_IS_OK(result) &&
2555 !NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
2556 DEBUG(1, ("Error during PAC signature verification: %s\n",
2557 nt_errstr(result)));
2558 return result;
2559 }
2560
2561 if (logon_info) {
2562 /*
2563 * Signature verification succeeded, we can
2564 * trust the PAC and prime the netsamlogon
2565 * and name2sid caches. DO NOT DO THIS
2566 * in the signature verification failed
2567 * code path.
2568 */
2569 struct winbindd_domain *domain = NULL;
2570
2571 result = create_info3_from_pac_logon_info(state->mem_ctx,
2572 logon_info,
2573 &info3_copy);
2574 if (!NT_STATUS_IS_OK(result)) {
2575 return result;
2576 }
2577 netsamlogon_cache_store(NULL, info3_copy);
2578
2579 /*
2580 * We're in the parent here, so find the child
2581 * pointer from the PAC domain name.
2582 */
2583 domain = find_domain_from_name_noinit(
2584 info3_copy->base.logon_domain.string);
2585 if (domain && domain->primary ) {
2586 struct dom_sid user_sid;
2587
2588 sid_compose(&user_sid,
2589 info3_copy->base.domain_sid,
2590 info3_copy->base.rid);
2591
2592 cache_name2sid_trusted(domain,
2593 info3_copy->base.logon_domain.string,
2594 info3_copy->base.account_name.string,
2595 SID_NAME_USER,
2596 &user_sid);
2597
2598 DBG_INFO("PAC for user %s\%s SID %s primed cache\n",
2599 info3_copy->base.logon_domain.string,
2600 info3_copy->base.account_name.string,
2601 sid_string_dbg(&user_sid));
2602 }
2603
2604 } else {
2605 /* Try without signature verification */
2606 result = kerberos_pac_logon_info(state->mem_ctx, pac_blob, NULL,
2607 NULL, NULL, NULL, 0,
2608 &logon_info);
2609 if (!NT_STATUS_IS_OK(result)) {
2610 DEBUG(10, ("Could not extract PAC: %s\n",
2611 nt_errstr(result)));
2612 return result;
2613 }
2614 if (logon_info) {
2615 /*
2616 * Don't strictly need to copy here,
2617 * but it makes it explicit we're
2618 * returning a copy talloc'ed off
2619 * the state->mem_ctx.
2620 */
2621 info3_copy = copy_netr_SamInfo3(state->mem_ctx,
2622 &logon_info->info3);
2623 if (info3_copy == NULL) {
2624 return NT_STATUS_NO_MEMORY;
2625 }
2626 }
2627 }
2628
2629 *info3 = info3_copy;
2630
2631 return NT_STATUS_OK;
2632}
2633#else /* HAVE_KRB5 */
2634NTSTATUS winbindd_pam_auth_pac_send(struct winbindd_cli_state *state,
2635 struct netr_SamInfo3 **info3)
2636{
2637 return NT_STATUS_NO_SUCH_USER;
2638}
2639#endif /* HAVE_KRB5 */
Note: See TracBrowser for help on using the repository browser.