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

Last change on this file was 740, checked in by Silvan Scherrer, 13 years ago

Samba Server: update vendor to 3.6.0

File size: 63.5 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
41#undef DBGC_CLASS
42#define DBGC_CLASS DBGC_WINBIND
43
44#define LOGON_KRB5_FAIL_CLOCK_SKEW 0x02000000
45
46static NTSTATUS append_info3_as_txt(TALLOC_CTX *mem_ctx,
47 struct winbindd_response *resp,
48 struct netr_SamInfo3 *info3)
49{
50 char *ex;
51 uint32_t i;
52
53 resp->data.auth.info3.logon_time =
54 nt_time_to_unix(info3->base.last_logon);
55 resp->data.auth.info3.logoff_time =
56 nt_time_to_unix(info3->base.last_logoff);
57 resp->data.auth.info3.kickoff_time =
58 nt_time_to_unix(info3->base.acct_expiry);
59 resp->data.auth.info3.pass_last_set_time =
60 nt_time_to_unix(info3->base.last_password_change);
61 resp->data.auth.info3.pass_can_change_time =
62 nt_time_to_unix(info3->base.allow_password_change);
63 resp->data.auth.info3.pass_must_change_time =
64 nt_time_to_unix(info3->base.force_password_change);
65
66 resp->data.auth.info3.logon_count = info3->base.logon_count;
67 resp->data.auth.info3.bad_pw_count = info3->base.bad_password_count;
68
69 resp->data.auth.info3.user_rid = info3->base.rid;
70 resp->data.auth.info3.group_rid = info3->base.primary_gid;
71 sid_to_fstring(resp->data.auth.info3.dom_sid, info3->base.domain_sid);
72
73 resp->data.auth.info3.num_groups = info3->base.groups.count;
74 resp->data.auth.info3.user_flgs = info3->base.user_flags;
75
76 resp->data.auth.info3.acct_flags = info3->base.acct_flags;
77 resp->data.auth.info3.num_other_sids = info3->sidcount;
78
79 fstrcpy(resp->data.auth.info3.user_name,
80 info3->base.account_name.string);
81 fstrcpy(resp->data.auth.info3.full_name,
82 info3->base.full_name.string);
83 fstrcpy(resp->data.auth.info3.logon_script,
84 info3->base.logon_script.string);
85 fstrcpy(resp->data.auth.info3.profile_path,
86 info3->base.profile_path.string);
87 fstrcpy(resp->data.auth.info3.home_dir,
88 info3->base.home_directory.string);
89 fstrcpy(resp->data.auth.info3.dir_drive,
90 info3->base.home_drive.string);
91
92 fstrcpy(resp->data.auth.info3.logon_srv,
93 info3->base.logon_server.string);
94 fstrcpy(resp->data.auth.info3.logon_dom,
95 info3->base.domain.string);
96
97 ex = talloc_strdup(mem_ctx, "");
98 NT_STATUS_HAVE_NO_MEMORY(ex);
99
100 for (i=0; i < info3->base.groups.count; i++) {
101 ex = talloc_asprintf_append_buffer(ex, "0x%08X:0x%08X\n",
102 info3->base.groups.rids[i].rid,
103 info3->base.groups.rids[i].attributes);
104 NT_STATUS_HAVE_NO_MEMORY(ex);
105 }
106
107 for (i=0; i < info3->sidcount; i++) {
108 char *sid;
109
110 sid = dom_sid_string(mem_ctx, info3->sids[i].sid);
111 NT_STATUS_HAVE_NO_MEMORY(sid);
112
113 ex = talloc_asprintf_append_buffer(ex, "%s:0x%08X\n",
114 sid,
115 info3->sids[i].attributes);
116 NT_STATUS_HAVE_NO_MEMORY(ex);
117
118 talloc_free(sid);
119 }
120
121 resp->extra_data.data = ex;
122 resp->length += talloc_get_size(ex);
123
124 return NT_STATUS_OK;
125}
126
127static NTSTATUS append_info3_as_ndr(TALLOC_CTX *mem_ctx,
128 struct winbindd_response *resp,
129 struct netr_SamInfo3 *info3)
130{
131 DATA_BLOB blob;
132 enum ndr_err_code ndr_err;
133
134 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, info3,
135 (ndr_push_flags_fn_t)ndr_push_netr_SamInfo3);
136 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
137 DEBUG(0,("append_info3_as_ndr: failed to append\n"));
138 return ndr_map_error2ntstatus(ndr_err);
139 }
140
141 resp->extra_data.data = blob.data;
142 resp->length += blob.length;
143
144 return NT_STATUS_OK;
145}
146
147static NTSTATUS append_unix_username(TALLOC_CTX *mem_ctx,
148 struct winbindd_response *resp,
149 const struct netr_SamInfo3 *info3,
150 const char *name_domain,
151 const char *name_user)
152{
153 /* We've been asked to return the unix username, per
154 'winbind use default domain' settings and the like */
155
156 const char *nt_username, *nt_domain;
157
158 nt_domain = talloc_strdup(mem_ctx, info3->base.domain.string);
159 if (!nt_domain) {
160 /* If the server didn't give us one, just use the one
161 * we sent them */
162 nt_domain = name_domain;
163 }
164
165 nt_username = talloc_strdup(mem_ctx, info3->base.account_name.string);
166 if (!nt_username) {
167 /* If the server didn't give us one, just use the one
168 * we sent them */
169 nt_username = name_user;
170 }
171
172 fill_domain_username(resp->data.auth.unix_username,
173 nt_domain, nt_username, true);
174
175 DEBUG(5, ("Setting unix username to [%s]\n",
176 resp->data.auth.unix_username));
177
178 return NT_STATUS_OK;
179}
180
181static NTSTATUS append_afs_token(TALLOC_CTX *mem_ctx,
182 struct winbindd_response *resp,
183 const struct netr_SamInfo3 *info3,
184 const char *name_domain,
185 const char *name_user)
186{
187 char *afsname = NULL;
188 char *cell;
189 char *token;
190
191 afsname = talloc_strdup(mem_ctx, lp_afs_username_map());
192 if (afsname == NULL) {
193 return NT_STATUS_NO_MEMORY;
194 }
195
196 afsname = talloc_string_sub(mem_ctx,
197 lp_afs_username_map(),
198 "%D", name_domain);
199 afsname = talloc_string_sub(mem_ctx, afsname,
200 "%u", name_user);
201 afsname = talloc_string_sub(mem_ctx, afsname,
202 "%U", name_user);
203
204 {
205 struct dom_sid user_sid;
206 fstring sidstr;
207
208 sid_compose(&user_sid, info3->base.domain_sid,
209 info3->base.rid);
210 sid_to_fstring(sidstr, &user_sid);
211 afsname = talloc_string_sub(mem_ctx, afsname,
212 "%s", sidstr);
213 }
214
215 if (afsname == NULL) {
216 return NT_STATUS_NO_MEMORY;
217 }
218
219 strlower_m(afsname);
220
221 DEBUG(10, ("Generating token for user %s\n", afsname));
222
223 cell = strchr(afsname, '@');
224
225 if (cell == NULL) {
226 return NT_STATUS_NO_MEMORY;
227 }
228
229 *cell = '\0';
230 cell += 1;
231
232 token = afs_createtoken_str(afsname, cell);
233 if (token == NULL) {
234 return NT_STATUS_OK;
235 }
236 resp->extra_data.data = talloc_strdup(mem_ctx, token);
237 if (resp->extra_data.data == NULL) {
238 return NT_STATUS_NO_MEMORY;
239 }
240 resp->length += strlen((const char *)resp->extra_data.data)+1;
241
242 return NT_STATUS_OK;
243}
244
245static NTSTATUS check_info3_in_group(struct netr_SamInfo3 *info3,
246 const char *group_sid)
247/**
248 * Check whether a user belongs to a group or list of groups.
249 *
250 * @param mem_ctx talloc memory context.
251 * @param info3 user information, including group membership info.
252 * @param group_sid One or more groups , separated by commas.
253 *
254 * @return NT_STATUS_OK on success,
255 * NT_STATUS_LOGON_FAILURE if the user does not belong,
256 * or other NT_STATUS_IS_ERR(status) for other kinds of failure.
257 */
258{
259 struct dom_sid *require_membership_of_sid;
260 uint32_t num_require_membership_of_sid;
261 char *req_sid;
262 const char *p;
263 struct dom_sid sid;
264 size_t i;
265 struct security_token *token;
266 TALLOC_CTX *frame = talloc_stackframe();
267 NTSTATUS status;
268
269 /* Parse the 'required group' SID */
270
271 if (!group_sid || !group_sid[0]) {
272 /* NO sid supplied, all users may access */
273 return NT_STATUS_OK;
274 }
275
276 token = talloc_zero(talloc_tos(), struct security_token);
277 if (token == NULL) {
278 DEBUG(0, ("talloc failed\n"));
279 TALLOC_FREE(frame);
280 return NT_STATUS_NO_MEMORY;
281 }
282
283 num_require_membership_of_sid = 0;
284 require_membership_of_sid = NULL;
285
286 p = group_sid;
287
288 while (next_token_talloc(talloc_tos(), &p, &req_sid, ",")) {
289 if (!string_to_sid(&sid, req_sid)) {
290 DEBUG(0, ("check_info3_in_group: could not parse %s "
291 "as a SID!", req_sid));
292 TALLOC_FREE(frame);
293 return NT_STATUS_INVALID_PARAMETER;
294 }
295
296 status = add_sid_to_array(talloc_tos(), &sid,
297 &require_membership_of_sid,
298 &num_require_membership_of_sid);
299 if (!NT_STATUS_IS_OK(status)) {
300 DEBUG(0, ("add_sid_to_array failed\n"));
301 TALLOC_FREE(frame);
302 return status;
303 }
304 }
305
306 status = sid_array_from_info3(talloc_tos(), info3,
307 &token->sids,
308 &token->num_sids,
309 true, false);
310 if (!NT_STATUS_IS_OK(status)) {
311 TALLOC_FREE(frame);
312 return status;
313 }
314
315 if (!NT_STATUS_IS_OK(status = add_aliases(get_global_sam_sid(),
316 token))
317 || !NT_STATUS_IS_OK(status = add_aliases(&global_sid_Builtin,
318 token))) {
319 DEBUG(3, ("could not add aliases: %s\n",
320 nt_errstr(status)));
321 TALLOC_FREE(frame);
322 return status;
323 }
324
325 security_token_debug(DBGC_CLASS, 10, token);
326
327 for (i=0; i<num_require_membership_of_sid; i++) {
328 DEBUG(10, ("Checking SID %s\n", sid_string_dbg(
329 &require_membership_of_sid[i])));
330 if (nt_token_check_sid(&require_membership_of_sid[i],
331 token)) {
332 DEBUG(10, ("Access ok\n"));
333 TALLOC_FREE(frame);
334 return NT_STATUS_OK;
335 }
336 }
337
338 /* Do not distinguish this error from a wrong username/pw */
339
340 TALLOC_FREE(frame);
341 return NT_STATUS_LOGON_FAILURE;
342}
343
344struct winbindd_domain *find_auth_domain(uint8_t flags,
345 const char *domain_name)
346{
347 struct winbindd_domain *domain;
348
349 if (IS_DC) {
350 domain = find_domain_from_name_noinit(domain_name);
351 if (domain == NULL) {
352 DEBUG(3, ("Authentication for domain [%s] refused "
353 "as it is not a trusted domain\n",
354 domain_name));
355 }
356 return domain;
357 }
358
359 if (strequal(domain_name, get_global_sam_name())) {
360 return find_domain_from_name_noinit(domain_name);
361 }
362
363 /* we can auth against trusted domains */
364 if (flags & WBFLAG_PAM_CONTACT_TRUSTDOM) {
365 domain = find_domain_from_name_noinit(domain_name);
366 if (domain == NULL) {
367 DEBUG(3, ("Authentication for domain [%s] skipped "
368 "as it is not a trusted domain\n",
369 domain_name));
370 } else {
371 return domain;
372 }
373 }
374
375 return find_our_domain();
376}
377
378static void fill_in_password_policy(struct winbindd_response *r,
379 const struct samr_DomInfo1 *p)
380{
381 r->data.auth.policy.min_length_password =
382 p->min_password_length;
383 r->data.auth.policy.password_history =
384 p->password_history_length;
385 r->data.auth.policy.password_properties =
386 p->password_properties;
387 r->data.auth.policy.expire =
388 nt_time_to_unix_abs((NTTIME *)&(p->max_password_age));
389 r->data.auth.policy.min_passwordage =
390 nt_time_to_unix_abs((NTTIME *)&(p->min_password_age));
391}
392
393static NTSTATUS fillup_password_policy(struct winbindd_domain *domain,
394 struct winbindd_response *response)
395{
396 TALLOC_CTX *frame = talloc_stackframe();
397 struct winbindd_methods *methods;
398 NTSTATUS status;
399 struct samr_DomInfo1 password_policy;
400
401 if ( !winbindd_can_contact_domain( domain ) ) {
402 DEBUG(5,("fillup_password_policy: No inbound trust to "
403 "contact domain %s\n", domain->name));
404 status = NT_STATUS_NOT_SUPPORTED;
405 goto done;
406 }
407
408 methods = domain->methods;
409
410 status = methods->password_policy(domain, talloc_tos(), &password_policy);
411 if (NT_STATUS_IS_ERR(status)) {
412 goto done;
413 }
414
415 fill_in_password_policy(response, &password_policy);
416
417done:
418 TALLOC_FREE(frame);
419 return NT_STATUS_OK;
420}
421
422static NTSTATUS get_max_bad_attempts_from_lockout_policy(struct winbindd_domain *domain,
423 TALLOC_CTX *mem_ctx,
424 uint16 *lockout_threshold)
425{
426 struct winbindd_methods *methods;
427 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
428 struct samr_DomInfo12 lockout_policy;
429
430 *lockout_threshold = 0;
431
432 methods = domain->methods;
433
434 status = methods->lockout_policy(domain, mem_ctx, &lockout_policy);
435 if (NT_STATUS_IS_ERR(status)) {
436 return status;
437 }
438
439 *lockout_threshold = lockout_policy.lockout_threshold;
440
441 return NT_STATUS_OK;
442}
443
444static NTSTATUS get_pwd_properties(struct winbindd_domain *domain,
445 TALLOC_CTX *mem_ctx,
446 uint32 *password_properties)
447{
448 struct winbindd_methods *methods;
449 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
450 struct samr_DomInfo1 password_policy;
451
452 *password_properties = 0;
453
454 methods = domain->methods;
455
456 status = methods->password_policy(domain, mem_ctx, &password_policy);
457 if (NT_STATUS_IS_ERR(status)) {
458 return status;
459 }
460
461 *password_properties = password_policy.password_properties;
462
463 return NT_STATUS_OK;
464}
465
466#ifdef HAVE_KRB5
467
468static const char *generate_krb5_ccache(TALLOC_CTX *mem_ctx,
469 const char *type,
470 uid_t uid,
471 const char **user_ccache_file)
472{
473 /* accept FILE and WRFILE as krb5_cc_type from the client and then
474 * build the full ccname string based on the user's uid here -
475 * Guenther*/
476
477 const char *gen_cc = NULL;
478
479 if (uid != -1) {
480 if (strequal(type, "FILE")) {
481 gen_cc = talloc_asprintf(
482 mem_ctx, "FILE:/tmp/krb5cc_%d", uid);
483 }
484 if (strequal(type, "WRFILE")) {
485 gen_cc = talloc_asprintf(
486 mem_ctx, "WRFILE:/tmp/krb5cc_%d", uid);
487 }
488 }
489
490 *user_ccache_file = gen_cc;
491
492 if (gen_cc == NULL) {
493 gen_cc = talloc_strdup(mem_ctx, "MEMORY:winbindd_pam_ccache");
494 }
495 if (gen_cc == NULL) {
496 DEBUG(0,("out of memory\n"));
497 return NULL;
498 }
499
500 DEBUG(10, ("using ccache: %s%s\n", gen_cc,
501 (*user_ccache_file == NULL) ? " (internal)":""));
502
503 return gen_cc;
504}
505
506#endif
507
508uid_t get_uid_from_request(struct winbindd_request *request)
509{
510 uid_t uid;
511
512 uid = request->data.auth.uid;
513
514 if (uid < 0) {
515 DEBUG(1,("invalid uid: '%u'\n", (unsigned int)uid));
516 return -1;
517 }
518 return uid;
519}
520
521/**********************************************************************
522 Authenticate a user with a clear text password using Kerberos and fill up
523 ccache if required
524 **********************************************************************/
525
526static NTSTATUS winbindd_raw_kerberos_login(TALLOC_CTX *mem_ctx,
527 struct winbindd_domain *domain,
528 const char *user,
529 const char *pass,
530 const char *krb5_cc_type,
531 uid_t uid,
532 struct netr_SamInfo3 **info3,
533 fstring krb5ccname)
534{
535#ifdef HAVE_KRB5
536 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
537 krb5_error_code krb5_ret;
538 const char *cc = NULL;
539 const char *principal_s = NULL;
540 const char *service = NULL;
541 char *realm = NULL;
542 fstring name_domain, name_user;
543 time_t ticket_lifetime = 0;
544 time_t renewal_until = 0;
545 ADS_STRUCT *ads;
546 time_t time_offset = 0;
547 const char *user_ccache_file;
548 struct PAC_LOGON_INFO *logon_info = NULL;
549
550 *info3 = NULL;
551
552 /* 1st step:
553 * prepare a krb5_cc_cache string for the user */
554
555 if (uid == -1) {
556 DEBUG(0,("no valid uid\n"));
557 }
558
559 cc = generate_krb5_ccache(mem_ctx,
560 krb5_cc_type,
561 uid,
562 &user_ccache_file);
563 if (cc == NULL) {
564 return NT_STATUS_NO_MEMORY;
565 }
566
567
568 /* 2nd step:
569 * get kerberos properties */
570
571 if (domain->private_data) {
572 ads = (ADS_STRUCT *)domain->private_data;
573 time_offset = ads->auth.time_offset;
574 }
575
576
577 /* 3rd step:
578 * do kerberos auth and setup ccache as the user */
579
580 parse_domain_user(user, name_domain, name_user);
581
582 realm = domain->alt_name;
583 strupper_m(realm);
584
585 principal_s = talloc_asprintf(mem_ctx, "%s@%s", name_user, realm);
586 if (principal_s == NULL) {
587 return NT_STATUS_NO_MEMORY;
588 }
589
590 service = talloc_asprintf(mem_ctx, "%s/%s@%s", KRB5_TGS_NAME, realm, realm);
591 if (service == NULL) {
592 return NT_STATUS_NO_MEMORY;
593 }
594
595 /* if this is a user ccache, we need to act as the user to let the krb5
596 * library handle the chown, etc. */
597
598 /************************ ENTERING NON-ROOT **********************/
599
600 if (user_ccache_file != NULL) {
601 set_effective_uid(uid);
602 DEBUG(10,("winbindd_raw_kerberos_login: uid is %d\n", uid));
603 }
604
605 result = kerberos_return_pac(mem_ctx,
606 principal_s,
607 pass,
608 time_offset,
609 &ticket_lifetime,
610 &renewal_until,
611 cc,
612 true,
613 true,
614 WINBINDD_PAM_AUTH_KRB5_RENEW_TIME,
615 NULL,
616 &logon_info);
617 if (user_ccache_file != NULL) {
618 gain_root_privilege();
619 }
620
621 /************************ RETURNED TO ROOT **********************/
622
623 if (!NT_STATUS_IS_OK(result)) {
624 goto failed;
625 }
626
627 *info3 = &logon_info->info3;
628
629 DEBUG(10,("winbindd_raw_kerberos_login: winbindd validated ticket of %s\n",
630 principal_s));
631
632 /* if we had a user's ccache then return that string for the pam
633 * environment */
634
635 if (user_ccache_file != NULL) {
636
637 fstrcpy(krb5ccname, user_ccache_file);
638
639 result = add_ccache_to_list(principal_s,
640 cc,
641 service,
642 user,
643 realm,
644 uid,
645 time(NULL),
646 ticket_lifetime,
647 renewal_until,
648 false);
649
650 if (!NT_STATUS_IS_OK(result)) {
651 DEBUG(10,("winbindd_raw_kerberos_login: failed to add ccache to list: %s\n",
652 nt_errstr(result)));
653 }
654 } else {
655
656 /* need to delete the memory cred cache, it is not used anymore */
657
658 krb5_ret = ads_kdestroy(cc);
659 if (krb5_ret) {
660 DEBUG(3,("winbindd_raw_kerberos_login: "
661 "could not destroy krb5 credential cache: "
662 "%s\n", error_message(krb5_ret)));
663 }
664
665 }
666
667 return NT_STATUS_OK;
668
669failed:
670
671 /* we could have created a new credential cache with a valid tgt in it
672 * but we werent able to get or verify the service ticket for this
673 * local host and therefor didn't get the PAC, we need to remove that
674 * cache entirely now */
675
676 krb5_ret = ads_kdestroy(cc);
677 if (krb5_ret) {
678 DEBUG(3,("winbindd_raw_kerberos_login: "
679 "could not destroy krb5 credential cache: "
680 "%s\n", error_message(krb5_ret)));
681 }
682
683 if (!NT_STATUS_IS_OK(remove_ccache(user))) {
684 DEBUG(3,("winbindd_raw_kerberos_login: "
685 "could not remove ccache for user %s\n",
686 user));
687 }
688
689 return result;
690#else
691 return NT_STATUS_NOT_SUPPORTED;
692#endif /* HAVE_KRB5 */
693}
694
695/****************************************************************
696****************************************************************/
697
698bool check_request_flags(uint32_t flags)
699{
700 uint32_t flags_edata = WBFLAG_PAM_AFS_TOKEN |
701 WBFLAG_PAM_INFO3_TEXT |
702 WBFLAG_PAM_INFO3_NDR;
703
704 if ( ( (flags & flags_edata) == WBFLAG_PAM_AFS_TOKEN) ||
705 ( (flags & flags_edata) == WBFLAG_PAM_INFO3_NDR) ||
706 ( (flags & flags_edata) == WBFLAG_PAM_INFO3_TEXT)||
707 !(flags & flags_edata) ) {
708 return true;
709 }
710
711 DEBUG(1, ("check_request_flags: invalid request flags[0x%08X]\n",
712 flags));
713
714 return false;
715}
716
717/****************************************************************
718****************************************************************/
719
720static NTSTATUS append_auth_data(TALLOC_CTX *mem_ctx,
721 struct winbindd_response *resp,
722 uint32_t request_flags,
723 struct netr_SamInfo3 *info3,
724 const char *name_domain,
725 const char *name_user)
726{
727 NTSTATUS result;
728
729 if (request_flags & WBFLAG_PAM_USER_SESSION_KEY) {
730 memcpy(resp->data.auth.user_session_key,
731 info3->base.key.key,
732 sizeof(resp->data.auth.user_session_key)
733 /* 16 */);
734 }
735
736 if (request_flags & WBFLAG_PAM_LMKEY) {
737 memcpy(resp->data.auth.first_8_lm_hash,
738 info3->base.LMSessKey.key,
739 sizeof(resp->data.auth.first_8_lm_hash)
740 /* 8 */);
741 }
742
743 if (request_flags & WBFLAG_PAM_UNIX_NAME) {
744 result = append_unix_username(mem_ctx, resp,
745 info3, name_domain, name_user);
746 if (!NT_STATUS_IS_OK(result)) {
747 DEBUG(10,("Failed to append Unix Username: %s\n",
748 nt_errstr(result)));
749 return result;
750 }
751 }
752
753 /* currently, anything from here on potentially overwrites extra_data. */
754
755 if (request_flags & WBFLAG_PAM_INFO3_NDR) {
756 result = append_info3_as_ndr(mem_ctx, resp, info3);
757 if (!NT_STATUS_IS_OK(result)) {
758 DEBUG(10,("Failed to append INFO3 (NDR): %s\n",
759 nt_errstr(result)));
760 return result;
761 }
762 }
763
764 if (request_flags & WBFLAG_PAM_INFO3_TEXT) {
765 result = append_info3_as_txt(mem_ctx, resp, info3);
766 if (!NT_STATUS_IS_OK(result)) {
767 DEBUG(10,("Failed to append INFO3 (TXT): %s\n",
768 nt_errstr(result)));
769 return result;
770 }
771 }
772
773 if (request_flags & WBFLAG_PAM_AFS_TOKEN) {
774 result = append_afs_token(mem_ctx, resp,
775 info3, name_domain, name_user);
776 if (!NT_STATUS_IS_OK(result)) {
777 DEBUG(10,("Failed to append AFS token: %s\n",
778 nt_errstr(result)));
779 return result;
780 }
781 }
782
783 return NT_STATUS_OK;
784}
785
786static NTSTATUS winbindd_dual_pam_auth_cached(struct winbindd_domain *domain,
787 struct winbindd_cli_state *state,
788 struct netr_SamInfo3 **info3)
789{
790 NTSTATUS result = NT_STATUS_LOGON_FAILURE;
791 uint16 max_allowed_bad_attempts;
792 fstring name_domain, name_user;
793 struct dom_sid sid;
794 enum lsa_SidType type;
795 uchar new_nt_pass[NT_HASH_LEN];
796 const uint8 *cached_nt_pass;
797 const uint8 *cached_salt;
798 struct netr_SamInfo3 *my_info3;
799 time_t kickoff_time, must_change_time;
800 bool password_good = false;
801#ifdef HAVE_KRB5
802 struct winbindd_tdc_domain *tdc_domain = NULL;
803#endif
804
805 *info3 = NULL;
806
807 ZERO_STRUCTP(info3);
808
809 DEBUG(10,("winbindd_dual_pam_auth_cached\n"));
810
811 /* Parse domain and username */
812
813 parse_domain_user(state->request->data.auth.user, name_domain, name_user);
814
815
816 if (!lookup_cached_name(name_domain,
817 name_user,
818 &sid,
819 &type)) {
820 DEBUG(10,("winbindd_dual_pam_auth_cached: no such user in the cache\n"));
821 return NT_STATUS_NO_SUCH_USER;
822 }
823
824 if (type != SID_NAME_USER) {
825 DEBUG(10,("winbindd_dual_pam_auth_cached: not a user (%s)\n", sid_type_lookup(type)));
826 return NT_STATUS_LOGON_FAILURE;
827 }
828
829 result = winbindd_get_creds(domain,
830 state->mem_ctx,
831 &sid,
832 &my_info3,
833 &cached_nt_pass,
834 &cached_salt);
835 if (!NT_STATUS_IS_OK(result)) {
836 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get creds: %s\n", nt_errstr(result)));
837 return result;
838 }
839
840 *info3 = my_info3;
841
842 E_md4hash(state->request->data.auth.pass, new_nt_pass);
843
844 dump_data_pw("new_nt_pass", new_nt_pass, NT_HASH_LEN);
845 dump_data_pw("cached_nt_pass", cached_nt_pass, NT_HASH_LEN);
846 if (cached_salt) {
847 dump_data_pw("cached_salt", cached_salt, NT_HASH_LEN);
848 }
849
850 if (cached_salt) {
851 /* In this case we didn't store the nt_hash itself,
852 but the MD5 combination of salt + nt_hash. */
853 uchar salted_hash[NT_HASH_LEN];
854 E_md5hash(cached_salt, new_nt_pass, salted_hash);
855
856 password_good = (memcmp(cached_nt_pass, salted_hash,
857 NT_HASH_LEN) == 0);
858 } else {
859 /* Old cached cred - direct store of nt_hash (bad bad bad !). */
860 password_good = (memcmp(cached_nt_pass, new_nt_pass,
861 NT_HASH_LEN) == 0);
862 }
863
864 if (password_good) {
865
866 /* User *DOES* know the password, update logon_time and reset
867 * bad_pw_count */
868
869 my_info3->base.user_flags |= NETLOGON_CACHED_ACCOUNT;
870
871 if (my_info3->base.acct_flags & ACB_AUTOLOCK) {
872 return NT_STATUS_ACCOUNT_LOCKED_OUT;
873 }
874
875 if (my_info3->base.acct_flags & ACB_DISABLED) {
876 return NT_STATUS_ACCOUNT_DISABLED;
877 }
878
879 if (my_info3->base.acct_flags & ACB_WSTRUST) {
880 return NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
881 }
882
883 if (my_info3->base.acct_flags & ACB_SVRTRUST) {
884 return NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT;
885 }
886
887 if (my_info3->base.acct_flags & ACB_DOMTRUST) {
888 return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT;
889 }
890
891 if (!(my_info3->base.acct_flags & ACB_NORMAL)) {
892 DEBUG(0,("winbindd_dual_pam_auth_cached: whats wrong with that one?: 0x%08x\n",
893 my_info3->base.acct_flags));
894 return NT_STATUS_LOGON_FAILURE;
895 }
896
897 kickoff_time = nt_time_to_unix(my_info3->base.acct_expiry);
898 if (kickoff_time != 0 && time(NULL) > kickoff_time) {
899 return NT_STATUS_ACCOUNT_EXPIRED;
900 }
901
902 must_change_time = nt_time_to_unix(my_info3->base.force_password_change);
903 if (must_change_time != 0 && must_change_time < time(NULL)) {
904 /* we allow grace logons when the password has expired */
905 my_info3->base.user_flags |= NETLOGON_GRACE_LOGON;
906 /* return NT_STATUS_PASSWORD_EXPIRED; */
907 goto success;
908 }
909
910#ifdef HAVE_KRB5
911 if ((state->request->flags & WBFLAG_PAM_KRB5) &&
912 ((tdc_domain = wcache_tdc_fetch_domain(state->mem_ctx, name_domain)) != NULL) &&
913 ((tdc_domain->trust_type & NETR_TRUST_TYPE_UPLEVEL) ||
914 /* used to cope with the case winbindd starting without network. */
915 !strequal(tdc_domain->domain_name, tdc_domain->dns_name))) {
916
917 uid_t uid = -1;
918 const char *cc = NULL;
919 char *realm = NULL;
920 const char *principal_s = NULL;
921 const char *service = NULL;
922 const char *user_ccache_file;
923
924 uid = get_uid_from_request(state->request);
925 if (uid == -1) {
926 DEBUG(0,("winbindd_dual_pam_auth_cached: invalid uid\n"));
927 return NT_STATUS_INVALID_PARAMETER;
928 }
929
930 cc = generate_krb5_ccache(state->mem_ctx,
931 state->request->data.auth.krb5_cc_type,
932 state->request->data.auth.uid,
933 &user_ccache_file);
934 if (cc == NULL) {
935 return NT_STATUS_NO_MEMORY;
936 }
937
938 realm = domain->alt_name;
939 strupper_m(realm);
940
941 principal_s = talloc_asprintf(state->mem_ctx, "%s@%s", name_user, realm);
942 if (principal_s == NULL) {
943 return NT_STATUS_NO_MEMORY;
944 }
945
946 service = talloc_asprintf(state->mem_ctx, "%s/%s@%s", KRB5_TGS_NAME, realm, realm);
947 if (service == NULL) {
948 return NT_STATUS_NO_MEMORY;
949 }
950
951 if (user_ccache_file != NULL) {
952
953 fstrcpy(state->response->data.auth.krb5ccname,
954 user_ccache_file);
955
956 result = add_ccache_to_list(principal_s,
957 cc,
958 service,
959 state->request->data.auth.user,
960 domain->alt_name,
961 uid,
962 time(NULL),
963 time(NULL) + lp_winbind_cache_time(),
964 time(NULL) + WINBINDD_PAM_AUTH_KRB5_RENEW_TIME,
965 true);
966
967 if (!NT_STATUS_IS_OK(result)) {
968 DEBUG(10,("winbindd_dual_pam_auth_cached: failed "
969 "to add ccache to list: %s\n",
970 nt_errstr(result)));
971 }
972 }
973 }
974#endif /* HAVE_KRB5 */
975 success:
976 /* FIXME: we possibly should handle logon hours as well (does xp when
977 * offline?) see auth/auth_sam.c:sam_account_ok for details */
978
979 unix_to_nt_time(&my_info3->base.last_logon, time(NULL));
980 my_info3->base.bad_password_count = 0;
981
982 result = winbindd_update_creds_by_info3(domain,
983 state->request->data.auth.user,
984 state->request->data.auth.pass,
985 my_info3);
986 if (!NT_STATUS_IS_OK(result)) {
987 DEBUG(1,("winbindd_dual_pam_auth_cached: failed to update creds: %s\n",
988 nt_errstr(result)));
989 return result;
990 }
991
992 return NT_STATUS_OK;
993
994 }
995
996 /* User does *NOT* know the correct password, modify info3 accordingly, but only if online */
997 if (domain->online == false) {
998 goto failed;
999 }
1000
1001 /* failure of this is not critical */
1002 result = get_max_bad_attempts_from_lockout_policy(domain, state->mem_ctx, &max_allowed_bad_attempts);
1003 if (!NT_STATUS_IS_OK(result)) {
1004 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get max_allowed_bad_attempts. "
1005 "Won't be able to honour account lockout policies\n"));
1006 }
1007
1008 /* increase counter */
1009 my_info3->base.bad_password_count++;
1010
1011 if (max_allowed_bad_attempts == 0) {
1012 goto failed;
1013 }
1014
1015 /* lockout user */
1016 if (my_info3->base.bad_password_count >= max_allowed_bad_attempts) {
1017
1018 uint32 password_properties;
1019
1020 result = get_pwd_properties(domain, state->mem_ctx, &password_properties);
1021 if (!NT_STATUS_IS_OK(result)) {
1022 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get password properties.\n"));
1023 }
1024
1025 if ((my_info3->base.rid != DOMAIN_RID_ADMINISTRATOR) ||
1026 (password_properties & DOMAIN_PASSWORD_LOCKOUT_ADMINS)) {
1027 my_info3->base.acct_flags |= ACB_AUTOLOCK;
1028 }
1029 }
1030
1031failed:
1032 result = winbindd_update_creds_by_info3(domain,
1033 state->request->data.auth.user,
1034 NULL,
1035 my_info3);
1036
1037 if (!NT_STATUS_IS_OK(result)) {
1038 DEBUG(0,("winbindd_dual_pam_auth_cached: failed to update creds %s\n",
1039 nt_errstr(result)));
1040 }
1041
1042 return NT_STATUS_LOGON_FAILURE;
1043}
1044
1045static NTSTATUS winbindd_dual_pam_auth_kerberos(struct winbindd_domain *domain,
1046 struct winbindd_cli_state *state,
1047 struct netr_SamInfo3 **info3)
1048{
1049 struct winbindd_domain *contact_domain;
1050 fstring name_domain, name_user;
1051 NTSTATUS result;
1052
1053 DEBUG(10,("winbindd_dual_pam_auth_kerberos\n"));
1054
1055 /* Parse domain and username */
1056
1057 parse_domain_user(state->request->data.auth.user, name_domain, name_user);
1058
1059 /* what domain should we contact? */
1060
1061 if ( IS_DC ) {
1062 if (!(contact_domain = find_domain_from_name(name_domain))) {
1063 DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
1064 state->request->data.auth.user, name_domain, name_user, name_domain));
1065 result = NT_STATUS_NO_SUCH_USER;
1066 goto done;
1067 }
1068
1069 } else {
1070 if (is_myname(name_domain)) {
1071 DEBUG(3, ("Authentication for domain %s (local domain to this server) not supported at this stage\n", name_domain));
1072 result = NT_STATUS_NO_SUCH_USER;
1073 goto done;
1074 }
1075
1076 contact_domain = find_domain_from_name(name_domain);
1077 if (contact_domain == NULL) {
1078 DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
1079 state->request->data.auth.user, name_domain, name_user, name_domain));
1080
1081 contact_domain = find_our_domain();
1082 }
1083 }
1084
1085 if (contact_domain->initialized &&
1086 contact_domain->active_directory) {
1087 goto try_login;
1088 }
1089
1090 if (!contact_domain->initialized) {
1091 init_dc_connection(contact_domain);
1092 }
1093
1094 if (!contact_domain->active_directory) {
1095 DEBUG(3,("krb5 auth requested but domain is not Active Directory\n"));
1096 return NT_STATUS_INVALID_LOGON_TYPE;
1097 }
1098try_login:
1099 result = winbindd_raw_kerberos_login(
1100 state->mem_ctx, contact_domain,
1101 state->request->data.auth.user,
1102 state->request->data.auth.pass,
1103 state->request->data.auth.krb5_cc_type,
1104 get_uid_from_request(state->request),
1105 info3, state->response->data.auth.krb5ccname);
1106done:
1107 return result;
1108}
1109
1110static NTSTATUS winbindd_dual_auth_passdb(TALLOC_CTX *mem_ctx,
1111 const char *domain, const char *user,
1112 const DATA_BLOB *challenge,
1113 const DATA_BLOB *lm_resp,
1114 const DATA_BLOB *nt_resp,
1115 struct netr_SamInfo3 **pinfo3)
1116{
1117 struct auth_usersupplied_info *user_info = NULL;
1118 NTSTATUS status;
1119
1120 status = make_user_info(&user_info, user, user, domain, domain,
1121 global_myname(), lm_resp, nt_resp, NULL, NULL,
1122 NULL, AUTH_PASSWORD_RESPONSE);
1123 if (!NT_STATUS_IS_OK(status)) {
1124 DEBUG(10, ("make_user_info failed: %s\n", nt_errstr(status)));
1125 return status;
1126 }
1127
1128 /* We don't want any more mapping of the username */
1129 user_info->mapped_state = True;
1130
1131 status = check_sam_security_info3(challenge, talloc_tos(), user_info,
1132 pinfo3);
1133 free_user_info(&user_info);
1134 DEBUG(10, ("Authenticaticating user %s\\%s returned %s\n", domain,
1135 user, nt_errstr(status)));
1136 return status;
1137}
1138
1139static NTSTATUS winbind_samlogon_retry_loop(struct winbindd_domain *domain,
1140 TALLOC_CTX *mem_ctx,
1141 uint32_t logon_parameters,
1142 const char *server,
1143 const char *username,
1144 const char *domainname,
1145 const char *workstation,
1146 const uint8_t chal[8],
1147 DATA_BLOB lm_response,
1148 DATA_BLOB nt_response,
1149 struct netr_SamInfo3 **info3)
1150{
1151 int attempts = 0;
1152 bool retry = false;
1153 NTSTATUS result;
1154
1155 do {
1156 struct rpc_pipe_client *netlogon_pipe;
1157 const struct pipe_auth_data *auth;
1158 uint32_t neg_flags = 0;
1159
1160 ZERO_STRUCTP(info3);
1161 retry = false;
1162
1163 result = cm_connect_netlogon(domain, &netlogon_pipe);
1164
1165 if (!NT_STATUS_IS_OK(result)) {
1166 DEBUG(3,("could not open handle to NETLOGON pipe (error: %s)\n",
1167 nt_errstr(result)));
1168 return result;
1169 }
1170 auth = netlogon_pipe->auth;
1171 if (netlogon_pipe->dc) {
1172 neg_flags = netlogon_pipe->dc->negotiate_flags;
1173 }
1174
1175 /* It is really important to try SamLogonEx here,
1176 * because in a clustered environment, we want to use
1177 * one machine account from multiple physical
1178 * computers.
1179 *
1180 * With a normal SamLogon call, we must keep the
1181 * credentials chain updated and intact between all
1182 * users of the machine account (which would imply
1183 * cross-node communication for every NTLM logon).
1184 *
1185 * (The credentials chain is not per NETLOGON pipe
1186 * connection, but globally on the server/client pair
1187 * by machine name).
1188 *
1189 * When using SamLogonEx, the credentials are not
1190 * supplied, but the session key is implied by the
1191 * wrapping SamLogon context.
1192 *
1193 * -- abartlet 21 April 2008
1194 *
1195 * It's also important to use NetlogonValidationSamInfo4 (6),
1196 * because it relies on the rpc transport encryption
1197 * and avoids using the global netlogon schannel
1198 * session key to en/decrypt secret information
1199 * like the user_session_key for network logons.
1200 *
1201 * [MS-APDS] 3.1.5.2 NTLM Network Logon
1202 * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
1203 * NETLOGON_NEG_AUTHENTICATED_RPC set together
1204 * are the indication that the server supports
1205 * NetlogonValidationSamInfo4 (6). And it must only
1206 * be used if "SealSecureChannel" is used.
1207 *
1208 * -- metze 4 February 2011
1209 */
1210
1211 if (auth == NULL) {
1212 domain->can_do_validation6 = false;
1213 } else if (auth->auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
1214 domain->can_do_validation6 = false;
1215 } else if (auth->auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
1216 domain->can_do_validation6 = false;
1217 } else if (!(neg_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
1218 domain->can_do_validation6 = false;
1219 } else if (!(neg_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
1220 domain->can_do_validation6 = false;
1221 }
1222
1223 if (domain->can_do_samlogon_ex) {
1224 result = rpccli_netlogon_sam_network_logon_ex(
1225 netlogon_pipe,
1226 mem_ctx,
1227 0,
1228 server, /* server name */
1229 username, /* user name */
1230 domainname, /* target domain */
1231 workstation, /* workstation */
1232 chal,
1233 domain->can_do_validation6 ? 6 : 3,
1234 lm_response,
1235 nt_response,
1236 info3);
1237 } else {
1238 result = rpccli_netlogon_sam_network_logon(
1239 netlogon_pipe,
1240 mem_ctx,
1241 0,
1242 server, /* server name */
1243 username, /* user name */
1244 domainname, /* target domain */
1245 workstation, /* workstation */
1246 chal,
1247 domain->can_do_validation6 ? 6 : 3,
1248 lm_response,
1249 nt_response,
1250 info3);
1251 }
1252
1253 if (NT_STATUS_EQUAL(result, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1254
1255 /*
1256 * It's likely that the server also does not support
1257 * validation level 6
1258 */
1259 domain->can_do_validation6 = false;
1260
1261 if (domain->can_do_samlogon_ex) {
1262 DEBUG(3, ("Got a DC that can not do NetSamLogonEx, "
1263 "retrying with NetSamLogon\n"));
1264 domain->can_do_samlogon_ex = false;
1265 retry = true;
1266 continue;
1267 }
1268
1269
1270 /* Got DCERPC_FAULT_OP_RNG_ERROR for SamLogon
1271 * (no Ex). This happens against old Samba
1272 * DCs. Drop the connection.
1273 */
1274 invalidate_cm_connection(&domain->conn);
1275 result = NT_STATUS_LOGON_FAILURE;
1276 break;
1277 }
1278
1279 if (domain->can_do_validation6 &&
1280 (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
1281 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
1282 NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL))) {
1283 DEBUG(3,("Got a DC that can not do validation level 6, "
1284 "retrying with level 3\n"));
1285 domain->can_do_validation6 = false;
1286 retry = true;
1287 continue;
1288 }
1289
1290 /*
1291 * we increment this after the "feature negotiation"
1292 * for can_do_samlogon_ex and can_do_validation6
1293 */
1294 attempts += 1;
1295
1296 /* We have to try a second time as cm_connect_netlogon
1297 might not yet have noticed that the DC has killed
1298 our connection. */
1299
1300 if (!rpccli_is_connected(netlogon_pipe)) {
1301 retry = true;
1302 continue;
1303 }
1304
1305 /* if we get access denied, a possible cause was that we had
1306 and open connection to the DC, but someone changed our
1307 machine account password out from underneath us using 'net
1308 rpc changetrustpw' */
1309
1310 if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
1311 DEBUG(3,("winbindd_pam_auth: sam_logon returned "
1312 "ACCESS_DENIED. Maybe the trust account "
1313 "password was changed and we didn't know it. "
1314 "Killing connections to domain %s\n",
1315 domainname));
1316 invalidate_cm_connection(&domain->conn);
1317 retry = true;
1318 }
1319
1320 } while ( (attempts < 2) && retry );
1321
1322 return result;
1323}
1324
1325static NTSTATUS winbindd_dual_pam_auth_samlogon(TALLOC_CTX *mem_ctx,
1326 struct winbindd_domain *domain,
1327 const char *user,
1328 const char *pass,
1329 uint32_t request_flags,
1330 struct netr_SamInfo3 **info3)
1331{
1332
1333 uchar chal[8];
1334 DATA_BLOB lm_resp;
1335 DATA_BLOB nt_resp;
1336 unsigned char local_nt_response[24];
1337 fstring name_domain, name_user;
1338 NTSTATUS result;
1339 struct netr_SamInfo3 *my_info3 = NULL;
1340
1341 *info3 = NULL;
1342
1343 DEBUG(10,("winbindd_dual_pam_auth_samlogon\n"));
1344
1345 /* Parse domain and username */
1346
1347 parse_domain_user(user, name_domain, name_user);
1348
1349 /* do password magic */
1350
1351 generate_random_buffer(chal, sizeof(chal));
1352
1353 if (lp_client_ntlmv2_auth()) {
1354 DATA_BLOB server_chal;
1355 DATA_BLOB names_blob;
1356 server_chal = data_blob_const(chal, 8);
1357
1358 /* note that the 'workgroup' here is for the local
1359 machine. The 'server name' must match the
1360 'workstation' passed to the actual SamLogon call.
1361 */
1362 names_blob = NTLMv2_generate_names_blob(
1363 mem_ctx, global_myname(), lp_workgroup());
1364
1365 if (!SMBNTLMv2encrypt(mem_ctx, name_user, name_domain,
1366 pass,
1367 &server_chal,
1368 &names_blob,
1369 &lm_resp, &nt_resp, NULL, NULL)) {
1370 data_blob_free(&names_blob);
1371 DEBUG(0, ("winbindd_pam_auth: SMBNTLMv2encrypt() failed!\n"));
1372 result = NT_STATUS_NO_MEMORY;
1373 goto done;
1374 }
1375 data_blob_free(&names_blob);
1376 } else {
1377 lm_resp = data_blob_null;
1378 SMBNTencrypt(pass, chal, local_nt_response);
1379
1380 nt_resp = data_blob_talloc(mem_ctx, local_nt_response,
1381 sizeof(local_nt_response));
1382 }
1383
1384 if (strequal(name_domain, get_global_sam_name())) {
1385 DATA_BLOB chal_blob = data_blob_const(chal, sizeof(chal));
1386
1387 result = winbindd_dual_auth_passdb(
1388 mem_ctx, name_domain, name_user,
1389 &chal_blob, &lm_resp, &nt_resp, info3);
1390 goto done;
1391 }
1392
1393 /* check authentication loop */
1394
1395 result = winbind_samlogon_retry_loop(domain,
1396 mem_ctx,
1397 0,
1398 domain->dcname,
1399 name_user,
1400 name_domain,
1401 global_myname(),
1402 chal,
1403 lm_resp,
1404 nt_resp,
1405 &my_info3);
1406 if (!NT_STATUS_IS_OK(result)) {
1407 goto done;
1408 }
1409
1410 /* handle the case where a NT4 DC does not fill in the acct_flags in
1411 * the samlogon reply info3. When accurate info3 is required by the
1412 * caller, we look up the account flags ourselve - gd */
1413
1414 if ((request_flags & WBFLAG_PAM_INFO3_TEXT) &&
1415 NT_STATUS_IS_OK(result) && (my_info3->base.acct_flags == 0)) {
1416
1417 struct rpc_pipe_client *samr_pipe;
1418 struct policy_handle samr_domain_handle, user_pol;
1419 union samr_UserInfo *info = NULL;
1420 NTSTATUS status_tmp, result_tmp;
1421 uint32 acct_flags;
1422 struct dcerpc_binding_handle *b;
1423
1424 status_tmp = cm_connect_sam(domain, mem_ctx,
1425 &samr_pipe, &samr_domain_handle);
1426
1427 if (!NT_STATUS_IS_OK(status_tmp)) {
1428 DEBUG(3, ("could not open handle to SAMR pipe: %s\n",
1429 nt_errstr(status_tmp)));
1430 goto done;
1431 }
1432
1433 b = samr_pipe->binding_handle;
1434
1435 status_tmp = dcerpc_samr_OpenUser(b, mem_ctx,
1436 &samr_domain_handle,
1437 MAXIMUM_ALLOWED_ACCESS,
1438 my_info3->base.rid,
1439 &user_pol,
1440 &result_tmp);
1441
1442 if (!NT_STATUS_IS_OK(status_tmp)) {
1443 DEBUG(3, ("could not open user handle on SAMR pipe: %s\n",
1444 nt_errstr(status_tmp)));
1445 goto done;
1446 }
1447 if (!NT_STATUS_IS_OK(result_tmp)) {
1448 DEBUG(3, ("could not open user handle on SAMR pipe: %s\n",
1449 nt_errstr(result_tmp)));
1450 goto done;
1451 }
1452
1453 status_tmp = dcerpc_samr_QueryUserInfo(b, mem_ctx,
1454 &user_pol,
1455 16,
1456 &info,
1457 &result_tmp);
1458
1459 if (!NT_STATUS_IS_OK(status_tmp)) {
1460 DEBUG(3, ("could not query user info on SAMR pipe: %s\n",
1461 nt_errstr(status_tmp)));
1462 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
1463 goto done;
1464 }
1465 if (!NT_STATUS_IS_OK(result_tmp)) {
1466 DEBUG(3, ("could not query user info on SAMR pipe: %s\n",
1467 nt_errstr(result_tmp)));
1468 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
1469 goto done;
1470 }
1471
1472 acct_flags = info->info16.acct_flags;
1473
1474 if (acct_flags == 0) {
1475 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
1476 goto done;
1477 }
1478
1479 my_info3->base.acct_flags = acct_flags;
1480
1481 DEBUG(10,("successfully retrieved acct_flags 0x%x\n", acct_flags));
1482
1483 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
1484 }
1485
1486 *info3 = my_info3;
1487done:
1488 return result;
1489}
1490
1491enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain,
1492 struct winbindd_cli_state *state)
1493{
1494 NTSTATUS result = NT_STATUS_LOGON_FAILURE;
1495 NTSTATUS krb5_result = NT_STATUS_OK;
1496 fstring name_domain, name_user;
1497 char *mapped_user;
1498 fstring domain_user;
1499 struct netr_SamInfo3 *info3 = NULL;
1500 NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL;
1501
1502 /* Ensure null termination */
1503 state->request->data.auth.user[sizeof(state->request->data.auth.user)-1]='\0';
1504
1505 /* Ensure null termination */
1506 state->request->data.auth.pass[sizeof(state->request->data.auth.pass)-1]='\0';
1507
1508 DEBUG(3, ("[%5lu]: dual pam auth %s\n", (unsigned long)state->pid,
1509 state->request->data.auth.user));
1510
1511 /* Parse domain and username */
1512
1513 name_map_status = normalize_name_unmap(state->mem_ctx,
1514 state->request->data.auth.user,
1515 &mapped_user);
1516
1517 /* If the name normalization didnt' actually do anything,
1518 just use the original name */
1519
1520 if (!NT_STATUS_IS_OK(name_map_status) &&
1521 !NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED))
1522 {
1523 mapped_user = state->request->data.auth.user;
1524 }
1525
1526 parse_domain_user(mapped_user, name_domain, name_user);
1527
1528 if ( mapped_user != state->request->data.auth.user ) {
1529 fstr_sprintf( domain_user, "%s%c%s", name_domain,
1530 *lp_winbind_separator(),
1531 name_user );
1532 safe_strcpy( state->request->data.auth.user, domain_user,
1533 sizeof(state->request->data.auth.user)-1 );
1534 }
1535
1536 if (!domain->online) {
1537 result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
1538 if (domain->startup) {
1539 /* Logons are very important to users. If we're offline and
1540 we get a request within the first 30 seconds of startup,
1541 try very hard to find a DC and go online. */
1542
1543 DEBUG(10,("winbindd_dual_pam_auth: domain: %s offline and auth "
1544 "request in startup mode.\n", domain->name ));
1545
1546 winbindd_flush_negative_conn_cache(domain);
1547 result = init_dc_connection(domain);
1548 }
1549 }
1550
1551 DEBUG(10,("winbindd_dual_pam_auth: domain: %s last was %s\n", domain->name, domain->online ? "online":"offline"));
1552
1553 /* Check for Kerberos authentication */
1554 if (domain->online && (state->request->flags & WBFLAG_PAM_KRB5)) {
1555
1556 result = winbindd_dual_pam_auth_kerberos(domain, state, &info3);
1557 /* save for later */
1558 krb5_result = result;
1559
1560
1561 if (NT_STATUS_IS_OK(result)) {
1562 DEBUG(10,("winbindd_dual_pam_auth_kerberos succeeded\n"));
1563 goto process_result;
1564 } else {
1565 DEBUG(10,("winbindd_dual_pam_auth_kerberos failed: %s\n", nt_errstr(result)));
1566 }
1567
1568 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
1569 NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
1570 NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1571 DEBUG(10,("winbindd_dual_pam_auth_kerberos setting domain to offline\n"));
1572 set_domain_offline( domain );
1573 goto cached_logon;
1574 }
1575
1576 /* there are quite some NT_STATUS errors where there is no
1577 * point in retrying with a samlogon, we explictly have to take
1578 * care not to increase the bad logon counter on the DC */
1579
1580 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_DISABLED) ||
1581 NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_EXPIRED) ||
1582 NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_LOCKED_OUT) ||
1583 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_LOGON_HOURS) ||
1584 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_WORKSTATION) ||
1585 NT_STATUS_EQUAL(result, NT_STATUS_LOGON_FAILURE) ||
1586 NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER) ||
1587 NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_EXPIRED) ||
1588 NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_MUST_CHANGE) ||
1589 NT_STATUS_EQUAL(result, NT_STATUS_WRONG_PASSWORD)) {
1590 goto done;
1591 }
1592
1593 if (state->request->flags & WBFLAG_PAM_FALLBACK_AFTER_KRB5) {
1594 DEBUG(3,("falling back to samlogon\n"));
1595 goto sam_logon;
1596 } else {
1597 goto cached_logon;
1598 }
1599 }
1600
1601sam_logon:
1602 /* Check for Samlogon authentication */
1603 if (domain->online) {
1604 result = winbindd_dual_pam_auth_samlogon(
1605 state->mem_ctx, domain,
1606 state->request->data.auth.user,
1607 state->request->data.auth.pass,
1608 state->request->flags,
1609 &info3);
1610
1611 if (NT_STATUS_IS_OK(result)) {
1612 DEBUG(10,("winbindd_dual_pam_auth_samlogon succeeded\n"));
1613 /* add the Krb5 err if we have one */
1614 if ( NT_STATUS_EQUAL(krb5_result, NT_STATUS_TIME_DIFFERENCE_AT_DC ) ) {
1615 info3->base.user_flags |= LOGON_KRB5_FAIL_CLOCK_SKEW;
1616 }
1617 goto process_result;
1618 }
1619
1620 DEBUG(10,("winbindd_dual_pam_auth_samlogon failed: %s\n",
1621 nt_errstr(result)));
1622
1623 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
1624 NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
1625 NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND))
1626 {
1627 DEBUG(10,("winbindd_dual_pam_auth_samlogon setting domain to offline\n"));
1628 set_domain_offline( domain );
1629 goto cached_logon;
1630 }
1631
1632 if (domain->online) {
1633 /* We're still online - fail. */
1634 goto done;
1635 }
1636 }
1637
1638cached_logon:
1639 /* Check for Cached logons */
1640 if (!domain->online && (state->request->flags & WBFLAG_PAM_CACHED_LOGIN) &&
1641 lp_winbind_offline_logon()) {
1642
1643 result = winbindd_dual_pam_auth_cached(domain, state, &info3);
1644
1645 if (NT_STATUS_IS_OK(result)) {
1646 DEBUG(10,("winbindd_dual_pam_auth_cached succeeded\n"));
1647 goto process_result;
1648 } else {
1649 DEBUG(10,("winbindd_dual_pam_auth_cached failed: %s\n", nt_errstr(result)));
1650 goto done;
1651 }
1652 }
1653
1654process_result:
1655
1656 if (NT_STATUS_IS_OK(result)) {
1657
1658 struct dom_sid user_sid;
1659
1660 /* In all codepaths where result == NT_STATUS_OK info3 must have
1661 been initialized. */
1662 if (!info3) {
1663 result = NT_STATUS_INTERNAL_ERROR;
1664 goto done;
1665 }
1666
1667 sid_compose(&user_sid, info3->base.domain_sid,
1668 info3->base.rid);
1669
1670 wcache_invalidate_samlogon(find_domain_from_name(name_domain),
1671 &user_sid);
1672 netsamlogon_cache_store(name_user, info3);
1673
1674 /* save name_to_sid info as early as possible (only if
1675 this is our primary domain so we don't invalidate
1676 the cache entry by storing the seq_num for the wrong
1677 domain). */
1678 if ( domain->primary ) {
1679 cache_name2sid(domain, name_domain, name_user,
1680 SID_NAME_USER, &user_sid);
1681 }
1682
1683 /* Check if the user is in the right group */
1684
1685 result = check_info3_in_group(
1686 info3,
1687 state->request->data.auth.require_membership_of_sid);
1688 if (!NT_STATUS_IS_OK(result)) {
1689 DEBUG(3, ("User %s is not in the required group (%s), so plaintext authentication is rejected\n",
1690 state->request->data.auth.user,
1691 state->request->data.auth.require_membership_of_sid));
1692 goto done;
1693 }
1694
1695 result = append_auth_data(state->mem_ctx, state->response,
1696 state->request->flags, info3,
1697 name_domain, name_user);
1698 if (!NT_STATUS_IS_OK(result)) {
1699 goto done;
1700 }
1701
1702 if ((state->request->flags & WBFLAG_PAM_CACHED_LOGIN)
1703 && lp_winbind_offline_logon()) {
1704
1705 result = winbindd_store_creds(domain,
1706 state->request->data.auth.user,
1707 state->request->data.auth.pass,
1708 info3);
1709 }
1710
1711 if (state->request->flags & WBFLAG_PAM_GET_PWD_POLICY) {
1712 struct winbindd_domain *our_domain = find_our_domain();
1713
1714 /* This is not entirely correct I believe, but it is
1715 consistent. Only apply the password policy settings
1716 too warn users for our own domain. Cannot obtain these
1717 from trusted DCs all the time so don't do it at all.
1718 -- jerry */
1719
1720 result = NT_STATUS_NOT_SUPPORTED;
1721 if (our_domain == domain ) {
1722 result = fillup_password_policy(
1723 our_domain, state->response);
1724 }
1725
1726 if (!NT_STATUS_IS_OK(result)
1727 && !NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED) )
1728 {
1729 DEBUG(10,("Failed to get password policies for domain %s: %s\n",
1730 domain->name, nt_errstr(result)));
1731 goto done;
1732 }
1733 }
1734
1735 result = NT_STATUS_OK;
1736 }
1737
1738done:
1739 /* give us a more useful (more correct?) error code */
1740 if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
1741 (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
1742 result = NT_STATUS_NO_LOGON_SERVERS;
1743 }
1744
1745 set_auth_errors(state->response, result);
1746
1747 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, ("Plain-text authentication for user %s returned %s (PAM: %d)\n",
1748 state->request->data.auth.user,
1749 state->response->data.auth.nt_status_string,
1750 state->response->data.auth.pam_error));
1751
1752 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
1753}
1754
1755enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain,
1756 struct winbindd_cli_state *state)
1757{
1758 NTSTATUS result;
1759 struct netr_SamInfo3 *info3 = NULL;
1760 const char *name_user = NULL;
1761 const char *name_domain = NULL;
1762 const char *workstation;
1763
1764 DATA_BLOB lm_resp, nt_resp;
1765
1766 /* This is child-only, so no check for privileged access is needed
1767 anymore */
1768
1769 /* Ensure null termination */
1770 state->request->data.auth_crap.user[sizeof(state->request->data.auth_crap.user)-1]=0;
1771 state->request->data.auth_crap.domain[sizeof(state->request->data.auth_crap.domain)-1]=0;
1772
1773 name_user = state->request->data.auth_crap.user;
1774 name_domain = state->request->data.auth_crap.domain;
1775 workstation = state->request->data.auth_crap.workstation;
1776
1777 DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n", (unsigned long)state->pid,
1778 name_domain, name_user));
1779
1780 if (state->request->data.auth_crap.lm_resp_len > sizeof(state->request->data.auth_crap.lm_resp)
1781 || state->request->data.auth_crap.nt_resp_len > sizeof(state->request->data.auth_crap.nt_resp)) {
1782 if (!(state->request->flags & WBFLAG_BIG_NTLMV2_BLOB) ||
1783 state->request->extra_len != state->request->data.auth_crap.nt_resp_len) {
1784 DEBUG(0, ("winbindd_pam_auth_crap: invalid password length %u/%u\n",
1785 state->request->data.auth_crap.lm_resp_len,
1786 state->request->data.auth_crap.nt_resp_len));
1787 result = NT_STATUS_INVALID_PARAMETER;
1788 goto done;
1789 }
1790 }
1791
1792 lm_resp = data_blob_talloc(state->mem_ctx, state->request->data.auth_crap.lm_resp,
1793 state->request->data.auth_crap.lm_resp_len);
1794
1795 if (state->request->flags & WBFLAG_BIG_NTLMV2_BLOB) {
1796 nt_resp = data_blob_talloc(state->mem_ctx,
1797 state->request->extra_data.data,
1798 state->request->data.auth_crap.nt_resp_len);
1799 } else {
1800 nt_resp = data_blob_talloc(state->mem_ctx,
1801 state->request->data.auth_crap.nt_resp,
1802 state->request->data.auth_crap.nt_resp_len);
1803 }
1804
1805 if (strequal(name_domain, get_global_sam_name())) {
1806 DATA_BLOB chal_blob = data_blob_const(
1807 state->request->data.auth_crap.chal,
1808 sizeof(state->request->data.auth_crap.chal));
1809
1810 result = winbindd_dual_auth_passdb(
1811 state->mem_ctx, name_domain, name_user,
1812 &chal_blob, &lm_resp, &nt_resp, &info3);
1813 goto process_result;
1814 }
1815
1816 result = winbind_samlogon_retry_loop(domain,
1817 state->mem_ctx,
1818 state->request->data.auth_crap.logon_parameters,
1819 domain->dcname,
1820 name_user,
1821 name_domain,
1822 /* Bug #3248 - found by Stefan Burkei. */
1823 workstation, /* We carefully set this above so use it... */
1824 state->request->data.auth_crap.chal,
1825 lm_resp,
1826 nt_resp,
1827 &info3);
1828 if (!NT_STATUS_IS_OK(result)) {
1829 goto done;
1830 }
1831
1832process_result:
1833
1834 if (NT_STATUS_IS_OK(result)) {
1835 struct dom_sid user_sid;
1836
1837 sid_compose(&user_sid, info3->base.domain_sid,
1838 info3->base.rid);
1839 wcache_invalidate_samlogon(find_domain_from_name(name_domain),
1840 &user_sid);
1841 netsamlogon_cache_store(name_user, info3);
1842
1843 /* Check if the user is in the right group */
1844
1845 result = check_info3_in_group(
1846 info3,
1847 state->request->data.auth_crap.require_membership_of_sid);
1848 if (!NT_STATUS_IS_OK(result)) {
1849 DEBUG(3, ("User %s is not in the required group (%s), so "
1850 "crap authentication is rejected\n",
1851 state->request->data.auth_crap.user,
1852 state->request->data.auth_crap.require_membership_of_sid));
1853 goto done;
1854 }
1855
1856 result = append_auth_data(state->mem_ctx, state->response,
1857 state->request->flags, info3,
1858 name_domain, name_user);
1859 if (!NT_STATUS_IS_OK(result)) {
1860 goto done;
1861 }
1862 }
1863
1864done:
1865
1866 /* give us a more useful (more correct?) error code */
1867 if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
1868 (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
1869 result = NT_STATUS_NO_LOGON_SERVERS;
1870 }
1871
1872 if (state->request->flags & WBFLAG_PAM_NT_STATUS_SQUASH) {
1873 result = nt_status_squash(result);
1874 }
1875
1876 set_auth_errors(state->response, result);
1877
1878 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
1879 ("NTLM CRAP authentication for user [%s]\\[%s] returned %s (PAM: %d)\n",
1880 name_domain,
1881 name_user,
1882 state->response->data.auth.nt_status_string,
1883 state->response->data.auth.pam_error));
1884
1885 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
1886}
1887
1888enum winbindd_result winbindd_dual_pam_chauthtok(struct winbindd_domain *contact_domain,
1889 struct winbindd_cli_state *state)
1890{
1891 char *oldpass;
1892 char *newpass = NULL;
1893 struct policy_handle dom_pol;
1894 struct rpc_pipe_client *cli = NULL;
1895 bool got_info = false;
1896 struct samr_DomInfo1 *info = NULL;
1897 struct userPwdChangeFailureInformation *reject = NULL;
1898 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1899 fstring domain, user;
1900 struct dcerpc_binding_handle *b = NULL;
1901
1902 ZERO_STRUCT(dom_pol);
1903
1904 DEBUG(3, ("[%5lu]: dual pam chauthtok %s\n", (unsigned long)state->pid,
1905 state->request->data.auth.user));
1906
1907 if (!parse_domain_user(state->request->data.chauthtok.user, domain, user)) {
1908 goto done;
1909 }
1910
1911 /* Change password */
1912
1913 oldpass = state->request->data.chauthtok.oldpass;
1914 newpass = state->request->data.chauthtok.newpass;
1915
1916 /* Initialize reject reason */
1917 state->response->data.auth.reject_reason = Undefined;
1918
1919 /* Get sam handle */
1920
1921 result = cm_connect_sam(contact_domain, state->mem_ctx, &cli,
1922 &dom_pol);
1923 if (!NT_STATUS_IS_OK(result)) {
1924 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
1925 goto done;
1926 }
1927
1928 b = cli->binding_handle;
1929
1930 result = rpccli_samr_chgpasswd_user3(cli, state->mem_ctx,
1931 user,
1932 newpass,
1933 oldpass,
1934 &info,
1935 &reject);
1936
1937 /* Windows 2003 returns NT_STATUS_PASSWORD_RESTRICTION */
1938
1939 if (NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_RESTRICTION) ) {
1940
1941 fill_in_password_policy(state->response, info);
1942
1943 state->response->data.auth.reject_reason =
1944 reject->extendedFailureReason;
1945
1946 got_info = true;
1947 }
1948
1949 /* atm the pidl generated rpccli_samr_ChangePasswordUser3 function will
1950 * return with NT_STATUS_BUFFER_TOO_SMALL for w2k dcs as w2k just
1951 * returns with 4byte error code (NT_STATUS_NOT_SUPPORTED) which is too
1952 * short to comply with the samr_ChangePasswordUser3 idl - gd */
1953
1954 /* only fallback when the chgpasswd_user3 call is not supported */
1955 if (NT_STATUS_EQUAL(result, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE) ||
1956 NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED) ||
1957 NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL) ||
1958 NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
1959
1960 DEBUG(10,("Password change with chgpasswd_user3 failed with: %s, retrying chgpasswd_user2\n",
1961 nt_errstr(result)));
1962
1963 result = rpccli_samr_chgpasswd_user2(cli, state->mem_ctx, user, newpass, oldpass);
1964
1965 /* Windows 2000 returns NT_STATUS_ACCOUNT_RESTRICTION.
1966 Map to the same status code as Windows 2003. */
1967
1968 if ( NT_STATUS_EQUAL(NT_STATUS_ACCOUNT_RESTRICTION, result ) ) {
1969 result = NT_STATUS_PASSWORD_RESTRICTION;
1970 }
1971 }
1972
1973done:
1974
1975 if (NT_STATUS_IS_OK(result)
1976 && (state->request->flags & WBFLAG_PAM_CACHED_LOGIN)
1977 && lp_winbind_offline_logon()) {
1978 result = winbindd_update_creds_by_name(contact_domain, user,
1979 newpass);
1980 /* Again, this happens when we login from gdm or xdm
1981 * and the password expires, *BUT* cached crendentials
1982 * doesn't exist. winbindd_update_creds_by_name()
1983 * returns NT_STATUS_NO_SUCH_USER.
1984 * This is not a failure.
1985 * --- BoYang
1986 * */
1987 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER)) {
1988 result = NT_STATUS_OK;
1989 }
1990
1991 if (!NT_STATUS_IS_OK(result)) {
1992 DEBUG(10, ("Failed to store creds: %s\n",
1993 nt_errstr(result)));
1994 goto process_result;
1995 }
1996 }
1997
1998 if (!NT_STATUS_IS_OK(result) && !got_info && contact_domain) {
1999
2000 NTSTATUS policy_ret;
2001
2002 policy_ret = fillup_password_policy(
2003 contact_domain, state->response);
2004
2005 /* failure of this is non critical, it will just provide no
2006 * additional information to the client why the change has
2007 * failed - Guenther */
2008
2009 if (!NT_STATUS_IS_OK(policy_ret)) {
2010 DEBUG(10,("Failed to get password policies: %s\n", nt_errstr(policy_ret)));
2011 goto process_result;
2012 }
2013 }
2014
2015process_result:
2016
2017 if (strequal(contact_domain->name, get_global_sam_name())) {
2018 /* FIXME: internal rpc pipe does not cache handles yet */
2019 if (b) {
2020 if (is_valid_policy_hnd(&dom_pol)) {
2021 NTSTATUS _result;
2022 dcerpc_samr_Close(b, state->mem_ctx, &dom_pol, &_result);
2023 }
2024 TALLOC_FREE(cli);
2025 }
2026 }
2027
2028 set_auth_errors(state->response, result);
2029
2030 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
2031 ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
2032 domain,
2033 user,
2034 state->response->data.auth.nt_status_string,
2035 state->response->data.auth.pam_error));
2036
2037 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2038}
2039
2040enum winbindd_result winbindd_dual_pam_logoff(struct winbindd_domain *domain,
2041 struct winbindd_cli_state *state)
2042{
2043 NTSTATUS result = NT_STATUS_NOT_SUPPORTED;
2044
2045 DEBUG(3, ("[%5lu]: pam dual logoff %s\n", (unsigned long)state->pid,
2046 state->request->data.logoff.user));
2047
2048 if (!(state->request->flags & WBFLAG_PAM_KRB5)) {
2049 result = NT_STATUS_OK;
2050 goto process_result;
2051 }
2052
2053 if (state->request->data.logoff.krb5ccname[0] == '\0') {
2054 result = NT_STATUS_OK;
2055 goto process_result;
2056 }
2057
2058#ifdef HAVE_KRB5
2059
2060 if (state->request->data.logoff.uid < 0) {
2061 DEBUG(0,("winbindd_pam_logoff: invalid uid\n"));
2062 goto process_result;
2063 }
2064
2065 /* what we need here is to find the corresponding krb5 ccache name *we*
2066 * created for a given username and destroy it */
2067
2068 if (!ccache_entry_exists(state->request->data.logoff.user)) {
2069 result = NT_STATUS_OK;
2070 DEBUG(10,("winbindd_pam_logoff: no entry found.\n"));
2071 goto process_result;
2072 }
2073
2074 if (!ccache_entry_identical(state->request->data.logoff.user,
2075 state->request->data.logoff.uid,
2076 state->request->data.logoff.krb5ccname)) {
2077 DEBUG(0,("winbindd_pam_logoff: cached entry differs.\n"));
2078 goto process_result;
2079 }
2080
2081 result = remove_ccache(state->request->data.logoff.user);
2082 if (!NT_STATUS_IS_OK(result)) {
2083 DEBUG(0,("winbindd_pam_logoff: failed to remove ccache: %s\n",
2084 nt_errstr(result)));
2085 goto process_result;
2086 }
2087
2088#else
2089 result = NT_STATUS_NOT_SUPPORTED;
2090#endif
2091
2092process_result:
2093
2094
2095 set_auth_errors(state->response, result);
2096
2097 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2098}
2099
2100/* Change user password with auth crap*/
2101
2102enum winbindd_result winbindd_dual_pam_chng_pswd_auth_crap(struct winbindd_domain *domainSt, struct winbindd_cli_state *state)
2103{
2104 NTSTATUS result;
2105 DATA_BLOB new_nt_password;
2106 DATA_BLOB old_nt_hash_enc;
2107 DATA_BLOB new_lm_password;
2108 DATA_BLOB old_lm_hash_enc;
2109 fstring domain,user;
2110 struct policy_handle dom_pol;
2111 struct winbindd_domain *contact_domain = domainSt;
2112 struct rpc_pipe_client *cli = NULL;
2113 struct dcerpc_binding_handle *b = NULL;
2114
2115 ZERO_STRUCT(dom_pol);
2116
2117 /* Ensure null termination */
2118 state->request->data.chng_pswd_auth_crap.user[
2119 sizeof(state->request->data.chng_pswd_auth_crap.user)-1]=0;
2120 state->request->data.chng_pswd_auth_crap.domain[
2121 sizeof(state->request->data.chng_pswd_auth_crap.domain)-1]=0;
2122 *domain = 0;
2123 *user = 0;
2124
2125 DEBUG(3, ("[%5lu]: pam change pswd auth crap domain: %s user: %s\n",
2126 (unsigned long)state->pid,
2127 state->request->data.chng_pswd_auth_crap.domain,
2128 state->request->data.chng_pswd_auth_crap.user));
2129
2130 if (lp_winbind_offline_logon()) {
2131 DEBUG(0,("Refusing password change as winbind offline logons are enabled. "));
2132 DEBUGADD(0,("Changing passwords here would risk inconsistent logons\n"));
2133 result = NT_STATUS_ACCESS_DENIED;
2134 goto done;
2135 }
2136
2137 if (*state->request->data.chng_pswd_auth_crap.domain) {
2138 fstrcpy(domain,state->request->data.chng_pswd_auth_crap.domain);
2139 } else {
2140 parse_domain_user(state->request->data.chng_pswd_auth_crap.user,
2141 domain, user);
2142
2143 if(!*domain) {
2144 DEBUG(3,("no domain specified with username (%s) - "
2145 "failing auth\n",
2146 state->request->data.chng_pswd_auth_crap.user));
2147 result = NT_STATUS_NO_SUCH_USER;
2148 goto done;
2149 }
2150 }
2151
2152 if (!*domain && lp_winbind_use_default_domain()) {
2153 fstrcpy(domain,(char *)lp_workgroup());
2154 }
2155
2156 if(!*user) {
2157 fstrcpy(user, state->request->data.chng_pswd_auth_crap.user);
2158 }
2159
2160 DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n",
2161 (unsigned long)state->pid, domain, user));
2162
2163 /* Change password */
2164 new_nt_password = data_blob_const(
2165 state->request->data.chng_pswd_auth_crap.new_nt_pswd,
2166 state->request->data.chng_pswd_auth_crap.new_nt_pswd_len);
2167
2168 old_nt_hash_enc = data_blob_const(
2169 state->request->data.chng_pswd_auth_crap.old_nt_hash_enc,
2170 state->request->data.chng_pswd_auth_crap.old_nt_hash_enc_len);
2171
2172 if(state->request->data.chng_pswd_auth_crap.new_lm_pswd_len > 0) {
2173 new_lm_password = data_blob_const(
2174 state->request->data.chng_pswd_auth_crap.new_lm_pswd,
2175 state->request->data.chng_pswd_auth_crap.new_lm_pswd_len);
2176
2177 old_lm_hash_enc = data_blob_const(
2178 state->request->data.chng_pswd_auth_crap.old_lm_hash_enc,
2179 state->request->data.chng_pswd_auth_crap.old_lm_hash_enc_len);
2180 } else {
2181 new_lm_password.length = 0;
2182 old_lm_hash_enc.length = 0;
2183 }
2184
2185 /* Get sam handle */
2186
2187 result = cm_connect_sam(contact_domain, state->mem_ctx, &cli, &dom_pol);
2188 if (!NT_STATUS_IS_OK(result)) {
2189 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
2190 goto done;
2191 }
2192
2193 b = cli->binding_handle;
2194
2195 result = rpccli_samr_chng_pswd_auth_crap(
2196 cli, state->mem_ctx, user, new_nt_password, old_nt_hash_enc,
2197 new_lm_password, old_lm_hash_enc);
2198
2199 done:
2200
2201 if (strequal(contact_domain->name, get_global_sam_name())) {
2202 /* FIXME: internal rpc pipe does not cache handles yet */
2203 if (b) {
2204 if (is_valid_policy_hnd(&dom_pol)) {
2205 NTSTATUS _result;
2206 dcerpc_samr_Close(b, state->mem_ctx, &dom_pol, &_result);
2207 }
2208 TALLOC_FREE(cli);
2209 }
2210 }
2211
2212 set_auth_errors(state->response, result);
2213
2214 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
2215 ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
2216 domain, user,
2217 state->response->data.auth.nt_status_string,
2218 state->response->data.auth.pam_error));
2219
2220 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2221}
Note: See TracBrowser for help on using the repository browser.