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