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