s3:smbd: change blocking.c to use fsp_fnum_dbg() for fsp->fnum logging.
[Samba/gebeck_regimport.git] / source3 / winbindd / winbindd_pam.c
blob216e1ffc339e6d3a77fd9078b45296809305d62d
1 /*
2 Unix SMB/CIFS implementation.
4 Winbind daemon - pam auth funcions
6 Copyright (C) Andrew Tridgell 2000
7 Copyright (C) Tim Potter 2001
8 Copyright (C) Andrew Bartlett 2001-2002
9 Copyright (C) Guenther Deschner 2005
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "includes.h"
26 #include "winbindd.h"
27 #include "../libcli/auth/libcli_auth.h"
28 #include "../librpc/gen_ndr/ndr_samr_c.h"
29 #include "rpc_client/cli_pipe.h"
30 #include "rpc_client/cli_samr.h"
31 #include "../librpc/gen_ndr/ndr_netlogon.h"
32 #include "rpc_client/cli_netlogon.h"
33 #include "smb_krb5.h"
34 #include "../lib/crypto/arcfour.h"
35 #include "../libcli/security/security.h"
36 #include "ads.h"
37 #include "../librpc/gen_ndr/krb5pac.h"
38 #include "passdb/machine_sid.h"
39 #include "auth.h"
40 #include "../lib/tsocket/tsocket.h"
42 #undef DBGC_CLASS
43 #define DBGC_CLASS DBGC_WINBIND
45 #define LOGON_KRB5_FAIL_CLOCK_SKEW 0x02000000
47 static NTSTATUS append_info3_as_txt(TALLOC_CTX *mem_ctx,
48 struct winbindd_response *resp,
49 struct netr_SamInfo3 *info3)
51 char *ex;
52 uint32_t i;
54 resp->data.auth.info3.logon_time =
55 nt_time_to_unix(info3->base.logon_time);
56 resp->data.auth.info3.logoff_time =
57 nt_time_to_unix(info3->base.logoff_time);
58 resp->data.auth.info3.kickoff_time =
59 nt_time_to_unix(info3->base.kickoff_time);
60 resp->data.auth.info3.pass_last_set_time =
61 nt_time_to_unix(info3->base.last_password_change);
62 resp->data.auth.info3.pass_can_change_time =
63 nt_time_to_unix(info3->base.allow_password_change);
64 resp->data.auth.info3.pass_must_change_time =
65 nt_time_to_unix(info3->base.force_password_change);
67 resp->data.auth.info3.logon_count = info3->base.logon_count;
68 resp->data.auth.info3.bad_pw_count = info3->base.bad_password_count;
70 resp->data.auth.info3.user_rid = info3->base.rid;
71 resp->data.auth.info3.group_rid = info3->base.primary_gid;
72 sid_to_fstring(resp->data.auth.info3.dom_sid, info3->base.domain_sid);
74 resp->data.auth.info3.num_groups = info3->base.groups.count;
75 resp->data.auth.info3.user_flgs = info3->base.user_flags;
77 resp->data.auth.info3.acct_flags = info3->base.acct_flags;
78 resp->data.auth.info3.num_other_sids = info3->sidcount;
80 fstrcpy(resp->data.auth.info3.user_name,
81 info3->base.account_name.string);
82 fstrcpy(resp->data.auth.info3.full_name,
83 info3->base.full_name.string);
84 fstrcpy(resp->data.auth.info3.logon_script,
85 info3->base.logon_script.string);
86 fstrcpy(resp->data.auth.info3.profile_path,
87 info3->base.profile_path.string);
88 fstrcpy(resp->data.auth.info3.home_dir,
89 info3->base.home_directory.string);
90 fstrcpy(resp->data.auth.info3.dir_drive,
91 info3->base.home_drive.string);
93 fstrcpy(resp->data.auth.info3.logon_srv,
94 info3->base.logon_server.string);
95 fstrcpy(resp->data.auth.info3.logon_dom,
96 info3->base.logon_domain.string);
98 ex = talloc_strdup(mem_ctx, "");
99 NT_STATUS_HAVE_NO_MEMORY(ex);
101 for (i=0; i < info3->base.groups.count; i++) {
102 ex = talloc_asprintf_append_buffer(ex, "0x%08X:0x%08X\n",
103 info3->base.groups.rids[i].rid,
104 info3->base.groups.rids[i].attributes);
105 NT_STATUS_HAVE_NO_MEMORY(ex);
108 for (i=0; i < info3->sidcount; i++) {
109 char *sid;
111 sid = dom_sid_string(mem_ctx, info3->sids[i].sid);
112 NT_STATUS_HAVE_NO_MEMORY(sid);
114 ex = talloc_asprintf_append_buffer(ex, "%s:0x%08X\n",
115 sid,
116 info3->sids[i].attributes);
117 NT_STATUS_HAVE_NO_MEMORY(ex);
119 talloc_free(sid);
122 resp->extra_data.data = ex;
123 resp->length += talloc_get_size(ex);
125 return NT_STATUS_OK;
128 static NTSTATUS append_info3_as_ndr(TALLOC_CTX *mem_ctx,
129 struct winbindd_response *resp,
130 struct netr_SamInfo3 *info3)
132 DATA_BLOB blob;
133 enum ndr_err_code ndr_err;
135 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, info3,
136 (ndr_push_flags_fn_t)ndr_push_netr_SamInfo3);
137 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
138 DEBUG(0,("append_info3_as_ndr: failed to append\n"));
139 return ndr_map_error2ntstatus(ndr_err);
142 resp->extra_data.data = blob.data;
143 resp->length += blob.length;
145 return NT_STATUS_OK;
148 static NTSTATUS append_unix_username(TALLOC_CTX *mem_ctx,
149 struct winbindd_response *resp,
150 const struct netr_SamInfo3 *info3,
151 const char *name_domain,
152 const char *name_user)
154 /* We've been asked to return the unix username, per
155 'winbind use default domain' settings and the like */
157 const char *nt_username, *nt_domain;
159 nt_domain = talloc_strdup(mem_ctx, info3->base.logon_domain.string);
160 if (!nt_domain) {
161 /* If the server didn't give us one, just use the one
162 * we sent them */
163 nt_domain = name_domain;
166 nt_username = talloc_strdup(mem_ctx, info3->base.account_name.string);
167 if (!nt_username) {
168 /* If the server didn't give us one, just use the one
169 * we sent them */
170 nt_username = name_user;
173 fill_domain_username(resp->data.auth.unix_username,
174 nt_domain, nt_username, true);
176 DEBUG(5, ("Setting unix username to [%s]\n",
177 resp->data.auth.unix_username));
179 return NT_STATUS_OK;
182 static NTSTATUS append_afs_token(TALLOC_CTX *mem_ctx,
183 struct winbindd_response *resp,
184 const struct netr_SamInfo3 *info3,
185 const char *name_domain,
186 const char *name_user)
188 char *afsname = NULL;
189 char *cell;
190 char *token;
192 afsname = talloc_strdup(mem_ctx, lp_afs_username_map());
193 if (afsname == NULL) {
194 return NT_STATUS_NO_MEMORY;
197 afsname = talloc_string_sub(mem_ctx,
198 lp_afs_username_map(),
199 "%D", name_domain);
200 afsname = talloc_string_sub(mem_ctx, afsname,
201 "%u", name_user);
202 afsname = talloc_string_sub(mem_ctx, afsname,
203 "%U", name_user);
206 struct dom_sid user_sid;
207 fstring sidstr;
209 sid_compose(&user_sid, info3->base.domain_sid,
210 info3->base.rid);
211 sid_to_fstring(sidstr, &user_sid);
212 afsname = talloc_string_sub(mem_ctx, afsname,
213 "%s", sidstr);
216 if (afsname == NULL) {
217 return NT_STATUS_NO_MEMORY;
220 strlower_m(afsname);
222 DEBUG(10, ("Generating token for user %s\n", afsname));
224 cell = strchr(afsname, '@');
226 if (cell == NULL) {
227 return NT_STATUS_NO_MEMORY;
230 *cell = '\0';
231 cell += 1;
233 token = afs_createtoken_str(afsname, cell);
234 if (token == NULL) {
235 return NT_STATUS_OK;
237 resp->extra_data.data = talloc_strdup(mem_ctx, token);
238 if (resp->extra_data.data == NULL) {
239 return NT_STATUS_NO_MEMORY;
241 resp->length += strlen((const char *)resp->extra_data.data)+1;
243 return NT_STATUS_OK;
246 static NTSTATUS check_info3_in_group(struct netr_SamInfo3 *info3,
247 const char *group_sid)
249 * Check whether a user belongs to a group or list of groups.
251 * @param mem_ctx talloc memory context.
252 * @param info3 user information, including group membership info.
253 * @param group_sid One or more groups , separated by commas.
255 * @return NT_STATUS_OK on success,
256 * NT_STATUS_LOGON_FAILURE if the user does not belong,
257 * or other NT_STATUS_IS_ERR(status) for other kinds of failure.
260 struct dom_sid *require_membership_of_sid;
261 uint32_t num_require_membership_of_sid;
262 char *req_sid;
263 const char *p;
264 struct dom_sid sid;
265 size_t i;
266 struct security_token *token;
267 TALLOC_CTX *frame = talloc_stackframe();
268 NTSTATUS status;
270 /* Parse the 'required group' SID */
272 if (!group_sid || !group_sid[0]) {
273 /* NO sid supplied, all users may access */
274 return NT_STATUS_OK;
277 token = talloc_zero(talloc_tos(), struct security_token);
278 if (token == NULL) {
279 DEBUG(0, ("talloc failed\n"));
280 TALLOC_FREE(frame);
281 return NT_STATUS_NO_MEMORY;
284 num_require_membership_of_sid = 0;
285 require_membership_of_sid = NULL;
287 p = group_sid;
289 while (next_token_talloc(talloc_tos(), &p, &req_sid, ",")) {
290 if (!string_to_sid(&sid, req_sid)) {
291 DEBUG(0, ("check_info3_in_group: could not parse %s "
292 "as a SID!", req_sid));
293 TALLOC_FREE(frame);
294 return NT_STATUS_INVALID_PARAMETER;
297 status = add_sid_to_array(talloc_tos(), &sid,
298 &require_membership_of_sid,
299 &num_require_membership_of_sid);
300 if (!NT_STATUS_IS_OK(status)) {
301 DEBUG(0, ("add_sid_to_array failed\n"));
302 TALLOC_FREE(frame);
303 return status;
307 status = sid_array_from_info3(talloc_tos(), info3,
308 &token->sids,
309 &token->num_sids,
310 true, false);
311 if (!NT_STATUS_IS_OK(status)) {
312 TALLOC_FREE(frame);
313 return status;
316 if (!NT_STATUS_IS_OK(status = add_aliases(get_global_sam_sid(),
317 token))
318 || !NT_STATUS_IS_OK(status = add_aliases(&global_sid_Builtin,
319 token))) {
320 DEBUG(3, ("could not add aliases: %s\n",
321 nt_errstr(status)));
322 TALLOC_FREE(frame);
323 return status;
326 security_token_debug(DBGC_CLASS, 10, token);
328 for (i=0; i<num_require_membership_of_sid; i++) {
329 DEBUG(10, ("Checking SID %s\n", sid_string_dbg(
330 &require_membership_of_sid[i])));
331 if (nt_token_check_sid(&require_membership_of_sid[i],
332 token)) {
333 DEBUG(10, ("Access ok\n"));
334 TALLOC_FREE(frame);
335 return NT_STATUS_OK;
339 /* Do not distinguish this error from a wrong username/pw */
341 TALLOC_FREE(frame);
342 return NT_STATUS_LOGON_FAILURE;
345 struct winbindd_domain *find_auth_domain(uint8_t flags,
346 const char *domain_name)
348 struct winbindd_domain *domain;
350 if (IS_DC) {
351 domain = find_domain_from_name_noinit(domain_name);
352 if (domain == NULL) {
353 DEBUG(3, ("Authentication for domain [%s] refused "
354 "as it is not a trusted domain\n",
355 domain_name));
357 return domain;
360 if (strequal(domain_name, get_global_sam_name())) {
361 return find_domain_from_name_noinit(domain_name);
364 /* we can auth against trusted domains */
365 if (flags & WBFLAG_PAM_CONTACT_TRUSTDOM) {
366 domain = find_domain_from_name_noinit(domain_name);
367 if (domain == NULL) {
368 DEBUG(3, ("Authentication for domain [%s] skipped "
369 "as it is not a trusted domain\n",
370 domain_name));
371 } else {
372 return domain;
376 return find_our_domain();
379 static void fill_in_password_policy(struct winbindd_response *r,
380 const struct samr_DomInfo1 *p)
382 r->data.auth.policy.min_length_password =
383 p->min_password_length;
384 r->data.auth.policy.password_history =
385 p->password_history_length;
386 r->data.auth.policy.password_properties =
387 p->password_properties;
388 r->data.auth.policy.expire =
389 nt_time_to_unix_abs((const NTTIME *)&(p->max_password_age));
390 r->data.auth.policy.min_passwordage =
391 nt_time_to_unix_abs((const NTTIME *)&(p->min_password_age));
394 static NTSTATUS fillup_password_policy(struct winbindd_domain *domain,
395 struct winbindd_response *response)
397 TALLOC_CTX *frame = talloc_stackframe();
398 struct winbindd_methods *methods;
399 NTSTATUS status;
400 struct samr_DomInfo1 password_policy;
402 if ( !winbindd_can_contact_domain( domain ) ) {
403 DEBUG(5,("fillup_password_policy: No inbound trust to "
404 "contact domain %s\n", domain->name));
405 status = NT_STATUS_NOT_SUPPORTED;
406 goto done;
409 methods = domain->methods;
411 status = methods->password_policy(domain, talloc_tos(), &password_policy);
412 if (NT_STATUS_IS_ERR(status)) {
413 goto done;
416 fill_in_password_policy(response, &password_policy);
418 done:
419 TALLOC_FREE(frame);
420 return NT_STATUS_OK;
423 static NTSTATUS get_max_bad_attempts_from_lockout_policy(struct winbindd_domain *domain,
424 TALLOC_CTX *mem_ctx,
425 uint16 *lockout_threshold)
427 struct winbindd_methods *methods;
428 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
429 struct samr_DomInfo12 lockout_policy;
431 *lockout_threshold = 0;
433 methods = domain->methods;
435 status = methods->lockout_policy(domain, mem_ctx, &lockout_policy);
436 if (NT_STATUS_IS_ERR(status)) {
437 return status;
440 *lockout_threshold = lockout_policy.lockout_threshold;
442 return NT_STATUS_OK;
445 static NTSTATUS get_pwd_properties(struct winbindd_domain *domain,
446 TALLOC_CTX *mem_ctx,
447 uint32 *password_properties)
449 struct winbindd_methods *methods;
450 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
451 struct samr_DomInfo1 password_policy;
453 *password_properties = 0;
455 methods = domain->methods;
457 status = methods->password_policy(domain, mem_ctx, &password_policy);
458 if (NT_STATUS_IS_ERR(status)) {
459 return status;
462 *password_properties = password_policy.password_properties;
464 return NT_STATUS_OK;
467 #ifdef HAVE_KRB5
469 static const char *generate_krb5_ccache(TALLOC_CTX *mem_ctx,
470 const char *type,
471 uid_t uid,
472 const char **user_ccache_file)
474 /* accept FILE and WRFILE as krb5_cc_type from the client and then
475 * build the full ccname string based on the user's uid here -
476 * Guenther*/
478 const char *gen_cc = NULL;
480 if (uid != -1) {
481 if (strequal(type, "FILE")) {
482 gen_cc = talloc_asprintf(
483 mem_ctx, "FILE:/tmp/krb5cc_%d", uid);
485 if (strequal(type, "WRFILE")) {
486 gen_cc = talloc_asprintf(
487 mem_ctx, "WRFILE:/tmp/krb5cc_%d", uid);
491 *user_ccache_file = gen_cc;
493 if (gen_cc == NULL) {
494 gen_cc = talloc_strdup(mem_ctx, "MEMORY:winbindd_pam_ccache");
496 if (gen_cc == NULL) {
497 DEBUG(0,("out of memory\n"));
498 return NULL;
501 DEBUG(10, ("using ccache: %s%s\n", gen_cc,
502 (*user_ccache_file == NULL) ? " (internal)":""));
504 return gen_cc;
507 #endif
509 uid_t get_uid_from_request(struct winbindd_request *request)
511 uid_t uid;
513 uid = request->data.auth.uid;
515 if (uid < 0) {
516 DEBUG(1,("invalid uid: '%u'\n", (unsigned int)uid));
517 return -1;
519 return uid;
522 /**********************************************************************
523 Authenticate a user with a clear text password using Kerberos and fill up
524 ccache if required
525 **********************************************************************/
527 static NTSTATUS winbindd_raw_kerberos_login(TALLOC_CTX *mem_ctx,
528 struct winbindd_domain *domain,
529 const char *user,
530 const char *pass,
531 const char *krb5_cc_type,
532 uid_t uid,
533 struct netr_SamInfo3 **info3,
534 fstring krb5ccname)
536 #ifdef HAVE_KRB5
537 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
538 krb5_error_code krb5_ret;
539 const char *cc = NULL;
540 const char *principal_s = NULL;
541 const char *service = NULL;
542 char *realm = NULL;
543 fstring name_domain, name_user;
544 time_t ticket_lifetime = 0;
545 time_t renewal_until = 0;
546 ADS_STRUCT *ads;
547 time_t time_offset = 0;
548 const char *user_ccache_file;
549 struct PAC_LOGON_INFO *logon_info = NULL;
551 *info3 = NULL;
553 /* 1st step:
554 * prepare a krb5_cc_cache string for the user */
556 if (uid == -1) {
557 DEBUG(0,("no valid uid\n"));
560 cc = generate_krb5_ccache(mem_ctx,
561 krb5_cc_type,
562 uid,
563 &user_ccache_file);
564 if (cc == NULL) {
565 return NT_STATUS_NO_MEMORY;
569 /* 2nd step:
570 * get kerberos properties */
572 if (domain->private_data) {
573 ads = (ADS_STRUCT *)domain->private_data;
574 time_offset = ads->auth.time_offset;
578 /* 3rd step:
579 * do kerberos auth and setup ccache as the user */
581 parse_domain_user(user, name_domain, name_user);
583 realm = domain->alt_name;
584 strupper_m(realm);
586 principal_s = talloc_asprintf(mem_ctx, "%s@%s", name_user, realm);
587 if (principal_s == NULL) {
588 return NT_STATUS_NO_MEMORY;
591 service = talloc_asprintf(mem_ctx, "%s/%s@%s", KRB5_TGS_NAME, realm, realm);
592 if (service == NULL) {
593 return NT_STATUS_NO_MEMORY;
596 /* if this is a user ccache, we need to act as the user to let the krb5
597 * library handle the chown, etc. */
599 /************************ ENTERING NON-ROOT **********************/
601 if (user_ccache_file != NULL) {
602 set_effective_uid(uid);
603 DEBUG(10,("winbindd_raw_kerberos_login: uid is %d\n", uid));
606 result = kerberos_return_pac(mem_ctx,
607 principal_s,
608 pass,
609 time_offset,
610 &ticket_lifetime,
611 &renewal_until,
613 true,
614 true,
615 WINBINDD_PAM_AUTH_KRB5_RENEW_TIME,
616 NULL,
617 &logon_info);
618 if (user_ccache_file != NULL) {
619 gain_root_privilege();
622 /************************ RETURNED TO ROOT **********************/
624 if (!NT_STATUS_IS_OK(result)) {
625 goto failed;
628 *info3 = &logon_info->info3;
630 DEBUG(10,("winbindd_raw_kerberos_login: winbindd validated ticket of %s\n",
631 principal_s));
633 /* if we had a user's ccache then return that string for the pam
634 * environment */
636 if (user_ccache_file != NULL) {
638 fstrcpy(krb5ccname, user_ccache_file);
640 result = add_ccache_to_list(principal_s,
642 service,
643 user,
644 realm,
645 uid,
646 time(NULL),
647 ticket_lifetime,
648 renewal_until,
649 false);
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)));
655 } else {
657 /* need to delete the memory cred cache, it is not used anymore */
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)));
668 return NT_STATUS_OK;
670 failed:
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 */
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)));
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));
690 return result;
691 #else
692 return NT_STATUS_NOT_SUPPORTED;
693 #endif /* HAVE_KRB5 */
696 /****************************************************************
697 ****************************************************************/
699 bool check_request_flags(uint32_t flags)
701 uint32_t flags_edata = WBFLAG_PAM_AFS_TOKEN |
702 WBFLAG_PAM_INFO3_TEXT |
703 WBFLAG_PAM_INFO3_NDR;
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;
712 DEBUG(1, ("check_request_flags: invalid request flags[0x%08X]\n",
713 flags));
715 return false;
718 /****************************************************************
719 ****************************************************************/
721 static 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)
728 NTSTATUS result;
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 */);
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 */);
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;
754 /* currently, anything from here on potentially overwrites extra_data. */
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;
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;
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;
784 return NT_STATUS_OK;
787 static NTSTATUS winbindd_dual_pam_auth_cached(struct winbindd_domain *domain,
788 struct winbindd_cli_state *state,
789 struct netr_SamInfo3 **info3)
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
806 *info3 = NULL;
808 ZERO_STRUCTP(info3);
810 DEBUG(10,("winbindd_dual_pam_auth_cached\n"));
812 /* Parse domain and username */
814 parse_domain_user(state->request->data.auth.user, name_domain, name_user);
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;
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;
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;
841 *info3 = my_info3;
843 E_md4hash(state->request->data.auth.pass, new_nt_pass);
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);
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);
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);
865 if (password_good) {
867 /* User *DOES* know the password, update logon_time and reset
868 * bad_pw_count */
870 my_info3->base.user_flags |= NETLOGON_CACHED_ACCOUNT;
872 if (my_info3->base.acct_flags & ACB_AUTOLOCK) {
873 return NT_STATUS_ACCOUNT_LOCKED_OUT;
876 if (my_info3->base.acct_flags & ACB_DISABLED) {
877 return NT_STATUS_ACCOUNT_DISABLED;
880 if (my_info3->base.acct_flags & ACB_WSTRUST) {
881 return NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
884 if (my_info3->base.acct_flags & ACB_SVRTRUST) {
885 return NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT;
888 if (my_info3->base.acct_flags & ACB_DOMTRUST) {
889 return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT;
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;
898 kickoff_time = nt_time_to_unix(my_info3->base.kickoff_time);
899 if (kickoff_time != 0 && time(NULL) > kickoff_time) {
900 return NT_STATUS_ACCOUNT_EXPIRED;
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;
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))) {
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;
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;
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;
939 realm = domain->alt_name;
940 strupper_m(realm);
942 principal_s = talloc_asprintf(state->mem_ctx, "%s@%s", name_user, realm);
943 if (principal_s == NULL) {
944 return NT_STATUS_NO_MEMORY;
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;
952 if (user_ccache_file != NULL) {
954 fstrcpy(state->response->data.auth.krb5ccname,
955 user_ccache_file);
957 result = add_ccache_to_list(principal_s,
959 service,
960 state->request->data.auth.user,
961 domain->alt_name,
962 uid,
963 time(NULL),
964 time(NULL) + lp_winbind_cache_time(),
965 time(NULL) + WINBINDD_PAM_AUTH_KRB5_RENEW_TIME,
966 true);
968 if (!NT_STATUS_IS_OK(result)) {
969 DEBUG(10,("winbindd_dual_pam_auth_cached: failed "
970 "to add ccache to list: %s\n",
971 nt_errstr(result)));
975 #endif /* HAVE_KRB5 */
976 success:
977 /* FIXME: we possibly should handle logon hours as well (does xp when
978 * offline?) see auth/auth_sam.c:sam_account_ok for details */
980 unix_to_nt_time(&my_info3->base.logon_time, time(NULL));
981 my_info3->base.bad_password_count = 0;
983 result = winbindd_update_creds_by_info3(domain,
984 state->request->data.auth.user,
985 state->request->data.auth.pass,
986 my_info3);
987 if (!NT_STATUS_IS_OK(result)) {
988 DEBUG(1,("winbindd_dual_pam_auth_cached: failed to update creds: %s\n",
989 nt_errstr(result)));
990 return result;
993 return NT_STATUS_OK;
997 /* User does *NOT* know the correct password, modify info3 accordingly, but only if online */
998 if (domain->online == false) {
999 goto failed;
1002 /* failure of this is not critical */
1003 result = get_max_bad_attempts_from_lockout_policy(domain, state->mem_ctx, &max_allowed_bad_attempts);
1004 if (!NT_STATUS_IS_OK(result)) {
1005 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get max_allowed_bad_attempts. "
1006 "Won't be able to honour account lockout policies\n"));
1009 /* increase counter */
1010 my_info3->base.bad_password_count++;
1012 if (max_allowed_bad_attempts == 0) {
1013 goto failed;
1016 /* lockout user */
1017 if (my_info3->base.bad_password_count >= max_allowed_bad_attempts) {
1019 uint32 password_properties;
1021 result = get_pwd_properties(domain, state->mem_ctx, &password_properties);
1022 if (!NT_STATUS_IS_OK(result)) {
1023 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get password properties.\n"));
1026 if ((my_info3->base.rid != DOMAIN_RID_ADMINISTRATOR) ||
1027 (password_properties & DOMAIN_PASSWORD_LOCKOUT_ADMINS)) {
1028 my_info3->base.acct_flags |= ACB_AUTOLOCK;
1032 failed:
1033 result = winbindd_update_creds_by_info3(domain,
1034 state->request->data.auth.user,
1035 NULL,
1036 my_info3);
1038 if (!NT_STATUS_IS_OK(result)) {
1039 DEBUG(0,("winbindd_dual_pam_auth_cached: failed to update creds %s\n",
1040 nt_errstr(result)));
1043 return NT_STATUS_LOGON_FAILURE;
1046 static NTSTATUS winbindd_dual_pam_auth_kerberos(struct winbindd_domain *domain,
1047 struct winbindd_cli_state *state,
1048 struct netr_SamInfo3 **info3)
1050 struct winbindd_domain *contact_domain;
1051 fstring name_domain, name_user;
1052 NTSTATUS result;
1054 DEBUG(10,("winbindd_dual_pam_auth_kerberos\n"));
1056 /* Parse domain and username */
1058 parse_domain_user(state->request->data.auth.user, name_domain, name_user);
1060 /* what domain should we contact? */
1062 if ( IS_DC ) {
1063 if (!(contact_domain = find_domain_from_name(name_domain))) {
1064 DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
1065 state->request->data.auth.user, name_domain, name_user, name_domain));
1066 result = NT_STATUS_NO_SUCH_USER;
1067 goto done;
1070 } else {
1071 if (is_myname(name_domain)) {
1072 DEBUG(3, ("Authentication for domain %s (local domain to this server) not supported at this stage\n", name_domain));
1073 result = NT_STATUS_NO_SUCH_USER;
1074 goto done;
1077 contact_domain = find_domain_from_name(name_domain);
1078 if (contact_domain == NULL) {
1079 DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
1080 state->request->data.auth.user, name_domain, name_user, name_domain));
1082 result = NT_STATUS_NO_SUCH_USER;
1083 goto done;
1087 if (contact_domain->initialized &&
1088 contact_domain->active_directory) {
1089 goto try_login;
1092 if (!contact_domain->initialized) {
1093 init_dc_connection(contact_domain);
1096 if (!contact_domain->active_directory) {
1097 DEBUG(3,("krb5 auth requested but domain is not Active Directory\n"));
1098 return NT_STATUS_INVALID_LOGON_TYPE;
1100 try_login:
1101 result = winbindd_raw_kerberos_login(
1102 state->mem_ctx, contact_domain,
1103 state->request->data.auth.user,
1104 state->request->data.auth.pass,
1105 state->request->data.auth.krb5_cc_type,
1106 get_uid_from_request(state->request),
1107 info3, state->response->data.auth.krb5ccname);
1108 done:
1109 return result;
1112 static NTSTATUS winbindd_dual_auth_passdb(TALLOC_CTX *mem_ctx,
1113 uint32_t logon_parameters,
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)
1120 struct auth_usersupplied_info *user_info = NULL;
1121 struct tsocket_address *local;
1122 NTSTATUS status;
1123 int rc;
1125 rc = tsocket_address_inet_from_strings(mem_ctx,
1126 "ip",
1127 "127.0.0.1",
1129 &local);
1130 if (rc < 0) {
1131 return NT_STATUS_NO_MEMORY;
1133 status = make_user_info(&user_info, user, user, domain, domain,
1134 lp_netbios_name(), local, lm_resp, nt_resp, NULL, NULL,
1135 NULL, AUTH_PASSWORD_RESPONSE);
1136 if (!NT_STATUS_IS_OK(status)) {
1137 DEBUG(10, ("make_user_info failed: %s\n", nt_errstr(status)));
1138 return status;
1140 user_info->logon_parameters = logon_parameters;
1142 /* We don't want any more mapping of the username */
1143 user_info->mapped_state = True;
1145 status = check_sam_security_info3(challenge, talloc_tos(), user_info,
1146 pinfo3);
1147 free_user_info(&user_info);
1148 DEBUG(10, ("Authenticaticating user %s\\%s returned %s\n", domain,
1149 user, nt_errstr(status)));
1150 return status;
1153 static NTSTATUS winbind_samlogon_retry_loop(struct winbindd_domain *domain,
1154 TALLOC_CTX *mem_ctx,
1155 uint32_t logon_parameters,
1156 const char *server,
1157 const char *username,
1158 const char *domainname,
1159 const char *workstation,
1160 const uint8_t chal[8],
1161 DATA_BLOB lm_response,
1162 DATA_BLOB nt_response,
1163 struct netr_SamInfo3 **info3)
1165 int attempts = 0;
1166 bool retry = false;
1167 NTSTATUS result;
1169 do {
1170 struct rpc_pipe_client *netlogon_pipe;
1171 const struct pipe_auth_data *auth;
1172 uint32_t neg_flags = 0;
1174 ZERO_STRUCTP(info3);
1175 retry = false;
1177 result = cm_connect_netlogon(domain, &netlogon_pipe);
1179 if (!NT_STATUS_IS_OK(result)) {
1180 DEBUG(3,("could not open handle to NETLOGON pipe (error: %s)\n",
1181 nt_errstr(result)));
1182 if (NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT)) {
1183 if (attempts > 0) {
1184 DEBUG(3, ("This is the second problem for this "
1185 "particular call, forcing the close of "
1186 "this connection\n"));
1187 invalidate_cm_connection(&domain->conn);
1188 } else {
1189 DEBUG(3, ("First call to cm_connect_netlogon "
1190 "has timed out, retrying\n"));
1191 continue;
1194 return result;
1196 auth = netlogon_pipe->auth;
1197 if (netlogon_pipe->dc) {
1198 neg_flags = netlogon_pipe->dc->negotiate_flags;
1201 /* It is really important to try SamLogonEx here,
1202 * because in a clustered environment, we want to use
1203 * one machine account from multiple physical
1204 * computers.
1206 * With a normal SamLogon call, we must keep the
1207 * credentials chain updated and intact between all
1208 * users of the machine account (which would imply
1209 * cross-node communication for every NTLM logon).
1211 * (The credentials chain is not per NETLOGON pipe
1212 * connection, but globally on the server/client pair
1213 * by machine name).
1215 * When using SamLogonEx, the credentials are not
1216 * supplied, but the session key is implied by the
1217 * wrapping SamLogon context.
1219 * -- abartlet 21 April 2008
1221 * It's also important to use NetlogonValidationSamInfo4 (6),
1222 * because it relies on the rpc transport encryption
1223 * and avoids using the global netlogon schannel
1224 * session key to en/decrypt secret information
1225 * like the user_session_key for network logons.
1227 * [MS-APDS] 3.1.5.2 NTLM Network Logon
1228 * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
1229 * NETLOGON_NEG_AUTHENTICATED_RPC set together
1230 * are the indication that the server supports
1231 * NetlogonValidationSamInfo4 (6). And it must only
1232 * be used if "SealSecureChannel" is used.
1234 * -- metze 4 February 2011
1237 if (auth == NULL) {
1238 domain->can_do_validation6 = false;
1239 } else if (auth->auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
1240 domain->can_do_validation6 = false;
1241 } else if (auth->auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
1242 domain->can_do_validation6 = false;
1243 } else if (!(neg_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
1244 domain->can_do_validation6 = false;
1245 } else if (!(neg_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
1246 domain->can_do_validation6 = false;
1249 if (domain->can_do_samlogon_ex && domain->can_do_validation6) {
1250 result = rpccli_netlogon_sam_network_logon_ex(
1251 netlogon_pipe,
1252 mem_ctx,
1253 logon_parameters,
1254 server, /* server name */
1255 username, /* user name */
1256 domainname, /* target domain */
1257 workstation, /* workstation */
1258 chal,
1260 lm_response,
1261 nt_response,
1262 info3);
1263 } else {
1264 result = rpccli_netlogon_sam_network_logon(
1265 netlogon_pipe,
1266 mem_ctx,
1267 logon_parameters,
1268 server, /* server name */
1269 username, /* user name */
1270 domainname, /* target domain */
1271 workstation, /* workstation */
1272 chal,
1273 domain->can_do_validation6 ? 6 : 3,
1274 lm_response,
1275 nt_response,
1276 info3);
1279 if (NT_STATUS_EQUAL(result, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1282 * It's likely that the server also does not support
1283 * validation level 6
1285 domain->can_do_validation6 = false;
1287 if (domain->can_do_samlogon_ex) {
1288 DEBUG(3, ("Got a DC that can not do NetSamLogonEx, "
1289 "retrying with NetSamLogon\n"));
1290 domain->can_do_samlogon_ex = false;
1291 retry = true;
1292 continue;
1296 /* Got DCERPC_FAULT_OP_RNG_ERROR for SamLogon
1297 * (no Ex). This happens against old Samba
1298 * DCs. Drop the connection.
1300 invalidate_cm_connection(&domain->conn);
1301 result = NT_STATUS_LOGON_FAILURE;
1302 break;
1305 if (domain->can_do_validation6 &&
1306 (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
1307 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
1308 NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL))) {
1309 DEBUG(3,("Got a DC that can not do validation level 6, "
1310 "retrying with level 3\n"));
1311 domain->can_do_validation6 = false;
1312 retry = true;
1313 continue;
1317 * we increment this after the "feature negotiation"
1318 * for can_do_samlogon_ex and can_do_validation6
1320 attempts += 1;
1322 /* We have to try a second time as cm_connect_netlogon
1323 might not yet have noticed that the DC has killed
1324 our connection. */
1326 if (!rpccli_is_connected(netlogon_pipe)) {
1327 retry = true;
1328 continue;
1331 /* if we get access denied, a possible cause was that we had
1332 and open connection to the DC, but someone changed our
1333 machine account password out from underneath us using 'net
1334 rpc changetrustpw' */
1336 if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
1337 DEBUG(3,("winbind_samlogon_retry_loop: sam_logon returned "
1338 "ACCESS_DENIED. Maybe the trust account "
1339 "password was changed and we didn't know it. "
1340 "Killing connections to domain %s\n",
1341 domainname));
1342 invalidate_cm_connection(&domain->conn);
1343 retry = true;
1346 } while ( (attempts < 2) && retry );
1348 if (NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT)) {
1349 DEBUG(3,("winbind_samlogon_retry_loop: sam_network_logon(ex) "
1350 "returned NT_STATUS_IO_TIMEOUT after the retry."
1351 "Killing connections to domain %s\n",
1352 domainname));
1353 invalidate_cm_connection(&domain->conn);
1355 return result;
1358 static NTSTATUS winbindd_dual_pam_auth_samlogon(TALLOC_CTX *mem_ctx,
1359 struct winbindd_domain *domain,
1360 const char *user,
1361 const char *pass,
1362 uint32_t request_flags,
1363 struct netr_SamInfo3 **info3)
1366 uchar chal[8];
1367 DATA_BLOB lm_resp;
1368 DATA_BLOB nt_resp;
1369 unsigned char local_nt_response[24];
1370 fstring name_domain, name_user;
1371 NTSTATUS result;
1372 struct netr_SamInfo3 *my_info3 = NULL;
1374 *info3 = NULL;
1376 DEBUG(10,("winbindd_dual_pam_auth_samlogon\n"));
1378 /* Parse domain and username */
1380 parse_domain_user(user, name_domain, name_user);
1382 /* do password magic */
1384 generate_random_buffer(chal, sizeof(chal));
1386 if (lp_client_ntlmv2_auth()) {
1387 DATA_BLOB server_chal;
1388 DATA_BLOB names_blob;
1389 server_chal = data_blob_const(chal, 8);
1391 /* note that the 'workgroup' here is for the local
1392 machine. The 'server name' must match the
1393 'workstation' passed to the actual SamLogon call.
1395 names_blob = NTLMv2_generate_names_blob(
1396 mem_ctx, lp_netbios_name(), lp_workgroup());
1398 if (!SMBNTLMv2encrypt(mem_ctx, name_user, name_domain,
1399 pass,
1400 &server_chal,
1401 &names_blob,
1402 &lm_resp, &nt_resp, NULL, NULL)) {
1403 data_blob_free(&names_blob);
1404 DEBUG(0, ("winbindd_pam_auth: SMBNTLMv2encrypt() failed!\n"));
1405 result = NT_STATUS_NO_MEMORY;
1406 goto done;
1408 data_blob_free(&names_blob);
1409 } else {
1410 lm_resp = data_blob_null;
1411 SMBNTencrypt(pass, chal, local_nt_response);
1413 nt_resp = data_blob_talloc(mem_ctx, local_nt_response,
1414 sizeof(local_nt_response));
1417 if (strequal(name_domain, get_global_sam_name())) {
1418 DATA_BLOB chal_blob = data_blob_const(chal, sizeof(chal));
1420 result = winbindd_dual_auth_passdb(
1421 mem_ctx, 0, name_domain, name_user,
1422 &chal_blob, &lm_resp, &nt_resp, info3);
1423 goto done;
1426 /* check authentication loop */
1428 result = winbind_samlogon_retry_loop(domain,
1429 mem_ctx,
1431 domain->dcname,
1432 name_user,
1433 name_domain,
1434 lp_netbios_name(),
1435 chal,
1436 lm_resp,
1437 nt_resp,
1438 &my_info3);
1439 if (!NT_STATUS_IS_OK(result)) {
1440 goto done;
1443 /* handle the case where a NT4 DC does not fill in the acct_flags in
1444 * the samlogon reply info3. When accurate info3 is required by the
1445 * caller, we look up the account flags ourselve - gd */
1447 if ((request_flags & WBFLAG_PAM_INFO3_TEXT) &&
1448 NT_STATUS_IS_OK(result) && (my_info3->base.acct_flags == 0)) {
1450 struct rpc_pipe_client *samr_pipe;
1451 struct policy_handle samr_domain_handle, user_pol;
1452 union samr_UserInfo *info = NULL;
1453 NTSTATUS status_tmp, result_tmp;
1454 uint32 acct_flags;
1455 struct dcerpc_binding_handle *b;
1457 status_tmp = cm_connect_sam(domain, mem_ctx,
1458 &samr_pipe, &samr_domain_handle);
1460 if (!NT_STATUS_IS_OK(status_tmp)) {
1461 DEBUG(3, ("could not open handle to SAMR pipe: %s\n",
1462 nt_errstr(status_tmp)));
1463 goto done;
1466 b = samr_pipe->binding_handle;
1468 status_tmp = dcerpc_samr_OpenUser(b, mem_ctx,
1469 &samr_domain_handle,
1470 MAXIMUM_ALLOWED_ACCESS,
1471 my_info3->base.rid,
1472 &user_pol,
1473 &result_tmp);
1475 if (!NT_STATUS_IS_OK(status_tmp)) {
1476 DEBUG(3, ("could not open user handle on SAMR pipe: %s\n",
1477 nt_errstr(status_tmp)));
1478 goto done;
1480 if (!NT_STATUS_IS_OK(result_tmp)) {
1481 DEBUG(3, ("could not open user handle on SAMR pipe: %s\n",
1482 nt_errstr(result_tmp)));
1483 goto done;
1486 status_tmp = dcerpc_samr_QueryUserInfo(b, mem_ctx,
1487 &user_pol,
1489 &info,
1490 &result_tmp);
1492 if (!NT_STATUS_IS_OK(status_tmp)) {
1493 DEBUG(3, ("could not query user info on SAMR pipe: %s\n",
1494 nt_errstr(status_tmp)));
1495 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
1496 goto done;
1498 if (!NT_STATUS_IS_OK(result_tmp)) {
1499 DEBUG(3, ("could not query user info on SAMR pipe: %s\n",
1500 nt_errstr(result_tmp)));
1501 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
1502 goto done;
1505 acct_flags = info->info16.acct_flags;
1507 if (acct_flags == 0) {
1508 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
1509 goto done;
1512 my_info3->base.acct_flags = acct_flags;
1514 DEBUG(10,("successfully retrieved acct_flags 0x%x\n", acct_flags));
1516 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
1519 *info3 = my_info3;
1520 done:
1521 return result;
1524 enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain,
1525 struct winbindd_cli_state *state)
1527 NTSTATUS result = NT_STATUS_LOGON_FAILURE;
1528 NTSTATUS krb5_result = NT_STATUS_OK;
1529 fstring name_domain, name_user;
1530 char *mapped_user;
1531 fstring domain_user;
1532 struct netr_SamInfo3 *info3 = NULL;
1533 NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL;
1535 /* Ensure null termination */
1536 state->request->data.auth.user[sizeof(state->request->data.auth.user)-1]='\0';
1538 /* Ensure null termination */
1539 state->request->data.auth.pass[sizeof(state->request->data.auth.pass)-1]='\0';
1541 DEBUG(3, ("[%5lu]: dual pam auth %s\n", (unsigned long)state->pid,
1542 state->request->data.auth.user));
1544 /* Parse domain and username */
1546 name_map_status = normalize_name_unmap(state->mem_ctx,
1547 state->request->data.auth.user,
1548 &mapped_user);
1550 /* If the name normalization didnt' actually do anything,
1551 just use the original name */
1553 if (!NT_STATUS_IS_OK(name_map_status) &&
1554 !NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED))
1556 mapped_user = state->request->data.auth.user;
1559 parse_domain_user(mapped_user, name_domain, name_user);
1561 if ( mapped_user != state->request->data.auth.user ) {
1562 fstr_sprintf( domain_user, "%s%c%s", name_domain,
1563 *lp_winbind_separator(),
1564 name_user );
1565 strlcpy( state->request->data.auth.user, domain_user,
1566 sizeof(state->request->data.auth.user));
1569 if (!domain->online) {
1570 result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
1571 if (domain->startup) {
1572 /* Logons are very important to users. If we're offline and
1573 we get a request within the first 30 seconds of startup,
1574 try very hard to find a DC and go online. */
1576 DEBUG(10,("winbindd_dual_pam_auth: domain: %s offline and auth "
1577 "request in startup mode.\n", domain->name ));
1579 winbindd_flush_negative_conn_cache(domain);
1580 result = init_dc_connection(domain);
1584 DEBUG(10,("winbindd_dual_pam_auth: domain: %s last was %s\n", domain->name, domain->online ? "online":"offline"));
1586 /* Check for Kerberos authentication */
1587 if (domain->online && (state->request->flags & WBFLAG_PAM_KRB5)) {
1589 result = winbindd_dual_pam_auth_kerberos(domain, state, &info3);
1590 /* save for later */
1591 krb5_result = result;
1594 if (NT_STATUS_IS_OK(result)) {
1595 DEBUG(10,("winbindd_dual_pam_auth_kerberos succeeded\n"));
1596 goto process_result;
1597 } else {
1598 DEBUG(10,("winbindd_dual_pam_auth_kerberos failed: %s\n", nt_errstr(result)));
1601 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
1602 NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
1603 NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1604 DEBUG(10,("winbindd_dual_pam_auth_kerberos setting domain to offline\n"));
1605 set_domain_offline( domain );
1606 goto cached_logon;
1609 /* there are quite some NT_STATUS errors where there is no
1610 * point in retrying with a samlogon, we explictly have to take
1611 * care not to increase the bad logon counter on the DC */
1613 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_DISABLED) ||
1614 NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_EXPIRED) ||
1615 NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_LOCKED_OUT) ||
1616 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_LOGON_HOURS) ||
1617 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_WORKSTATION) ||
1618 NT_STATUS_EQUAL(result, NT_STATUS_LOGON_FAILURE) ||
1619 NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER) ||
1620 NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_EXPIRED) ||
1621 NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_MUST_CHANGE) ||
1622 NT_STATUS_EQUAL(result, NT_STATUS_WRONG_PASSWORD)) {
1623 goto done;
1626 if (state->request->flags & WBFLAG_PAM_FALLBACK_AFTER_KRB5) {
1627 DEBUG(3,("falling back to samlogon\n"));
1628 goto sam_logon;
1629 } else {
1630 goto cached_logon;
1634 sam_logon:
1635 /* Check for Samlogon authentication */
1636 if (domain->online) {
1637 result = winbindd_dual_pam_auth_samlogon(
1638 state->mem_ctx, domain,
1639 state->request->data.auth.user,
1640 state->request->data.auth.pass,
1641 state->request->flags,
1642 &info3);
1644 if (NT_STATUS_IS_OK(result)) {
1645 DEBUG(10,("winbindd_dual_pam_auth_samlogon succeeded\n"));
1646 /* add the Krb5 err if we have one */
1647 if ( NT_STATUS_EQUAL(krb5_result, NT_STATUS_TIME_DIFFERENCE_AT_DC ) ) {
1648 info3->base.user_flags |= LOGON_KRB5_FAIL_CLOCK_SKEW;
1650 goto process_result;
1653 DEBUG(10,("winbindd_dual_pam_auth_samlogon failed: %s\n",
1654 nt_errstr(result)));
1656 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
1657 NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
1658 NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND))
1660 DEBUG(10,("winbindd_dual_pam_auth_samlogon setting domain to offline\n"));
1661 set_domain_offline( domain );
1662 goto cached_logon;
1665 if (domain->online) {
1666 /* We're still online - fail. */
1667 goto done;
1671 cached_logon:
1672 /* Check for Cached logons */
1673 if (!domain->online && (state->request->flags & WBFLAG_PAM_CACHED_LOGIN) &&
1674 lp_winbind_offline_logon()) {
1676 result = winbindd_dual_pam_auth_cached(domain, state, &info3);
1678 if (NT_STATUS_IS_OK(result)) {
1679 DEBUG(10,("winbindd_dual_pam_auth_cached succeeded\n"));
1680 goto process_result;
1681 } else {
1682 DEBUG(10,("winbindd_dual_pam_auth_cached failed: %s\n", nt_errstr(result)));
1683 goto done;
1687 process_result:
1689 if (NT_STATUS_IS_OK(result)) {
1691 struct dom_sid user_sid;
1693 /* In all codepaths where result == NT_STATUS_OK info3 must have
1694 been initialized. */
1695 if (!info3) {
1696 result = NT_STATUS_INTERNAL_ERROR;
1697 goto done;
1700 sid_compose(&user_sid, info3->base.domain_sid,
1701 info3->base.rid);
1703 wcache_invalidate_samlogon(find_domain_from_name(name_domain),
1704 &user_sid);
1705 netsamlogon_cache_store(name_user, info3);
1707 /* save name_to_sid info as early as possible (only if
1708 this is our primary domain so we don't invalidate
1709 the cache entry by storing the seq_num for the wrong
1710 domain). */
1711 if ( domain->primary ) {
1712 cache_name2sid(domain, name_domain, name_user,
1713 SID_NAME_USER, &user_sid);
1716 /* Check if the user is in the right group */
1718 result = check_info3_in_group(
1719 info3,
1720 state->request->data.auth.require_membership_of_sid);
1721 if (!NT_STATUS_IS_OK(result)) {
1722 DEBUG(3, ("User %s is not in the required group (%s), so plaintext authentication is rejected\n",
1723 state->request->data.auth.user,
1724 state->request->data.auth.require_membership_of_sid));
1725 goto done;
1728 result = append_auth_data(state->mem_ctx, state->response,
1729 state->request->flags, info3,
1730 name_domain, name_user);
1731 if (!NT_STATUS_IS_OK(result)) {
1732 goto done;
1735 if ((state->request->flags & WBFLAG_PAM_CACHED_LOGIN)
1736 && lp_winbind_offline_logon()) {
1738 result = winbindd_store_creds(domain,
1739 state->request->data.auth.user,
1740 state->request->data.auth.pass,
1741 info3);
1744 if (state->request->flags & WBFLAG_PAM_GET_PWD_POLICY) {
1745 struct winbindd_domain *our_domain = find_our_domain();
1747 /* This is not entirely correct I believe, but it is
1748 consistent. Only apply the password policy settings
1749 too warn users for our own domain. Cannot obtain these
1750 from trusted DCs all the time so don't do it at all.
1751 -- jerry */
1753 result = NT_STATUS_NOT_SUPPORTED;
1754 if (our_domain == domain ) {
1755 result = fillup_password_policy(
1756 our_domain, state->response);
1759 if (!NT_STATUS_IS_OK(result)
1760 && !NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED) )
1762 DEBUG(10,("Failed to get password policies for domain %s: %s\n",
1763 domain->name, nt_errstr(result)));
1764 goto done;
1768 result = NT_STATUS_OK;
1771 done:
1772 /* give us a more useful (more correct?) error code */
1773 if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
1774 (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
1775 result = NT_STATUS_NO_LOGON_SERVERS;
1778 set_auth_errors(state->response, result);
1780 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, ("Plain-text authentication for user %s returned %s (PAM: %d)\n",
1781 state->request->data.auth.user,
1782 state->response->data.auth.nt_status_string,
1783 state->response->data.auth.pam_error));
1785 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
1788 enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain,
1789 struct winbindd_cli_state *state)
1791 NTSTATUS result;
1792 struct netr_SamInfo3 *info3 = NULL;
1793 const char *name_user = NULL;
1794 const char *name_domain = NULL;
1795 const char *workstation;
1797 DATA_BLOB lm_resp, nt_resp;
1799 /* This is child-only, so no check for privileged access is needed
1800 anymore */
1802 /* Ensure null termination */
1803 state->request->data.auth_crap.user[sizeof(state->request->data.auth_crap.user)-1]=0;
1804 state->request->data.auth_crap.domain[sizeof(state->request->data.auth_crap.domain)-1]=0;
1806 name_user = state->request->data.auth_crap.user;
1807 name_domain = state->request->data.auth_crap.domain;
1808 workstation = state->request->data.auth_crap.workstation;
1810 DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n", (unsigned long)state->pid,
1811 name_domain, name_user));
1813 if (state->request->data.auth_crap.lm_resp_len > sizeof(state->request->data.auth_crap.lm_resp)
1814 || state->request->data.auth_crap.nt_resp_len > sizeof(state->request->data.auth_crap.nt_resp)) {
1815 if (!(state->request->flags & WBFLAG_BIG_NTLMV2_BLOB) ||
1816 state->request->extra_len != state->request->data.auth_crap.nt_resp_len) {
1817 DEBUG(0, ("winbindd_pam_auth_crap: invalid password length %u/%u\n",
1818 state->request->data.auth_crap.lm_resp_len,
1819 state->request->data.auth_crap.nt_resp_len));
1820 result = NT_STATUS_INVALID_PARAMETER;
1821 goto done;
1825 lm_resp = data_blob_talloc(state->mem_ctx, state->request->data.auth_crap.lm_resp,
1826 state->request->data.auth_crap.lm_resp_len);
1828 if (state->request->flags & WBFLAG_BIG_NTLMV2_BLOB) {
1829 nt_resp = data_blob_talloc(state->mem_ctx,
1830 state->request->extra_data.data,
1831 state->request->data.auth_crap.nt_resp_len);
1832 } else {
1833 nt_resp = data_blob_talloc(state->mem_ctx,
1834 state->request->data.auth_crap.nt_resp,
1835 state->request->data.auth_crap.nt_resp_len);
1838 if (strequal(name_domain, get_global_sam_name())) {
1839 DATA_BLOB chal_blob = data_blob_const(
1840 state->request->data.auth_crap.chal,
1841 sizeof(state->request->data.auth_crap.chal));
1843 result = winbindd_dual_auth_passdb(
1844 state->mem_ctx,
1845 state->request->data.auth_crap.logon_parameters,
1846 name_domain, name_user,
1847 &chal_blob, &lm_resp, &nt_resp, &info3);
1848 goto process_result;
1851 result = winbind_samlogon_retry_loop(domain,
1852 state->mem_ctx,
1853 state->request->data.auth_crap.logon_parameters,
1854 domain->dcname,
1855 name_user,
1856 name_domain,
1857 /* Bug #3248 - found by Stefan Burkei. */
1858 workstation, /* We carefully set this above so use it... */
1859 state->request->data.auth_crap.chal,
1860 lm_resp,
1861 nt_resp,
1862 &info3);
1863 if (!NT_STATUS_IS_OK(result)) {
1864 goto done;
1867 process_result:
1869 if (NT_STATUS_IS_OK(result)) {
1870 struct dom_sid user_sid;
1872 sid_compose(&user_sid, info3->base.domain_sid,
1873 info3->base.rid);
1874 wcache_invalidate_samlogon(find_domain_from_name(name_domain),
1875 &user_sid);
1876 netsamlogon_cache_store(name_user, info3);
1878 /* Check if the user is in the right group */
1880 result = check_info3_in_group(
1881 info3,
1882 state->request->data.auth_crap.require_membership_of_sid);
1883 if (!NT_STATUS_IS_OK(result)) {
1884 DEBUG(3, ("User %s is not in the required group (%s), so "
1885 "crap authentication is rejected\n",
1886 state->request->data.auth_crap.user,
1887 state->request->data.auth_crap.require_membership_of_sid));
1888 goto done;
1891 result = append_auth_data(state->mem_ctx, state->response,
1892 state->request->flags, info3,
1893 name_domain, name_user);
1894 if (!NT_STATUS_IS_OK(result)) {
1895 goto done;
1899 done:
1901 /* give us a more useful (more correct?) error code */
1902 if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
1903 (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
1904 result = NT_STATUS_NO_LOGON_SERVERS;
1907 if (state->request->flags & WBFLAG_PAM_NT_STATUS_SQUASH) {
1908 result = nt_status_squash(result);
1911 set_auth_errors(state->response, result);
1913 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
1914 ("NTLM CRAP authentication for user [%s]\\[%s] returned %s (PAM: %d)\n",
1915 name_domain,
1916 name_user,
1917 state->response->data.auth.nt_status_string,
1918 state->response->data.auth.pam_error));
1920 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
1923 enum winbindd_result winbindd_dual_pam_chauthtok(struct winbindd_domain *contact_domain,
1924 struct winbindd_cli_state *state)
1926 char *oldpass;
1927 char *newpass = NULL;
1928 struct policy_handle dom_pol;
1929 struct rpc_pipe_client *cli = NULL;
1930 bool got_info = false;
1931 struct samr_DomInfo1 *info = NULL;
1932 struct userPwdChangeFailureInformation *reject = NULL;
1933 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1934 fstring domain, user;
1935 struct dcerpc_binding_handle *b = NULL;
1937 ZERO_STRUCT(dom_pol);
1939 DEBUG(3, ("[%5lu]: dual pam chauthtok %s\n", (unsigned long)state->pid,
1940 state->request->data.auth.user));
1942 if (!parse_domain_user(state->request->data.chauthtok.user, domain, user)) {
1943 goto done;
1946 /* Change password */
1948 oldpass = state->request->data.chauthtok.oldpass;
1949 newpass = state->request->data.chauthtok.newpass;
1951 /* Initialize reject reason */
1952 state->response->data.auth.reject_reason = Undefined;
1954 /* Get sam handle */
1956 result = cm_connect_sam(contact_domain, state->mem_ctx, &cli,
1957 &dom_pol);
1958 if (!NT_STATUS_IS_OK(result)) {
1959 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
1960 goto done;
1963 b = cli->binding_handle;
1965 result = rpccli_samr_chgpasswd_user3(cli, state->mem_ctx,
1966 user,
1967 newpass,
1968 oldpass,
1969 &info,
1970 &reject);
1972 /* Windows 2003 returns NT_STATUS_PASSWORD_RESTRICTION */
1974 if (NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_RESTRICTION) ) {
1976 fill_in_password_policy(state->response, info);
1978 state->response->data.auth.reject_reason =
1979 reject->extendedFailureReason;
1981 got_info = true;
1984 /* atm the pidl generated rpccli_samr_ChangePasswordUser3 function will
1985 * return with NT_STATUS_BUFFER_TOO_SMALL for w2k dcs as w2k just
1986 * returns with 4byte error code (NT_STATUS_NOT_SUPPORTED) which is too
1987 * short to comply with the samr_ChangePasswordUser3 idl - gd */
1989 /* only fallback when the chgpasswd_user3 call is not supported */
1990 if (NT_STATUS_EQUAL(result, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE) ||
1991 NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED) ||
1992 NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL) ||
1993 NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
1995 DEBUG(10,("Password change with chgpasswd_user3 failed with: %s, retrying chgpasswd_user2\n",
1996 nt_errstr(result)));
1998 result = rpccli_samr_chgpasswd_user2(cli, state->mem_ctx, user, newpass, oldpass);
2000 /* Windows 2000 returns NT_STATUS_ACCOUNT_RESTRICTION.
2001 Map to the same status code as Windows 2003. */
2003 if ( NT_STATUS_EQUAL(NT_STATUS_ACCOUNT_RESTRICTION, result ) ) {
2004 result = NT_STATUS_PASSWORD_RESTRICTION;
2008 done:
2010 if (NT_STATUS_IS_OK(result)
2011 && (state->request->flags & WBFLAG_PAM_CACHED_LOGIN)
2012 && lp_winbind_offline_logon()) {
2013 result = winbindd_update_creds_by_name(contact_domain, user,
2014 newpass);
2015 /* Again, this happens when we login from gdm or xdm
2016 * and the password expires, *BUT* cached crendentials
2017 * doesn't exist. winbindd_update_creds_by_name()
2018 * returns NT_STATUS_NO_SUCH_USER.
2019 * This is not a failure.
2020 * --- BoYang
2021 * */
2022 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER)) {
2023 result = NT_STATUS_OK;
2026 if (!NT_STATUS_IS_OK(result)) {
2027 DEBUG(10, ("Failed to store creds: %s\n",
2028 nt_errstr(result)));
2029 goto process_result;
2033 if (!NT_STATUS_IS_OK(result) && !got_info && contact_domain) {
2035 NTSTATUS policy_ret;
2037 policy_ret = fillup_password_policy(
2038 contact_domain, state->response);
2040 /* failure of this is non critical, it will just provide no
2041 * additional information to the client why the change has
2042 * failed - Guenther */
2044 if (!NT_STATUS_IS_OK(policy_ret)) {
2045 DEBUG(10,("Failed to get password policies: %s\n", nt_errstr(policy_ret)));
2046 goto process_result;
2050 process_result:
2052 if (strequal(contact_domain->name, get_global_sam_name())) {
2053 /* FIXME: internal rpc pipe does not cache handles yet */
2054 if (b) {
2055 if (is_valid_policy_hnd(&dom_pol)) {
2056 NTSTATUS _result;
2057 dcerpc_samr_Close(b, state->mem_ctx, &dom_pol, &_result);
2059 TALLOC_FREE(cli);
2063 set_auth_errors(state->response, result);
2065 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
2066 ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
2067 domain,
2068 user,
2069 state->response->data.auth.nt_status_string,
2070 state->response->data.auth.pam_error));
2072 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2075 enum winbindd_result winbindd_dual_pam_logoff(struct winbindd_domain *domain,
2076 struct winbindd_cli_state *state)
2078 NTSTATUS result = NT_STATUS_NOT_SUPPORTED;
2080 DEBUG(3, ("[%5lu]: pam dual logoff %s\n", (unsigned long)state->pid,
2081 state->request->data.logoff.user));
2083 if (!(state->request->flags & WBFLAG_PAM_KRB5)) {
2084 result = NT_STATUS_OK;
2085 goto process_result;
2088 if (state->request->data.logoff.krb5ccname[0] == '\0') {
2089 result = NT_STATUS_OK;
2090 goto process_result;
2093 #ifdef HAVE_KRB5
2095 if (state->request->data.logoff.uid < 0) {
2096 DEBUG(0,("winbindd_pam_logoff: invalid uid\n"));
2097 goto process_result;
2100 /* what we need here is to find the corresponding krb5 ccache name *we*
2101 * created for a given username and destroy it */
2103 if (!ccache_entry_exists(state->request->data.logoff.user)) {
2104 result = NT_STATUS_OK;
2105 DEBUG(10,("winbindd_pam_logoff: no entry found.\n"));
2106 goto process_result;
2109 if (!ccache_entry_identical(state->request->data.logoff.user,
2110 state->request->data.logoff.uid,
2111 state->request->data.logoff.krb5ccname)) {
2112 DEBUG(0,("winbindd_pam_logoff: cached entry differs.\n"));
2113 goto process_result;
2116 result = remove_ccache(state->request->data.logoff.user);
2117 if (!NT_STATUS_IS_OK(result)) {
2118 DEBUG(0,("winbindd_pam_logoff: failed to remove ccache: %s\n",
2119 nt_errstr(result)));
2120 goto process_result;
2123 #else
2124 result = NT_STATUS_NOT_SUPPORTED;
2125 #endif
2127 process_result:
2130 set_auth_errors(state->response, result);
2132 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2135 /* Change user password with auth crap*/
2137 enum winbindd_result winbindd_dual_pam_chng_pswd_auth_crap(struct winbindd_domain *domainSt, struct winbindd_cli_state *state)
2139 NTSTATUS result;
2140 DATA_BLOB new_nt_password;
2141 DATA_BLOB old_nt_hash_enc;
2142 DATA_BLOB new_lm_password;
2143 DATA_BLOB old_lm_hash_enc;
2144 fstring domain,user;
2145 struct policy_handle dom_pol;
2146 struct winbindd_domain *contact_domain = domainSt;
2147 struct rpc_pipe_client *cli = NULL;
2148 struct dcerpc_binding_handle *b = NULL;
2150 ZERO_STRUCT(dom_pol);
2152 /* Ensure null termination */
2153 state->request->data.chng_pswd_auth_crap.user[
2154 sizeof(state->request->data.chng_pswd_auth_crap.user)-1]=0;
2155 state->request->data.chng_pswd_auth_crap.domain[
2156 sizeof(state->request->data.chng_pswd_auth_crap.domain)-1]=0;
2157 *domain = 0;
2158 *user = 0;
2160 DEBUG(3, ("[%5lu]: pam change pswd auth crap domain: %s user: %s\n",
2161 (unsigned long)state->pid,
2162 state->request->data.chng_pswd_auth_crap.domain,
2163 state->request->data.chng_pswd_auth_crap.user));
2165 if (lp_winbind_offline_logon()) {
2166 DEBUG(0,("Refusing password change as winbind offline logons are enabled. "));
2167 DEBUGADD(0,("Changing passwords here would risk inconsistent logons\n"));
2168 result = NT_STATUS_ACCESS_DENIED;
2169 goto done;
2172 if (*state->request->data.chng_pswd_auth_crap.domain) {
2173 fstrcpy(domain,state->request->data.chng_pswd_auth_crap.domain);
2174 } else {
2175 parse_domain_user(state->request->data.chng_pswd_auth_crap.user,
2176 domain, user);
2178 if(!*domain) {
2179 DEBUG(3,("no domain specified with username (%s) - "
2180 "failing auth\n",
2181 state->request->data.chng_pswd_auth_crap.user));
2182 result = NT_STATUS_NO_SUCH_USER;
2183 goto done;
2187 if (!*domain && lp_winbind_use_default_domain()) {
2188 fstrcpy(domain,lp_workgroup());
2191 if(!*user) {
2192 fstrcpy(user, state->request->data.chng_pswd_auth_crap.user);
2195 DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n",
2196 (unsigned long)state->pid, domain, user));
2198 /* Change password */
2199 new_nt_password = data_blob_const(
2200 state->request->data.chng_pswd_auth_crap.new_nt_pswd,
2201 state->request->data.chng_pswd_auth_crap.new_nt_pswd_len);
2203 old_nt_hash_enc = data_blob_const(
2204 state->request->data.chng_pswd_auth_crap.old_nt_hash_enc,
2205 state->request->data.chng_pswd_auth_crap.old_nt_hash_enc_len);
2207 if(state->request->data.chng_pswd_auth_crap.new_lm_pswd_len > 0) {
2208 new_lm_password = data_blob_const(
2209 state->request->data.chng_pswd_auth_crap.new_lm_pswd,
2210 state->request->data.chng_pswd_auth_crap.new_lm_pswd_len);
2212 old_lm_hash_enc = data_blob_const(
2213 state->request->data.chng_pswd_auth_crap.old_lm_hash_enc,
2214 state->request->data.chng_pswd_auth_crap.old_lm_hash_enc_len);
2215 } else {
2216 new_lm_password = data_blob_null;
2217 old_lm_hash_enc = data_blob_null;
2220 /* Get sam handle */
2222 result = cm_connect_sam(contact_domain, state->mem_ctx, &cli, &dom_pol);
2223 if (!NT_STATUS_IS_OK(result)) {
2224 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
2225 goto done;
2228 b = cli->binding_handle;
2230 result = rpccli_samr_chng_pswd_auth_crap(
2231 cli, state->mem_ctx, user, new_nt_password, old_nt_hash_enc,
2232 new_lm_password, old_lm_hash_enc);
2234 done:
2236 if (strequal(contact_domain->name, get_global_sam_name())) {
2237 /* FIXME: internal rpc pipe does not cache handles yet */
2238 if (b) {
2239 if (is_valid_policy_hnd(&dom_pol)) {
2240 NTSTATUS _result;
2241 dcerpc_samr_Close(b, state->mem_ctx, &dom_pol, &_result);
2243 TALLOC_FREE(cli);
2247 set_auth_errors(state->response, result);
2249 DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
2250 ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
2251 domain, user,
2252 state->response->data.auth.nt_status_string,
2253 state->response->data.auth.pam_error));
2255 return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;