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