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/>.
30
#define DBGC_CLASS DBGC_WINBIND
32
#define LOGON_KRB5_FAIL_CLOCK_SKEW 0x02000000
34
static NTSTATUS append_info3_as_txt(TALLOC_CTX *mem_ctx,
35
struct winbindd_cli_state *state,
36
struct netr_SamInfo3 *info3)
42
state->response.data.auth.info3.logon_time =
43
nt_time_to_unix(info3->base.last_logon);
44
state->response.data.auth.info3.logoff_time =
45
nt_time_to_unix(info3->base.last_logoff);
46
state->response.data.auth.info3.kickoff_time =
47
nt_time_to_unix(info3->base.acct_expiry);
48
state->response.data.auth.info3.pass_last_set_time =
49
nt_time_to_unix(info3->base.last_password_change);
50
state->response.data.auth.info3.pass_can_change_time =
51
nt_time_to_unix(info3->base.allow_password_change);
52
state->response.data.auth.info3.pass_must_change_time =
53
nt_time_to_unix(info3->base.force_password_change);
55
state->response.data.auth.info3.logon_count = info3->base.logon_count;
56
state->response.data.auth.info3.bad_pw_count = info3->base.bad_password_count;
58
state->response.data.auth.info3.user_rid = info3->base.rid;
59
state->response.data.auth.info3.group_rid = info3->base.primary_gid;
60
sid_to_fstring(state->response.data.auth.info3.dom_sid, info3->base.domain_sid);
62
state->response.data.auth.info3.num_groups = info3->base.groups.count;
63
state->response.data.auth.info3.user_flgs = info3->base.user_flags;
65
state->response.data.auth.info3.acct_flags = info3->base.acct_flags;
66
state->response.data.auth.info3.num_other_sids = info3->sidcount;
68
fstrcpy(state->response.data.auth.info3.user_name,
69
info3->base.account_name.string);
70
fstrcpy(state->response.data.auth.info3.full_name,
71
info3->base.full_name.string);
72
fstrcpy(state->response.data.auth.info3.logon_script,
73
info3->base.logon_script.string);
74
fstrcpy(state->response.data.auth.info3.profile_path,
75
info3->base.profile_path.string);
76
fstrcpy(state->response.data.auth.info3.home_dir,
77
info3->base.home_directory.string);
78
fstrcpy(state->response.data.auth.info3.dir_drive,
79
info3->base.home_drive.string);
81
fstrcpy(state->response.data.auth.info3.logon_srv,
82
info3->base.logon_server.string);
83
fstrcpy(state->response.data.auth.info3.logon_dom,
84
info3->base.domain.string);
86
ex = talloc_strdup(mem_ctx, "");
87
NT_STATUS_HAVE_NO_MEMORY(ex);
89
for (i=0; i < info3->base.groups.count; i++) {
90
ex = talloc_asprintf_append_buffer(ex, "0x%08X:0x%08X\n",
91
info3->base.groups.rids[i].rid,
92
info3->base.groups.rids[i].attributes);
93
NT_STATUS_HAVE_NO_MEMORY(ex);
96
for (i=0; i < info3->sidcount; i++) {
99
sid = dom_sid_string(mem_ctx, info3->sids[i].sid);
100
NT_STATUS_HAVE_NO_MEMORY(sid);
102
ex = talloc_asprintf_append_buffer(ex, "%s:0x%08X\n",
104
info3->sids[i].attributes);
105
NT_STATUS_HAVE_NO_MEMORY(ex);
110
size = talloc_get_size(ex);
112
SAFE_FREE(state->response.extra_data.data);
113
state->response.extra_data.data = SMB_MALLOC(size);
114
if (!state->response.extra_data.data) {
115
return NT_STATUS_NO_MEMORY;
117
memcpy(state->response.extra_data.data, ex, size);
120
state->response.length += size;
125
static NTSTATUS append_info3_as_ndr(TALLOC_CTX *mem_ctx,
126
struct winbindd_cli_state *state,
127
struct netr_SamInfo3 *info3)
130
enum ndr_err_code ndr_err;
132
ndr_err = ndr_push_struct_blob(&blob, mem_ctx, NULL, info3,
133
(ndr_push_flags_fn_t)ndr_push_netr_SamInfo3);
134
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
135
DEBUG(0,("append_info3_as_ndr: failed to append\n"));
136
return ndr_map_error2ntstatus(ndr_err);
139
SAFE_FREE(state->response.extra_data.data);
140
state->response.extra_data.data = SMB_MALLOC(blob.length);
141
if (!state->response.extra_data.data) {
142
data_blob_free(&blob);
143
return NT_STATUS_NO_MEMORY;
146
memset(state->response.extra_data.data, '\0', blob.length);
147
memcpy(state->response.extra_data.data, blob.data, blob.length);
148
state->response.length += blob.length;
150
data_blob_free(&blob);
155
static NTSTATUS append_unix_username(TALLOC_CTX *mem_ctx,
156
struct winbindd_cli_state *state,
157
const struct netr_SamInfo3 *info3,
158
const char *name_domain,
159
const char *name_user)
161
/* We've been asked to return the unix username, per
162
'winbind use default domain' settings and the like */
164
const char *nt_username, *nt_domain;
166
nt_domain = talloc_strdup(mem_ctx, info3->base.domain.string);
168
/* If the server didn't give us one, just use the one
170
nt_domain = name_domain;
173
nt_username = talloc_strdup(mem_ctx, info3->base.account_name.string);
175
/* If the server didn't give us one, just use the one
177
nt_username = name_user;
180
fill_domain_username(state->response.data.auth.unix_username,
181
nt_domain, nt_username, true);
183
DEBUG(5,("Setting unix username to [%s]\n",
184
state->response.data.auth.unix_username));
189
static NTSTATUS append_afs_token(TALLOC_CTX *mem_ctx,
190
struct winbindd_cli_state *state,
191
const struct netr_SamInfo3 *info3,
192
const char *name_domain,
193
const char *name_user)
195
char *afsname = NULL;
198
afsname = talloc_strdup(mem_ctx, lp_afs_username_map());
199
if (afsname == NULL) {
200
return NT_STATUS_NO_MEMORY;
203
afsname = talloc_string_sub(mem_ctx,
204
lp_afs_username_map(),
206
afsname = talloc_string_sub(mem_ctx, afsname,
208
afsname = talloc_string_sub(mem_ctx, afsname,
215
sid_copy(&user_sid, info3->base.domain_sid);
216
sid_append_rid(&user_sid, info3->base.rid);
217
sid_to_fstring(sidstr, &user_sid);
218
afsname = talloc_string_sub(mem_ctx, afsname,
222
if (afsname == NULL) {
223
return NT_STATUS_NO_MEMORY;
228
DEBUG(10, ("Generating token for user %s\n", afsname));
230
cell = strchr(afsname, '@');
233
return NT_STATUS_NO_MEMORY;
239
/* Append an AFS token string */
240
SAFE_FREE(state->response.extra_data.data);
241
state->response.extra_data.data =
242
afs_createtoken_str(afsname, cell);
244
if (state->response.extra_data.data != NULL) {
245
state->response.length +=
246
strlen((const char *)state->response.extra_data.data)+1;
252
static NTSTATUS check_info3_in_group(TALLOC_CTX *mem_ctx,
253
struct netr_SamInfo3 *info3,
254
const char *group_sid)
256
* Check whether a user belongs to a group or list of groups.
258
* @param mem_ctx talloc memory context.
259
* @param info3 user information, including group membership info.
260
* @param group_sid One or more groups , separated by commas.
262
* @return NT_STATUS_OK on success,
263
* NT_STATUS_LOGON_FAILURE if the user does not belong,
264
* or other NT_STATUS_IS_ERR(status) for other kinds of failure.
267
DOM_SID *require_membership_of_sid;
268
size_t num_require_membership_of_sid;
273
struct nt_user_token *token;
274
TALLOC_CTX *frame = NULL;
277
/* Parse the 'required group' SID */
279
if (!group_sid || !group_sid[0]) {
280
/* NO sid supplied, all users may access */
284
if (!(token = TALLOC_ZERO_P(mem_ctx, struct nt_user_token))) {
285
DEBUG(0, ("talloc failed\n"));
286
return NT_STATUS_NO_MEMORY;
289
num_require_membership_of_sid = 0;
290
require_membership_of_sid = NULL;
294
frame = talloc_stackframe();
295
while (next_token_talloc(frame, &p, &req_sid, ",")) {
296
if (!string_to_sid(&sid, req_sid)) {
297
DEBUG(0, ("check_info3_in_group: could not parse %s "
298
"as a SID!", req_sid));
300
return NT_STATUS_INVALID_PARAMETER;
303
status = add_sid_to_array(mem_ctx, &sid,
304
&require_membership_of_sid,
305
&num_require_membership_of_sid);
306
if (!NT_STATUS_IS_OK(status)) {
307
DEBUG(0, ("add_sid_to_array failed\n"));
315
status = sid_array_from_info3(mem_ctx, info3,
319
if (!NT_STATUS_IS_OK(status)) {
323
if (!NT_STATUS_IS_OK(status = add_aliases(get_global_sam_sid(),
325
|| !NT_STATUS_IS_OK(status = add_aliases(&global_sid_Builtin,
327
DEBUG(3, ("could not add aliases: %s\n",
332
debug_nt_user_token(DBGC_CLASS, 10, token);
334
for (i=0; i<num_require_membership_of_sid; i++) {
335
DEBUG(10, ("Checking SID %s\n", sid_string_dbg(
336
&require_membership_of_sid[i])));
337
if (nt_token_check_sid(&require_membership_of_sid[i],
339
DEBUG(10, ("Access ok\n"));
344
/* Do not distinguish this error from a wrong username/pw */
346
return NT_STATUS_LOGON_FAILURE;
349
struct winbindd_domain *find_auth_domain(struct winbindd_cli_state *state,
350
const char *domain_name)
352
struct winbindd_domain *domain;
355
domain = find_domain_from_name_noinit(domain_name);
356
if (domain == NULL) {
357
DEBUG(3, ("Authentication for domain [%s] refused "
358
"as it is not a trusted domain\n",
364
if (is_myname(domain_name)) {
365
DEBUG(3, ("Authentication for domain %s (local domain "
366
"to this server) not supported at this "
367
"stage\n", domain_name));
371
/* we can auth against trusted domains */
372
if (state->request.flags & WBFLAG_PAM_CONTACT_TRUSTDOM) {
373
domain = find_domain_from_name_noinit(domain_name);
374
if (domain == NULL) {
375
DEBUG(3, ("Authentication for domain [%s] skipped "
376
"as it is not a trusted domain\n",
383
return find_our_domain();
386
static void fill_in_password_policy(struct winbindd_response *r,
387
const struct samr_DomInfo1 *p)
389
r->data.auth.policy.min_length_password =
390
p->min_password_length;
391
r->data.auth.policy.password_history =
392
p->password_history_length;
393
r->data.auth.policy.password_properties =
394
p->password_properties;
395
r->data.auth.policy.expire =
396
nt_time_to_unix_abs((NTTIME *)&(p->max_password_age));
397
r->data.auth.policy.min_passwordage =
398
nt_time_to_unix_abs((NTTIME *)&(p->min_password_age));
401
static NTSTATUS fillup_password_policy(struct winbindd_domain *domain,
402
struct winbindd_cli_state *state)
404
struct winbindd_methods *methods;
405
NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
406
struct samr_DomInfo1 password_policy;
408
if ( !winbindd_can_contact_domain( domain ) ) {
409
DEBUG(5,("fillup_password_policy: No inbound trust to "
410
"contact domain %s\n", domain->name));
411
return NT_STATUS_NOT_SUPPORTED;
414
methods = domain->methods;
416
status = methods->password_policy(domain, state->mem_ctx, &password_policy);
417
if (NT_STATUS_IS_ERR(status)) {
421
fill_in_password_policy(&state->response, &password_policy);
426
static NTSTATUS get_max_bad_attempts_from_lockout_policy(struct winbindd_domain *domain,
428
uint16 *lockout_threshold)
430
struct winbindd_methods *methods;
431
NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
432
struct samr_DomInfo12 lockout_policy;
434
*lockout_threshold = 0;
436
methods = domain->methods;
438
status = methods->lockout_policy(domain, mem_ctx, &lockout_policy);
439
if (NT_STATUS_IS_ERR(status)) {
443
*lockout_threshold = lockout_policy.lockout_threshold;
448
static NTSTATUS get_pwd_properties(struct winbindd_domain *domain,
450
uint32 *password_properties)
452
struct winbindd_methods *methods;
453
NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
454
struct samr_DomInfo1 password_policy;
456
*password_properties = 0;
458
methods = domain->methods;
460
status = methods->password_policy(domain, mem_ctx, &password_policy);
461
if (NT_STATUS_IS_ERR(status)) {
465
*password_properties = password_policy.password_properties;
472
static const char *generate_krb5_ccache(TALLOC_CTX *mem_ctx,
475
bool *internal_ccache)
477
/* accept FILE and WRFILE as krb5_cc_type from the client and then
478
* build the full ccname string based on the user's uid here -
481
const char *gen_cc = NULL;
483
*internal_ccache = true;
489
if (!type || type[0] == '\0') {
493
if (strequal(type, "FILE")) {
494
gen_cc = talloc_asprintf(mem_ctx, "FILE:/tmp/krb5cc_%d", uid);
495
} else if (strequal(type, "WRFILE")) {
496
gen_cc = talloc_asprintf(mem_ctx, "WRFILE:/tmp/krb5cc_%d", uid);
498
DEBUG(10,("we don't allow to set a %s type ccache\n", type));
502
*internal_ccache = false;
506
gen_cc = talloc_strdup(mem_ctx, "MEMORY:winbindd_pam_ccache");
509
if (gen_cc == NULL) {
510
DEBUG(0,("out of memory\n"));
514
DEBUG(10,("using ccache: %s %s\n", gen_cc, *internal_ccache ? "(internal)":""));
519
static void setup_return_cc_name(struct winbindd_cli_state *state, const char *cc)
521
const char *type = state->request.data.auth.krb5_cc_type;
523
state->response.data.auth.krb5ccname[0] = '\0';
525
if (type[0] == '\0') {
529
if (!strequal(type, "FILE") &&
530
!strequal(type, "WRFILE")) {
531
DEBUG(10,("won't return krbccname for a %s type ccache\n",
536
fstrcpy(state->response.data.auth.krb5ccname, cc);
541
static uid_t get_uid_from_state(struct winbindd_cli_state *state)
545
uid = state->request.data.auth.uid;
548
DEBUG(1,("invalid uid: '%u'\n", (unsigned int)uid));
554
/**********************************************************************
555
Authenticate a user with a clear text password using Kerberos and fill up
557
**********************************************************************/
559
static NTSTATUS winbindd_raw_kerberos_login(struct winbindd_domain *domain,
560
struct winbindd_cli_state *state,
561
struct netr_SamInfo3 **info3)
564
NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
565
krb5_error_code krb5_ret;
566
const char *cc = NULL;
567
const char *principal_s = NULL;
568
const char *service = NULL;
570
fstring name_domain, name_user;
571
time_t ticket_lifetime = 0;
572
time_t renewal_until = 0;
575
time_t time_offset = 0;
576
bool internal_ccache = true;
583
* prepare a krb5_cc_cache string for the user */
585
uid = get_uid_from_state(state);
587
DEBUG(0,("no valid uid\n"));
590
cc = generate_krb5_ccache(state->mem_ctx,
591
state->request.data.auth.krb5_cc_type,
592
state->request.data.auth.uid,
595
return NT_STATUS_NO_MEMORY;
600
* get kerberos properties */
602
if (domain->private_data) {
603
ads = (ADS_STRUCT *)domain->private_data;
604
time_offset = ads->auth.time_offset;
609
* do kerberos auth and setup ccache as the user */
611
parse_domain_user(state->request.data.auth.user, name_domain, name_user);
613
realm = domain->alt_name;
616
principal_s = talloc_asprintf(state->mem_ctx, "%s@%s", name_user, realm);
617
if (principal_s == NULL) {
618
return NT_STATUS_NO_MEMORY;
621
service = talloc_asprintf(state->mem_ctx, "%s/%s@%s", KRB5_TGS_NAME, realm, realm);
622
if (service == NULL) {
623
return NT_STATUS_NO_MEMORY;
626
/* if this is a user ccache, we need to act as the user to let the krb5
627
* library handle the chown, etc. */
629
/************************ ENTERING NON-ROOT **********************/
631
if (!internal_ccache) {
632
set_effective_uid(uid);
633
DEBUG(10,("winbindd_raw_kerberos_login: uid is %d\n", uid));
636
result = kerberos_return_info3_from_pac(state->mem_ctx,
638
state->request.data.auth.pass,
645
WINBINDD_PAM_AUTH_KRB5_RENEW_TIME,
647
if (!internal_ccache) {
648
gain_root_privilege();
651
/************************ RETURNED TO ROOT **********************/
653
if (!NT_STATUS_IS_OK(result)) {
657
DEBUG(10,("winbindd_raw_kerberos_login: winbindd validated ticket of %s\n",
660
/* if we had a user's ccache then return that string for the pam
663
if (!internal_ccache) {
665
setup_return_cc_name(state, cc);
667
result = add_ccache_to_list(principal_s,
670
state->request.data.auth.user,
678
if (!NT_STATUS_IS_OK(result)) {
679
DEBUG(10,("winbindd_raw_kerberos_login: failed to add ccache to list: %s\n",
684
/* need to delete the memory cred cache, it is not used anymore */
686
krb5_ret = ads_kdestroy(cc);
688
DEBUG(3,("winbindd_raw_kerberos_login: "
689
"could not destroy krb5 credential cache: "
690
"%s\n", error_message(krb5_ret)));
699
/* we could have created a new credential cache with a valid tgt in it
700
* but we werent able to get or verify the service ticket for this
701
* local host and therefor didn't get the PAC, we need to remove that
702
* cache entirely now */
704
krb5_ret = ads_kdestroy(cc);
706
DEBUG(3,("winbindd_raw_kerberos_login: "
707
"could not destroy krb5 credential cache: "
708
"%s\n", error_message(krb5_ret)));
711
if (!NT_STATUS_IS_OK(remove_ccache(state->request.data.auth.user))) {
712
DEBUG(3,("winbindd_raw_kerberos_login: "
713
"could not remove ccache for user %s\n",
714
state->request.data.auth.user));
719
return NT_STATUS_NOT_SUPPORTED;
720
#endif /* HAVE_KRB5 */
723
/****************************************************************
724
****************************************************************/
726
static bool check_request_flags(uint32_t flags)
728
uint32_t flags_edata = WBFLAG_PAM_AFS_TOKEN |
729
WBFLAG_PAM_INFO3_TEXT |
730
WBFLAG_PAM_INFO3_NDR;
732
if ( ( (flags & flags_edata) == WBFLAG_PAM_AFS_TOKEN) ||
733
( (flags & flags_edata) == WBFLAG_PAM_INFO3_NDR) ||
734
( (flags & flags_edata) == WBFLAG_PAM_INFO3_TEXT)||
735
!(flags & flags_edata) ) {
739
DEBUG(1,("check_request_flags: invalid request flags[0x%08X]\n",flags));
744
/****************************************************************
745
****************************************************************/
747
static NTSTATUS append_data(struct winbindd_cli_state *state,
748
struct netr_SamInfo3 *info3,
749
const char *name_domain,
750
const char *name_user)
753
uint32_t flags = state->request.flags;
755
if (flags & WBFLAG_PAM_USER_SESSION_KEY) {
756
memcpy(state->response.data.auth.user_session_key,
758
sizeof(state->response.data.auth.user_session_key)
762
if (flags & WBFLAG_PAM_LMKEY) {
763
memcpy(state->response.data.auth.first_8_lm_hash,
764
info3->base.LMSessKey.key,
765
sizeof(state->response.data.auth.first_8_lm_hash)
769
if (flags & WBFLAG_PAM_INFO3_TEXT) {
770
result = append_info3_as_txt(state->mem_ctx, state, info3);
771
if (!NT_STATUS_IS_OK(result)) {
772
DEBUG(10,("Failed to append INFO3 (TXT): %s\n",
778
/* currently, anything from here on potentially overwrites extra_data. */
780
if (flags & WBFLAG_PAM_INFO3_NDR) {
781
result = append_info3_as_ndr(state->mem_ctx, state, info3);
782
if (!NT_STATUS_IS_OK(result)) {
783
DEBUG(10,("Failed to append INFO3 (NDR): %s\n",
789
if (flags & WBFLAG_PAM_UNIX_NAME) {
790
result = append_unix_username(state->mem_ctx, state, info3,
791
name_domain, name_user);
792
if (!NT_STATUS_IS_OK(result)) {
793
DEBUG(10,("Failed to append Unix Username: %s\n",
799
if (flags & WBFLAG_PAM_AFS_TOKEN) {
800
result = append_afs_token(state->mem_ctx, state, info3,
801
name_domain, name_user);
802
if (!NT_STATUS_IS_OK(result)) {
803
DEBUG(10,("Failed to append AFS token: %s\n",
812
void winbindd_pam_auth(struct winbindd_cli_state *state)
814
struct winbindd_domain *domain;
815
fstring name_domain, name_user, mapped_user;
818
NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL;
820
/* Ensure null termination */
821
state->request.data.auth.user
822
[sizeof(state->request.data.auth.user)-1]='\0';
824
/* Ensure null termination */
825
state->request.data.auth.pass
826
[sizeof(state->request.data.auth.pass)-1]='\0';
828
DEBUG(3, ("[%5lu]: pam auth %s\n", (unsigned long)state->pid,
829
state->request.data.auth.user));
831
if (!check_request_flags(state->request.flags)) {
832
result = NT_STATUS_INVALID_PARAMETER_MIX;
836
/* Parse domain and username */
838
name_map_status = normalize_name_unmap(state->mem_ctx,
839
state->request.data.auth.user,
842
/* If the name normalization didnt' actually do anything,
843
just use the original name */
845
if (NT_STATUS_IS_OK(name_map_status)
846
||NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED)) {
847
fstrcpy(mapped_user, mapped);
849
fstrcpy(mapped_user, state->request.data.auth.user);
852
if (!canonicalize_username(mapped_user, name_domain, name_user)) {
853
result = NT_STATUS_NO_SUCH_USER;
857
domain = find_auth_domain(state, name_domain);
859
if (domain == NULL) {
860
result = NT_STATUS_NO_SUCH_USER;
864
sendto_domain(state, domain);
867
set_auth_errors(&state->response, result);
868
DEBUG(5, ("Plain text authentication for %s returned %s "
870
state->request.data.auth.user,
871
state->response.data.auth.nt_status_string,
872
state->response.data.auth.pam_error));
873
request_error(state);
876
NTSTATUS winbindd_dual_pam_auth_cached(struct winbindd_domain *domain,
877
struct winbindd_cli_state *state,
878
struct netr_SamInfo3 **info3)
880
NTSTATUS result = NT_STATUS_LOGON_FAILURE;
881
uint16 max_allowed_bad_attempts;
882
fstring name_domain, name_user;
884
enum lsa_SidType type;
885
uchar new_nt_pass[NT_HASH_LEN];
886
const uint8 *cached_nt_pass;
887
const uint8 *cached_salt;
888
struct netr_SamInfo3 *my_info3;
889
time_t kickoff_time, must_change_time;
890
bool password_good = false;
892
struct winbindd_tdc_domain *tdc_domain = NULL;
899
DEBUG(10,("winbindd_dual_pam_auth_cached\n"));
901
/* Parse domain and username */
903
parse_domain_user(state->request.data.auth.user, name_domain, name_user);
906
if (!lookup_cached_name(state->mem_ctx,
911
DEBUG(10,("winbindd_dual_pam_auth_cached: no such user in the cache\n"));
912
return NT_STATUS_NO_SUCH_USER;
915
if (type != SID_NAME_USER) {
916
DEBUG(10,("winbindd_dual_pam_auth_cached: not a user (%s)\n", sid_type_lookup(type)));
917
return NT_STATUS_LOGON_FAILURE;
920
result = winbindd_get_creds(domain,
926
if (!NT_STATUS_IS_OK(result)) {
927
DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get creds: %s\n", nt_errstr(result)));
933
E_md4hash(state->request.data.auth.pass, new_nt_pass);
935
dump_data_pw("new_nt_pass", new_nt_pass, NT_HASH_LEN);
936
dump_data_pw("cached_nt_pass", cached_nt_pass, NT_HASH_LEN);
938
dump_data_pw("cached_salt", cached_salt, NT_HASH_LEN);
942
/* In this case we didn't store the nt_hash itself,
943
but the MD5 combination of salt + nt_hash. */
944
uchar salted_hash[NT_HASH_LEN];
945
E_md5hash(cached_salt, new_nt_pass, salted_hash);
947
password_good = (memcmp(cached_nt_pass, salted_hash, NT_HASH_LEN) == 0) ?
950
/* Old cached cred - direct store of nt_hash (bad bad bad !). */
951
password_good = (memcmp(cached_nt_pass, new_nt_pass, NT_HASH_LEN) == 0) ?
957
/* User *DOES* know the password, update logon_time and reset
960
my_info3->base.user_flags |= NETLOGON_CACHED_ACCOUNT;
962
if (my_info3->base.acct_flags & ACB_AUTOLOCK) {
963
return NT_STATUS_ACCOUNT_LOCKED_OUT;
966
if (my_info3->base.acct_flags & ACB_DISABLED) {
967
return NT_STATUS_ACCOUNT_DISABLED;
970
if (my_info3->base.acct_flags & ACB_WSTRUST) {
971
return NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
974
if (my_info3->base.acct_flags & ACB_SVRTRUST) {
975
return NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT;
978
if (my_info3->base.acct_flags & ACB_DOMTRUST) {
979
return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT;
982
if (!(my_info3->base.acct_flags & ACB_NORMAL)) {
983
DEBUG(0,("winbindd_dual_pam_auth_cached: whats wrong with that one?: 0x%08x\n",
984
my_info3->base.acct_flags));
985
return NT_STATUS_LOGON_FAILURE;
988
kickoff_time = nt_time_to_unix(my_info3->base.acct_expiry);
989
if (kickoff_time != 0 && time(NULL) > kickoff_time) {
990
return NT_STATUS_ACCOUNT_EXPIRED;
993
must_change_time = nt_time_to_unix(my_info3->base.force_password_change);
994
if (must_change_time != 0 && must_change_time < time(NULL)) {
995
/* we allow grace logons when the password has expired */
996
my_info3->base.user_flags |= NETLOGON_GRACE_LOGON;
997
/* return NT_STATUS_PASSWORD_EXPIRED; */
1002
if ((state->request.flags & WBFLAG_PAM_KRB5) &&
1003
((tdc_domain = wcache_tdc_fetch_domain(state->mem_ctx, name_domain)) != NULL) &&
1004
(tdc_domain->trust_type & NETR_TRUST_TYPE_UPLEVEL)) {
1007
const char *cc = NULL;
1009
const char *principal_s = NULL;
1010
const char *service = NULL;
1011
bool internal_ccache = false;
1013
uid = get_uid_from_state(state);
1015
DEBUG(0,("winbindd_dual_pam_auth_cached: invalid uid\n"));
1016
return NT_STATUS_INVALID_PARAMETER;
1019
cc = generate_krb5_ccache(state->mem_ctx,
1020
state->request.data.auth.krb5_cc_type,
1021
state->request.data.auth.uid,
1024
return NT_STATUS_NO_MEMORY;
1027
realm = domain->alt_name;
1030
principal_s = talloc_asprintf(state->mem_ctx, "%s@%s", name_user, realm);
1031
if (principal_s == NULL) {
1032
return NT_STATUS_NO_MEMORY;
1035
service = talloc_asprintf(state->mem_ctx, "%s/%s@%s", KRB5_TGS_NAME, realm, realm);
1036
if (service == NULL) {
1037
return NT_STATUS_NO_MEMORY;
1040
if (!internal_ccache) {
1042
setup_return_cc_name(state, cc);
1044
result = add_ccache_to_list(principal_s,
1047
state->request.data.auth.user,
1051
time(NULL) + lp_winbind_cache_time(),
1052
time(NULL) + WINBINDD_PAM_AUTH_KRB5_RENEW_TIME,
1055
if (!NT_STATUS_IS_OK(result)) {
1056
DEBUG(10,("winbindd_dual_pam_auth_cached: failed "
1057
"to add ccache to list: %s\n",
1058
nt_errstr(result)));
1062
#endif /* HAVE_KRB5 */
1064
/* FIXME: we possibly should handle logon hours as well (does xp when
1065
* offline?) see auth/auth_sam.c:sam_account_ok for details */
1067
unix_to_nt_time(&my_info3->base.last_logon, time(NULL));
1068
my_info3->base.bad_password_count = 0;
1070
result = winbindd_update_creds_by_info3(domain,
1072
state->request.data.auth.user,
1073
state->request.data.auth.pass,
1075
if (!NT_STATUS_IS_OK(result)) {
1076
DEBUG(1,("winbindd_dual_pam_auth_cached: failed to update creds: %s\n",
1077
nt_errstr(result)));
1081
return NT_STATUS_OK;
1085
/* User does *NOT* know the correct password, modify info3 accordingly */
1087
/* failure of this is not critical */
1088
result = get_max_bad_attempts_from_lockout_policy(domain, state->mem_ctx, &max_allowed_bad_attempts);
1089
if (!NT_STATUS_IS_OK(result)) {
1090
DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get max_allowed_bad_attempts. "
1091
"Won't be able to honour account lockout policies\n"));
1094
/* increase counter */
1095
my_info3->base.bad_password_count++;
1097
if (max_allowed_bad_attempts == 0) {
1102
if (my_info3->base.bad_password_count >= max_allowed_bad_attempts) {
1104
uint32 password_properties;
1106
result = get_pwd_properties(domain, state->mem_ctx, &password_properties);
1107
if (!NT_STATUS_IS_OK(result)) {
1108
DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get password properties.\n"));
1111
if ((my_info3->base.rid != DOMAIN_USER_RID_ADMIN) ||
1112
(password_properties & DOMAIN_PASSWORD_LOCKOUT_ADMINS)) {
1113
my_info3->base.acct_flags |= ACB_AUTOLOCK;
1118
result = winbindd_update_creds_by_info3(domain,
1120
state->request.data.auth.user,
1124
if (!NT_STATUS_IS_OK(result)) {
1125
DEBUG(0,("winbindd_dual_pam_auth_cached: failed to update creds %s\n",
1126
nt_errstr(result)));
1129
return NT_STATUS_LOGON_FAILURE;
1132
NTSTATUS winbindd_dual_pam_auth_kerberos(struct winbindd_domain *domain,
1133
struct winbindd_cli_state *state,
1134
struct netr_SamInfo3 **info3)
1136
struct winbindd_domain *contact_domain;
1137
fstring name_domain, name_user;
1140
DEBUG(10,("winbindd_dual_pam_auth_kerberos\n"));
1142
/* Parse domain and username */
1144
parse_domain_user(state->request.data.auth.user, name_domain, name_user);
1146
/* what domain should we contact? */
1149
if (!(contact_domain = find_domain_from_name(name_domain))) {
1150
DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
1151
state->request.data.auth.user, name_domain, name_user, name_domain));
1152
result = NT_STATUS_NO_SUCH_USER;
1157
if (is_myname(name_domain)) {
1158
DEBUG(3, ("Authentication for domain %s (local domain to this server) not supported at this stage\n", name_domain));
1159
result = NT_STATUS_NO_SUCH_USER;
1163
contact_domain = find_domain_from_name(name_domain);
1164
if (contact_domain == NULL) {
1165
DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
1166
state->request.data.auth.user, name_domain, name_user, name_domain));
1168
contact_domain = find_our_domain();
1172
if (contact_domain->initialized &&
1173
contact_domain->active_directory) {
1177
if (!contact_domain->initialized) {
1178
init_dc_connection(contact_domain);
1181
if (!contact_domain->active_directory) {
1182
DEBUG(3,("krb5 auth requested but domain is not Active Directory\n"));
1183
return NT_STATUS_INVALID_LOGON_TYPE;
1186
result = winbindd_raw_kerberos_login(contact_domain, state, info3);
1191
typedef NTSTATUS (*netlogon_fn_t)(struct rpc_pipe_client *cli,
1192
TALLOC_CTX *mem_ctx,
1193
uint32 logon_parameters,
1195
const char *username,
1197
const char *workstation,
1198
const uint8 chal[8],
1199
DATA_BLOB lm_response,
1200
DATA_BLOB nt_response,
1201
struct netr_SamInfo3 **info3);
1203
NTSTATUS winbindd_dual_pam_auth_samlogon(struct winbindd_domain *domain,
1204
struct winbindd_cli_state *state,
1205
struct netr_SamInfo3 **info3)
1208
struct rpc_pipe_client *netlogon_pipe;
1213
unsigned char local_lm_response[24];
1214
unsigned char local_nt_response[24];
1215
struct winbindd_domain *contact_domain;
1216
fstring name_domain, name_user;
1219
struct netr_SamInfo3 *my_info3 = NULL;
1223
DEBUG(10,("winbindd_dual_pam_auth_samlogon\n"));
1225
/* Parse domain and username */
1227
parse_domain_user(state->request.data.auth.user, name_domain, name_user);
1229
/* do password magic */
1232
generate_random_buffer(chal, 8);
1233
if (lp_client_ntlmv2_auth()) {
1234
DATA_BLOB server_chal;
1235
DATA_BLOB names_blob;
1236
DATA_BLOB nt_response;
1237
DATA_BLOB lm_response;
1238
server_chal = data_blob_talloc(state->mem_ctx, chal, 8);
1240
/* note that the 'workgroup' here is a best guess - we don't know
1241
the server's domain at this point. The 'server name' is also
1244
names_blob = NTLMv2_generate_names_blob(global_myname(), lp_workgroup());
1246
if (!SMBNTLMv2encrypt(name_user, name_domain,
1247
state->request.data.auth.pass,
1250
&lm_response, &nt_response, NULL)) {
1251
data_blob_free(&names_blob);
1252
data_blob_free(&server_chal);
1253
DEBUG(0, ("winbindd_pam_auth: SMBNTLMv2encrypt() failed!\n"));
1254
result = NT_STATUS_NO_MEMORY;
1257
data_blob_free(&names_blob);
1258
data_blob_free(&server_chal);
1259
lm_resp = data_blob_talloc(state->mem_ctx, lm_response.data,
1260
lm_response.length);
1261
nt_resp = data_blob_talloc(state->mem_ctx, nt_response.data,
1262
nt_response.length);
1263
data_blob_free(&lm_response);
1264
data_blob_free(&nt_response);
1267
if (lp_client_lanman_auth()
1268
&& SMBencrypt(state->request.data.auth.pass,
1270
local_lm_response)) {
1271
lm_resp = data_blob_talloc(state->mem_ctx,
1273
sizeof(local_lm_response));
1275
lm_resp = data_blob_null;
1277
SMBNTencrypt(state->request.data.auth.pass,
1281
nt_resp = data_blob_talloc(state->mem_ctx,
1283
sizeof(local_nt_response));
1286
/* what domain should we contact? */
1289
if (!(contact_domain = find_domain_from_name(name_domain))) {
1290
DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
1291
state->request.data.auth.user, name_domain, name_user, name_domain));
1292
result = NT_STATUS_NO_SUCH_USER;
1297
if (is_myname(name_domain)) {
1298
DEBUG(3, ("Authentication for domain %s (local domain to this server) not supported at this stage\n", name_domain));
1299
result = NT_STATUS_NO_SUCH_USER;
1303
contact_domain = find_our_domain();
1306
/* check authentication loop */
1309
netlogon_fn_t logon_fn;
1311
ZERO_STRUCTP(my_info3);
1314
result = cm_connect_netlogon(contact_domain, &netlogon_pipe);
1316
if (!NT_STATUS_IS_OK(result)) {
1317
DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
1321
/* It is really important to try SamLogonEx here,
1322
* because in a clustered environment, we want to use
1323
* one machine account from multiple physical
1326
* With a normal SamLogon call, we must keep the
1327
* credentials chain updated and intact between all
1328
* users of the machine account (which would imply
1329
* cross-node communication for every NTLM logon).
1331
* (The credentials chain is not per NETLOGON pipe
1332
* connection, but globally on the server/client pair
1335
* When using SamLogonEx, the credentials are not
1336
* supplied, but the session key is implied by the
1337
* wrapping SamLogon context.
1339
* -- abartlet 21 April 2008
1342
logon_fn = contact_domain->can_do_samlogon_ex
1343
? rpccli_netlogon_sam_network_logon_ex
1344
: rpccli_netlogon_sam_network_logon;
1346
result = logon_fn(netlogon_pipe,
1349
contact_domain->dcname, /* server name */
1350
name_user, /* user name */
1351
name_domain, /* target domain */
1352
global_myname(), /* workstation */
1359
if ((NT_STATUS_V(result) == DCERPC_FAULT_OP_RNG_ERROR)
1360
&& contact_domain->can_do_samlogon_ex) {
1361
DEBUG(3, ("Got a DC that can not do NetSamLogonEx, "
1362
"retrying with NetSamLogon\n"));
1363
contact_domain->can_do_samlogon_ex = false;
1368
/* We have to try a second time as cm_connect_netlogon
1369
might not yet have noticed that the DC has killed
1372
if (!rpccli_is_connected(netlogon_pipe)) {
1377
/* if we get access denied, a possible cause was that we had
1378
and open connection to the DC, but someone changed our
1379
machine account password out from underneath us using 'net
1380
rpc changetrustpw' */
1382
if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
1383
DEBUG(3,("winbindd_pam_auth: sam_logon returned "
1384
"ACCESS_DENIED. Maybe the trust account "
1385
"password was changed and we didn't know it. "
1386
"Killing connections to domain %s\n",
1388
invalidate_cm_connection(&contact_domain->conn);
1392
} while ( (attempts < 2) && retry );
1394
/* handle the case where a NT4 DC does not fill in the acct_flags in
1395
* the samlogon reply info3. When accurate info3 is required by the
1396
* caller, we look up the account flags ourselve - gd */
1398
if ((state->request.flags & WBFLAG_PAM_INFO3_TEXT) &&
1399
NT_STATUS_IS_OK(result) && (my_info3->base.acct_flags == 0)) {
1401
struct rpc_pipe_client *samr_pipe;
1402
struct policy_handle samr_domain_handle, user_pol;
1403
union samr_UserInfo *info = NULL;
1404
NTSTATUS status_tmp;
1407
status_tmp = cm_connect_sam(contact_domain, state->mem_ctx,
1408
&samr_pipe, &samr_domain_handle);
1410
if (!NT_STATUS_IS_OK(status_tmp)) {
1411
DEBUG(3, ("could not open handle to SAMR pipe: %s\n",
1412
nt_errstr(status_tmp)));
1416
status_tmp = rpccli_samr_OpenUser(samr_pipe, state->mem_ctx,
1417
&samr_domain_handle,
1418
MAXIMUM_ALLOWED_ACCESS,
1422
if (!NT_STATUS_IS_OK(status_tmp)) {
1423
DEBUG(3, ("could not open user handle on SAMR pipe: %s\n",
1424
nt_errstr(status_tmp)));
1428
status_tmp = rpccli_samr_QueryUserInfo(samr_pipe, state->mem_ctx,
1433
if (!NT_STATUS_IS_OK(status_tmp)) {
1434
DEBUG(3, ("could not query user info on SAMR pipe: %s\n",
1435
nt_errstr(status_tmp)));
1436
rpccli_samr_Close(samr_pipe, state->mem_ctx, &user_pol);
1440
acct_flags = info->info16.acct_flags;
1442
if (acct_flags == 0) {
1443
rpccli_samr_Close(samr_pipe, state->mem_ctx, &user_pol);
1447
my_info3->base.acct_flags = acct_flags;
1449
DEBUG(10,("successfully retrieved acct_flags 0x%x\n", acct_flags));
1451
rpccli_samr_Close(samr_pipe, state->mem_ctx, &user_pol);
1459
enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain,
1460
struct winbindd_cli_state *state)
1462
NTSTATUS result = NT_STATUS_LOGON_FAILURE;
1463
NTSTATUS krb5_result = NT_STATUS_OK;
1464
fstring name_domain, name_user;
1466
fstring domain_user;
1467
struct netr_SamInfo3 *info3 = NULL;
1468
NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL;
1470
/* Ensure null termination */
1471
state->request.data.auth.user[sizeof(state->request.data.auth.user)-1]='\0';
1473
/* Ensure null termination */
1474
state->request.data.auth.pass[sizeof(state->request.data.auth.pass)-1]='\0';
1476
DEBUG(3, ("[%5lu]: dual pam auth %s\n", (unsigned long)state->pid,
1477
state->request.data.auth.user));
1479
if (!check_request_flags(state->request.flags)) {
1480
result = NT_STATUS_INVALID_PARAMETER_MIX;
1484
/* Parse domain and username */
1486
name_map_status = normalize_name_unmap(state->mem_ctx,
1487
state->request.data.auth.user,
1490
/* If the name normalization didnt' actually do anything,
1491
just use the original name */
1493
if (!NT_STATUS_IS_OK(name_map_status) &&
1494
!NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED))
1496
mapped_user = state->request.data.auth.user;
1499
parse_domain_user(mapped_user, name_domain, name_user);
1501
if ( mapped_user != state->request.data.auth.user ) {
1502
fstr_sprintf( domain_user, "%s\\%s", name_domain, name_user );
1503
safe_strcpy( state->request.data.auth.user, domain_user,
1504
sizeof(state->request.data.auth.user)-1 );
1507
if (domain->online == false) {
1508
result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
1509
if (domain->startup) {
1510
/* Logons are very important to users. If we're offline and
1511
we get a request within the first 30 seconds of startup,
1512
try very hard to find a DC and go online. */
1514
DEBUG(10,("winbindd_dual_pam_auth: domain: %s offline and auth "
1515
"request in startup mode.\n", domain->name ));
1517
winbindd_flush_negative_conn_cache(domain);
1518
result = init_dc_connection(domain);
1522
DEBUG(10,("winbindd_dual_pam_auth: domain: %s last was %s\n", domain->name, domain->online ? "online":"offline"));
1524
/* Check for Kerberos authentication */
1525
if (domain->online && (state->request.flags & WBFLAG_PAM_KRB5)) {
1527
result = winbindd_dual_pam_auth_kerberos(domain, state, &info3);
1528
/* save for later */
1529
krb5_result = result;
1532
if (NT_STATUS_IS_OK(result)) {
1533
DEBUG(10,("winbindd_dual_pam_auth_kerberos succeeded\n"));
1534
goto process_result;
1536
DEBUG(10,("winbindd_dual_pam_auth_kerberos failed: %s\n", nt_errstr(result)));
1539
if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
1540
NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
1541
NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1542
DEBUG(10,("winbindd_dual_pam_auth_kerberos setting domain to offline\n"));
1543
set_domain_offline( domain );
1547
/* there are quite some NT_STATUS errors where there is no
1548
* point in retrying with a samlogon, we explictly have to take
1549
* care not to increase the bad logon counter on the DC */
1551
if (NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_DISABLED) ||
1552
NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_EXPIRED) ||
1553
NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_LOCKED_OUT) ||
1554
NT_STATUS_EQUAL(result, NT_STATUS_INVALID_LOGON_HOURS) ||
1555
NT_STATUS_EQUAL(result, NT_STATUS_INVALID_WORKSTATION) ||
1556
NT_STATUS_EQUAL(result, NT_STATUS_LOGON_FAILURE) ||
1557
NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER) ||
1558
NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_EXPIRED) ||
1559
NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_MUST_CHANGE) ||
1560
NT_STATUS_EQUAL(result, NT_STATUS_WRONG_PASSWORD)) {
1561
goto process_result;
1564
if (state->request.flags & WBFLAG_PAM_FALLBACK_AFTER_KRB5) {
1565
DEBUG(3,("falling back to samlogon\n"));
1573
/* Check for Samlogon authentication */
1574
if (domain->online) {
1575
result = winbindd_dual_pam_auth_samlogon(domain, state, &info3);
1577
if (NT_STATUS_IS_OK(result)) {
1578
DEBUG(10,("winbindd_dual_pam_auth_samlogon succeeded\n"));
1579
/* add the Krb5 err if we have one */
1580
if ( NT_STATUS_EQUAL(krb5_result, NT_STATUS_TIME_DIFFERENCE_AT_DC ) ) {
1581
info3->base.user_flags |= LOGON_KRB5_FAIL_CLOCK_SKEW;
1583
goto process_result;
1586
DEBUG(10,("winbindd_dual_pam_auth_samlogon failed: %s\n",
1587
nt_errstr(result)));
1589
if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
1590
NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
1591
NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND))
1593
DEBUG(10,("winbindd_dual_pam_auth_samlogon setting domain to offline\n"));
1594
set_domain_offline( domain );
1598
if (domain->online) {
1599
/* We're still online - fail. */
1605
/* Check for Cached logons */
1606
if (!domain->online && (state->request.flags & WBFLAG_PAM_CACHED_LOGIN) &&
1607
lp_winbind_offline_logon()) {
1609
result = winbindd_dual_pam_auth_cached(domain, state, &info3);
1611
if (NT_STATUS_IS_OK(result)) {
1612
DEBUG(10,("winbindd_dual_pam_auth_cached succeeded\n"));
1613
goto process_result;
1615
DEBUG(10,("winbindd_dual_pam_auth_cached failed: %s\n", nt_errstr(result)));
1622
if (NT_STATUS_IS_OK(result)) {
1626
/* In all codepaths where result == NT_STATUS_OK info3 must have
1627
been initialized. */
1629
result = NT_STATUS_INTERNAL_ERROR;
1633
wcache_invalidate_samlogon(find_domain_from_name(name_domain), info3);
1634
netsamlogon_cache_store(name_user, info3);
1636
/* save name_to_sid info as early as possible (only if
1637
this is our primary domain so we don't invalidate
1638
the cache entry by storing the seq_num for the wrong
1640
if ( domain->primary ) {
1641
sid_compose(&user_sid, info3->base.domain_sid,
1643
cache_name2sid(domain, name_domain, name_user,
1644
SID_NAME_USER, &user_sid);
1647
/* Check if the user is in the right group */
1649
if (!NT_STATUS_IS_OK(result = check_info3_in_group(state->mem_ctx, info3,
1650
state->request.data.auth.require_membership_of_sid))) {
1651
DEBUG(3, ("User %s is not in the required group (%s), so plaintext authentication is rejected\n",
1652
state->request.data.auth.user,
1653
state->request.data.auth.require_membership_of_sid));
1657
result = append_data(state, info3, name_domain, name_user);
1658
if (!NT_STATUS_IS_OK(result)) {
1662
if ((state->request.flags & WBFLAG_PAM_CACHED_LOGIN)) {
1664
/* Store in-memory creds for single-signon using ntlm_auth. */
1665
result = winbindd_add_memory_creds(state->request.data.auth.user,
1666
get_uid_from_state(state),
1667
state->request.data.auth.pass);
1669
if (!NT_STATUS_IS_OK(result)) {
1670
DEBUG(10,("Failed to store memory creds: %s\n", nt_errstr(result)));
1674
if (lp_winbind_offline_logon()) {
1675
result = winbindd_store_creds(domain,
1677
state->request.data.auth.user,
1678
state->request.data.auth.pass,
1680
if (!NT_STATUS_IS_OK(result)) {
1682
/* Release refcount. */
1683
winbindd_delete_memory_creds(state->request.data.auth.user);
1685
DEBUG(10,("Failed to store creds: %s\n", nt_errstr(result)));
1692
if (state->request.flags & WBFLAG_PAM_GET_PWD_POLICY) {
1693
struct winbindd_domain *our_domain = find_our_domain();
1695
/* This is not entirely correct I believe, but it is
1696
consistent. Only apply the password policy settings
1697
too warn users for our own domain. Cannot obtain these
1698
from trusted DCs all the time so don't do it at all.
1701
result = NT_STATUS_NOT_SUPPORTED;
1702
if (our_domain == domain ) {
1703
result = fillup_password_policy(our_domain, state);
1706
if (!NT_STATUS_IS_OK(result)
1707
&& !NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED) )
1709
DEBUG(10,("Failed to get password policies for domain %s: %s\n",
1710
domain->name, nt_errstr(result)));
1715
result = NT_STATUS_OK;
1719
/* give us a more useful (more correct?) error code */
1720
if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
1721
(NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
1722
result = NT_STATUS_NO_LOGON_SERVERS;
1725
set_auth_errors(&state->response, result);
1727
DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, ("Plain-text authentication for user %s returned %s (PAM: %d)\n",
1728
state->request.data.auth.user,
1729
state->response.data.auth.nt_status_string,
1730
state->response.data.auth.pam_error));
1732
return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
1736
/**********************************************************************
1737
Challenge Response Authentication Protocol
1738
**********************************************************************/
1740
void winbindd_pam_auth_crap(struct winbindd_cli_state *state)
1742
struct winbindd_domain *domain = NULL;
1743
const char *domain_name = NULL;
1746
if (!check_request_flags(state->request.flags)) {
1747
result = NT_STATUS_INVALID_PARAMETER_MIX;
1751
if (!state->privileged) {
1752
char *error_string = NULL;
1753
DEBUG(2, ("winbindd_pam_auth_crap: non-privileged access "
1755
DEBUGADD(2, ("winbindd_pam_auth_crap: Ensure permissions "
1756
"on %s are set correctly.\n",
1757
get_winbind_priv_pipe_dir()));
1758
/* send a better message than ACCESS_DENIED */
1759
error_string = talloc_asprintf(state->mem_ctx,
1760
"winbind client not authorized "
1761
"to use winbindd_pam_auth_crap."
1762
" Ensure permissions on %s "
1763
"are set correctly.",
1764
get_winbind_priv_pipe_dir());
1765
fstrcpy(state->response.data.auth.error_string, error_string);
1766
result = NT_STATUS_ACCESS_DENIED;
1770
/* Ensure null termination */
1771
state->request.data.auth_crap.user
1772
[sizeof(state->request.data.auth_crap.user)-1]=0;
1773
state->request.data.auth_crap.domain
1774
[sizeof(state->request.data.auth_crap.domain)-1]=0;
1776
DEBUG(3, ("[%5lu]: pam auth crap domain: [%s] user: %s\n",
1777
(unsigned long)state->pid,
1778
state->request.data.auth_crap.domain,
1779
state->request.data.auth_crap.user));
1781
if (*state->request.data.auth_crap.domain != '\0') {
1782
domain_name = state->request.data.auth_crap.domain;
1783
} else if (lp_winbind_use_default_domain()) {
1784
domain_name = lp_workgroup();
1787
if (domain_name != NULL)
1788
domain = find_auth_domain(state, domain_name);
1790
if (domain != NULL) {
1791
sendto_domain(state, domain);
1795
result = NT_STATUS_NO_SUCH_USER;
1798
set_auth_errors(&state->response, result);
1799
DEBUG(5, ("CRAP authentication for %s\\%s returned %s (PAM: %d)\n",
1800
state->request.data.auth_crap.domain,
1801
state->request.data.auth_crap.user,
1802
state->response.data.auth.nt_status_string,
1803
state->response.data.auth.pam_error));
1804
request_error(state);
1809
enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain,
1810
struct winbindd_cli_state *state)
1813
struct netr_SamInfo3 *info3 = NULL;
1814
struct rpc_pipe_client *netlogon_pipe;
1815
const char *name_user = NULL;
1816
const char *name_domain = NULL;
1817
const char *workstation;
1818
struct winbindd_domain *contact_domain;
1822
DATA_BLOB lm_resp, nt_resp;
1824
/* This is child-only, so no check for privileged access is needed
1827
/* Ensure null termination */
1828
state->request.data.auth_crap.user[sizeof(state->request.data.auth_crap.user)-1]=0;
1829
state->request.data.auth_crap.domain[sizeof(state->request.data.auth_crap.domain)-1]=0;
1831
if (!check_request_flags(state->request.flags)) {
1832
result = NT_STATUS_INVALID_PARAMETER_MIX;
1836
name_user = state->request.data.auth_crap.user;
1838
if (*state->request.data.auth_crap.domain) {
1839
name_domain = state->request.data.auth_crap.domain;
1840
} else if (lp_winbind_use_default_domain()) {
1841
name_domain = lp_workgroup();
1843
DEBUG(5,("no domain specified with username (%s) - failing auth\n",
1845
result = NT_STATUS_NO_SUCH_USER;
1849
DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n", (unsigned long)state->pid,
1850
name_domain, name_user));
1852
if (*state->request.data.auth_crap.workstation) {
1853
workstation = state->request.data.auth_crap.workstation;
1855
workstation = global_myname();
1858
if (state->request.data.auth_crap.lm_resp_len > sizeof(state->request.data.auth_crap.lm_resp)
1859
|| state->request.data.auth_crap.nt_resp_len > sizeof(state->request.data.auth_crap.nt_resp)) {
1860
if (!(state->request.flags & WBFLAG_BIG_NTLMV2_BLOB) ||
1861
state->request.extra_len != state->request.data.auth_crap.nt_resp_len) {
1862
DEBUG(0, ("winbindd_pam_auth_crap: invalid password length %u/%u\n",
1863
state->request.data.auth_crap.lm_resp_len,
1864
state->request.data.auth_crap.nt_resp_len));
1865
result = NT_STATUS_INVALID_PARAMETER;
1870
lm_resp = data_blob_talloc(state->mem_ctx, state->request.data.auth_crap.lm_resp,
1871
state->request.data.auth_crap.lm_resp_len);
1873
if (state->request.flags & WBFLAG_BIG_NTLMV2_BLOB) {
1874
nt_resp = data_blob_talloc(state->mem_ctx,
1875
state->request.extra_data.data,
1876
state->request.data.auth_crap.nt_resp_len);
1878
nt_resp = data_blob_talloc(state->mem_ctx,
1879
state->request.data.auth_crap.nt_resp,
1880
state->request.data.auth_crap.nt_resp_len);
1883
/* what domain should we contact? */
1886
if (!(contact_domain = find_domain_from_name(name_domain))) {
1887
DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
1888
state->request.data.auth_crap.user, name_domain, name_user, name_domain));
1889
result = NT_STATUS_NO_SUCH_USER;
1893
if (is_myname(name_domain)) {
1894
DEBUG(3, ("Authentication for domain %s (local domain to this server) not supported at this stage\n", name_domain));
1895
result = NT_STATUS_NO_SUCH_USER;
1898
contact_domain = find_our_domain();
1902
netlogon_fn_t logon_fn;
1906
netlogon_pipe = NULL;
1907
result = cm_connect_netlogon(contact_domain, &netlogon_pipe);
1909
if (!NT_STATUS_IS_OK(result)) {
1910
DEBUG(3, ("could not open handle to NETLOGON pipe (error: %s)\n",
1911
nt_errstr(result)));
1915
logon_fn = contact_domain->can_do_samlogon_ex
1916
? rpccli_netlogon_sam_network_logon_ex
1917
: rpccli_netlogon_sam_network_logon;
1919
result = logon_fn(netlogon_pipe,
1921
state->request.data.auth_crap.logon_parameters,
1922
contact_domain->dcname,
1925
/* Bug #3248 - found by Stefan Burkei. */
1926
workstation, /* We carefully set this above so use it... */
1927
state->request.data.auth_crap.chal,
1932
if ((NT_STATUS_V(result) == DCERPC_FAULT_OP_RNG_ERROR)
1933
&& contact_domain->can_do_samlogon_ex) {
1934
DEBUG(3, ("Got a DC that can not do NetSamLogonEx, "
1935
"retrying with NetSamLogon\n"));
1936
contact_domain->can_do_samlogon_ex = false;
1943
/* We have to try a second time as cm_connect_netlogon
1944
might not yet have noticed that the DC has killed
1947
if (!rpccli_is_connected(netlogon_pipe)) {
1952
/* if we get access denied, a possible cause was that we had and open
1953
connection to the DC, but someone changed our machine account password
1954
out from underneath us using 'net rpc changetrustpw' */
1956
if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
1957
DEBUG(3,("winbindd_pam_auth: sam_logon returned "
1958
"ACCESS_DENIED. Maybe the trust account "
1959
"password was changed and we didn't know it. "
1960
"Killing connections to domain %s\n",
1962
invalidate_cm_connection(&contact_domain->conn);
1966
} while ( (attempts < 2) && retry );
1968
if (NT_STATUS_IS_OK(result)) {
1970
wcache_invalidate_samlogon(find_domain_from_name(name_domain), info3);
1971
netsamlogon_cache_store(name_user, info3);
1973
/* Check if the user is in the right group */
1975
if (!NT_STATUS_IS_OK(result = check_info3_in_group(state->mem_ctx, info3,
1976
state->request.data.auth_crap.require_membership_of_sid))) {
1977
DEBUG(3, ("User %s is not in the required group (%s), so "
1978
"crap authentication is rejected\n",
1979
state->request.data.auth_crap.user,
1980
state->request.data.auth_crap.require_membership_of_sid));
1984
result = append_data(state, info3, name_domain, name_user);
1985
if (!NT_STATUS_IS_OK(result)) {
1992
/* give us a more useful (more correct?) error code */
1993
if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
1994
(NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
1995
result = NT_STATUS_NO_LOGON_SERVERS;
1998
if (state->request.flags & WBFLAG_PAM_NT_STATUS_SQUASH) {
1999
result = nt_status_squash(result);
2002
set_auth_errors(&state->response, result);
2004
DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
2005
("NTLM CRAP authentication for user [%s]\\[%s] returned %s (PAM: %d)\n",
2008
state->response.data.auth.nt_status_string,
2009
state->response.data.auth.pam_error));
2011
return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2014
/* Change a user password */
2016
void winbindd_pam_chauthtok(struct winbindd_cli_state *state)
2018
fstring domain, user;
2020
struct winbindd_domain *contact_domain;
2021
NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
2023
DEBUG(3, ("[%5lu]: pam chauthtok %s\n", (unsigned long)state->pid,
2024
state->request.data.chauthtok.user));
2028
nt_status = normalize_name_unmap(state->mem_ctx,
2029
state->request.data.chauthtok.user,
2032
/* Update the chauthtok name if we did any mapping */
2034
if (NT_STATUS_IS_OK(nt_status) ||
2035
NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED))
2037
fstrcpy(state->request.data.chauthtok.user, mapped_user);
2040
/* Must pass in state->...chauthtok.user because
2041
canonicalize_username() assumes an fstring(). Since
2042
we have already copied it (if necessary), this is ok. */
2044
if (!canonicalize_username(state->request.data.chauthtok.user, domain, user)) {
2045
set_auth_errors(&state->response, NT_STATUS_NO_SUCH_USER);
2046
DEBUG(5, ("winbindd_pam_chauthtok: canonicalize_username %s failed with %s"
2048
state->request.data.auth.user,
2049
state->response.data.auth.nt_status_string,
2050
state->response.data.auth.pam_error));
2051
request_error(state);
2055
contact_domain = find_domain_from_name(domain);
2056
if (!contact_domain) {
2057
set_auth_errors(&state->response, NT_STATUS_NO_SUCH_USER);
2058
DEBUG(3, ("Cannot change password for [%s] -> [%s]\\[%s] as %s is not a trusted domain\n",
2059
state->request.data.chauthtok.user, domain, user, domain));
2060
request_error(state);
2064
sendto_domain(state, contact_domain);
2067
enum winbindd_result winbindd_dual_pam_chauthtok(struct winbindd_domain *contact_domain,
2068
struct winbindd_cli_state *state)
2071
char *newpass = NULL;
2072
struct policy_handle dom_pol;
2073
struct rpc_pipe_client *cli;
2074
bool got_info = false;
2075
struct samr_DomInfo1 *info = NULL;
2076
struct samr_ChangeReject *reject = NULL;
2077
NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
2078
fstring domain, user;
2080
DEBUG(3, ("[%5lu]: dual pam chauthtok %s\n", (unsigned long)state->pid,
2081
state->request.data.auth.user));
2083
if (!parse_domain_user(state->request.data.chauthtok.user, domain, user)) {
2087
/* Change password */
2089
oldpass = state->request.data.chauthtok.oldpass;
2090
newpass = state->request.data.chauthtok.newpass;
2092
/* Initialize reject reason */
2093
state->response.data.auth.reject_reason = Undefined;
2095
/* Get sam handle */
2097
result = cm_connect_sam(contact_domain, state->mem_ctx, &cli,
2099
if (!NT_STATUS_IS_OK(result)) {
2100
DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
2104
result = rpccli_samr_chgpasswd_user3(cli, state->mem_ctx,
2111
/* Windows 2003 returns NT_STATUS_PASSWORD_RESTRICTION */
2113
if (NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_RESTRICTION) ) {
2115
fill_in_password_policy(&state->response, info);
2117
state->response.data.auth.reject_reason =
2123
/* atm the pidl generated rpccli_samr_ChangePasswordUser3 function will
2124
* return with NT_STATUS_BUFFER_TOO_SMALL for w2k dcs as w2k just
2125
* returns with 4byte error code (NT_STATUS_NOT_SUPPORTED) which is too
2126
* short to comply with the samr_ChangePasswordUser3 idl - gd */
2128
/* only fallback when the chgpasswd_user3 call is not supported */
2129
if ((NT_STATUS_EQUAL(result, NT_STATUS(DCERPC_FAULT_OP_RNG_ERROR))) ||
2130
(NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED)) ||
2131
(NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)) ||
2132
(NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED))) {
2134
DEBUG(10,("Password change with chgpasswd_user3 failed with: %s, retrying chgpasswd_user2\n",
2135
nt_errstr(result)));
2137
result = rpccli_samr_chgpasswd_user2(cli, state->mem_ctx, user, newpass, oldpass);
2139
/* Windows 2000 returns NT_STATUS_ACCOUNT_RESTRICTION.
2140
Map to the same status code as Windows 2003. */
2142
if ( NT_STATUS_EQUAL(NT_STATUS_ACCOUNT_RESTRICTION, result ) ) {
2143
result = NT_STATUS_PASSWORD_RESTRICTION;
2149
if (NT_STATUS_IS_OK(result) && (state->request.flags & WBFLAG_PAM_CACHED_LOGIN)) {
2151
/* Update the single sign-on memory creds. */
2152
result = winbindd_replace_memory_creds(state->request.data.chauthtok.user,
2155
/* When we login from gdm or xdm and password expires,
2156
* we change password, but there are no memory crendentials
2157
* So, winbindd_replace_memory_creds() returns
2158
* NT_STATUS_OBJECT_NAME_NOT_FOUND. This is not a failure.
2161
if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
2162
result = NT_STATUS_OK;
2165
if (!NT_STATUS_IS_OK(result)) {
2166
DEBUG(10,("Failed to replace memory creds: %s\n", nt_errstr(result)));
2167
goto process_result;
2170
if (lp_winbind_offline_logon()) {
2171
result = winbindd_update_creds_by_name(contact_domain,
2172
state->mem_ctx, user,
2174
/* Again, this happens when we login from gdm or xdm
2175
* and the password expires, *BUT* cached crendentials
2176
* doesn't exist. winbindd_update_creds_by_name()
2177
* returns NT_STATUS_NO_SUCH_USER.
2178
* This is not a failure.
2181
if (NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER)) {
2182
result = NT_STATUS_OK;
2185
if (!NT_STATUS_IS_OK(result)) {
2186
DEBUG(10,("Failed to store creds: %s\n", nt_errstr(result)));
2187
goto process_result;
2192
if (!NT_STATUS_IS_OK(result) && !got_info && contact_domain) {
2194
NTSTATUS policy_ret;
2196
policy_ret = fillup_password_policy(contact_domain, state);
2198
/* failure of this is non critical, it will just provide no
2199
* additional information to the client why the change has
2200
* failed - Guenther */
2202
if (!NT_STATUS_IS_OK(policy_ret)) {
2203
DEBUG(10,("Failed to get password policies: %s\n", nt_errstr(policy_ret)));
2204
goto process_result;
2210
set_auth_errors(&state->response, result);
2212
DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
2213
("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
2216
state->response.data.auth.nt_status_string,
2217
state->response.data.auth.pam_error));
2219
return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2222
void winbindd_pam_logoff(struct winbindd_cli_state *state)
2224
struct winbindd_domain *domain;
2225
fstring name_domain, user;
2226
uid_t caller_uid = (uid_t)-1;
2227
uid_t request_uid = state->request.data.logoff.uid;
2229
DEBUG(3, ("[%5lu]: pam logoff %s\n", (unsigned long)state->pid,
2230
state->request.data.logoff.user));
2232
/* Ensure null termination */
2233
state->request.data.logoff.user
2234
[sizeof(state->request.data.logoff.user)-1]='\0';
2236
state->request.data.logoff.krb5ccname
2237
[sizeof(state->request.data.logoff.krb5ccname)-1]='\0';
2239
if (request_uid == (gid_t)-1) {
2243
if (!canonicalize_username(state->request.data.logoff.user, name_domain, user)) {
2247
if ((domain = find_auth_domain(state, name_domain)) == NULL) {
2251
if ((sys_getpeereid(state->sock, &caller_uid)) != 0) {
2252
DEBUG(1,("winbindd_pam_logoff: failed to check peerid: %s\n",
2257
switch (caller_uid) {
2261
/* root must be able to logoff any user - gd */
2262
state->request.data.logoff.uid = request_uid;
2265
if (caller_uid != request_uid) {
2266
DEBUG(1,("winbindd_pam_logoff: caller requested invalid uid\n"));
2269
state->request.data.logoff.uid = caller_uid;
2273
sendto_domain(state, domain);
2277
set_auth_errors(&state->response, NT_STATUS_NO_SUCH_USER);
2278
DEBUG(5, ("Pam Logoff for %s returned %s "
2280
state->request.data.logoff.user,
2281
state->response.data.auth.nt_status_string,
2282
state->response.data.auth.pam_error));
2283
request_error(state);
2287
enum winbindd_result winbindd_dual_pam_logoff(struct winbindd_domain *domain,
2288
struct winbindd_cli_state *state)
2290
NTSTATUS result = NT_STATUS_NOT_SUPPORTED;
2292
DEBUG(3, ("[%5lu]: pam dual logoff %s\n", (unsigned long)state->pid,
2293
state->request.data.logoff.user));
2295
if (!(state->request.flags & WBFLAG_PAM_KRB5)) {
2296
result = NT_STATUS_OK;
2297
goto process_result;
2300
if (state->request.data.logoff.krb5ccname[0] == '\0') {
2301
result = NT_STATUS_OK;
2302
goto process_result;
2307
if (state->request.data.logoff.uid < 0) {
2308
DEBUG(0,("winbindd_pam_logoff: invalid uid\n"));
2309
goto process_result;
2312
/* what we need here is to find the corresponding krb5 ccache name *we*
2313
* created for a given username and destroy it */
2315
if (!ccache_entry_exists(state->request.data.logoff.user)) {
2316
result = NT_STATUS_OK;
2317
DEBUG(10,("winbindd_pam_logoff: no entry found.\n"));
2318
goto process_result;
2321
if (!ccache_entry_identical(state->request.data.logoff.user,
2322
state->request.data.logoff.uid,
2323
state->request.data.logoff.krb5ccname)) {
2324
DEBUG(0,("winbindd_pam_logoff: cached entry differs.\n"));
2325
goto process_result;
2328
result = remove_ccache(state->request.data.logoff.user);
2329
if (!NT_STATUS_IS_OK(result)) {
2330
DEBUG(0,("winbindd_pam_logoff: failed to remove ccache: %s\n",
2331
nt_errstr(result)));
2332
goto process_result;
2336
result = NT_STATUS_NOT_SUPPORTED;
2341
winbindd_delete_memory_creds(state->request.data.logoff.user);
2343
set_auth_errors(&state->response, result);
2345
return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2348
/* Change user password with auth crap*/
2350
void winbindd_pam_chng_pswd_auth_crap(struct winbindd_cli_state *state)
2352
struct winbindd_domain *domain = NULL;
2353
const char *domain_name = NULL;
2355
/* Ensure null termination */
2356
state->request.data.chng_pswd_auth_crap.user[
2357
sizeof(state->request.data.chng_pswd_auth_crap.user)-1]=0;
2358
state->request.data.chng_pswd_auth_crap.domain[
2359
sizeof(state->request.data.chng_pswd_auth_crap.domain)-1]=0;
2361
DEBUG(3, ("[%5lu]: pam change pswd auth crap domain: %s user: %s\n",
2362
(unsigned long)state->pid,
2363
state->request.data.chng_pswd_auth_crap.domain,
2364
state->request.data.chng_pswd_auth_crap.user));
2366
if (*state->request.data.chng_pswd_auth_crap.domain != '\0') {
2367
domain_name = state->request.data.chng_pswd_auth_crap.domain;
2368
} else if (lp_winbind_use_default_domain()) {
2369
domain_name = lp_workgroup();
2372
if (domain_name != NULL)
2373
domain = find_domain_from_name(domain_name);
2375
if (domain != NULL) {
2376
DEBUG(7, ("[%5lu]: pam auth crap changing pswd in domain: "
2377
"%s\n", (unsigned long)state->pid,domain->name));
2378
sendto_domain(state, domain);
2382
set_auth_errors(&state->response, NT_STATUS_NO_SUCH_USER);
2383
DEBUG(5, ("CRAP change password for %s\\%s returned %s (PAM: %d)\n",
2384
state->request.data.chng_pswd_auth_crap.domain,
2385
state->request.data.chng_pswd_auth_crap.user,
2386
state->response.data.auth.nt_status_string,
2387
state->response.data.auth.pam_error));
2388
request_error(state);
2392
enum winbindd_result winbindd_dual_pam_chng_pswd_auth_crap(struct winbindd_domain *domainSt, struct winbindd_cli_state *state)
2395
DATA_BLOB new_nt_password;
2396
DATA_BLOB old_nt_hash_enc;
2397
DATA_BLOB new_lm_password;
2398
DATA_BLOB old_lm_hash_enc;
2399
fstring domain,user;
2400
struct policy_handle dom_pol;
2401
struct winbindd_domain *contact_domain = domainSt;
2402
struct rpc_pipe_client *cli;
2404
/* Ensure null termination */
2405
state->request.data.chng_pswd_auth_crap.user[
2406
sizeof(state->request.data.chng_pswd_auth_crap.user)-1]=0;
2407
state->request.data.chng_pswd_auth_crap.domain[
2408
sizeof(state->request.data.chng_pswd_auth_crap.domain)-1]=0;
2412
DEBUG(3, ("[%5lu]: pam change pswd auth crap domain: %s user: %s\n",
2413
(unsigned long)state->pid,
2414
state->request.data.chng_pswd_auth_crap.domain,
2415
state->request.data.chng_pswd_auth_crap.user));
2417
if (lp_winbind_offline_logon()) {
2418
DEBUG(0,("Refusing password change as winbind offline logons are enabled. "));
2419
DEBUGADD(0,("Changing passwords here would risk inconsistent logons\n"));
2420
result = NT_STATUS_ACCESS_DENIED;
2424
if (*state->request.data.chng_pswd_auth_crap.domain) {
2425
fstrcpy(domain,state->request.data.chng_pswd_auth_crap.domain);
2427
parse_domain_user(state->request.data.chng_pswd_auth_crap.user,
2431
DEBUG(3,("no domain specified with username (%s) - "
2433
state->request.data.chng_pswd_auth_crap.user));
2434
result = NT_STATUS_NO_SUCH_USER;
2439
if (!*domain && lp_winbind_use_default_domain()) {
2440
fstrcpy(domain,(char *)lp_workgroup());
2444
fstrcpy(user, state->request.data.chng_pswd_auth_crap.user);
2447
DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n",
2448
(unsigned long)state->pid, domain, user));
2450
/* Change password */
2451
new_nt_password = data_blob_talloc(
2453
state->request.data.chng_pswd_auth_crap.new_nt_pswd,
2454
state->request.data.chng_pswd_auth_crap.new_nt_pswd_len);
2456
old_nt_hash_enc = data_blob_talloc(
2458
state->request.data.chng_pswd_auth_crap.old_nt_hash_enc,
2459
state->request.data.chng_pswd_auth_crap.old_nt_hash_enc_len);
2461
if(state->request.data.chng_pswd_auth_crap.new_lm_pswd_len > 0) {
2462
new_lm_password = data_blob_talloc(
2464
state->request.data.chng_pswd_auth_crap.new_lm_pswd,
2465
state->request.data.chng_pswd_auth_crap.new_lm_pswd_len);
2467
old_lm_hash_enc = data_blob_talloc(
2469
state->request.data.chng_pswd_auth_crap.old_lm_hash_enc,
2470
state->request.data.chng_pswd_auth_crap.old_lm_hash_enc_len);
2472
new_lm_password.length = 0;
2473
old_lm_hash_enc.length = 0;
2476
/* Get sam handle */
2478
result = cm_connect_sam(contact_domain, state->mem_ctx, &cli, &dom_pol);
2479
if (!NT_STATUS_IS_OK(result)) {
2480
DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
2484
result = rpccli_samr_chng_pswd_auth_crap(
2485
cli, state->mem_ctx, user, new_nt_password, old_nt_hash_enc,
2486
new_lm_password, old_lm_hash_enc);
2490
set_auth_errors(&state->response, result);
2492
DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
2493
("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
2495
state->response.data.auth.nt_status_string,
2496
state->response.data.auth.pam_error));
2498
return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;