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

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

Samba Server: updated vendor to 3.6.9

File size: 64.4 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);
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 pass,
644 realm,
645 uid,
646 time(NULL),
647 ticket_lifetime,
648 renewal_until,
649 false);
650
651 if (!NT_STATUS_IS_OK(result)) {
652 DEBUG(10,("winbindd_raw_kerberos_login: failed to add ccache to list: %s\n",
653 nt_errstr(result)));
654 }
655 } else {
656
657 /* need to delete the memory cred cache, it is not used anymore */
658
659 krb5_ret = ads_kdestroy(cc);
660 if (krb5_ret) {
661 DEBUG(3,("winbindd_raw_kerberos_login: "
662 "could not destroy krb5 credential cache: "
663 "%s\n", error_message(krb5_ret)));
664 }
665
666 }
667
668 return NT_STATUS_OK;
669
670failed:
671
672 /* we could have created a new credential cache with a valid tgt in it
673 * but we werent able to get or verify the service ticket for this
674 * local host and therefor didn't get the PAC, we need to remove that
675 * cache entirely now */
676
677 krb5_ret = ads_kdestroy(cc);
678 if (krb5_ret) {
679 DEBUG(3,("winbindd_raw_kerberos_login: "
680 "could not destroy krb5 credential cache: "
681 "%s\n", error_message(krb5_ret)));
682 }
683
684 if (!NT_STATUS_IS_OK(remove_ccache(user))) {
685 DEBUG(3,("winbindd_raw_kerberos_login: "
686 "could not remove ccache for user %s\n",
687 user));
688 }
689
690 return result;
691#else
692 return NT_STATUS_NOT_SUPPORTED;
693#endif /* HAVE_KRB5 */
694}
695
696/****************************************************************
697****************************************************************/
698
699bool check_request_flags(uint32_t flags)
700{
701 uint32_t flags_edata = WBFLAG_PAM_AFS_TOKEN |
702 WBFLAG_PAM_INFO3_TEXT |
703 WBFLAG_PAM_INFO3_NDR;
704
705 if ( ( (flags & flags_edata) == WBFLAG_PAM_AFS_TOKEN) ||
706 ( (flags & flags_edata) == WBFLAG_PAM_INFO3_NDR) ||
707 ( (flags & flags_edata) == WBFLAG_PAM_INFO3_TEXT)||
708 !(flags & flags_edata) ) {
709 return true;
710 }
711
712 DEBUG(1, ("check_request_flags: invalid request flags[0x%08X]\n",
713 flags));
714
715 return false;
716}
717
718/****************************************************************
719****************************************************************/
720
721static NTSTATUS append_auth_data(TALLOC_CTX *mem_ctx,
722 struct winbindd_response *resp,
723 uint32_t request_flags,
724 struct netr_SamInfo3 *info3,
725 const char *name_domain,
726 const char *name_user)
727{
728 NTSTATUS result;
729
730 if (request_flags & WBFLAG_PAM_USER_SESSION_KEY) {
731 memcpy(resp->data.auth.user_session_key,
732 info3->base.key.key,
733 sizeof(resp->data.auth.user_session_key)
734 /* 16 */);
735 }
736
737 if (request_flags & WBFLAG_PAM_LMKEY) {
738 memcpy(resp->data.auth.first_8_lm_hash,
739 info3->base.LMSessKey.key,
740 sizeof(resp->data.auth.first_8_lm_hash)
741 /* 8 */);
742 }
743
744 if (request_flags & WBFLAG_PAM_UNIX_NAME) {
745 result = append_unix_username(mem_ctx, resp,
746 info3, name_domain, name_user);
747 if (!NT_STATUS_IS_OK(result)) {
748 DEBUG(10,("Failed to append Unix Username: %s\n",
749 nt_errstr(result)));
750 return result;
751 }
752 }
753
754 /* currently, anything from here on potentially overwrites extra_data. */
755
756 if (request_flags & WBFLAG_PAM_INFO3_NDR) {
757 result = append_info3_as_ndr(mem_ctx, resp, info3);
758 if (!NT_STATUS_IS_OK(result)) {
759 DEBUG(10,("Failed to append INFO3 (NDR): %s\n",
760 nt_errstr(result)));
761 return result;
762 }
763 }
764
765 if (request_flags & WBFLAG_PAM_INFO3_TEXT) {
766 result = append_info3_as_txt(mem_ctx, resp, info3);
767 if (!NT_STATUS_IS_OK(result)) {
768 DEBUG(10,("Failed to append INFO3 (TXT): %s\n",
769 nt_errstr(result)));
770 return result;
771 }
772 }
773
774 if (request_flags & WBFLAG_PAM_AFS_TOKEN) {
775 result = append_afs_token(mem_ctx, resp,
776 info3, name_domain, name_user);
777 if (!NT_STATUS_IS_OK(result)) {
778 DEBUG(10,("Failed to append AFS token: %s\n",
779 nt_errstr(result)));
780 return result;
781 }
782 }
783
784 return NT_STATUS_OK;
785}
786
787static NTSTATUS winbindd_dual_pam_auth_cached(struct winbindd_domain *domain,
788 struct winbindd_cli_state *state,
789 struct netr_SamInfo3 **info3)
790{
791 NTSTATUS result = NT_STATUS_LOGON_FAILURE;
792 uint16 max_allowed_bad_attempts;
793 fstring name_domain, name_user;
794 struct dom_sid sid;
795 enum lsa_SidType type;
796 uchar new_nt_pass[NT_HASH_LEN];
797 const uint8 *cached_nt_pass;
798 const uint8 *cached_salt;
799 struct netr_SamInfo3 *my_info3;
800 time_t kickoff_time, must_change_time;
801 bool password_good = false;
802#ifdef HAVE_KRB5
803 struct winbindd_tdc_domain *tdc_domain = NULL;
804#endif
805
806 *info3 = NULL;
807
808 ZERO_STRUCTP(info3);
809
810 DEBUG(10,("winbindd_dual_pam_auth_cached\n"));
811
812 /* Parse domain and username */
813
814 parse_domain_user(state->request->data.auth.user, name_domain, name_user);
815
816
817 if (!lookup_cached_name(name_domain,
818 name_user,
819 &sid,
820 &type)) {
821 DEBUG(10,("winbindd_dual_pam_auth_cached: no such user in the cache\n"));
822 return NT_STATUS_NO_SUCH_USER;
823 }
824
825 if (type != SID_NAME_USER) {
826 DEBUG(10,("winbindd_dual_pam_auth_cached: not a user (%s)\n", sid_type_lookup(type)));
827 return NT_STATUS_LOGON_FAILURE;
828 }
829
830 result = winbindd_get_creds(domain,
831 state->mem_ctx,
832 &sid,
833 &my_info3,
834 &cached_nt_pass,
835 &cached_salt);
836 if (!NT_STATUS_IS_OK(result)) {
837 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get creds: %s\n", nt_errstr(result)));
838 return result;
839 }
840
841 *info3 = my_info3;
842
843 E_md4hash(state->request->data.auth.pass, new_nt_pass);
844
845 dump_data_pw("new_nt_pass", new_nt_pass, NT_HASH_LEN);
846 dump_data_pw("cached_nt_pass", cached_nt_pass, NT_HASH_LEN);
847 if (cached_salt) {
848 dump_data_pw("cached_salt", cached_salt, NT_HASH_LEN);
849 }
850
851 if (cached_salt) {
852 /* In this case we didn't store the nt_hash itself,
853 but the MD5 combination of salt + nt_hash. */
854 uchar salted_hash[NT_HASH_LEN];
855 E_md5hash(cached_salt, new_nt_pass, salted_hash);
856
857 password_good = (memcmp(cached_nt_pass, salted_hash,
858 NT_HASH_LEN) == 0);
859 } else {
860 /* Old cached cred - direct store of nt_hash (bad bad bad !). */
861 password_good = (memcmp(cached_nt_pass, new_nt_pass,
862 NT_HASH_LEN) == 0);
863 }
864
865 if (password_good) {
866
867 /* User *DOES* know the password, update logon_time and reset
868 * bad_pw_count */
869
870 my_info3->base.user_flags |= NETLOGON_CACHED_ACCOUNT;
871
872 if (my_info3->base.acct_flags & ACB_AUTOLOCK) {
873 return NT_STATUS_ACCOUNT_LOCKED_OUT;
874 }
875
876 if (my_info3->base.acct_flags & ACB_DISABLED) {
877 return NT_STATUS_ACCOUNT_DISABLED;
878 }
879
880 if (my_info3->base.acct_flags & ACB_WSTRUST) {
881 return NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
882 }
883
884 if (my_info3->base.acct_flags & ACB_SVRTRUST) {
885 return NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT;
886 }
887
888 if (my_info3->base.acct_flags & ACB_DOMTRUST) {
889 return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT;
890 }
891
892 if (!(my_info3->base.acct_flags & ACB_NORMAL)) {
893 DEBUG(0,("winbindd_dual_pam_auth_cached: whats wrong with that one?: 0x%08x\n",
894 my_info3->base.acct_flags));
895 return NT_STATUS_LOGON_FAILURE;
896 }
897
898 kickoff_time = nt_time_to_unix(my_info3->base.acct_expiry);
899 if (kickoff_time != 0 && time(NULL) > kickoff_time) {
900 return NT_STATUS_ACCOUNT_EXPIRED;
901 }
902
903 must_change_time = nt_time_to_unix(my_info3->base.force_password_change);
904 if (must_change_time != 0 && must_change_time < time(NULL)) {
905 /* we allow grace logons when the password has expired */
906 my_info3->base.user_flags |= NETLOGON_GRACE_LOGON;
907 /* return NT_STATUS_PASSWORD_EXPIRED; */
908 goto success;
909 }
910
911#ifdef HAVE_KRB5
912 if ((state->request->flags & WBFLAG_PAM_KRB5) &&
913 ((tdc_domain = wcache_tdc_fetch_domain(state->mem_ctx, name_domain)) != NULL) &&
914 ((tdc_domain->trust_type & NETR_TRUST_TYPE_UPLEVEL) ||
915 /* used to cope with the case winbindd starting without network. */
916 !strequal(tdc_domain->domain_name, tdc_domain->dns_name))) {
917
918 uid_t uid = -1;
919 const char *cc = NULL;
920 char *realm = NULL;
921 const char *principal_s = NULL;
922 const char *service = NULL;
923 const char *user_ccache_file;
924
925 uid = get_uid_from_request(state->request);
926 if (uid == -1) {
927 DEBUG(0,("winbindd_dual_pam_auth_cached: invalid uid\n"));
928 return NT_STATUS_INVALID_PARAMETER;
929 }
930
931 cc = generate_krb5_ccache(state->mem_ctx,
932 state->request->data.auth.krb5_cc_type,
933 state->request->data.auth.uid,
934 &user_ccache_file);
935 if (cc == NULL) {
936 return NT_STATUS_NO_MEMORY;
937 }
938
939 realm = domain->alt_name;
940 strupper_m(realm);
941
942 principal_s = talloc_asprintf(state->mem_ctx, "%s@%s", name_user, realm);
943 if (principal_s == NULL) {
944 return NT_STATUS_NO_MEMORY;
945 }
946
947 service = talloc_asprintf(state->mem_ctx, "%s/%s@%s", KRB5_TGS_NAME, realm, realm);
948 if (service == NULL) {
949 return NT_STATUS_NO_MEMORY;
950 }
951
952 if (user_ccache_file != NULL) {
953
954 fstrcpy(state->response->data.auth.krb5ccname,
955 user_ccache_file);
956
957 result = add_ccache_to_list(principal_s,
958 cc,
959 service,
960 state->request->data.auth.user,
961 state->request->data.auth.pass,
962 domain->alt_name,
963 uid,
964 time(NULL),
965 time(NULL) + lp_winbind_cache_time(),
966 time(NULL) + WINBINDD_PAM_AUTH_KRB5_RENEW_TIME,
967 true);
968
969 if (!NT_STATUS_IS_OK(result)) {
970 DEBUG(10,("winbindd_dual_pam_auth_cached: failed "
971 "to add ccache to list: %s\n",
972 nt_errstr(result)));
973 }
974 }
975 }
976#endif /* HAVE_KRB5 */
977 success:
978 /* FIXME: we possibly should handle logon hours as well (does xp when
979 * offline?) see auth/auth_sam.c:sam_account_ok for details */
980
981 unix_to_nt_time(&my_info3->base.last_logon, time(NULL));
982 my_info3->base.bad_password_count = 0;
983
984 result = winbindd_update_creds_by_info3(domain,
985 state->request->data.auth.user,
986 state->request->data.auth.pass,
987 my_info3);
988 if (!NT_STATUS_IS_OK(result)) {
989 DEBUG(1,("winbindd_dual_pam_auth_cached: failed to update creds: %s\n",
990 nt_errstr(result)));
991 return result;
992 }
993
994 return NT_STATUS_OK;
995
996 }
997
998 /* User does *NOT* know the correct password, modify info3 accordingly, but only if online */
999 if (domain->online == false) {
1000 goto failed;
1001 }
1002
1003 /* failure of this is not critical */
1004 result = get_max_bad_attempts_from_lockout_policy(domain, state->mem_ctx, &max_allowed_bad_attempts);
1005 if (!NT_STATUS_IS_OK(result)) {
1006 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get max_allowed_bad_attempts. "
1007 "Won't be able to honour account lockout policies\n"));
1008 }
1009
1010 /* increase counter */
1011 my_info3->base.bad_password_count++;
1012
1013 if (max_allowed_bad_attempts == 0) {
1014 goto failed;
1015 }
1016
1017 /* lockout user */
1018 if (my_info3->base.bad_password_count >= max_allowed_bad_attempts) {
1019
1020 uint32 password_properties;
1021
1022 result = get_pwd_properties(domain, state->mem_ctx, &password_properties);
1023 if (!NT_STATUS_IS_OK(result)) {
1024 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get password properties.\n"));
1025 }
1026
1027 if ((my_info3->base.rid != DOMAIN_RID_ADMINISTRATOR) ||
1028 (password_properties & DOMAIN_PASSWORD_LOCKOUT_ADMINS)) {
1029 my_info3->base.acct_flags |= ACB_AUTOLOCK;
1030 }
1031 }
1032
1033failed:
1034 result = winbindd_update_creds_by_info3(domain,
1035 state->request->data.auth.user,
1036 NULL,
1037 my_info3);
1038
1039 if (!NT_STATUS_IS_OK(result)) {
1040 DEBUG(0,("winbindd_dual_pam_auth_cached: failed to update creds %s\n",
1041 nt_errstr(result)));
1042 }
1043
1044 return NT_STATUS_LOGON_FAILURE;
1045}
1046
1047static NTSTATUS winbindd_dual_pam_auth_kerberos(struct winbindd_domain *domain,
1048 struct winbindd_cli_state *state,
1049 struct netr_SamInfo3 **info3)
1050{
1051 struct winbindd_domain *contact_domain;
1052 fstring name_domain, name_user;
1053 NTSTATUS result;
1054
1055 DEBUG(10,("winbindd_dual_pam_auth_kerberos\n"));
1056
1057 /* Parse domain and username */
1058
1059 parse_domain_user(state->request->data.auth.user, name_domain, name_user);
1060
1061 /* what domain should we contact? */
1062
1063 if ( IS_DC ) {
1064 if (!(contact_domain = find_domain_from_name(name_domain))) {
1065 DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
1066 state->request->data.auth.user, name_domain, name_user, name_domain));
1067 result = NT_STATUS_NO_SUCH_USER;
1068 goto done;
1069 }
1070
1071 } else {
1072 if (is_myname(name_domain)) {
1073 DEBUG(3, ("Authentication for domain %s (local domain to this server) not supported at this stage\n", name_domain));
1074 result = NT_STATUS_NO_SUCH_USER;
1075 goto done;
1076 }
1077
1078 contact_domain = find_domain_from_name(name_domain);
1079 if (contact_domain == NULL) {
1080 DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
1081 state->request->data.auth.user, name_domain, name_user, name_domain));
1082
1083 result = NT_STATUS_NO_SUCH_USER;
1084 goto done;
1085 }
1086 }
1087
1088 if (contact_domain->initialized &&
1089 contact_domain->active_directory) {
1090 goto try_login;
1091 }
1092
1093 if (!contact_domain->initialized) {
1094 init_dc_connection(contact_domain);
1095 }
1096
1097 if (!contact_domain->active_directory) {
1098 DEBUG(3,("krb5 auth requested but domain is not Active Directory\n"));
1099 return NT_STATUS_INVALID_LOGON_TYPE;
1100 }
1101try_login:
1102 result = winbindd_raw_kerberos_login(
1103 state->mem_ctx, contact_domain,
1104 state->request->data.auth.user,
1105 state->request->data.auth.pass,
1106 state->request->data.auth.krb5_cc_type,
1107 get_uid_from_request(state->request),
1108 info3, state->response->data.auth.krb5ccname);
1109done:
1110 return result;
1111}
1112
1113static NTSTATUS winbindd_dual_auth_passdb(TALLOC_CTX *mem_ctx,
1114 const char *domain, const char *user,
1115 const DATA_BLOB *challenge,
1116 const DATA_BLOB *lm_resp,
1117 const DATA_BLOB *nt_resp,
1118 struct netr_SamInfo3 **pinfo3)
1119{
1120 struct auth_usersupplied_info *user_info = NULL;
1121 NTSTATUS status;
1122
1123 status = make_user_info(&user_info, user, user, domain, domain,
1124 global_myname(), lm_resp, nt_resp, NULL, NULL,
1125 NULL, AUTH_PASSWORD_RESPONSE);
1126 if (!NT_STATUS_IS_OK(status)) {
1127 DEBUG(10, ("make_user_info failed: %s\n", nt_errstr(status)));
1128 return status;
1129 }
1130
1131 /* We don't want any more mapping of the username */
1132 user_info->mapped_state = True;
1133
1134 status = check_sam_security_info3(challenge, talloc_tos(), user_info,
1135 pinfo3);
1136 free_user_info(&user_info);
1137 DEBUG(10, ("Authenticaticating user %s\\%s returned %s\n", domain,
1138 user, nt_errstr(status)));
1139 return status;
1140}
1141
1142static NTSTATUS winbind_samlogon_retry_loop(struct winbindd_domain *domain,
1143 TALLOC_CTX *mem_ctx,
1144 uint32_t logon_parameters,
1145 const char *server,
1146 const char *username,
1147 const char *domainname,
1148 const char *workstation,
1149 const uint8_t chal[8],
1150 DATA_BLOB lm_response,
1151 DATA_BLOB nt_response,
1152 struct netr_SamInfo3 **info3)
1153{
1154 int attempts = 0;
1155 bool retry = false;
1156 NTSTATUS result;
1157
1158 do {
1159 struct rpc_pipe_client *netlogon_pipe;
1160 const struct pipe_auth_data *auth;
1161 uint32_t neg_flags = 0;
1162
1163 ZERO_STRUCTP(info3);
1164 retry = false;
1165
1166 result = cm_connect_netlogon(domain, &netlogon_pipe);
1167
1168 if (!NT_STATUS_IS_OK(result)) {
1169 DEBUG(3,("could not open handle to NETLOGON pipe (error: %s)\n",
1170 nt_errstr(result)));
1171 if (NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT)) {
1172 if (attempts > 0) {
1173 DEBUG(3, ("This is the second problem for this "
1174 "particular call, forcing the close of "
1175 "this connection\n"));
1176 invalidate_cm_connection(&domain->conn);
1177 } else {
1178 DEBUG(3, ("First call to cm_connect_netlogon "
1179 "has timed out, retrying\n"));
1180 continue;
1181 }
1182 }
1183 return result;
1184 }
1185 auth = netlogon_pipe->auth;
1186 if (netlogon_pipe->dc) {
1187 neg_flags = netlogon_pipe->dc->negotiate_flags;
1188 }
1189
1190 /* It is really important to try SamLogonEx here,
1191 * because in a clustered environment, we want to use
1192 * one machine account from multiple physical
1193 * computers.
1194 *
1195 * With a normal SamLogon call, we must keep the
1196 * credentials chain updated and intact between all
1197 * users of the machine account (which would imply
1198 * cross-node communication for every NTLM logon).
1199 *
1200 * (The credentials chain is not per NETLOGON pipe
1201 * connection, but globally on the server/client pair
1202 * by machine name).
1203 *
1204 * When using SamLogonEx, the credentials are not
1205 * supplied, but the session key is implied by the
1206 * wrapping SamLogon context.
1207 *
1208 * -- abartlet 21 April 2008
1209 *
1210 * It's also important to use NetlogonValidationSamInfo4 (6),
1211 * because it relies on the rpc transport encryption
1212 * and avoids using the global netlogon schannel
1213 * session key to en/decrypt secret information
1214 * like the user_session_key for network logons.
1215 *
1216 * [MS-APDS] 3.1.5.2 NTLM Network Logon
1217 * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
1218 * NETLOGON_NEG_AUTHENTICATED_RPC set together
1219 * are the indication that the server supports
1220 * NetlogonValidationSamInfo4 (6). And it must only
1221 * be used if "SealSecureChannel" is used.
1222 *
1223 * -- metze 4 February 2011
1224 */
1225
1226 if (auth == NULL) {
1227 domain->can_do_validation6 = false;
1228 } else if (auth->auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
1229 domain->can_do_validation6 = false;
1230 } else if (auth->auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
1231 domain->can_do_validation6 = false;
1232 } else if (!(neg_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
1233 domain->can_do_validation6 = false;
1234 } else if (!(neg_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
1235 domain->can_do_validation6 = false;
1236 }
1237
1238 if (domain->can_do_samlogon_ex && domain->can_do_validation6) {
1239 result = rpccli_netlogon_sam_network_logon_ex(
1240 netlogon_pipe,
1241 mem_ctx,
1242 logon_parameters,
1243 server, /* server name */
1244 username, /* user name */
1245 domainname, /* target domain */
1246 workstation, /* workstation */
1247 chal,
1248 6,
1249 lm_response,
1250 nt_response,
1251 info3);
1252 } else {
1253 result = rpccli_netlogon_sam_network_logon(
1254 netlogon_pipe,
1255 mem_ctx,
1256 logon_parameters,
1257 server, /* server name */
1258 username, /* user name */
1259 domainname, /* target domain */
1260 workstation, /* workstation */
1261 chal,
1262 domain->can_do_validation6 ? 6 : 3,
1263 lm_response,
1264 nt_response,
1265 info3);
1266 }
1267
1268 if (NT_STATUS_EQUAL(result, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1269
1270 /*
1271 * It's likely that the server also does not support
1272 * validation level 6
1273 */
1274 domain->can_do_validation6 = false;
1275
1276 if (domain->can_do_samlogon_ex) {
1277 DEBUG(3, ("Got a DC that can not do NetSamLogonEx, "
1278 "retrying with NetSamLogon\n"));
1279 domain->can_do_samlogon_ex = false;
1280 retry = true;
1281 continue;
1282 }
1283
1284
1285 /* Got DCERPC_FAULT_OP_RNG_ERROR for SamLogon
1286 * (no Ex). This happens against old Samba
1287 * DCs. Drop the connection.
1288 */
1289 invalidate_cm_connection(&domain->conn);
1290 result = NT_STATUS_LOGON_FAILURE;
1291 break;
1292 }
1293
1294 if (domain->can_do_validation6 &&
1295 (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
1296 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
1297 NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL))) {
1298 DEBUG(3,("Got a DC that can not do validation level 6, "
1299 "retrying with level 3\n"));
1300 domain->can_do_validation6 = false;
1301 retry = true;
1302 continue;
1303 }
1304
1305 /*
1306 * we increment this after the "feature negotiation"
1307 * for can_do_samlogon_ex and can_do_validation6
1308 */
1309 attempts += 1;
1310
1311 /* We have to try a second time as cm_connect_netlogon
1312 might not yet have noticed that the DC has killed
1313 our connection. */
1314
1315 if (!rpccli_is_connected(netlogon_pipe)) {
1316 retry = true;
1317 continue;
1318 }
1319
1320 /* if we get access denied, a possible cause was that we had
1321 and open connection to the DC, but someone changed our
1322 machine account password out from underneath us using 'net
1323 rpc changetrustpw' */
1324
1325 if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
1326 DEBUG(3,("winbind_samlogon_retry_loop: sam_logon returned "
1327 "ACCESS_DENIED. Maybe the trust account "
1328 "password was changed and we didn't know it. "
1329 "Killing connections to domain %s\n",
1330 domainname));
1331 invalidate_cm_connection(&domain->conn);
1332 retry = true;
1333 }
1334
1335 } while ( (attempts < 2) && retry );
1336
1337 if (NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT)) {
1338 DEBUG(3,("winbind_samlogon_retry_loop: sam_network_logon(ex) "
1339 "returned NT_STATUS_IO_TIMEOUT after the retry."
1340 "Killing connections to domain %s\n",
1341 domainname));
1342 invalidate_cm_connection(&domain->conn);
1343 }
1344 return result;
1345}
1346
1347static NTSTATUS winbindd_dual_pam_auth_samlogon(TALLOC_CTX *mem_ctx,
1348 struct winbindd_domain *domain,
1349 const char *user,
1350 const char *pass,
1351 uint32_t request_flags,
1352 struct netr_SamInfo3 **info3)
1353{
1354
1355 uchar chal[8];
1356 DATA_BLOB lm_resp;
1357 DATA_BLOB nt_resp;
1358 unsigned char local_nt_response[24];
1359 fstring name_domain, name_user;
1360 NTSTATUS result;
1361 struct netr_SamInfo3 *my_info3 = NULL;
1362
1363 *info3 = NULL;
1364
1365 DEBUG(10,("winbindd_dual_pam_auth_samlogon\n"));
1366
1367 /* Parse domain and username */
1368
1369 parse_domain_user(user, name_domain, name_user);
1370
1371 /* do password magic */
1372
1373 generate_random_buffer(chal, sizeof(chal));
1374
1375 if (lp_client_ntlmv2_auth()) {
1376 DATA_BLOB server_chal;
1377 DATA_BLOB names_blob;
1378 server_chal = data_blob_const(chal, 8);
1379
1380 /* note that the 'workgroup' here is for the local
1381 machine. The 'server name' must match the
1382 'workstation' passed to the actual SamLogon call.
1383 */
1384 names_blob = NTLMv2_generate_names_blob(
1385 mem_ctx, global_myname(), lp_workgroup());
1386
1387 if (!SMBNTLMv2encrypt(mem_ctx, name_user, name_domain,
1388 pass,
1389 &server_chal,
1390 &names_blob,
1391 &lm_resp, &nt_resp, NULL, NULL)) {
1392 data_blob_free(&names_blob);
1393 DEBUG(0, ("winbindd_pam_auth: SMBNTLMv2encrypt() failed!\n"));
1394 result = NT_STATUS_NO_MEMORY;
1395 goto done;
1396 }
1397 data_blob_free(&names_blob);
1398 } else {
1399 lm_resp = data_blob_null;
1400 SMBNTencrypt(pass, chal, local_nt_response);
1401
1402 nt_resp = data_blob_talloc(mem_ctx, local_nt_response,
1403 sizeof(local_nt_response));
1404 }
1405
1406 if (strequal(name_domain, get_global_sam_name())) {
1407 DATA_BLOB chal_blob = data_blob_const(chal, sizeof(chal));
1408
1409 result = winbindd_dual_auth_passdb(
1410 mem_ctx, name_domain, name_user,
1411 &chal_blob, &lm_resp, &nt_resp, info3);
1412 goto done;
1413 }
1414
1415 /* check authentication loop */
1416
1417 result = winbind_samlogon_retry_loop(domain,
1418 mem_ctx,
1419 0,
1420 domain->dcname,
1421 name_user,
1422 name_domain,
1423 global_myname(),
1424 chal,
1425 lm_resp,
1426 nt_resp,
1427 &my_info3);
1428 if (!NT_STATUS_IS_OK(result)) {
1429 goto done;
1430 }
1431
1432 /* handle the case where a NT4 DC does not fill in the acct_flags in
1433 * the samlogon reply info3. When accurate info3 is required by the
1434 * caller, we look up the account flags ourselve - gd */
1435
1436 if ((request_flags & WBFLAG_PAM_INFO3_TEXT) &&
1437 NT_STATUS_IS_OK(result) && (my_info3->base.acct_flags == 0)) {
1438
1439 struct rpc_pipe_client *samr_pipe;
1440 struct policy_handle samr_domain_handle, user_pol;
1441 union samr_UserInfo *info = NULL;
1442 NTSTATUS status_tmp, result_tmp;
1443 uint32 acct_flags;
1444 struct dcerpc_binding_handle *b;
1445
1446 status_tmp = cm_connect_sam(domain, mem_ctx,
1447 &samr_pipe, &samr_domain_handle);
1448
1449 if (!NT_STATUS_IS_OK(status_tmp)) {
1450 DEBUG(3, ("could not open handle to SAMR pipe: %s\n",
1451 nt_errstr(status_tmp)));
1452 goto done;
1453 }
1454
1455 b = samr_pipe->binding_handle;
1456
1457 status_tmp = dcerpc_samr_OpenUser(b, mem_ctx,
1458 &samr_domain_handle,
1459 MAXIMUM_ALLOWED_ACCESS,
1460 my_info3->base.rid,
1461 &user_pol,
1462 &result_tmp);
1463
1464 if (!NT_STATUS_IS_OK(status_tmp)) {
1465 DEBUG(3, ("could not open user handle on SAMR pipe: %s\n",
1466 nt_errstr(status_tmp)));
1467 goto done;
1468 }
1469 if (!NT_STATUS_IS_OK(result_tmp)) {
1470 DEBUG(3, ("could not open user handle on SAMR pipe: %s\n",
1471 nt_errstr(result_tmp)));
1472 goto done;
1473 }
1474
1475 status_tmp = dcerpc_samr_QueryUserInfo(b, mem_ctx,
1476 &user_pol,
1477 16,
1478 &info,
1479 &result_tmp);
1480
1481 if (!NT_STATUS_IS_OK(status_tmp)) {
1482 DEBUG(3, ("could not query user info on SAMR pipe: %s\n",
1483 nt_errstr(status_tmp)));
1484 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
1485 goto done;
1486 }
1487 if (!NT_STATUS_IS_OK(result_tmp)) {
1488 DEBUG(3, ("could not query user info on SAMR pipe: %s\n",
1489 nt_errstr(result_tmp)));
1490 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
1491 goto done;
1492 }
1493
1494 acct_flags = info->info16.acct_flags;
1495
1496 if (acct_flags == 0) {
1497 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
1498 goto done;
1499 }
1500
1501 my_info3->base.acct_flags = acct_flags;
1502
1503 DEBUG(10,("successfully retrieved acct_flags 0x%x\n", acct_flags));
1504
1505 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
1506 }
1507
1508 *info3 = my_info3;
1509done:
1510 return result;
1511}
1512
1513enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain,
1514 struct winbindd_cli_state *state)
1515{
1516 NTSTATUS result = NT_STATUS_LOGON_FAILURE;
1517 NTSTATUS krb5_result = NT_STATUS_OK;
1518 fstring name_domain, name_user;
1519 char *mapped_user;
1520 fstring domain_user;
1521 struct netr_SamInfo3 *info3 = NULL;
1522 NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL;
1523
1524 /* Ensure null termination */
1525 state->request->data.auth.user[sizeof(state->request->data.auth.user)-1]='\0';
1526
1527 /* Ensure null termination */
1528 state->request->data.auth.pass[sizeof(state->request->data.auth.pass)-1]='\0';
1529
1530 DEBUG(3, ("[%5lu]: dual pam auth %s\n", (unsigned long)state->pid,
1531 state->request->data.auth.user));
1532
1533 /* Parse domain and username */
1534
1535 name_map_status = normalize_name_unmap(state->mem_ctx,
1536 state->request->data.auth.user,
1537 &mapped_user);
1538
1539 /* If the name normalization didnt' actually do anything,
1540 just use the original name */
1541
1542 if (!NT_STATUS_IS_OK(name_map_status) &&
1543 !NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED))
1544 {
1545 mapped_user = state->request->data.auth.user;
1546 }
1547
1548 parse_domain_user(mapped_user, name_domain, name_user);
1549
1550 if ( mapped_user != state->request->data.auth.user ) {
1551 fstr_sprintf( domain_user, "%s%c%s", name_domain,
1552 *lp_winbind_separator(),
1553 name_user );
1554 safe_strcpy( state->request->data.auth.user, domain_user,
1555 sizeof(state->request->data.auth.user)-1 );
1556 }
1557
1558 if (!domain->online) {
1559 result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
1560 if (domain->startup) {
1561 /* Logons are very important to users. If we're offline and
1562 we get a request within the first 30 seconds of startup,
1563 try very hard to find a DC and go online. */
1564
1565 DEBUG(10,("winbindd_dual_pam_auth: domain: %s offline and auth "
1566 "request in startup mode.\n", domain->name ));
1567
1568 winbindd_flush_negative_conn_cache(domain);
1569 result = init_dc_connection(domain);
1570 }
1571 }
1572
1573 DEBUG(10,("winbindd_dual_pam_auth: domain: %s last was %s\n", domain->name, domain->online ? "online":"offline"));
1574
1575 /* Check for Kerberos authentication */
1576 if (domain->online && (state->request->flags & WBFLAG_PAM_KRB5)) {
1577
1578 result = winbindd_dual_pam_auth_kerberos(domain, state, &info3);
1579 /* save for later */
1580 krb5_result = result;
1581
1582
1583 if (NT_STATUS_IS_OK(result)) {
1584 DEBUG(10,("winbindd_dual_pam_auth_kerberos succeeded\n"));
1585 goto process_result;
1586 } else {
1587 DEBUG(10,("winbindd_dual_pam_auth_kerberos failed: %s\n", nt_errstr(result)));
1588 }
1589
1590 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
1591 NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
1592 NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1593 DEBUG(10,("winbindd_dual_pam_auth_kerberos setting domain to offline\n"));
1594 set_domain_offline( domain );
1595 goto cached_logon;
1596 }
1597
1598 /* there are quite some NT_STATUS errors where there is no
1599 * point in retrying with a samlogon, we explictly have to take
1600 * care not to increase the bad logon counter on the DC */
1601
1602 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_DISABLED) ||
1603 NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_EXPIRED) ||
1604 NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_LOCKED_OUT) ||
1605 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_LOGON_HOURS) ||
1606 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_WORKSTATION) ||
1607 NT_STATUS_EQUAL(result, NT_STATUS_LOGON_FAILURE) ||
1608 NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER) ||
1609 NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_EXPIRED) ||
1610 NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_MUST_CHANGE) ||
1611 NT_STATUS_EQUAL(result, NT_STATUS_WRONG_PASSWORD)) {
1612 goto done;
1613 }
1614
1615 if (state->request->flags & WBFLAG_PAM_FALLBACK_AFTER_KRB5) {
1616 DEBUG(3,("falling back to samlogon\n"));
1617 goto sam_logon;
1618 } else {
1619 goto cached_logon;
1620 }
1621 }
1622
1623sam_logon:
1624 /* Check for Samlogon authentication */
1625 if (domain->online) {
1626 result = winbindd_dual_pam_auth_samlogon(
1627 state->mem_ctx, domain,
1628 state->request->data.auth.user,
1629 state->request->data.auth.pass,
1630 state->request->flags,
1631 &info3);
1632
1633 if (NT_STATUS_IS_OK(result)) {
1634 DEBUG(10,("winbindd_dual_pam_auth_samlogon succeeded\n"));
1635 /* add the Krb5 err if we have one */
1636 if ( NT_STATUS_EQUAL(krb5_result, NT_STATUS_TIME_DIFFERENCE_AT_DC ) ) {
1637 info3->base.user_flags |= LOGON_KRB5_FAIL_CLOCK_SKEW;
1638 }
1639 goto process_result;
1640 }
1641
1642 DEBUG(10,("winbindd_dual_pam_auth_samlogon failed: %s\n",
1643 nt_errstr(result)));
1644
1645 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
1646 NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
1647 NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND))
1648 {
1649 DEBUG(10,("winbindd_dual_pam_auth_samlogon setting domain to offline\n"));
1650 set_domain_offline( domain );
1651 goto cached_logon;
1652 }
1653
1654 if (domain->online) {
1655 /* We're still online - fail. */
1656 goto done;
1657 }
1658 }
1659
1660cached_logon:
1661 /* Check for Cached logons */
1662 if (!domain->online && (state->request->flags & WBFLAG_PAM_CACHED_LOGIN) &&
1663 lp_winbind_offline_logon()) {
1664
1665 result = winbindd_dual_pam_auth_cached(domain, state, &info3);
1666
1667 if (NT_STATUS_IS_OK(result)) {
1668 DEBUG(10,("winbindd_dual_pam_auth_cached succeeded\n"));
1669 goto process_result;
1670 } else {
1671 DEBUG(10,("winbindd_dual_pam_auth_cached failed: %s\n", nt_errstr(result)));
1672 goto done;
1673 }
1674 }
1675
1676process_result:
1677
1678 if (NT_STATUS_IS_OK(result)) {
1679
1680 struct dom_sid user_sid;
1681
1682 /* In all codepaths where result == NT_STATUS_OK info3 must have
1683 been initialized. */
1684 if (!info3) {
1685 result = NT_STATUS_INTERNAL_ERROR;
1686 goto done;
1687 }
1688
1689 sid_compose(&user_sid, info3->base.domain_sid,
1690 info3->base.rid);
1691
1692 wcache_invalidate_samlogon(find_domain_from_name(name_domain),
1693 &user_sid);
1694 netsamlogon_cache_store(name_user, info3);
1695
1696 /* save name_to_sid info as early as possible (only if
1697 this is our primary domain so we don't invalidate
1698 the cache entry by storing the seq_num for the wrong
1699 domain). */
1700 if ( domain->primary ) {
1701 cache_name2sid(domain, name_domain, name_user,
1702 SID_NAME_USER, &user_sid);
1703 }
1704
1705 /* Check if the user is in the right group */
1706
1707 result = check_info3_in_group(
1708 info3,
1709 state->request->data.auth.require_membership_of_sid);
1710 if (!NT_STATUS_IS_OK(result)) {
1711 DEBUG(3, ("User %s is not in the required group (%s), so plaintext authentication is rejected\n",
1712 state->request->data.auth.user,
1713 state->request->data.auth.require_membership_of_sid));
1714 goto done;
1715 }
1716
1717 result = append_auth_data(state->mem_ctx, state->response,
1718 state->request->flags, info3,
1719 name_domain, name_user);
1720 if (!NT_STATUS_IS_OK(result)) {
1721 goto done;
1722 }
1723
1724 if ((state->request->flags & WBFLAG_PAM_CACHED_LOGIN)
1725 && lp_winbind_offline_logon()) {
1726
1727 result = winbindd_store_creds(domain,
1728 state->request->data.auth.user,
1729 state->request->data.auth.pass,
1730 info3);
1731 }
1732
1733 if (state->request->flags & WBFLAG_PAM_GET_PWD_POLICY) {
1734 struct winbindd_domain *our_domain = find_our_domain();
1735
1736 /* This is not entirely correct I believe, but it is
1737 consistent. Only apply the password policy settings
1738 too warn users for our own domain. Cannot obtain these
1739 from trusted DCs all the time so don't do it at all.
1740 -- jerry */
1741
1742 result = NT_STATUS_NOT_SUPPORTED;
1743 if (our_domain == domain ) {
1744 result = fillup_password_policy(
1745 our_domain, state->response);
1746 }
1747
1748 if (!NT_STATUS_IS_OK(result)
1749 && !NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED) )
1750 {
1751 DEBUG(10,("Failed to get password policies for domain %s: %s\n",
1752 domain->name, nt_errstr(result)));
1753 goto done;
1754 }
1755 }
1756
1757 result = NT_STATUS_OK;
1758 }
1759
1760done:
1761 /* give us a more useful (more correct?) error code */
1762 if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
1763 (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
1764 result = NT_STATUS_NO_LOGON_SERVERS;
1765 }
1766
1767 set_auth_errors(state->response, result);
1768
1769 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, ("Plain-text authentication for user %s returned %s (PAM: %d)\n",
1770 state->request->data.auth.user,
1771 state->response->data.auth.nt_status_string,
1772 state->response->data.auth.pam_error));
1773
1774 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
1775}
1776
1777enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain,
1778 struct winbindd_cli_state *state)
1779{
1780 NTSTATUS result;
1781 struct netr_SamInfo3 *info3 = NULL;
1782 const char *name_user = NULL;
1783 const char *name_domain = NULL;
1784 const char *workstation;
1785
1786 DATA_BLOB lm_resp, nt_resp;
1787
1788 /* This is child-only, so no check for privileged access is needed
1789 anymore */
1790
1791 /* Ensure null termination */
1792 state->request->data.auth_crap.user[sizeof(state->request->data.auth_crap.user)-1]=0;
1793 state->request->data.auth_crap.domain[sizeof(state->request->data.auth_crap.domain)-1]=0;
1794
1795 name_user = state->request->data.auth_crap.user;
1796 name_domain = state->request->data.auth_crap.domain;
1797 workstation = state->request->data.auth_crap.workstation;
1798
1799 DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n", (unsigned long)state->pid,
1800 name_domain, name_user));
1801
1802 if (state->request->data.auth_crap.lm_resp_len > sizeof(state->request->data.auth_crap.lm_resp)
1803 || state->request->data.auth_crap.nt_resp_len > sizeof(state->request->data.auth_crap.nt_resp)) {
1804 if (!(state->request->flags & WBFLAG_BIG_NTLMV2_BLOB) ||
1805 state->request->extra_len != state->request->data.auth_crap.nt_resp_len) {
1806 DEBUG(0, ("winbindd_pam_auth_crap: invalid password length %u/%u\n",
1807 state->request->data.auth_crap.lm_resp_len,
1808 state->request->data.auth_crap.nt_resp_len));
1809 result = NT_STATUS_INVALID_PARAMETER;
1810 goto done;
1811 }
1812 }
1813
1814 lm_resp = data_blob_talloc(state->mem_ctx, state->request->data.auth_crap.lm_resp,
1815 state->request->data.auth_crap.lm_resp_len);
1816
1817 if (state->request->flags & WBFLAG_BIG_NTLMV2_BLOB) {
1818 nt_resp = data_blob_talloc(state->mem_ctx,
1819 state->request->extra_data.data,
1820 state->request->data.auth_crap.nt_resp_len);
1821 } else {
1822 nt_resp = data_blob_talloc(state->mem_ctx,
1823 state->request->data.auth_crap.nt_resp,
1824 state->request->data.auth_crap.nt_resp_len);
1825 }
1826
1827 if (strequal(name_domain, get_global_sam_name())) {
1828 DATA_BLOB chal_blob = data_blob_const(
1829 state->request->data.auth_crap.chal,
1830 sizeof(state->request->data.auth_crap.chal));
1831
1832 result = winbindd_dual_auth_passdb(
1833 state->mem_ctx, name_domain, name_user,
1834 &chal_blob, &lm_resp, &nt_resp, &info3);
1835 goto process_result;
1836 }
1837
1838 result = winbind_samlogon_retry_loop(domain,
1839 state->mem_ctx,
1840 state->request->data.auth_crap.logon_parameters,
1841 domain->dcname,
1842 name_user,
1843 name_domain,
1844 /* Bug #3248 - found by Stefan Burkei. */
1845 workstation, /* We carefully set this above so use it... */
1846 state->request->data.auth_crap.chal,
1847 lm_resp,
1848 nt_resp,
1849 &info3);
1850 if (!NT_STATUS_IS_OK(result)) {
1851 goto done;
1852 }
1853
1854process_result:
1855
1856 if (NT_STATUS_IS_OK(result)) {
1857 struct dom_sid user_sid;
1858
1859 sid_compose(&user_sid, info3->base.domain_sid,
1860 info3->base.rid);
1861 wcache_invalidate_samlogon(find_domain_from_name(name_domain),
1862 &user_sid);
1863 netsamlogon_cache_store(name_user, info3);
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_crap.require_membership_of_sid);
1870 if (!NT_STATUS_IS_OK(result)) {
1871 DEBUG(3, ("User %s is not in the required group (%s), so "
1872 "crap authentication is rejected\n",
1873 state->request->data.auth_crap.user,
1874 state->request->data.auth_crap.require_membership_of_sid));
1875 goto done;
1876 }
1877
1878 result = append_auth_data(state->mem_ctx, state->response,
1879 state->request->flags, info3,
1880 name_domain, name_user);
1881 if (!NT_STATUS_IS_OK(result)) {
1882 goto done;
1883 }
1884 }
1885
1886done:
1887
1888 /* give us a more useful (more correct?) error code */
1889 if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
1890 (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
1891 result = NT_STATUS_NO_LOGON_SERVERS;
1892 }
1893
1894 if (state->request->flags & WBFLAG_PAM_NT_STATUS_SQUASH) {
1895 result = nt_status_squash(result);
1896 }
1897
1898 set_auth_errors(state->response, result);
1899
1900 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
1901 ("NTLM CRAP authentication for user [%s]\\[%s] returned %s (PAM: %d)\n",
1902 name_domain,
1903 name_user,
1904 state->response->data.auth.nt_status_string,
1905 state->response->data.auth.pam_error));
1906
1907 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
1908}
1909
1910enum winbindd_result winbindd_dual_pam_chauthtok(struct winbindd_domain *contact_domain,
1911 struct winbindd_cli_state *state)
1912{
1913 char *oldpass;
1914 char *newpass = NULL;
1915 struct policy_handle dom_pol;
1916 struct rpc_pipe_client *cli = NULL;
1917 bool got_info = false;
1918 struct samr_DomInfo1 *info = NULL;
1919 struct userPwdChangeFailureInformation *reject = NULL;
1920 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1921 fstring domain, user;
1922 struct dcerpc_binding_handle *b = NULL;
1923
1924 ZERO_STRUCT(dom_pol);
1925
1926 DEBUG(3, ("[%5lu]: dual pam chauthtok %s\n", (unsigned long)state->pid,
1927 state->request->data.auth.user));
1928
1929 if (!parse_domain_user(state->request->data.chauthtok.user, domain, user)) {
1930 goto done;
1931 }
1932
1933 /* Change password */
1934
1935 oldpass = state->request->data.chauthtok.oldpass;
1936 newpass = state->request->data.chauthtok.newpass;
1937
1938 /* Initialize reject reason */
1939 state->response->data.auth.reject_reason = Undefined;
1940
1941 /* Get sam handle */
1942
1943 result = cm_connect_sam(contact_domain, state->mem_ctx, &cli,
1944 &dom_pol);
1945 if (!NT_STATUS_IS_OK(result)) {
1946 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
1947 goto done;
1948 }
1949
1950 b = cli->binding_handle;
1951
1952 result = rpccli_samr_chgpasswd_user3(cli, state->mem_ctx,
1953 user,
1954 newpass,
1955 oldpass,
1956 &info,
1957 &reject);
1958
1959 /* Windows 2003 returns NT_STATUS_PASSWORD_RESTRICTION */
1960
1961 if (NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_RESTRICTION) ) {
1962
1963 fill_in_password_policy(state->response, info);
1964
1965 state->response->data.auth.reject_reason =
1966 reject->extendedFailureReason;
1967
1968 got_info = true;
1969 }
1970
1971 /* atm the pidl generated rpccli_samr_ChangePasswordUser3 function will
1972 * return with NT_STATUS_BUFFER_TOO_SMALL for w2k dcs as w2k just
1973 * returns with 4byte error code (NT_STATUS_NOT_SUPPORTED) which is too
1974 * short to comply with the samr_ChangePasswordUser3 idl - gd */
1975
1976 /* only fallback when the chgpasswd_user3 call is not supported */
1977 if (NT_STATUS_EQUAL(result, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE) ||
1978 NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED) ||
1979 NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL) ||
1980 NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
1981
1982 DEBUG(10,("Password change with chgpasswd_user3 failed with: %s, retrying chgpasswd_user2\n",
1983 nt_errstr(result)));
1984
1985 result = rpccli_samr_chgpasswd_user2(cli, state->mem_ctx, user, newpass, oldpass);
1986
1987 /* Windows 2000 returns NT_STATUS_ACCOUNT_RESTRICTION.
1988 Map to the same status code as Windows 2003. */
1989
1990 if ( NT_STATUS_EQUAL(NT_STATUS_ACCOUNT_RESTRICTION, result ) ) {
1991 result = NT_STATUS_PASSWORD_RESTRICTION;
1992 }
1993 }
1994
1995done:
1996
1997 if (NT_STATUS_IS_OK(result)
1998 && (state->request->flags & WBFLAG_PAM_CACHED_LOGIN)
1999 && lp_winbind_offline_logon()) {
2000 result = winbindd_update_creds_by_name(contact_domain, user,
2001 newpass);
2002 /* Again, this happens when we login from gdm or xdm
2003 * and the password expires, *BUT* cached crendentials
2004 * doesn't exist. winbindd_update_creds_by_name()
2005 * returns NT_STATUS_NO_SUCH_USER.
2006 * This is not a failure.
2007 * --- BoYang
2008 * */
2009 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER)) {
2010 result = NT_STATUS_OK;
2011 }
2012
2013 if (!NT_STATUS_IS_OK(result)) {
2014 DEBUG(10, ("Failed to store creds: %s\n",
2015 nt_errstr(result)));
2016 goto process_result;
2017 }
2018 }
2019
2020 if (!NT_STATUS_IS_OK(result) && !got_info && contact_domain) {
2021
2022 NTSTATUS policy_ret;
2023
2024 policy_ret = fillup_password_policy(
2025 contact_domain, state->response);
2026
2027 /* failure of this is non critical, it will just provide no
2028 * additional information to the client why the change has
2029 * failed - Guenther */
2030
2031 if (!NT_STATUS_IS_OK(policy_ret)) {
2032 DEBUG(10,("Failed to get password policies: %s\n", nt_errstr(policy_ret)));
2033 goto process_result;
2034 }
2035 }
2036
2037process_result:
2038
2039 if (strequal(contact_domain->name, get_global_sam_name())) {
2040 /* FIXME: internal rpc pipe does not cache handles yet */
2041 if (b) {
2042 if (is_valid_policy_hnd(&dom_pol)) {
2043 NTSTATUS _result;
2044 dcerpc_samr_Close(b, state->mem_ctx, &dom_pol, &_result);
2045 }
2046 TALLOC_FREE(cli);
2047 }
2048 }
2049
2050 set_auth_errors(state->response, result);
2051
2052 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
2053 ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
2054 domain,
2055 user,
2056 state->response->data.auth.nt_status_string,
2057 state->response->data.auth.pam_error));
2058
2059 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2060}
2061
2062enum winbindd_result winbindd_dual_pam_logoff(struct winbindd_domain *domain,
2063 struct winbindd_cli_state *state)
2064{
2065 NTSTATUS result = NT_STATUS_NOT_SUPPORTED;
2066
2067 DEBUG(3, ("[%5lu]: pam dual logoff %s\n", (unsigned long)state->pid,
2068 state->request->data.logoff.user));
2069
2070 if (!(state->request->flags & WBFLAG_PAM_KRB5)) {
2071 result = NT_STATUS_OK;
2072 goto process_result;
2073 }
2074
2075 if (state->request->data.logoff.krb5ccname[0] == '\0') {
2076 result = NT_STATUS_OK;
2077 goto process_result;
2078 }
2079
2080#ifdef HAVE_KRB5
2081
2082 if (state->request->data.logoff.uid < 0) {
2083 DEBUG(0,("winbindd_pam_logoff: invalid uid\n"));
2084 goto process_result;
2085 }
2086
2087 /* what we need here is to find the corresponding krb5 ccache name *we*
2088 * created for a given username and destroy it */
2089
2090 if (!ccache_entry_exists(state->request->data.logoff.user)) {
2091 result = NT_STATUS_OK;
2092 DEBUG(10,("winbindd_pam_logoff: no entry found.\n"));
2093 goto process_result;
2094 }
2095
2096 if (!ccache_entry_identical(state->request->data.logoff.user,
2097 state->request->data.logoff.uid,
2098 state->request->data.logoff.krb5ccname)) {
2099 DEBUG(0,("winbindd_pam_logoff: cached entry differs.\n"));
2100 goto process_result;
2101 }
2102
2103 result = remove_ccache(state->request->data.logoff.user);
2104 if (!NT_STATUS_IS_OK(result)) {
2105 DEBUG(0,("winbindd_pam_logoff: failed to remove ccache: %s\n",
2106 nt_errstr(result)));
2107 goto process_result;
2108 }
2109
2110 /*
2111 * Remove any mlock'ed memory creds in the child
2112 * we might be using for krb5 ticket renewal.
2113 */
2114
2115 winbindd_delete_memory_creds(state->request->data.logoff.user);
2116
2117#else
2118 result = NT_STATUS_NOT_SUPPORTED;
2119#endif
2120
2121process_result:
2122
2123
2124 set_auth_errors(state->response, result);
2125
2126 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2127}
2128
2129/* Change user password with auth crap*/
2130
2131enum winbindd_result winbindd_dual_pam_chng_pswd_auth_crap(struct winbindd_domain *domainSt, struct winbindd_cli_state *state)
2132{
2133 NTSTATUS result;
2134 DATA_BLOB new_nt_password;
2135 DATA_BLOB old_nt_hash_enc;
2136 DATA_BLOB new_lm_password;
2137 DATA_BLOB old_lm_hash_enc;
2138 fstring domain,user;
2139 struct policy_handle dom_pol;
2140 struct winbindd_domain *contact_domain = domainSt;
2141 struct rpc_pipe_client *cli = NULL;
2142 struct dcerpc_binding_handle *b = NULL;
2143
2144 ZERO_STRUCT(dom_pol);
2145
2146 /* Ensure null termination */
2147 state->request->data.chng_pswd_auth_crap.user[
2148 sizeof(state->request->data.chng_pswd_auth_crap.user)-1]=0;
2149 state->request->data.chng_pswd_auth_crap.domain[
2150 sizeof(state->request->data.chng_pswd_auth_crap.domain)-1]=0;
2151 *domain = 0;
2152 *user = 0;
2153
2154 DEBUG(3, ("[%5lu]: pam change pswd auth crap domain: %s user: %s\n",
2155 (unsigned long)state->pid,
2156 state->request->data.chng_pswd_auth_crap.domain,
2157 state->request->data.chng_pswd_auth_crap.user));
2158
2159 if (lp_winbind_offline_logon()) {
2160 DEBUG(0,("Refusing password change as winbind offline logons are enabled. "));
2161 DEBUGADD(0,("Changing passwords here would risk inconsistent logons\n"));
2162 result = NT_STATUS_ACCESS_DENIED;
2163 goto done;
2164 }
2165
2166 if (*state->request->data.chng_pswd_auth_crap.domain) {
2167 fstrcpy(domain,state->request->data.chng_pswd_auth_crap.domain);
2168 } else {
2169 parse_domain_user(state->request->data.chng_pswd_auth_crap.user,
2170 domain, user);
2171
2172 if(!*domain) {
2173 DEBUG(3,("no domain specified with username (%s) - "
2174 "failing auth\n",
2175 state->request->data.chng_pswd_auth_crap.user));
2176 result = NT_STATUS_NO_SUCH_USER;
2177 goto done;
2178 }
2179 }
2180
2181 if (!*domain && lp_winbind_use_default_domain()) {
2182 fstrcpy(domain,(char *)lp_workgroup());
2183 }
2184
2185 if(!*user) {
2186 fstrcpy(user, state->request->data.chng_pswd_auth_crap.user);
2187 }
2188
2189 DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n",
2190 (unsigned long)state->pid, domain, user));
2191
2192 /* Change password */
2193 new_nt_password = data_blob_const(
2194 state->request->data.chng_pswd_auth_crap.new_nt_pswd,
2195 state->request->data.chng_pswd_auth_crap.new_nt_pswd_len);
2196
2197 old_nt_hash_enc = data_blob_const(
2198 state->request->data.chng_pswd_auth_crap.old_nt_hash_enc,
2199 state->request->data.chng_pswd_auth_crap.old_nt_hash_enc_len);
2200
2201 if(state->request->data.chng_pswd_auth_crap.new_lm_pswd_len > 0) {
2202 new_lm_password = data_blob_const(
2203 state->request->data.chng_pswd_auth_crap.new_lm_pswd,
2204 state->request->data.chng_pswd_auth_crap.new_lm_pswd_len);
2205
2206 old_lm_hash_enc = data_blob_const(
2207 state->request->data.chng_pswd_auth_crap.old_lm_hash_enc,
2208 state->request->data.chng_pswd_auth_crap.old_lm_hash_enc_len);
2209 } else {
2210 new_lm_password.length = 0;
2211 old_lm_hash_enc.length = 0;
2212 }
2213
2214 /* Get sam handle */
2215
2216 result = cm_connect_sam(contact_domain, state->mem_ctx, &cli, &dom_pol);
2217 if (!NT_STATUS_IS_OK(result)) {
2218 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
2219 goto done;
2220 }
2221
2222 b = cli->binding_handle;
2223
2224 result = rpccli_samr_chng_pswd_auth_crap(
2225 cli, state->mem_ctx, user, new_nt_password, old_nt_hash_enc,
2226 new_lm_password, old_lm_hash_enc);
2227
2228 done:
2229
2230 if (strequal(contact_domain->name, get_global_sam_name())) {
2231 /* FIXME: internal rpc pipe does not cache handles yet */
2232 if (b) {
2233 if (is_valid_policy_hnd(&dom_pol)) {
2234 NTSTATUS _result;
2235 dcerpc_samr_Close(b, state->mem_ctx, &dom_pol, &_result);
2236 }
2237 TALLOC_FREE(cli);
2238 }
2239 }
2240
2241 set_auth_errors(state->response, result);
2242
2243 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
2244 ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
2245 domain, user,
2246 state->response->data.auth.nt_status_string,
2247 state->response->data.auth.pam_error));
2248
2249 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2250}
Note: See TracBrowser for help on using the repository browser.