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