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