26fdc5a409a9bfad3ce463036eae1356e1e0fe89
[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
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\\%s", name_domain, name_user );
1562                 safe_strcpy( state->request->data.auth.user, domain_user,
1563                              sizeof(state->request->data.auth.user)-1 );
1564         }
1565
1566         if (domain->online == false) {
1567                 result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
1568                 if (domain->startup) {
1569                         /* Logons are very important to users. If we're offline and
1570                            we get a request within the first 30 seconds of startup,
1571                            try very hard to find a DC and go online. */
1572
1573                         DEBUG(10,("winbindd_dual_pam_auth: domain: %s offline and auth "
1574                                 "request in startup mode.\n", domain->name ));
1575
1576                         winbindd_flush_negative_conn_cache(domain);
1577                         result = init_dc_connection(domain);
1578                 }
1579         }
1580
1581         DEBUG(10,("winbindd_dual_pam_auth: domain: %s last was %s\n", domain->name, domain->online ? "online":"offline"));
1582
1583         /* Check for Kerberos authentication */
1584         if (domain->online && (state->request->flags & WBFLAG_PAM_KRB5)) {
1585
1586                 result = winbindd_dual_pam_auth_kerberos(domain, state, &info3);
1587                 /* save for later */
1588                 krb5_result = result;
1589
1590
1591                 if (NT_STATUS_IS_OK(result)) {
1592                         DEBUG(10,("winbindd_dual_pam_auth_kerberos succeeded\n"));
1593                         goto process_result;
1594                 } else {
1595                         DEBUG(10,("winbindd_dual_pam_auth_kerberos failed: %s\n", nt_errstr(result)));
1596                 }
1597
1598                 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
1599                     NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
1600                     NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1601                         DEBUG(10,("winbindd_dual_pam_auth_kerberos setting domain to offline\n"));
1602                         set_domain_offline( domain );
1603                         goto cached_logon;
1604                 }
1605
1606                 /* there are quite some NT_STATUS errors where there is no
1607                  * point in retrying with a samlogon, we explictly have to take
1608                  * care not to increase the bad logon counter on the DC */
1609
1610                 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_DISABLED) ||
1611                     NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_EXPIRED) ||
1612                     NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_LOCKED_OUT) ||
1613                     NT_STATUS_EQUAL(result, NT_STATUS_INVALID_LOGON_HOURS) ||
1614                     NT_STATUS_EQUAL(result, NT_STATUS_INVALID_WORKSTATION) ||
1615                     NT_STATUS_EQUAL(result, NT_STATUS_LOGON_FAILURE) ||
1616                     NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER) ||
1617                     NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_EXPIRED) ||
1618                     NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_MUST_CHANGE) ||
1619                     NT_STATUS_EQUAL(result, NT_STATUS_WRONG_PASSWORD)) {
1620                         goto process_result;
1621                 }
1622
1623                 if (state->request->flags & WBFLAG_PAM_FALLBACK_AFTER_KRB5) {
1624                         DEBUG(3,("falling back to samlogon\n"));
1625                         goto sam_logon;
1626                 } else {
1627                         goto cached_logon;
1628                 }
1629         }
1630
1631 sam_logon:
1632         /* Check for Samlogon authentication */
1633         if (domain->online) {
1634                 result = winbindd_dual_pam_auth_samlogon(domain, state, &info3);
1635
1636                 if (NT_STATUS_IS_OK(result)) {
1637                         DEBUG(10,("winbindd_dual_pam_auth_samlogon succeeded\n"));
1638                         /* add the Krb5 err if we have one */
1639                         if ( NT_STATUS_EQUAL(krb5_result, NT_STATUS_TIME_DIFFERENCE_AT_DC ) ) {
1640                                 info3->base.user_flags |= LOGON_KRB5_FAIL_CLOCK_SKEW;
1641                         }
1642                         goto process_result;
1643                 }
1644
1645                 DEBUG(10,("winbindd_dual_pam_auth_samlogon failed: %s\n",
1646                           nt_errstr(result)));
1647
1648                 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
1649                     NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
1650                     NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND))
1651                 {
1652                         DEBUG(10,("winbindd_dual_pam_auth_samlogon setting domain to offline\n"));
1653                         set_domain_offline( domain );
1654                         goto cached_logon;
1655                 }
1656
1657                         if (domain->online) {
1658                                 /* We're still online - fail. */
1659                                 goto done;
1660                         }
1661         }
1662
1663 cached_logon:
1664         /* Check for Cached logons */
1665         if (!domain->online && (state->request->flags & WBFLAG_PAM_CACHED_LOGIN) &&
1666             lp_winbind_offline_logon()) {
1667
1668                 result = winbindd_dual_pam_auth_cached(domain, state, &info3);
1669
1670                 if (NT_STATUS_IS_OK(result)) {
1671                         DEBUG(10,("winbindd_dual_pam_auth_cached succeeded\n"));
1672                         goto process_result;
1673                 } else {
1674                         DEBUG(10,("winbindd_dual_pam_auth_cached failed: %s\n", nt_errstr(result)));
1675                         goto done;
1676                 }
1677         }
1678
1679 process_result:
1680
1681         if (NT_STATUS_IS_OK(result)) {
1682
1683                 DOM_SID user_sid;
1684
1685                 /* In all codepaths where result == NT_STATUS_OK info3 must have
1686                    been initialized. */
1687                 if (!info3) {
1688                         result = NT_STATUS_INTERNAL_ERROR;
1689                         goto done;
1690                 }
1691
1692                 wcache_invalidate_samlogon(find_domain_from_name(name_domain), info3);
1693                 netsamlogon_cache_store(name_user, info3);
1694
1695                 /* save name_to_sid info as early as possible (only if
1696                    this is our primary domain so we don't invalidate
1697                    the cache entry by storing the seq_num for the wrong
1698                    domain). */
1699                 if ( domain->primary ) {
1700                         sid_compose(&user_sid, info3->base.domain_sid,
1701                                     info3->base.rid);
1702                         cache_name2sid(domain, name_domain, name_user,
1703                                        SID_NAME_USER, &user_sid);
1704                 }
1705
1706                 /* Check if the user is in the right group */
1707
1708                 result = check_info3_in_group(
1709                         info3,
1710                         state->request->data.auth.require_membership_of_sid);
1711                 if (!NT_STATUS_IS_OK(result)) {
1712                         DEBUG(3, ("User %s is not in the required group (%s), so plaintext authentication is rejected\n",
1713                                   state->request->data.auth.user,
1714                                   state->request->data.auth.require_membership_of_sid));
1715                         goto done;
1716                 }
1717
1718                 result = append_auth_data(state, info3, name_domain,
1719                                           name_user);
1720                 if (!NT_STATUS_IS_OK(result)) {
1721                         goto done;
1722                 }
1723
1724                 if ((state->request->flags & WBFLAG_PAM_CACHED_LOGIN)) {
1725
1726                         /* Store in-memory creds for single-signon using ntlm_auth. */
1727                         result = winbindd_add_memory_creds(state->request->data.auth.user,
1728                                                         get_uid_from_state(state),
1729                                                         state->request->data.auth.pass);
1730
1731                         if (!NT_STATUS_IS_OK(result)) {
1732                                 DEBUG(10,("Failed to store memory creds: %s\n", nt_errstr(result)));
1733                                 goto done;
1734                         }
1735
1736                         if (lp_winbind_offline_logon()) {
1737                                 result = winbindd_store_creds(domain,
1738                                                       state->mem_ctx,
1739                                                       state->request->data.auth.user,
1740                                                       state->request->data.auth.pass,
1741                                                       info3, NULL);
1742                                 if (!NT_STATUS_IS_OK(result)) {
1743
1744                                         /* Release refcount. */
1745                                         winbindd_delete_memory_creds(state->request->data.auth.user);
1746
1747                                         DEBUG(10,("Failed to store creds: %s\n", nt_errstr(result)));
1748                                         goto done;
1749                                 }
1750                         }
1751                 }
1752
1753
1754                 if (state->request->flags & WBFLAG_PAM_GET_PWD_POLICY) {
1755                         struct winbindd_domain *our_domain = find_our_domain();
1756
1757                         /* This is not entirely correct I believe, but it is
1758                            consistent.  Only apply the password policy settings
1759                            too warn users for our own domain.  Cannot obtain these
1760                            from trusted DCs all the  time so don't do it at all.
1761                            -- jerry */
1762
1763                         result = NT_STATUS_NOT_SUPPORTED;
1764                         if (our_domain == domain ) {
1765                                 result = fillup_password_policy(our_domain, state);
1766                         }
1767
1768                         if (!NT_STATUS_IS_OK(result)
1769                             && !NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED) )
1770                         {
1771                                 DEBUG(10,("Failed to get password policies for domain %s: %s\n",
1772                                           domain->name, nt_errstr(result)));
1773                                 goto done;
1774                         }
1775                 }
1776
1777                 result = NT_STATUS_OK;
1778         }
1779
1780 done:
1781         /* give us a more useful (more correct?) error code */
1782         if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
1783             (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
1784                 result = NT_STATUS_NO_LOGON_SERVERS;
1785         }
1786
1787         set_auth_errors(state->response, result);
1788
1789         DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, ("Plain-text authentication for user %s returned %s (PAM: %d)\n",
1790               state->request->data.auth.user,
1791               state->response->data.auth.nt_status_string,
1792               state->response->data.auth.pam_error));
1793
1794         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
1795 }
1796
1797
1798 /**********************************************************************
1799  Challenge Response Authentication Protocol
1800 **********************************************************************/
1801
1802 void winbindd_pam_auth_crap(struct winbindd_cli_state *state)
1803 {
1804         struct winbindd_domain *domain = NULL;
1805         const char *domain_name = NULL;
1806         NTSTATUS result;
1807
1808         if (!check_request_flags(state->request->flags)) {
1809                 result = NT_STATUS_INVALID_PARAMETER_MIX;
1810                 goto done;
1811         }
1812
1813         if (!state->privileged) {
1814                 DEBUG(2, ("winbindd_pam_auth_crap: non-privileged access "
1815                           "denied.  !\n"));
1816                 DEBUGADD(2, ("winbindd_pam_auth_crap: Ensure permissions "
1817                              "on %s are set correctly.\n",
1818                              get_winbind_priv_pipe_dir()));
1819                 /* send a better message than ACCESS_DENIED */
1820                 fstr_sprintf(state->response->data.auth.error_string,
1821                              "winbind client not authorized to use "
1822                              "winbindd_pam_auth_crap. Ensure permissions on "
1823                              "%s are set correctly.",
1824                              get_winbind_priv_pipe_dir());
1825                 result = NT_STATUS_ACCESS_DENIED;
1826                 goto done;
1827         }
1828
1829         /* Ensure null termination */
1830         state->request->data.auth_crap.user
1831                 [sizeof(state->request->data.auth_crap.user)-1]=0;
1832         state->request->data.auth_crap.domain
1833                 [sizeof(state->request->data.auth_crap.domain)-1]=0;
1834
1835         DEBUG(3, ("[%5lu]: pam auth crap domain: [%s] user: %s\n",
1836                   (unsigned long)state->pid,
1837                   state->request->data.auth_crap.domain,
1838                   state->request->data.auth_crap.user));
1839
1840         if (*state->request->data.auth_crap.domain != '\0') {
1841                 domain_name = state->request->data.auth_crap.domain;
1842         } else if (lp_winbind_use_default_domain()) {
1843                 domain_name = lp_workgroup();
1844         }
1845
1846         if (domain_name != NULL)
1847                 domain = find_auth_domain(state->request->flags, domain_name);
1848
1849         if (domain != NULL) {
1850                 sendto_domain(state, domain);
1851                 return;
1852         }
1853
1854         result = NT_STATUS_NO_SUCH_USER;
1855
1856  done:
1857         set_auth_errors(state->response, result);
1858         DEBUG(5, ("CRAP authentication for %s\\%s returned %s (PAM: %d)\n",
1859                   state->request->data.auth_crap.domain,
1860                   state->request->data.auth_crap.user,
1861                   state->response->data.auth.nt_status_string,
1862                   state->response->data.auth.pam_error));
1863         request_error(state);
1864         return;
1865 }
1866
1867
1868 enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain,
1869                                                  struct winbindd_cli_state *state)
1870 {
1871         NTSTATUS result;
1872         struct netr_SamInfo3 *info3 = NULL;
1873         struct rpc_pipe_client *netlogon_pipe;
1874         const char *name_user = NULL;
1875         const char *name_domain = NULL;
1876         const char *workstation;
1877         struct winbindd_domain *contact_domain;
1878         int attempts = 0;
1879         bool retry;
1880
1881         DATA_BLOB lm_resp, nt_resp;
1882
1883         /* This is child-only, so no check for privileged access is needed
1884            anymore */
1885
1886         /* Ensure null termination */
1887         state->request->data.auth_crap.user[sizeof(state->request->data.auth_crap.user)-1]=0;
1888         state->request->data.auth_crap.domain[sizeof(state->request->data.auth_crap.domain)-1]=0;
1889
1890         if (!check_request_flags(state->request->flags)) {
1891                 result = NT_STATUS_INVALID_PARAMETER_MIX;
1892                 goto done;
1893         }
1894
1895         name_user = state->request->data.auth_crap.user;
1896
1897         if (*state->request->data.auth_crap.domain) {
1898                 name_domain = state->request->data.auth_crap.domain;
1899         } else if (lp_winbind_use_default_domain()) {
1900                 name_domain = lp_workgroup();
1901         } else {
1902                 DEBUG(5,("no domain specified with username (%s) - failing auth\n",
1903                          name_user));
1904                 result = NT_STATUS_NO_SUCH_USER;
1905                 goto done;
1906         }
1907
1908         DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n", (unsigned long)state->pid,
1909                   name_domain, name_user));
1910
1911         if (*state->request->data.auth_crap.workstation) {
1912                 workstation = state->request->data.auth_crap.workstation;
1913         } else {
1914                 workstation = global_myname();
1915         }
1916
1917         if (state->request->data.auth_crap.lm_resp_len > sizeof(state->request->data.auth_crap.lm_resp)
1918                 || state->request->data.auth_crap.nt_resp_len > sizeof(state->request->data.auth_crap.nt_resp)) {
1919                 if (!(state->request->flags & WBFLAG_BIG_NTLMV2_BLOB) ||
1920                      state->request->extra_len != state->request->data.auth_crap.nt_resp_len) {
1921                         DEBUG(0, ("winbindd_pam_auth_crap: invalid password length %u/%u\n",
1922                                   state->request->data.auth_crap.lm_resp_len,
1923                                   state->request->data.auth_crap.nt_resp_len));
1924                         result = NT_STATUS_INVALID_PARAMETER;
1925                         goto done;
1926                 }
1927         }
1928
1929         lm_resp = data_blob_talloc(state->mem_ctx, state->request->data.auth_crap.lm_resp,
1930                                         state->request->data.auth_crap.lm_resp_len);
1931
1932         if (state->request->flags & WBFLAG_BIG_NTLMV2_BLOB) {
1933                 nt_resp = data_blob_talloc(state->mem_ctx,
1934                                            state->request->extra_data.data,
1935                                            state->request->data.auth_crap.nt_resp_len);
1936         } else {
1937                 nt_resp = data_blob_talloc(state->mem_ctx,
1938                                            state->request->data.auth_crap.nt_resp,
1939                                            state->request->data.auth_crap.nt_resp_len);
1940         }
1941
1942         /* what domain should we contact? */
1943
1944         if ( IS_DC ) {
1945                 if (!(contact_domain = find_domain_from_name(name_domain))) {
1946                         DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
1947                                   state->request->data.auth_crap.user, name_domain, name_user, name_domain));
1948                         result = NT_STATUS_NO_SUCH_USER;
1949                         goto done;
1950                 }
1951         } else {
1952                 if (is_myname(name_domain)) {
1953                         DEBUG(3, ("Authentication for domain %s (local domain to this server) not supported at this stage\n", name_domain));
1954                         result =  NT_STATUS_NO_SUCH_USER;
1955                         goto done;
1956                 }
1957                 contact_domain = find_our_domain();
1958         }
1959
1960         do {
1961                 netlogon_fn_t logon_fn;
1962                 const struct cli_pipe_auth_data *auth;
1963                 uint32_t neg_flags = 0;
1964
1965                 retry = false;
1966
1967                 netlogon_pipe = NULL;
1968                 result = cm_connect_netlogon(contact_domain, &netlogon_pipe);
1969
1970                 if (!NT_STATUS_IS_OK(result)) {
1971                         DEBUG(3, ("could not open handle to NETLOGON pipe (error: %s)\n",
1972                                   nt_errstr(result)));
1973                         goto done;
1974                 }
1975                 auth = netlogon_pipe->auth;
1976                 if (netlogon_pipe->dc) {
1977                         neg_flags = netlogon_pipe->dc->negotiate_flags;
1978                 }
1979
1980                 if (auth == NULL) {
1981                         domain->can_do_validation6 = false;
1982                 } else if (auth->auth_type != PIPE_AUTH_TYPE_SCHANNEL) {
1983                         domain->can_do_validation6 = false;
1984                 } else if (auth->auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
1985                         domain->can_do_validation6 = false;
1986                 } else if (!(neg_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
1987                         domain->can_do_validation6 = false;
1988                 } else if (!(neg_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
1989                         domain->can_do_validation6 = false;
1990                 }
1991
1992                 logon_fn = contact_domain->can_do_samlogon_ex
1993                         ? rpccli_netlogon_sam_network_logon_ex
1994                         : rpccli_netlogon_sam_network_logon;
1995
1996                 result = logon_fn(netlogon_pipe,
1997                                   state->mem_ctx,
1998                                   state->request->data.auth_crap.logon_parameters,
1999                                   contact_domain->dcname,
2000                                   name_user,
2001                                   name_domain,
2002                                   /* Bug #3248 - found by Stefan Burkei. */
2003                                   workstation, /* We carefully set this above so use it... */
2004                                   state->request->data.auth_crap.chal,
2005                                   domain->can_do_validation6 ? 6 : 3,
2006                                   lm_resp,
2007                                   nt_resp,
2008                                   &info3);
2009
2010                 if (NT_STATUS_V(result) == DCERPC_FAULT_OP_RNG_ERROR) {
2011
2012                         /*
2013                          * It's likely that the server also does not support
2014                          * validation level 6
2015                          */
2016                         domain->can_do_validation6 = false;
2017
2018                         if (contact_domain->can_do_samlogon_ex) {
2019                                 DEBUG(3, ("Got a DC that can not do NetSamLogonEx, "
2020                                           "retrying with NetSamLogon\n"));
2021                                 contact_domain->can_do_samlogon_ex = false;
2022                                 retry = true;
2023                                 continue;
2024                         }
2025
2026                         /* Got DCERPC_FAULT_OP_RNG_ERROR for SamLogon
2027                          * (no Ex). This happens against old Samba
2028                          * DCs. Drop the connection.
2029                          */
2030                         invalidate_cm_connection(&contact_domain->conn);
2031                         result = NT_STATUS_LOGON_FAILURE;
2032                         break;
2033                 }
2034
2035                 if (domain->can_do_validation6 &&
2036                     (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
2037                      NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
2038                      NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL))) {
2039                         DEBUG(3,("Got a DC that can not do validation level 6, "
2040                                   "retrying with level 3\n"));
2041                         domain->can_do_validation6 = false;
2042                         retry = true;
2043                         continue;
2044                 }
2045
2046                 /*
2047                  * we increment this after the "feature negotiation"
2048                  * for can_do_samlogon_ex and can_do_validation6
2049                  */
2050                 attempts += 1;
2051
2052                 /* We have to try a second time as cm_connect_netlogon
2053                    might not yet have noticed that the DC has killed
2054                    our connection. */
2055
2056                 if (!rpccli_is_connected(netlogon_pipe)) {
2057                         retry = true;
2058                         continue;
2059                 }
2060
2061                 /* if we get access denied, a possible cause was that we had and open
2062                    connection to the DC, but someone changed our machine account password
2063                    out from underneath us using 'net rpc changetrustpw' */
2064
2065                 if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
2066                         DEBUG(3,("winbindd_pam_auth: sam_logon returned "
2067                                  "ACCESS_DENIED.  Maybe the trust account "
2068                                 "password was changed and we didn't know it. "
2069                                  "Killing connections to domain %s\n",
2070                                 name_domain));
2071                         invalidate_cm_connection(&contact_domain->conn);
2072                         retry = true;
2073                 }
2074
2075         } while ( (attempts < 2) && retry );
2076
2077         if (NT_STATUS_IS_OK(result)) {
2078
2079                 wcache_invalidate_samlogon(find_domain_from_name(name_domain), info3);
2080                 netsamlogon_cache_store(name_user, info3);
2081
2082                 /* Check if the user is in the right group */
2083
2084                 result = check_info3_in_group(
2085                         info3,
2086                         state->request->data.auth_crap.require_membership_of_sid);
2087                 if (!NT_STATUS_IS_OK(result)) {
2088                         DEBUG(3, ("User %s is not in the required group (%s), so "
2089                                   "crap authentication is rejected\n",
2090                                   state->request->data.auth_crap.user,
2091                                   state->request->data.auth_crap.require_membership_of_sid));
2092                         goto done;
2093                 }
2094
2095                 result = append_auth_data(state, info3, name_domain,
2096                                           name_user);
2097                 if (!NT_STATUS_IS_OK(result)) {
2098                         goto done;
2099                 }
2100         }
2101
2102 done:
2103
2104         if (NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT)) {
2105                 DEBUG(3,("winbindd_dual_pam_auth_crap: sam_network_logon(ex) "
2106                                 "returned NT_STATUS_IO_TIMEOUT after the retry."
2107                                 "We didn't know what's going on killing "
2108                                 "connections to domain %s\n",
2109                                 name_domain));
2110                 invalidate_cm_connection(&contact_domain->conn);
2111         }
2112
2113         /* give us a more useful (more correct?) error code */
2114         if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
2115             (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
2116                 result = NT_STATUS_NO_LOGON_SERVERS;
2117         }
2118
2119         if (state->request->flags & WBFLAG_PAM_NT_STATUS_SQUASH) {
2120                 result = nt_status_squash(result);
2121         }
2122
2123         set_auth_errors(state->response, result);
2124
2125         DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
2126               ("NTLM CRAP authentication for user [%s]\\[%s] returned %s (PAM: %d)\n",
2127                name_domain,
2128                name_user,
2129                state->response->data.auth.nt_status_string,
2130                state->response->data.auth.pam_error));
2131
2132         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2133 }
2134
2135 /* Change a user password */
2136
2137 void winbindd_pam_chauthtok(struct winbindd_cli_state *state)
2138 {
2139         fstring domain, user;
2140         char *mapped_user;
2141         struct winbindd_domain *contact_domain;
2142         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
2143
2144         DEBUG(3, ("[%5lu]: pam chauthtok %s\n", (unsigned long)state->pid,
2145                 state->request->data.chauthtok.user));
2146
2147         /* Setup crap */
2148
2149         nt_status = normalize_name_unmap(state->mem_ctx,
2150                                          state->request->data.chauthtok.user,
2151                                          &mapped_user);
2152
2153         /* Update the chauthtok name if we did any mapping */
2154
2155         if (NT_STATUS_IS_OK(nt_status) ||
2156             NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED))
2157         {
2158                 fstrcpy(state->request->data.chauthtok.user, mapped_user);
2159         }
2160
2161         /* Must pass in state->...chauthtok.user because
2162            canonicalize_username() assumes an fstring().  Since
2163            we have already copied it (if necessary), this is ok. */
2164
2165         if (!canonicalize_username(state->request->data.chauthtok.user, domain, user)) {
2166                 set_auth_errors(state->response, NT_STATUS_NO_SUCH_USER);
2167                 DEBUG(5, ("winbindd_pam_chauthtok: canonicalize_username %s failed with %s"
2168                           "(PAM: %d)\n",
2169                           state->request->data.auth.user,
2170                           state->response->data.auth.nt_status_string,
2171                           state->response->data.auth.pam_error));
2172                 request_error(state);
2173                 return;
2174         }
2175
2176         contact_domain = find_domain_from_name(domain);
2177         if (!contact_domain) {
2178                 set_auth_errors(state->response, NT_STATUS_NO_SUCH_USER);
2179                 DEBUG(3, ("Cannot change password for [%s] -> [%s]\\[%s] as %s is not a trusted domain\n",
2180                           state->request->data.chauthtok.user, domain, user, domain));
2181                 request_error(state);
2182                 return;
2183         }
2184
2185         sendto_domain(state, contact_domain);
2186 }
2187
2188 enum winbindd_result winbindd_dual_pam_chauthtok(struct winbindd_domain *contact_domain,
2189                                                  struct winbindd_cli_state *state)
2190 {
2191         char *oldpass;
2192         char *newpass = NULL;
2193         struct policy_handle dom_pol;
2194         struct rpc_pipe_client *cli;
2195         bool got_info = false;
2196         struct samr_DomInfo1 *info = NULL;
2197         struct samr_ChangeReject *reject = NULL;
2198         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
2199         fstring domain, user;
2200
2201         DEBUG(3, ("[%5lu]: dual pam chauthtok %s\n", (unsigned long)state->pid,
2202                   state->request->data.auth.user));
2203
2204         if (!parse_domain_user(state->request->data.chauthtok.user, domain, user)) {
2205                 goto done;
2206         }
2207
2208         /* Change password */
2209
2210         oldpass = state->request->data.chauthtok.oldpass;
2211         newpass = state->request->data.chauthtok.newpass;
2212
2213         /* Initialize reject reason */
2214         state->response->data.auth.reject_reason = Undefined;
2215
2216         /* Get sam handle */
2217
2218         result = cm_connect_sam(contact_domain, state->mem_ctx, &cli,
2219                                 &dom_pol);
2220         if (!NT_STATUS_IS_OK(result)) {
2221                 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
2222                 goto done;
2223         }
2224
2225         result = rpccli_samr_chgpasswd_user3(cli, state->mem_ctx,
2226                                              user,
2227                                              newpass,
2228                                              oldpass,
2229                                              &info,
2230                                              &reject);
2231
2232         /* Windows 2003 returns NT_STATUS_PASSWORD_RESTRICTION */
2233
2234         if (NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_RESTRICTION) ) {
2235
2236                 fill_in_password_policy(state->response, info);
2237
2238                 state->response->data.auth.reject_reason =
2239                         reject->reason;
2240
2241                 got_info = true;
2242         }
2243
2244         /* atm the pidl generated rpccli_samr_ChangePasswordUser3 function will
2245          * return with NT_STATUS_BUFFER_TOO_SMALL for w2k dcs as w2k just
2246          * returns with 4byte error code (NT_STATUS_NOT_SUPPORTED) which is too
2247          * short to comply with the samr_ChangePasswordUser3 idl - gd */
2248
2249         /* only fallback when the chgpasswd_user3 call is not supported */
2250         if ((NT_STATUS_EQUAL(result, NT_STATUS(DCERPC_FAULT_OP_RNG_ERROR))) ||
2251                    (NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED)) ||
2252                    (NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)) ||
2253                    (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED))) {
2254
2255                 DEBUG(10,("Password change with chgpasswd_user3 failed with: %s, retrying chgpasswd_user2\n",
2256                         nt_errstr(result)));
2257
2258                 result = rpccli_samr_chgpasswd_user2(cli, state->mem_ctx, user, newpass, oldpass);
2259
2260                 /* Windows 2000 returns NT_STATUS_ACCOUNT_RESTRICTION.
2261                    Map to the same status code as Windows 2003. */
2262
2263                 if ( NT_STATUS_EQUAL(NT_STATUS_ACCOUNT_RESTRICTION, result ) ) {
2264                         result = NT_STATUS_PASSWORD_RESTRICTION;
2265                 }
2266         }
2267
2268 done:
2269
2270         if (NT_STATUS_IS_OK(result) && (state->request->flags & WBFLAG_PAM_CACHED_LOGIN)) {
2271
2272                 /* Update the single sign-on memory creds. */
2273                 result = winbindd_replace_memory_creds(state->request->data.chauthtok.user,
2274                                                         newpass);
2275
2276                 /* When we login from gdm or xdm and password expires,
2277                  * we change password, but there are no memory crendentials
2278                  * So, winbindd_replace_memory_creds() returns
2279                  * NT_STATUS_OBJECT_NAME_NOT_FOUND. This is not a failure.
2280                  * --- BoYang
2281                  * */
2282                 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
2283                         result = NT_STATUS_OK;
2284                 }
2285
2286                 if (!NT_STATUS_IS_OK(result)) {
2287                         DEBUG(10,("Failed to replace memory creds: %s\n", nt_errstr(result)));
2288                         goto process_result;
2289                 }
2290
2291                 if (lp_winbind_offline_logon()) {
2292                         result = winbindd_update_creds_by_name(contact_domain,
2293                                                          state->mem_ctx, user,
2294                                                          newpass);
2295                         /* Again, this happens when we login from gdm or xdm
2296                          * and the password expires, *BUT* cached crendentials
2297                          * doesn't exist. winbindd_update_creds_by_name()
2298                          * returns NT_STATUS_NO_SUCH_USER.
2299                          * This is not a failure.
2300                          * --- BoYang
2301                          * */
2302                         if (NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER)) {
2303                                 result = NT_STATUS_OK;
2304                         }
2305
2306                         if (!NT_STATUS_IS_OK(result)) {
2307                                 DEBUG(10,("Failed to store creds: %s\n", nt_errstr(result)));
2308                                 goto process_result;
2309                         }
2310                 }
2311         }
2312
2313         if (!NT_STATUS_IS_OK(result) && !got_info && contact_domain) {
2314
2315                 NTSTATUS policy_ret;
2316
2317                 policy_ret = fillup_password_policy(contact_domain, state);
2318
2319                 /* failure of this is non critical, it will just provide no
2320                  * additional information to the client why the change has
2321                  * failed - Guenther */
2322
2323                 if (!NT_STATUS_IS_OK(policy_ret)) {
2324                         DEBUG(10,("Failed to get password policies: %s\n", nt_errstr(policy_ret)));
2325                         goto process_result;
2326                 }
2327         }
2328
2329 process_result:
2330
2331         set_auth_errors(state->response, result);
2332
2333         DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
2334               ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
2335                domain,
2336                user,
2337                state->response->data.auth.nt_status_string,
2338                state->response->data.auth.pam_error));
2339
2340         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2341 }
2342
2343 void winbindd_pam_logoff(struct winbindd_cli_state *state)
2344 {
2345         struct winbindd_domain *domain;
2346         fstring name_domain, user;
2347         uid_t caller_uid = (uid_t)-1;
2348         uid_t request_uid = state->request->data.logoff.uid;
2349
2350         DEBUG(3, ("[%5lu]: pam logoff %s\n", (unsigned long)state->pid,
2351                 state->request->data.logoff.user));
2352
2353         /* Ensure null termination */
2354         state->request->data.logoff.user
2355                 [sizeof(state->request->data.logoff.user)-1]='\0';
2356
2357         state->request->data.logoff.krb5ccname
2358                 [sizeof(state->request->data.logoff.krb5ccname)-1]='\0';
2359
2360         if (request_uid == (gid_t)-1) {
2361                 goto failed;
2362         }
2363
2364         if (!canonicalize_username(state->request->data.logoff.user, name_domain, user)) {
2365                 goto failed;
2366         }
2367
2368         if ((domain = find_auth_domain(state->request->flags,
2369                                        name_domain)) == NULL) {
2370                 goto failed;
2371         }
2372
2373         if ((sys_getpeereid(state->sock, &caller_uid)) != 0) {
2374                 DEBUG(1,("winbindd_pam_logoff: failed to check peerid: %s\n",
2375                         strerror(errno)));
2376                 goto failed;
2377         }
2378
2379         switch (caller_uid) {
2380                 case -1:
2381                         goto failed;
2382                 case 0:
2383                         /* root must be able to logoff any user - gd */
2384                         state->request->data.logoff.uid = request_uid;
2385                         break;
2386                 default:
2387                         if (caller_uid != request_uid) {
2388                                 DEBUG(1,("winbindd_pam_logoff: caller requested invalid uid\n"));
2389                                 goto failed;
2390                         }
2391                         state->request->data.logoff.uid = caller_uid;
2392                         break;
2393         }
2394
2395         sendto_domain(state, domain);
2396         return;
2397
2398  failed:
2399         set_auth_errors(state->response, NT_STATUS_NO_SUCH_USER);
2400         DEBUG(5, ("Pam Logoff for %s returned %s "
2401                   "(PAM: %d)\n",
2402                   state->request->data.logoff.user,
2403                   state->response->data.auth.nt_status_string,
2404                   state->response->data.auth.pam_error));
2405         request_error(state);
2406         return;
2407 }
2408
2409 enum winbindd_result winbindd_dual_pam_logoff(struct winbindd_domain *domain,
2410                                               struct winbindd_cli_state *state)
2411 {
2412         NTSTATUS result = NT_STATUS_NOT_SUPPORTED;
2413
2414         DEBUG(3, ("[%5lu]: pam dual logoff %s\n", (unsigned long)state->pid,
2415                 state->request->data.logoff.user));
2416
2417         if (!(state->request->flags & WBFLAG_PAM_KRB5)) {
2418                 result = NT_STATUS_OK;
2419                 goto process_result;
2420         }
2421
2422         if (state->request->data.logoff.krb5ccname[0] == '\0') {
2423                 result = NT_STATUS_OK;
2424                 goto process_result;
2425         }
2426
2427 #ifdef HAVE_KRB5
2428
2429         if (state->request->data.logoff.uid < 0) {
2430                 DEBUG(0,("winbindd_pam_logoff: invalid uid\n"));
2431                 goto process_result;
2432         }
2433
2434         /* what we need here is to find the corresponding krb5 ccache name *we*
2435          * created for a given username and destroy it */
2436
2437         if (!ccache_entry_exists(state->request->data.logoff.user)) {
2438                 result = NT_STATUS_OK;
2439                 DEBUG(10,("winbindd_pam_logoff: no entry found.\n"));
2440                 goto process_result;
2441         }
2442
2443         if (!ccache_entry_identical(state->request->data.logoff.user,
2444                                         state->request->data.logoff.uid,
2445                                         state->request->data.logoff.krb5ccname)) {
2446                 DEBUG(0,("winbindd_pam_logoff: cached entry differs.\n"));
2447                 goto process_result;
2448         }
2449
2450         result = remove_ccache(state->request->data.logoff.user);
2451         if (!NT_STATUS_IS_OK(result)) {
2452                 DEBUG(0,("winbindd_pam_logoff: failed to remove ccache: %s\n",
2453                         nt_errstr(result)));
2454                 goto process_result;
2455         }
2456
2457 #else
2458         result = NT_STATUS_NOT_SUPPORTED;
2459 #endif
2460
2461 process_result:
2462
2463         winbindd_delete_memory_creds(state->request->data.logoff.user);
2464
2465         set_auth_errors(state->response, result);
2466
2467         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2468 }
2469
2470 /* Change user password with auth crap*/
2471
2472 void winbindd_pam_chng_pswd_auth_crap(struct winbindd_cli_state *state)
2473 {
2474         struct winbindd_domain *domain = NULL;
2475         const char *domain_name = NULL;
2476
2477         /* Ensure null termination */
2478         state->request->data.chng_pswd_auth_crap.user[
2479                 sizeof(state->request->data.chng_pswd_auth_crap.user)-1]=0;
2480         state->request->data.chng_pswd_auth_crap.domain[
2481                 sizeof(state->request->data.chng_pswd_auth_crap.domain)-1]=0;
2482
2483         DEBUG(3, ("[%5lu]: pam change pswd auth crap domain: %s user: %s\n",
2484                   (unsigned long)state->pid,
2485                   state->request->data.chng_pswd_auth_crap.domain,
2486                   state->request->data.chng_pswd_auth_crap.user));
2487
2488         if (*state->request->data.chng_pswd_auth_crap.domain != '\0') {
2489                 domain_name = state->request->data.chng_pswd_auth_crap.domain;
2490         } else if (lp_winbind_use_default_domain()) {
2491                 domain_name = lp_workgroup();
2492         }
2493
2494         if (domain_name != NULL)
2495                 domain = find_domain_from_name(domain_name);
2496
2497         if (domain != NULL) {
2498                 DEBUG(7, ("[%5lu]: pam auth crap changing pswd in domain: "
2499                           "%s\n", (unsigned long)state->pid,domain->name));
2500                 sendto_domain(state, domain);
2501                 return;
2502         }
2503
2504         set_auth_errors(state->response, NT_STATUS_NO_SUCH_USER);
2505         DEBUG(5, ("CRAP change password  for %s\\%s returned %s (PAM: %d)\n",
2506                   state->request->data.chng_pswd_auth_crap.domain,
2507                   state->request->data.chng_pswd_auth_crap.user,
2508                   state->response->data.auth.nt_status_string,
2509                   state->response->data.auth.pam_error));
2510         request_error(state);
2511         return;
2512 }
2513
2514 enum winbindd_result winbindd_dual_pam_chng_pswd_auth_crap(struct winbindd_domain *domainSt, struct winbindd_cli_state *state)
2515 {
2516         NTSTATUS result;
2517         DATA_BLOB new_nt_password;
2518         DATA_BLOB old_nt_hash_enc;
2519         DATA_BLOB new_lm_password;
2520         DATA_BLOB old_lm_hash_enc;
2521         fstring  domain,user;
2522         struct policy_handle dom_pol;
2523         struct winbindd_domain *contact_domain = domainSt;
2524         struct rpc_pipe_client *cli;
2525
2526         /* Ensure null termination */
2527         state->request->data.chng_pswd_auth_crap.user[
2528                 sizeof(state->request->data.chng_pswd_auth_crap.user)-1]=0;
2529         state->request->data.chng_pswd_auth_crap.domain[
2530                 sizeof(state->request->data.chng_pswd_auth_crap.domain)-1]=0;
2531         *domain = 0;
2532         *user = 0;
2533
2534         DEBUG(3, ("[%5lu]: pam change pswd auth crap domain: %s user: %s\n",
2535                   (unsigned long)state->pid,
2536                   state->request->data.chng_pswd_auth_crap.domain,
2537                   state->request->data.chng_pswd_auth_crap.user));
2538
2539         if (lp_winbind_offline_logon()) {
2540                 DEBUG(0,("Refusing password change as winbind offline logons are enabled. "));
2541                 DEBUGADD(0,("Changing passwords here would risk inconsistent logons\n"));
2542                 result = NT_STATUS_ACCESS_DENIED;
2543                 goto done;
2544         }
2545
2546         if (*state->request->data.chng_pswd_auth_crap.domain) {
2547                 fstrcpy(domain,state->request->data.chng_pswd_auth_crap.domain);
2548         } else {
2549                 parse_domain_user(state->request->data.chng_pswd_auth_crap.user,
2550                                   domain, user);
2551
2552                 if(!*domain) {
2553                         DEBUG(3,("no domain specified with username (%s) - "
2554                                  "failing auth\n",
2555                                  state->request->data.chng_pswd_auth_crap.user));
2556                         result = NT_STATUS_NO_SUCH_USER;
2557                         goto done;
2558                 }
2559         }
2560
2561         if (!*domain && lp_winbind_use_default_domain()) {
2562                 fstrcpy(domain,(char *)lp_workgroup());
2563         }
2564
2565         if(!*user) {
2566                 fstrcpy(user, state->request->data.chng_pswd_auth_crap.user);
2567         }
2568
2569         DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n",
2570                   (unsigned long)state->pid, domain, user));
2571
2572         /* Change password */
2573         new_nt_password = data_blob_talloc(
2574                 state->mem_ctx,
2575                 state->request->data.chng_pswd_auth_crap.new_nt_pswd,
2576                 state->request->data.chng_pswd_auth_crap.new_nt_pswd_len);
2577
2578         old_nt_hash_enc = data_blob_talloc(
2579                 state->mem_ctx,
2580                 state->request->data.chng_pswd_auth_crap.old_nt_hash_enc,
2581                 state->request->data.chng_pswd_auth_crap.old_nt_hash_enc_len);
2582
2583         if(state->request->data.chng_pswd_auth_crap.new_lm_pswd_len > 0)        {
2584                 new_lm_password = data_blob_talloc(
2585                         state->mem_ctx,
2586                         state->request->data.chng_pswd_auth_crap.new_lm_pswd,
2587                         state->request->data.chng_pswd_auth_crap.new_lm_pswd_len);
2588
2589                 old_lm_hash_enc = data_blob_talloc(
2590                         state->mem_ctx,
2591                         state->request->data.chng_pswd_auth_crap.old_lm_hash_enc,
2592                         state->request->data.chng_pswd_auth_crap.old_lm_hash_enc_len);
2593         } else {
2594                 new_lm_password.length = 0;
2595                 old_lm_hash_enc.length = 0;
2596         }
2597
2598         /* Get sam handle */
2599
2600         result = cm_connect_sam(contact_domain, state->mem_ctx, &cli, &dom_pol);
2601         if (!NT_STATUS_IS_OK(result)) {
2602                 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
2603                 goto done;
2604         }
2605
2606         result = rpccli_samr_chng_pswd_auth_crap(
2607                 cli, state->mem_ctx, user, new_nt_password, old_nt_hash_enc,
2608                 new_lm_password, old_lm_hash_enc);
2609
2610  done:
2611
2612         set_auth_errors(state->response, result);
2613
2614         DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
2615               ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
2616                domain, user,
2617                state->response->data.auth.nt_status_string,
2618                state->response->data.auth.pam_error));
2619
2620         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2621 }