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