source: trunk/server/source3/winbindd/winbindd_pam.c

Last change on this file was 862, checked in by Silvan Scherrer, 11 years ago

Samba Server: update trunk to 3.6.23

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