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