lib: give global_contexts.c its own header file
[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 "libsmb/namequery.h"
28 #include "../libcli/auth/libcli_auth.h"
29 #include "../librpc/gen_ndr/ndr_samr_c.h"
30 #include "rpc_client/cli_pipe.h"
31 #include "rpc_client/cli_samr.h"
32 #include "../librpc/gen_ndr/ndr_netlogon.h"
33 #include "rpc_client/cli_netlogon.h"
34 #include "smb_krb5.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 #include "lib/afs/afs_funcs.h"
45 #include "libsmb/samlogon_cache.h"
46 #include "rpc_client/util_netlogon.h"
47 #include "param/param.h"
48 #include "messaging/messaging.h"
49 #include "lib/util/string_wrappers.h"
50 #include "lib/crypto/gnutls_helpers.h"
51
52 #include "lib/crypto/gnutls_helpers.h"
53 #include <gnutls/crypto.h>
54 #include "lib/global_contexts.h"
55
56 #undef DBGC_CLASS
57 #define DBGC_CLASS DBGC_WINBIND
58
59 #define LOGON_KRB5_FAIL_CLOCK_SKEW      0x02000000
60
61 static NTSTATUS append_info3_as_txt(TALLOC_CTX *mem_ctx,
62                                     struct winbindd_response *resp,
63                                     uint16_t validation_level,
64                                     union netr_Validation *validation)
65 {
66         struct netr_SamInfo3 *info3 = NULL;
67         char *ex = NULL;
68         uint32_t i;
69         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
70         TALLOC_CTX *frame = talloc_stackframe();
71
72         status = map_validation_to_info3(frame,
73                                          validation_level,
74                                          validation,
75                                          &info3);
76         if (!NT_STATUS_IS_OK(status)) {
77                 goto out;
78         }
79
80         resp->data.auth.info3.logon_time =
81                 nt_time_to_unix(info3->base.logon_time);
82         resp->data.auth.info3.logoff_time =
83                 nt_time_to_unix(info3->base.logoff_time);
84         resp->data.auth.info3.kickoff_time =
85                 nt_time_to_unix(info3->base.kickoff_time);
86         resp->data.auth.info3.pass_last_set_time =
87                 nt_time_to_unix(info3->base.last_password_change);
88         resp->data.auth.info3.pass_can_change_time =
89                 nt_time_to_unix(info3->base.allow_password_change);
90         resp->data.auth.info3.pass_must_change_time =
91                 nt_time_to_unix(info3->base.force_password_change);
92
93         resp->data.auth.info3.logon_count = info3->base.logon_count;
94         resp->data.auth.info3.bad_pw_count = info3->base.bad_password_count;
95
96         resp->data.auth.info3.user_rid = info3->base.rid;
97         resp->data.auth.info3.group_rid = info3->base.primary_gid;
98         sid_to_fstring(resp->data.auth.info3.dom_sid, info3->base.domain_sid);
99
100         resp->data.auth.info3.num_groups = info3->base.groups.count;
101         resp->data.auth.info3.user_flgs = info3->base.user_flags;
102
103         resp->data.auth.info3.acct_flags = info3->base.acct_flags;
104         resp->data.auth.info3.num_other_sids = info3->sidcount;
105
106         fstrcpy(resp->data.auth.info3.user_name,
107                 info3->base.account_name.string);
108         fstrcpy(resp->data.auth.info3.full_name,
109                 info3->base.full_name.string);
110         fstrcpy(resp->data.auth.info3.logon_script,
111                 info3->base.logon_script.string);
112         fstrcpy(resp->data.auth.info3.profile_path,
113                 info3->base.profile_path.string);
114         fstrcpy(resp->data.auth.info3.home_dir,
115                 info3->base.home_directory.string);
116         fstrcpy(resp->data.auth.info3.dir_drive,
117                 info3->base.home_drive.string);
118
119         fstrcpy(resp->data.auth.info3.logon_srv,
120                 info3->base.logon_server.string);
121         fstrcpy(resp->data.auth.info3.logon_dom,
122                 info3->base.logon_domain.string);
123
124         resp->data.auth.validation_level = validation_level;
125         if (validation_level == 6) {
126                 fstrcpy(resp->data.auth.info6.dns_domainname,
127                         validation->sam6->dns_domainname.string);
128                 fstrcpy(resp->data.auth.info6.principal_name,
129                         validation->sam6->principal_name.string);
130         }
131
132         ex = talloc_strdup(frame, "");
133         if (ex == NULL) {
134                 status = NT_STATUS_NO_MEMORY;
135                 goto out;
136         }
137
138         for (i=0; i < info3->base.groups.count; i++) {
139                 ex = talloc_asprintf_append_buffer(ex, "0x%08X:0x%08X\n",
140                                                    info3->base.groups.rids[i].rid,
141                                                    info3->base.groups.rids[i].attributes);
142                 if (ex == NULL) {
143                         status = NT_STATUS_NO_MEMORY;
144                         goto out;
145                 }
146         }
147
148         for (i=0; i < info3->sidcount; i++) {
149                 struct dom_sid_buf sidbuf;
150
151                 ex = talloc_asprintf_append_buffer(
152                         ex,
153                         "%s:0x%08X\n",
154                         dom_sid_str_buf(info3->sids[i].sid, &sidbuf),
155                         info3->sids[i].attributes);
156                 if (ex == NULL) {
157                         status = NT_STATUS_NO_MEMORY;
158                         goto out;
159                 }
160         }
161
162         resp->length += talloc_get_size(ex);
163         resp->extra_data.data = talloc_move(mem_ctx, &ex);
164
165         status = NT_STATUS_OK;
166 out:
167         TALLOC_FREE(frame);
168         return status;
169 }
170
171 static NTSTATUS append_info3_as_ndr(TALLOC_CTX *mem_ctx,
172                                     struct winbindd_response *resp,
173                                     struct netr_SamInfo3 *info3)
174 {
175         DATA_BLOB blob;
176         enum ndr_err_code ndr_err;
177
178         ndr_err = ndr_push_struct_blob(&blob, mem_ctx, info3,
179                                        (ndr_push_flags_fn_t)ndr_push_netr_SamInfo3);
180         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
181                 DEBUG(0,("append_info3_as_ndr: failed to append\n"));
182                 return ndr_map_error2ntstatus(ndr_err);
183         }
184
185         resp->extra_data.data = blob.data;
186         resp->length += blob.length;
187
188         return NT_STATUS_OK;
189 }
190
191 static NTSTATUS append_unix_username(TALLOC_CTX *mem_ctx,
192                                      struct winbindd_response *resp,
193                                      const struct netr_SamInfo3 *info3,
194                                      const char *name_domain,
195                                      const char *name_user)
196 {
197         /* We've been asked to return the unix username, per
198            'winbind use default domain' settings and the like */
199
200         const char *nt_username, *nt_domain, *unix_username;
201
202         nt_domain = talloc_strdup(mem_ctx, info3->base.logon_domain.string);
203         if (!nt_domain) {
204                 /* If the server didn't give us one, just use the one
205                  * we sent them */
206                 nt_domain = name_domain;
207         }
208
209         nt_username = talloc_strdup(mem_ctx, info3->base.account_name.string);
210         if (!nt_username) {
211                 /* If the server didn't give us one, just use the one
212                  * we sent them */
213                 nt_username = name_user;
214         }
215
216         unix_username = fill_domain_username_talloc(mem_ctx,
217                                                     nt_domain,
218                                                     nt_username,
219                                                     true);
220         if (unix_username == NULL) {
221                 return NT_STATUS_NO_MEMORY;
222         }
223
224         fstrcpy(resp->data.auth.unix_username, unix_username);
225
226         DEBUG(5, ("Setting unix username to [%s]\n",
227                   resp->data.auth.unix_username));
228
229         return NT_STATUS_OK;
230 }
231
232 static NTSTATUS append_afs_token(TALLOC_CTX *mem_ctx,
233                                  struct winbindd_response *resp,
234                                  const struct netr_SamInfo3 *info3,
235                                  const char *name_domain,
236                                  const char *name_user)
237 {
238         char *afsname = NULL;
239         char *cell;
240         char *token;
241
242         afsname = talloc_strdup(mem_ctx, lp_afs_username_map());
243         if (afsname == NULL) {
244                 return NT_STATUS_NO_MEMORY;
245         }
246
247         afsname = talloc_string_sub(mem_ctx,
248                                     lp_afs_username_map(),
249                                     "%D", name_domain);
250         afsname = talloc_string_sub(mem_ctx, afsname,
251                                     "%u", name_user);
252         afsname = talloc_string_sub(mem_ctx, afsname,
253                                     "%U", name_user);
254
255         {
256                 struct dom_sid user_sid;
257                 struct dom_sid_buf sidstr;
258
259                 sid_compose(&user_sid, info3->base.domain_sid,
260                             info3->base.rid);
261                 afsname = talloc_string_sub(
262                         mem_ctx,
263                         afsname,
264                         "%s",
265                         dom_sid_str_buf(&user_sid, &sidstr));
266         }
267
268         if (afsname == NULL) {
269                 return NT_STATUS_NO_MEMORY;
270         }
271
272         if (!strlower_m(afsname)) {
273                 return NT_STATUS_INVALID_PARAMETER;
274         }
275
276         DEBUG(10, ("Generating token for user %s\n", afsname));
277
278         cell = strchr(afsname, '@');
279
280         if (cell == NULL) {
281                 return NT_STATUS_NO_MEMORY;
282         }
283
284         *cell = '\0';
285         cell += 1;
286
287         token = afs_createtoken_str(afsname, cell);
288         if (token == NULL) {
289                 return NT_STATUS_OK;
290         }
291         resp->extra_data.data = talloc_strdup(mem_ctx, token);
292         if (resp->extra_data.data == NULL) {
293                 return NT_STATUS_NO_MEMORY;
294         }
295         resp->length += strlen((const char *)resp->extra_data.data)+1;
296
297         return NT_STATUS_OK;
298 }
299
300 static NTSTATUS check_info3_in_group(struct netr_SamInfo3 *info3,
301                                      const char *group_sid)
302 /**
303  * Check whether a user belongs to a group or list of groups.
304  *
305  * @param mem_ctx talloc memory context.
306  * @param info3 user information, including group membership info.
307  * @param group_sid One or more groups , separated by commas.
308  *
309  * @return NT_STATUS_OK on success,
310  *    NT_STATUS_LOGON_FAILURE if the user does not belong,
311  *    or other NT_STATUS_IS_ERR(status) for other kinds of failure.
312  */
313 {
314         struct dom_sid *require_membership_of_sid;
315         uint32_t num_require_membership_of_sid;
316         char *req_sid;
317         const char *p;
318         struct dom_sid sid;
319         size_t i;
320         struct security_token *token;
321         TALLOC_CTX *frame = talloc_stackframe();
322         NTSTATUS status;
323
324         /* Parse the 'required group' SID */
325
326         if (!group_sid || !group_sid[0]) {
327                 /* NO sid supplied, all users may access */
328                 TALLOC_FREE(frame);
329                 return NT_STATUS_OK;
330         }
331
332         token = talloc_zero(talloc_tos(), struct security_token);
333         if (token == NULL) {
334                 DEBUG(0, ("talloc failed\n"));
335                 TALLOC_FREE(frame);
336                 return NT_STATUS_NO_MEMORY;
337         }
338
339         num_require_membership_of_sid = 0;
340         require_membership_of_sid = NULL;
341
342         p = group_sid;
343
344         while (next_token_talloc(talloc_tos(), &p, &req_sid, ",")) {
345                 if (!string_to_sid(&sid, req_sid)) {
346                         DEBUG(0, ("check_info3_in_group: could not parse %s "
347                                   "as a SID!", req_sid));
348                         TALLOC_FREE(frame);
349                         return NT_STATUS_INVALID_PARAMETER;
350                 }
351
352                 status = add_sid_to_array(talloc_tos(), &sid,
353                                           &require_membership_of_sid,
354                                           &num_require_membership_of_sid);
355                 if (!NT_STATUS_IS_OK(status)) {
356                         DEBUG(0, ("add_sid_to_array failed\n"));
357                         TALLOC_FREE(frame);
358                         return status;
359                 }
360         }
361
362         status = sid_array_from_info3(talloc_tos(), info3,
363                                       &token->sids,
364                                       &token->num_sids,
365                                       true);
366         if (!NT_STATUS_IS_OK(status)) {
367                 TALLOC_FREE(frame);
368                 return status;
369         }
370
371         if (!NT_STATUS_IS_OK(status = add_aliases(get_global_sam_sid(),
372                                                   token))
373             || !NT_STATUS_IS_OK(status = add_aliases(&global_sid_Builtin,
374                                                      token))) {
375                 DEBUG(3, ("could not add aliases: %s\n",
376                           nt_errstr(status)));
377                 TALLOC_FREE(frame);
378                 return status;
379         }
380
381         security_token_debug(DBGC_CLASS, 10, token);
382
383         for (i=0; i<num_require_membership_of_sid; i++) {
384                 struct dom_sid_buf buf;
385                 DEBUG(10, ("Checking SID %s\n",
386                            dom_sid_str_buf(&require_membership_of_sid[i],
387                                            &buf)));
388                 if (nt_token_check_sid(&require_membership_of_sid[i],
389                                        token)) {
390                         DEBUG(10, ("Access ok\n"));
391                         TALLOC_FREE(frame);
392                         return NT_STATUS_OK;
393                 }
394         }
395
396         /* Do not distinguish this error from a wrong username/pw */
397
398         TALLOC_FREE(frame);
399         return NT_STATUS_LOGON_FAILURE;
400 }
401
402 struct winbindd_domain *find_auth_domain(uint8_t flags,
403                                          const char *domain_name)
404 {
405         struct winbindd_domain *domain;
406
407         if (IS_DC) {
408                 domain = find_domain_from_name_noinit(domain_name);
409                 if (domain == NULL) {
410                         DEBUG(3, ("Authentication for domain [%s] refused "
411                                   "as it is not a trusted domain\n",
412                                   domain_name));
413                         return NULL;
414                 }
415
416                 if (domain->secure_channel_type != SEC_CHAN_NULL) {
417                         return domain;
418                 }
419
420                 return domain->routing_domain;
421         }
422
423         if (strequal(domain_name, get_global_sam_name())) {
424                 return find_domain_from_name_noinit(domain_name);
425         }
426
427         if (lp_winbind_use_krb5_enterprise_principals()) {
428                 /*
429                  * If we use enterprise principals
430                  * we always go trough our primary domain
431                  * and follow the WRONG_REALM replies.
432                  */
433                 flags &= ~WBFLAG_PAM_CONTACT_TRUSTDOM;
434         }
435
436         /* we can auth against trusted domains */
437         if (flags & WBFLAG_PAM_CONTACT_TRUSTDOM) {
438                 domain = find_domain_from_name_noinit(domain_name);
439                 if (domain == NULL) {
440                         DEBUG(3, ("Authentication for domain [%s] skipped "
441                                   "as it is not a trusted domain\n",
442                                   domain_name));
443                 } else {
444                         return domain;
445                 }
446         }
447
448         return find_our_domain();
449 }
450
451 static void fake_password_policy(struct winbindd_response *r,
452                                  const struct netr_SamBaseInfo *bi)
453 {
454         NTTIME min_password_age;
455         NTTIME max_password_age;
456
457         if (bi->allow_password_change > bi->last_password_change) {
458                 min_password_age = bi->allow_password_change -
459                                    bi->last_password_change;
460         } else {
461                 min_password_age = 0;
462         }
463
464         if (bi->force_password_change > bi->last_password_change) {
465                 max_password_age = bi->force_password_change -
466                                    bi->last_password_change;
467         } else {
468                 max_password_age = 0;
469         }
470
471         r->data.auth.policy.min_length_password = 0;
472         r->data.auth.policy.password_history = 0;
473         r->data.auth.policy.password_properties = 0;
474         r->data.auth.policy.expire =
475                 nt_time_to_unix_abs(&max_password_age);
476         r->data.auth.policy.min_passwordage =
477                 nt_time_to_unix_abs(&min_password_age);
478 }
479
480 static void fill_in_password_policy(struct winbindd_response *r,
481                                     const struct samr_DomInfo1 *p)
482 {
483         r->data.auth.policy.min_length_password =
484                 p->min_password_length;
485         r->data.auth.policy.password_history =
486                 p->password_history_length;
487         r->data.auth.policy.password_properties =
488                 p->password_properties;
489         r->data.auth.policy.expire      =
490                 nt_time_to_unix_abs((const NTTIME *)&(p->max_password_age));
491         r->data.auth.policy.min_passwordage =
492                 nt_time_to_unix_abs((const NTTIME *)&(p->min_password_age));
493 }
494
495 static NTSTATUS fillup_password_policy(struct winbindd_domain *domain,
496                                        struct winbindd_response *response)
497 {
498         TALLOC_CTX *frame = talloc_stackframe();
499         NTSTATUS status;
500         struct samr_DomInfo1 password_policy;
501
502         if ( !winbindd_can_contact_domain( domain ) ) {
503                 DEBUG(5,("fillup_password_policy: No inbound trust to "
504                          "contact domain %s\n", domain->name));
505                 status = NT_STATUS_NOT_SUPPORTED;
506                 goto done;
507         }
508
509         status = wb_cache_password_policy(domain, talloc_tos(),
510                                           &password_policy);
511         if (NT_STATUS_IS_ERR(status)) {
512                 goto done;
513         }
514
515         fill_in_password_policy(response, &password_policy);
516
517 done:
518         TALLOC_FREE(frame);
519         return NT_STATUS_OK;
520 }
521
522 static NTSTATUS get_max_bad_attempts_from_lockout_policy(struct winbindd_domain *domain,
523                                                          TALLOC_CTX *mem_ctx,
524                                                          uint16_t *lockout_threshold)
525 {
526         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
527         struct samr_DomInfo12 lockout_policy;
528
529         *lockout_threshold = 0;
530
531         status = wb_cache_lockout_policy(domain, mem_ctx, &lockout_policy);
532         if (NT_STATUS_IS_ERR(status)) {
533                 return status;
534         }
535
536         *lockout_threshold = lockout_policy.lockout_threshold;
537
538         return NT_STATUS_OK;
539 }
540
541 static NTSTATUS get_pwd_properties(struct winbindd_domain *domain,
542                                    TALLOC_CTX *mem_ctx,
543                                    uint32_t *password_properties)
544 {
545         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
546         struct samr_DomInfo1 password_policy;
547
548         *password_properties = 0;
549
550         status = wb_cache_password_policy(domain, mem_ctx, &password_policy);
551         if (NT_STATUS_IS_ERR(status)) {
552                 return status;
553         }
554
555         *password_properties = password_policy.password_properties;
556
557         return NT_STATUS_OK;
558 }
559
560 #ifdef HAVE_KRB5
561
562 static const char *generate_krb5_ccache(TALLOC_CTX *mem_ctx,
563                                         const char *type,
564                                         uid_t uid,
565                                         const char **user_ccache_file)
566 {
567         /* accept FILE and WRFILE as krb5_cc_type from the client and then
568          * build the full ccname string based on the user's uid here -
569          * Guenther*/
570
571         const char *gen_cc = NULL;
572
573         if (uid != -1) {
574                 if (strequal(type, "FILE")) {
575                         gen_cc = talloc_asprintf(
576                                 mem_ctx, "FILE:/tmp/krb5cc_%d", uid);
577                 }
578                 if (strequal(type, "WRFILE")) {
579                         gen_cc = talloc_asprintf(
580                                 mem_ctx, "WRFILE:/tmp/krb5cc_%d", uid);
581                 }
582                 if (strequal(type, "KEYRING")) {
583                         gen_cc = talloc_asprintf(
584                                 mem_ctx, "KEYRING:persistent:%d", uid);
585                 }
586                 if (strequal(type, "KCM")) {
587                         gen_cc = talloc_asprintf(mem_ctx,
588                                                  "KCM:%d",
589                                                  uid);
590                 }
591
592                 if (strnequal(type, "FILE:/", 6) ||
593                     strnequal(type, "WRFILE:/", 8) ||
594                     strnequal(type, "DIR:/", 5)) {
595
596                         /* we allow only one "%u" substitution */
597
598                         char *p;
599
600                         p = strchr(type, '%');
601                         if (p != NULL) {
602
603                                 p++;
604
605                                 if (p != NULL && *p == 'u' && strchr(p, '%') == NULL) {
606                                         char uid_str[sizeof("18446744073709551615")];
607
608                                         snprintf(uid_str, sizeof(uid_str), "%u", uid);
609
610                                         gen_cc = talloc_string_sub2(mem_ctx,
611                                                         type,
612                                                         "%u",
613                                                         uid_str,
614                                                         /* remove_unsafe_characters */
615                                                         false,
616                                                         /* replace_once */
617                                                         true,
618                                                         /* allow_trailing_dollar */
619                                                         false);
620                                 }
621                         }
622                 }
623         }
624
625         *user_ccache_file = gen_cc;
626
627         if (gen_cc == NULL) {
628                 gen_cc = talloc_strdup(mem_ctx, "MEMORY:winbindd_pam_ccache");
629         }
630         if (gen_cc == NULL) {
631                 DEBUG(0,("out of memory\n"));
632                 return NULL;
633         }
634
635         DEBUG(10, ("using ccache: %s%s\n", gen_cc,
636                    (*user_ccache_file == NULL) ? " (internal)":""));
637
638         return gen_cc;
639 }
640
641 #endif
642
643 uid_t get_uid_from_request(struct winbindd_request *request)
644 {
645         uid_t uid;
646
647         uid = request->data.auth.uid;
648
649         if (uid == (uid_t)-1) {
650                 DEBUG(1,("invalid uid: '%u'\n", (unsigned int)uid));
651                 return -1;
652         }
653         return uid;
654 }
655
656 /**********************************************************************
657  Authenticate a user with a clear text password using Kerberos and fill up
658  ccache if required
659  **********************************************************************/
660
661 static NTSTATUS winbindd_raw_kerberos_login(TALLOC_CTX *mem_ctx,
662                                             struct winbindd_domain *domain,
663                                             const char *user,
664                                             const char *pass,
665                                             const char *krb5_cc_type,
666                                             uid_t uid,
667                                             struct netr_SamInfo6 **info6,
668                                             fstring krb5ccname)
669 {
670 #ifdef HAVE_KRB5
671         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
672         krb5_error_code krb5_ret;
673         const char *cc = NULL;
674         const char *principal_s = NULL;
675         const char *service = NULL;
676         char *realm = NULL;
677         fstring name_namespace, name_domain, name_user;
678         time_t ticket_lifetime = 0;
679         time_t renewal_until = 0;
680         ADS_STRUCT *ads;
681         time_t time_offset = 0;
682         const char *user_ccache_file;
683         struct PAC_LOGON_INFO *logon_info = NULL;
684         struct PAC_UPN_DNS_INFO *upn_dns_info = NULL;
685         struct PAC_DATA *pac_data = NULL;
686         struct PAC_DATA_CTR *pac_data_ctr = NULL;
687         const char *local_service;
688         uint32_t i;
689         struct netr_SamInfo6 *info6_copy = NULL;
690         bool ok;
691
692         *info6 = NULL;
693
694         if (domain->alt_name == NULL) {
695                 return NT_STATUS_INVALID_PARAMETER;
696         }
697
698         /* 1st step:
699          * prepare a krb5_cc_cache string for the user */
700
701         if (uid == -1) {
702                 DEBUG(0,("no valid uid\n"));
703         }
704
705         cc = generate_krb5_ccache(mem_ctx,
706                                   krb5_cc_type,
707                                   uid,
708                                   &user_ccache_file);
709         if (cc == NULL) {
710                 return NT_STATUS_NO_MEMORY;
711         }
712
713
714         /* 2nd step:
715          * get kerberos properties */
716
717         if (domain->private_data) {
718                 ads = (ADS_STRUCT *)domain->private_data;
719                 time_offset = ads->auth.time_offset;
720         }
721
722
723         /* 3rd step:
724          * do kerberos auth and setup ccache as the user */
725
726         ok = parse_domain_user(user, name_namespace, name_domain, name_user);
727         if (!ok) {
728                 return NT_STATUS_INVALID_PARAMETER;
729         }
730
731         realm = talloc_strdup(mem_ctx, domain->alt_name);
732         if (realm == NULL) {
733                 return NT_STATUS_NO_MEMORY;
734         }
735
736         if (!strupper_m(realm)) {
737                 return NT_STATUS_INVALID_PARAMETER;
738         }
739
740         if (lp_winbind_use_krb5_enterprise_principals() &&
741             name_namespace[0] != '\0')
742         {
743                 principal_s = talloc_asprintf(mem_ctx,
744                                               "%s@%s@%s",
745                                               name_user,
746                                               name_namespace,
747                                               realm);
748         } else {
749                 principal_s = talloc_asprintf(mem_ctx,
750                                               "%s@%s",
751                                               name_user,
752                                               realm);
753         }
754         if (principal_s == NULL) {
755                 return NT_STATUS_NO_MEMORY;
756         }
757
758         service = talloc_asprintf(mem_ctx, "%s/%s@%s", KRB5_TGS_NAME, realm, realm);
759         if (service == NULL) {
760                 return NT_STATUS_NO_MEMORY;
761         }
762
763         local_service = talloc_asprintf(mem_ctx, "%s$@%s",
764                                         lp_netbios_name(), lp_realm());
765         if (local_service == NULL) {
766                 return NT_STATUS_NO_MEMORY;
767         }
768
769
770         /* if this is a user ccache, we need to act as the user to let the krb5
771          * library handle the chown, etc. */
772
773         /************************ ENTERING NON-ROOT **********************/
774
775         if (user_ccache_file != NULL) {
776                 set_effective_uid(uid);
777                 DEBUG(10,("winbindd_raw_kerberos_login: uid is %d\n", uid));
778         }
779
780         result = kerberos_return_pac(mem_ctx,
781                                      principal_s,
782                                      pass,
783                                      time_offset,
784                                      &ticket_lifetime,
785                                      &renewal_until,
786                                      cc,
787                                      true,
788                                      true,
789                                      WINBINDD_PAM_AUTH_KRB5_RENEW_TIME,
790                                      NULL,
791                                      local_service,
792                                      &pac_data_ctr);
793         if (user_ccache_file != NULL) {
794                 gain_root_privilege();
795         }
796
797         /************************ RETURNED TO ROOT **********************/
798
799         if (!NT_STATUS_IS_OK(result)) {
800                 goto failed;
801         }
802
803         if (pac_data_ctr == NULL) {
804                 goto failed;
805         }
806
807         pac_data = pac_data_ctr->pac_data;
808         if (pac_data == NULL) {
809                 goto failed;
810         }
811
812         for (i=0; i < pac_data->num_buffers; i++) {
813
814                 if (pac_data->buffers[i].type == PAC_TYPE_LOGON_INFO) {
815                         logon_info = pac_data->buffers[i].info->logon_info.info;
816                         continue;
817                 }
818
819                 if (pac_data->buffers[i].type == PAC_TYPE_UPN_DNS_INFO) {
820                         upn_dns_info = &pac_data->buffers[i].info->upn_dns_info;
821                         continue;
822                 }
823         }
824
825         if (logon_info == NULL) {
826                 DEBUG(10,("Missing logon_info in ticket of %s\n",
827                         principal_s));
828                 return NT_STATUS_INVALID_PARAMETER;
829         }
830
831         DEBUG(10,("winbindd_raw_kerberos_login: winbindd validated ticket of %s\n",
832                 principal_s));
833
834         result = create_info6_from_pac(mem_ctx, logon_info,
835                                        upn_dns_info, &info6_copy);
836         if (!NT_STATUS_IS_OK(result)) {
837                 goto failed;
838         }
839
840         /* if we had a user's ccache then return that string for the pam
841          * environment */
842
843         if (user_ccache_file != NULL) {
844
845                 fstrcpy(krb5ccname, user_ccache_file);
846
847                 result = add_ccache_to_list(principal_s,
848                                             cc,
849                                             service,
850                                             user,
851                                             pass,
852                                             realm,
853                                             uid,
854                                             time(NULL),
855                                             ticket_lifetime,
856                                             renewal_until,
857                                             false);
858
859                 if (!NT_STATUS_IS_OK(result)) {
860                         DEBUG(10,("winbindd_raw_kerberos_login: failed to add ccache to list: %s\n",
861                                 nt_errstr(result)));
862                 }
863         } else {
864
865                 /* need to delete the memory cred cache, it is not used anymore */
866
867                 krb5_ret = ads_kdestroy(cc);
868                 if (krb5_ret) {
869                         DEBUG(3,("winbindd_raw_kerberos_login: "
870                                  "could not destroy krb5 credential cache: "
871                                  "%s\n", error_message(krb5_ret)));
872                 }
873
874         }
875         *info6 = info6_copy;
876         return NT_STATUS_OK;
877
878 failed:
879         /*
880          * Do not delete an existing valid credential cache, if the user
881          * e.g. enters a wrong password
882          */
883         if ((strequal(krb5_cc_type, "FILE") || strequal(krb5_cc_type, "WRFILE"))
884             && user_ccache_file != NULL) {
885                 return result;
886         }
887
888         /* we could have created a new credential cache with a valid tgt in it
889          * but we werent able to get or verify the service ticket for this
890          * local host and therefor didn't get the PAC, we need to remove that
891          * cache entirely now */
892
893         krb5_ret = ads_kdestroy(cc);
894         if (krb5_ret) {
895                 DEBUG(3,("winbindd_raw_kerberos_login: "
896                          "could not destroy krb5 credential cache: "
897                          "%s\n", error_message(krb5_ret)));
898         }
899
900         if (!NT_STATUS_IS_OK(remove_ccache(user))) {
901                 DEBUG(3,("winbindd_raw_kerberos_login: "
902                           "could not remove ccache for user %s\n",
903                         user));
904         }
905
906         return result;
907 #else
908         return NT_STATUS_NOT_SUPPORTED;
909 #endif /* HAVE_KRB5 */
910 }
911
912 /****************************************************************
913 ****************************************************************/
914
915 bool check_request_flags(uint32_t flags)
916 {
917         uint32_t flags_edata = WBFLAG_PAM_AFS_TOKEN |
918                                WBFLAG_PAM_INFO3_TEXT |
919                                WBFLAG_PAM_INFO3_NDR;
920
921         if ( ( (flags & flags_edata) == WBFLAG_PAM_AFS_TOKEN) ||
922              ( (flags & flags_edata) == WBFLAG_PAM_INFO3_NDR) ||
923              ( (flags & flags_edata) == WBFLAG_PAM_INFO3_TEXT)||
924               !(flags & flags_edata) ) {
925                 return true;
926         }
927
928         DEBUG(1, ("check_request_flags: invalid request flags[0x%08X]\n",
929                   flags));
930
931         return false;
932 }
933
934 /****************************************************************
935 ****************************************************************/
936
937 NTSTATUS append_auth_data(TALLOC_CTX *mem_ctx,
938                           struct winbindd_response *resp,
939                           uint32_t request_flags,
940                           uint16_t validation_level,
941                           union netr_Validation *validation,
942                           const char *name_domain,
943                           const char *name_user)
944 {
945         struct netr_SamInfo3 *info3 = NULL;
946         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
947
948         result = map_validation_to_info3(talloc_tos(),
949                                          validation_level,
950                                          validation,
951                                          &info3);
952         if (!NT_STATUS_IS_OK(result)) {
953                 goto out;
954         }
955
956         if (request_flags & WBFLAG_PAM_USER_SESSION_KEY) {
957                 memcpy(resp->data.auth.user_session_key,
958                        info3->base.key.key,
959                        sizeof(resp->data.auth.user_session_key)
960                        /* 16 */);
961         }
962
963         if (request_flags & WBFLAG_PAM_LMKEY) {
964                 memcpy(resp->data.auth.first_8_lm_hash,
965                        info3->base.LMSessKey.key,
966                        sizeof(resp->data.auth.first_8_lm_hash)
967                        /* 8 */);
968         }
969
970         if (request_flags & WBFLAG_PAM_UNIX_NAME) {
971                 result = append_unix_username(mem_ctx, resp,
972                                               info3, name_domain, name_user);
973                 if (!NT_STATUS_IS_OK(result)) {
974                         DEBUG(10,("Failed to append Unix Username: %s\n",
975                                 nt_errstr(result)));
976                         goto out;
977                 }
978         }
979
980         /* currently, anything from here on potentially overwrites extra_data. */
981
982         if (request_flags & WBFLAG_PAM_INFO3_NDR) {
983                 result = append_info3_as_ndr(mem_ctx, resp, info3);
984                 if (!NT_STATUS_IS_OK(result)) {
985                         DEBUG(10,("Failed to append INFO3 (NDR): %s\n",
986                                 nt_errstr(result)));
987                         goto out;
988                 }
989         }
990
991         if (request_flags & WBFLAG_PAM_INFO3_TEXT) {
992                 result = append_info3_as_txt(mem_ctx, resp,
993                                              validation_level,
994                                              validation);
995                 if (!NT_STATUS_IS_OK(result)) {
996                         DEBUG(10,("Failed to append INFO3 (TXT): %s\n",
997                                 nt_errstr(result)));
998                         goto out;
999                 }
1000         }
1001
1002         if (request_flags & WBFLAG_PAM_AFS_TOKEN) {
1003                 result = append_afs_token(mem_ctx, resp,
1004                                           info3, name_domain, name_user);
1005                 if (!NT_STATUS_IS_OK(result)) {
1006                         DEBUG(10,("Failed to append AFS token: %s\n",
1007                                 nt_errstr(result)));
1008                         goto out;
1009                 }
1010         }
1011
1012         result = NT_STATUS_OK;
1013 out:
1014         TALLOC_FREE(info3);
1015         return result;
1016 }
1017
1018 static NTSTATUS winbindd_dual_pam_auth_cached(struct winbindd_domain *domain,
1019                                               struct winbindd_cli_state *state,
1020                                               struct netr_SamInfo3 **info3)
1021 {
1022         NTSTATUS result = NT_STATUS_LOGON_FAILURE;
1023         uint16_t max_allowed_bad_attempts;
1024         fstring name_namespace, name_domain, name_user;
1025         struct dom_sid sid;
1026         enum lsa_SidType type;
1027         uchar new_nt_pass[NT_HASH_LEN];
1028         const uint8_t *cached_nt_pass;
1029         const uint8_t *cached_salt;
1030         struct netr_SamInfo3 *my_info3;
1031         time_t kickoff_time, must_change_time;
1032         bool password_good = false;
1033         bool ok;
1034 #ifdef HAVE_KRB5
1035         struct winbindd_tdc_domain *tdc_domain = NULL;
1036 #endif
1037
1038         *info3 = NULL;
1039
1040         ZERO_STRUCTP(info3);
1041
1042         DEBUG(10,("winbindd_dual_pam_auth_cached\n"));
1043
1044         /* Parse domain and username */
1045
1046         ok = parse_domain_user(state->request->data.auth.user,
1047                                name_namespace,
1048                                name_domain,
1049                                name_user);
1050         if (!ok) {
1051                 DBG_DEBUG("parse_domain_user failed\n");
1052                 return NT_STATUS_NO_SUCH_USER;
1053         }
1054
1055         if (!lookup_cached_name(name_namespace,
1056                                 name_domain,
1057                                 name_user,
1058                                 &sid,
1059                                 &type)) {
1060                 DEBUG(10,("winbindd_dual_pam_auth_cached: no such user in the cache\n"));
1061                 return NT_STATUS_NO_SUCH_USER;
1062         }
1063
1064         if (type != SID_NAME_USER) {
1065                 DEBUG(10,("winbindd_dual_pam_auth_cached: not a user (%s)\n", sid_type_lookup(type)));
1066                 return NT_STATUS_LOGON_FAILURE;
1067         }
1068
1069         result = winbindd_get_creds(domain,
1070                                     state->mem_ctx,
1071                                     &sid,
1072                                     &my_info3,
1073                                     &cached_nt_pass,
1074                                     &cached_salt);
1075         if (!NT_STATUS_IS_OK(result)) {
1076                 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get creds: %s\n", nt_errstr(result)));
1077                 return result;
1078         }
1079
1080         *info3 = my_info3;
1081
1082         E_md4hash(state->request->data.auth.pass, new_nt_pass);
1083
1084         dump_data_pw("new_nt_pass", new_nt_pass, NT_HASH_LEN);
1085         dump_data_pw("cached_nt_pass", cached_nt_pass, NT_HASH_LEN);
1086         if (cached_salt) {
1087                 dump_data_pw("cached_salt", cached_salt, NT_HASH_LEN);
1088         }
1089
1090         if (cached_salt) {
1091                 /* In this case we didn't store the nt_hash itself,
1092                    but the MD5 combination of salt + nt_hash. */
1093                 uchar salted_hash[NT_HASH_LEN];
1094                 gnutls_hash_hd_t hash_hnd = NULL;
1095                 int rc;
1096
1097                 rc = gnutls_hash_init(&hash_hnd, GNUTLS_DIG_MD5);
1098                 if (rc < 0) {
1099                         return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
1100                 }
1101
1102                 rc = gnutls_hash(hash_hnd, cached_salt, 16);
1103                 if (rc < 0) {
1104                         gnutls_hash_deinit(hash_hnd, NULL);
1105                         return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
1106                 }
1107                 rc = gnutls_hash(hash_hnd, new_nt_pass, 16);
1108                 if (rc < 0) {
1109                         gnutls_hash_deinit(hash_hnd, NULL);
1110                         return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
1111                 }
1112                 gnutls_hash_deinit(hash_hnd, salted_hash);
1113
1114                 password_good = (memcmp(cached_nt_pass, salted_hash,
1115                                         NT_HASH_LEN) == 0);
1116         } else {
1117                 /* Old cached cred - direct store of nt_hash (bad bad bad !). */
1118                 password_good = (memcmp(cached_nt_pass, new_nt_pass,
1119                                         NT_HASH_LEN) == 0);
1120         }
1121
1122         if (password_good) {
1123
1124                 /* User *DOES* know the password, update logon_time and reset
1125                  * bad_pw_count */
1126
1127                 my_info3->base.user_flags |= NETLOGON_CACHED_ACCOUNT;
1128
1129                 if (my_info3->base.acct_flags & ACB_AUTOLOCK) {
1130                         return NT_STATUS_ACCOUNT_LOCKED_OUT;
1131                 }
1132
1133                 if (my_info3->base.acct_flags & ACB_DISABLED) {
1134                         return NT_STATUS_ACCOUNT_DISABLED;
1135                 }
1136
1137                 if (my_info3->base.acct_flags & ACB_WSTRUST) {
1138                         return NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
1139                 }
1140
1141                 if (my_info3->base.acct_flags & ACB_SVRTRUST) {
1142                         return NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT;
1143                 }
1144
1145                 if (my_info3->base.acct_flags & ACB_DOMTRUST) {
1146                         return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT;
1147                 }
1148
1149                 if (!(my_info3->base.acct_flags & ACB_NORMAL)) {
1150                         DEBUG(0,("winbindd_dual_pam_auth_cached: whats wrong with that one?: 0x%08x\n",
1151                                 my_info3->base.acct_flags));
1152                         return NT_STATUS_LOGON_FAILURE;
1153                 }
1154
1155                 kickoff_time = nt_time_to_unix(my_info3->base.kickoff_time);
1156                 if (kickoff_time != 0 && time(NULL) > kickoff_time) {
1157                         return NT_STATUS_ACCOUNT_EXPIRED;
1158                 }
1159
1160                 must_change_time = nt_time_to_unix(my_info3->base.force_password_change);
1161                 if (must_change_time != 0 && must_change_time < time(NULL)) {
1162                         /* we allow grace logons when the password has expired */
1163                         my_info3->base.user_flags |= NETLOGON_GRACE_LOGON;
1164                         /* return NT_STATUS_PASSWORD_EXPIRED; */
1165                         goto success;
1166                 }
1167
1168 #ifdef HAVE_KRB5
1169                 if ((state->request->flags & WBFLAG_PAM_KRB5) &&
1170                     ((tdc_domain = wcache_tdc_fetch_domain(state->mem_ctx, name_domain)) != NULL) &&
1171                     ((tdc_domain->trust_type & LSA_TRUST_TYPE_UPLEVEL) ||
1172                     /* used to cope with the case winbindd starting without network. */
1173                     !strequal(tdc_domain->domain_name, tdc_domain->dns_name))) {
1174
1175                         uid_t uid = -1;
1176                         const char *cc = NULL;
1177                         char *realm = NULL;
1178                         const char *principal_s = NULL;
1179                         const char *service = NULL;
1180                         const char *user_ccache_file;
1181
1182                         if (domain->alt_name == NULL) {
1183                                 return NT_STATUS_INVALID_PARAMETER;
1184                         }
1185
1186                         uid = get_uid_from_request(state->request);
1187                         if (uid == -1) {
1188                                 DEBUG(0,("winbindd_dual_pam_auth_cached: invalid uid\n"));
1189                                 return NT_STATUS_INVALID_PARAMETER;
1190                         }
1191
1192                         cc = generate_krb5_ccache(state->mem_ctx,
1193                                                 state->request->data.auth.krb5_cc_type,
1194                                                 state->request->data.auth.uid,
1195                                                 &user_ccache_file);
1196                         if (cc == NULL) {
1197                                 return NT_STATUS_NO_MEMORY;
1198                         }
1199
1200                         realm = talloc_strdup(state->mem_ctx, domain->alt_name);
1201                         if (realm == NULL) {
1202                                 return NT_STATUS_NO_MEMORY;
1203                         }
1204
1205                         if (!strupper_m(realm)) {
1206                                 return NT_STATUS_INVALID_PARAMETER;
1207                         }
1208
1209                         principal_s = talloc_asprintf(state->mem_ctx, "%s@%s", name_user, realm);
1210                         if (principal_s == NULL) {
1211                                 return NT_STATUS_NO_MEMORY;
1212                         }
1213
1214                         service = talloc_asprintf(state->mem_ctx, "%s/%s@%s", KRB5_TGS_NAME, realm, realm);
1215                         if (service == NULL) {
1216                                 return NT_STATUS_NO_MEMORY;
1217                         }
1218
1219                         if (user_ccache_file != NULL) {
1220
1221                                 fstrcpy(state->response->data.auth.krb5ccname,
1222                                         user_ccache_file);
1223
1224                                 result = add_ccache_to_list(principal_s,
1225                                                             cc,
1226                                                             service,
1227                                                             state->request->data.auth.user,
1228                                                             state->request->data.auth.pass,
1229                                                             realm,
1230                                                             uid,
1231                                                             time(NULL),
1232                                                             time(NULL) + lp_winbind_cache_time(),
1233                                                             time(NULL) + WINBINDD_PAM_AUTH_KRB5_RENEW_TIME,
1234                                                             true);
1235
1236                                 if (!NT_STATUS_IS_OK(result)) {
1237                                         DEBUG(10,("winbindd_dual_pam_auth_cached: failed "
1238                                                 "to add ccache to list: %s\n",
1239                                                 nt_errstr(result)));
1240                                 }
1241                         }
1242                 }
1243 #endif /* HAVE_KRB5 */
1244  success:
1245                 /* FIXME: we possibly should handle logon hours as well (does xp when
1246                  * offline?) see auth/auth_sam.c:sam_account_ok for details */
1247
1248                 unix_to_nt_time(&my_info3->base.logon_time, time(NULL));
1249                 my_info3->base.bad_password_count = 0;
1250
1251                 result = winbindd_update_creds_by_info3(domain,
1252                                                         state->request->data.auth.user,
1253                                                         state->request->data.auth.pass,
1254                                                         my_info3);
1255                 if (!NT_STATUS_IS_OK(result)) {
1256                         DEBUG(1,("winbindd_dual_pam_auth_cached: failed to update creds: %s\n",
1257                                 nt_errstr(result)));
1258                         return result;
1259                 }
1260
1261                 return NT_STATUS_OK;
1262
1263         }
1264
1265         /* User does *NOT* know the correct password, modify info3 accordingly, but only if online */
1266         if (domain->online == false) {
1267                 goto failed;
1268         }
1269
1270         /* failure of this is not critical */
1271         result = get_max_bad_attempts_from_lockout_policy(domain, state->mem_ctx, &max_allowed_bad_attempts);
1272         if (!NT_STATUS_IS_OK(result)) {
1273                 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get max_allowed_bad_attempts. "
1274                           "Won't be able to honour account lockout policies\n"));
1275         }
1276
1277         /* increase counter */
1278         my_info3->base.bad_password_count++;
1279
1280         if (max_allowed_bad_attempts == 0) {
1281                 goto failed;
1282         }
1283
1284         /* lockout user */
1285         if (my_info3->base.bad_password_count >= max_allowed_bad_attempts) {
1286
1287                 uint32_t password_properties;
1288
1289                 result = get_pwd_properties(domain, state->mem_ctx, &password_properties);
1290                 if (!NT_STATUS_IS_OK(result)) {
1291                         DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get password properties.\n"));
1292                 }
1293
1294                 if ((my_info3->base.rid != DOMAIN_RID_ADMINISTRATOR) ||
1295                     (password_properties & DOMAIN_PASSWORD_LOCKOUT_ADMINS)) {
1296                         my_info3->base.acct_flags |= ACB_AUTOLOCK;
1297                 }
1298         }
1299
1300 failed:
1301         result = winbindd_update_creds_by_info3(domain,
1302                                                 state->request->data.auth.user,
1303                                                 NULL,
1304                                                 my_info3);
1305
1306         if (!NT_STATUS_IS_OK(result)) {
1307                 DEBUG(0,("winbindd_dual_pam_auth_cached: failed to update creds %s\n",
1308                         nt_errstr(result)));
1309         }
1310
1311         return NT_STATUS_LOGON_FAILURE;
1312 }
1313
1314 static NTSTATUS winbindd_dual_pam_auth_kerberos(struct winbindd_domain *domain,
1315                                                 struct winbindd_cli_state *state,
1316                                                 struct netr_SamInfo6 **info6)
1317 {
1318         struct winbindd_domain *contact_domain;
1319         fstring name_namespace, name_domain, name_user;
1320         NTSTATUS result;
1321         bool ok;
1322
1323         DEBUG(10,("winbindd_dual_pam_auth_kerberos\n"));
1324
1325         /* Parse domain and username */
1326
1327         ok = parse_domain_user(state->request->data.auth.user,
1328                                name_namespace,
1329                                name_domain,
1330                                name_user);
1331         if (!ok) {
1332                 result = NT_STATUS_INVALID_PARAMETER;
1333                 goto done;
1334         }
1335
1336         /* what domain should we contact? */
1337
1338         if (lp_winbind_use_krb5_enterprise_principals()) {
1339                 contact_domain = find_auth_domain(0, name_namespace);
1340         } else {
1341                 contact_domain = find_domain_from_name(name_namespace);
1342         }
1343         if (contact_domain == NULL) {
1344                 DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
1345                           state->request->data.auth.user, name_domain, name_user, name_namespace));
1346                 result = NT_STATUS_NO_SUCH_USER;
1347                 goto done;
1348         }
1349
1350         if (contact_domain->initialized &&
1351             contact_domain->active_directory) {
1352                 goto try_login;
1353         }
1354
1355         if (!contact_domain->initialized) {
1356                 init_dc_connection(contact_domain, false);
1357         }
1358
1359         if (!contact_domain->active_directory) {
1360                 DEBUG(3,("krb5 auth requested but domain (%s) is not Active Directory\n",
1361                       contact_domain->name));
1362                 return NT_STATUS_INVALID_LOGON_TYPE;
1363         }
1364 try_login:
1365         result = winbindd_raw_kerberos_login(
1366                 state->mem_ctx, contact_domain,
1367                 state->request->data.auth.user,
1368                 state->request->data.auth.pass,
1369                 state->request->data.auth.krb5_cc_type,
1370                 get_uid_from_request(state->request),
1371                 info6, state->response->data.auth.krb5ccname);
1372 done:
1373         return result;
1374 }
1375
1376 static NTSTATUS winbindd_dual_auth_passdb(TALLOC_CTX *mem_ctx,
1377                                           uint32_t logon_parameters,
1378                                           const char *domain,
1379                                           const char *user,
1380                                           const uint64_t logon_id,
1381                                           const char *client_name,
1382                                           const int client_pid,
1383                                           const DATA_BLOB *challenge,
1384                                           const DATA_BLOB *lm_resp,
1385                                           const DATA_BLOB *nt_resp,
1386                                           const struct tsocket_address *remote,
1387                                           const struct tsocket_address *local,
1388                                           bool interactive,
1389                                           uint8_t *pauthoritative,
1390                                           struct netr_SamInfo3 **pinfo3)
1391 {
1392         struct auth_context *auth_context;
1393         struct auth_serversupplied_info *server_info;
1394         struct auth_usersupplied_info *user_info = NULL;
1395         struct netr_SamInfo3 *info3;
1396         NTSTATUS status;
1397         bool ok;
1398         TALLOC_CTX *frame = talloc_stackframe();
1399
1400         /*
1401          * We are authoritative by default
1402          */
1403         *pauthoritative = 1;
1404
1405         status = make_user_info(frame, &user_info, user, user, domain, domain,
1406                                 lp_netbios_name(), remote, local,
1407                                 "winbind",
1408                                 lm_resp, nt_resp, NULL, NULL,
1409                                 NULL, AUTH_PASSWORD_RESPONSE);
1410         if (!NT_STATUS_IS_OK(status)) {
1411                 DEBUG(10, ("make_user_info failed: %s\n", nt_errstr(status)));
1412                 TALLOC_FREE(frame);
1413                 return status;
1414         }
1415
1416         user_info->logon_parameters = logon_parameters;
1417         user_info->logon_id = logon_id;
1418         user_info->auth_description = talloc_asprintf(
1419                 frame, "PASSDB, %s, %d", client_name, client_pid);
1420         if (user_info->auth_description == NULL) {
1421                 TALLOC_FREE(frame);
1422                 return NT_STATUS_NO_MEMORY;
1423         }
1424
1425         /* We don't want any more mapping of the username */
1426         user_info->mapped_state = True;
1427
1428         /* We don't want to come back to winbindd or to do PAM account checks */
1429         user_info->flags |= USER_INFO_INFO3_AND_NO_AUTHZ;
1430
1431         if (interactive) {
1432                 user_info->flags |= USER_INFO_INTERACTIVE_LOGON;
1433         }
1434
1435         status = make_auth3_context_for_winbind(frame, &auth_context);
1436         if (!NT_STATUS_IS_OK(status)) {
1437                 DBG_ERR("make_auth3_context_for_winbind failed: %s\n",
1438                         nt_errstr(status));
1439                 TALLOC_FREE(frame);
1440                 return status;
1441         }
1442
1443         ok = auth3_context_set_challenge(auth_context,
1444                                          challenge->data, "fixed");
1445         if (!ok) {
1446                 TALLOC_FREE(frame);
1447                 return NT_STATUS_NO_MEMORY;
1448         }
1449
1450         status = auth_check_ntlm_password(mem_ctx,
1451                                           auth_context,
1452                                           user_info,
1453                                           &server_info,
1454                                           pauthoritative);
1455         if (!NT_STATUS_IS_OK(status)) {
1456                 TALLOC_FREE(frame);
1457                 return status;
1458         }
1459
1460         info3 = talloc_zero(mem_ctx, struct netr_SamInfo3);
1461         if (info3 == NULL) {
1462                 TALLOC_FREE(frame);
1463                 return NT_STATUS_NO_MEMORY;
1464         }
1465
1466         status = serverinfo_to_SamInfo3(server_info, info3);
1467         if (!NT_STATUS_IS_OK(status)) {
1468                 TALLOC_FREE(frame);
1469                 TALLOC_FREE(info3);
1470                 DEBUG(0, ("serverinfo_to_SamInfo3 failed: %s\n",
1471                           nt_errstr(status)));
1472                 return status;
1473         }
1474
1475         *pinfo3 = info3;
1476         DEBUG(10, ("Authenticaticating user %s\\%s returned %s\n", domain,
1477                    user, nt_errstr(status)));
1478         TALLOC_FREE(frame);
1479         return status;
1480 }
1481
1482 static NTSTATUS winbind_samlogon_retry_loop(struct winbindd_domain *domain,
1483                                             TALLOC_CTX *mem_ctx,
1484                                             uint32_t logon_parameters,
1485                                             const char *username,
1486                                             const char *password,
1487                                             const char *domainname,
1488                                             const char *workstation,
1489                                             const uint64_t logon_id,
1490                                             bool plaintext_given,
1491                                             const uint8_t chal[8],
1492                                             DATA_BLOB lm_response,
1493                                             DATA_BLOB nt_response,
1494                                             bool interactive,
1495                                             uint8_t *authoritative,
1496                                             uint32_t *flags,
1497                                             uint16_t *_validation_level,
1498                                             union netr_Validation **_validation)
1499 {
1500         int attempts = 0;
1501         int netr_attempts = 0;
1502         bool retry = false;
1503         NTSTATUS result;
1504         enum netr_LogonInfoClass logon_type_i;
1505         enum netr_LogonInfoClass logon_type_n;
1506         uint16_t validation_level = UINT16_MAX;
1507         union netr_Validation *validation = NULL;
1508
1509         do {
1510                 struct rpc_pipe_client *netlogon_pipe;
1511                 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1512
1513                 retry = false;
1514
1515                 result = cm_connect_netlogon_secure(domain, &netlogon_pipe,
1516                                                     &netlogon_creds_ctx);
1517
1518                 if (NT_STATUS_EQUAL(result,
1519                                     NT_STATUS_CANT_ACCESS_DOMAIN_INFO)) {
1520                         /*
1521                          * This means we don't have a trust account.
1522                          */
1523                         *authoritative = 0;
1524                         result = NT_STATUS_NO_SUCH_USER;
1525                         break;
1526                 }
1527
1528                 if (!NT_STATUS_IS_OK(result)) {
1529                         DEBUG(3,("Could not open handle to NETLOGON pipe "
1530                                  "(error: %s, attempts: %d)\n",
1531                                   nt_errstr(result), netr_attempts));
1532
1533                         /* After the first retry always close the connection */
1534                         if (netr_attempts > 0) {
1535                                 DEBUG(3, ("This is again a problem for this "
1536                                           "particular call, forcing the close "
1537                                           "of this connection\n"));
1538                                 invalidate_cm_connection(domain);
1539                         }
1540
1541                         /* After the second retry failover to the next DC */
1542                         if (netr_attempts > 1) {
1543                                 /*
1544                                  * If the netlogon server is not reachable then
1545                                  * it is possible that the DC is rebuilding
1546                                  * sysvol and shutdown netlogon for that time.
1547                                  * We should failover to the next dc.
1548                                  */
1549                                 DEBUG(3, ("This is the third problem for this "
1550                                           "particular call, adding DC to the "
1551                                           "negative cache list: %s %s\n", domain->name, domain->dcname));
1552                                 add_failed_connection_entry(domain->name,
1553                                                             domain->dcname,
1554                                                             result);
1555                                 saf_delete(domain->name);
1556                         }
1557
1558                         /* Only allow 3 retries */
1559                         if (netr_attempts < 3) {
1560                                 DEBUG(3, ("The connection to netlogon "
1561                                           "failed, retrying\n"));
1562                                 netr_attempts++;
1563                                 retry = true;
1564                                 continue;
1565                         }
1566                         return result;
1567                 }
1568
1569                 logon_type_i = NetlogonInteractiveInformation;
1570                 logon_type_n = NetlogonNetworkInformation;
1571                 if (domain->domain_trust_attribs & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
1572                         logon_type_i = NetlogonInteractiveTransitiveInformation;
1573                         logon_type_n = NetlogonNetworkTransitiveInformation;
1574                 }
1575
1576                 if (domain->domain_trust_attribs & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1577                         logon_type_i = NetlogonInteractiveTransitiveInformation;
1578                         logon_type_n = NetlogonNetworkTransitiveInformation;
1579                 }
1580
1581                 if (domain->domain_trust_attribs & LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE) {
1582                         logon_type_i = NetlogonInteractiveInformation;
1583                         logon_type_n = NetlogonNetworkInformation;
1584                 }
1585
1586                 if (domain->domain_trust_attribs & LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) {
1587                         logon_type_i = NetlogonInteractiveInformation;
1588                         logon_type_n = NetlogonNetworkInformation;
1589                 }
1590
1591                 netr_attempts = 0;
1592                 if (plaintext_given) {
1593                         result = rpccli_netlogon_password_logon(
1594                                 netlogon_creds_ctx,
1595                                 netlogon_pipe->binding_handle,
1596                                 mem_ctx,
1597                                 logon_parameters,
1598                                 domainname,
1599                                 username,
1600                                 password,
1601                                 workstation,
1602                                 logon_id,
1603                                 logon_type_i,
1604                                 authoritative,
1605                                 flags,
1606                                 &validation_level,
1607                                 &validation);
1608                 } else if (interactive) {
1609                         result = rpccli_netlogon_interactive_logon(
1610                                 netlogon_creds_ctx,
1611                                 netlogon_pipe->binding_handle,
1612                                 mem_ctx,
1613                                 logon_parameters,
1614                                 username,
1615                                 domainname,
1616                                 workstation,
1617                                 logon_id,
1618                                 lm_response,
1619                                 nt_response,
1620                                 logon_type_i,
1621                                 authoritative,
1622                                 flags,
1623                                 &validation_level,
1624                                 &validation);
1625                 } else {
1626                         result = rpccli_netlogon_network_logon(
1627                                 netlogon_creds_ctx,
1628                                 netlogon_pipe->binding_handle,
1629                                 mem_ctx,
1630                                 logon_parameters,
1631                                 username,
1632                                 domainname,
1633                                 workstation,
1634                                 logon_id,
1635                                 chal,
1636                                 lm_response,
1637                                 nt_response,
1638                                 logon_type_n,
1639                                 authoritative,
1640                                 flags,
1641                                 &validation_level,
1642                                 &validation);
1643                 }
1644
1645                 /*
1646                  * we increment this after the "feature negotiation"
1647                  * for can_do_samlogon_ex and can_do_validation6
1648                  */
1649                 attempts += 1;
1650
1651                 /* We have to try a second time as cm_connect_netlogon
1652                    might not yet have noticed that the DC has killed
1653                    our connection. */
1654
1655                 if (!rpccli_is_connected(netlogon_pipe)) {
1656                         retry = true;
1657                         continue;
1658                 }
1659
1660                 /* if we get access denied, a possible cause was that we had
1661                    an open connection to the DC, but someone changed our
1662                    machine account password out from underneath us using 'net
1663                    rpc changetrustpw' */
1664
1665                 if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
1666                         DEBUG(1,("winbind_samlogon_retry_loop: sam_logon returned "
1667                                  "ACCESS_DENIED.  Maybe the DC has Restrict "
1668                                  "NTLM set or the trust account "
1669                                 "password was changed and we didn't know it. "
1670                                  "Killing connections to domain %s\n",
1671                                 domainname));
1672                         invalidate_cm_connection(domain);
1673                         retry = true;
1674                 }
1675
1676                 if (NT_STATUS_EQUAL(result, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1677                         /*
1678                          * Got DCERPC_FAULT_OP_RNG_ERROR for SamLogon
1679                          * (no Ex). This happens against old Samba
1680                          * DCs, if LogonSamLogonEx() fails with an error
1681                          * e.g. NT_STATUS_NO_SUCH_USER or NT_STATUS_WRONG_PASSWORD.
1682                          *
1683                          * The server will log something like this:
1684                          * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
1685                          *
1686                          * This sets the whole connection into a fault_state mode
1687                          * and all following request get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
1688                          *
1689                          * This also happens to our retry with LogonSamLogonWithFlags()
1690                          * and LogonSamLogon().
1691                          *
1692                          * In order to recover from this situation, we need to
1693                          * drop the connection.
1694                          */
1695                         invalidate_cm_connection(domain);
1696                         result = NT_STATUS_LOGON_FAILURE;
1697                         break;
1698                 }
1699
1700         } while ( (attempts < 2) && retry );
1701
1702         if (NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT)) {
1703                 DEBUG(3,("winbind_samlogon_retry_loop: sam_network_logon(ex) "
1704                                 "returned NT_STATUS_IO_TIMEOUT after the retry. "
1705                                 "Killing connections to domain %s\n",
1706                         domainname));
1707                 invalidate_cm_connection(domain);
1708         }
1709
1710         if (!NT_STATUS_IS_OK(result)) {
1711                 return result;
1712         }
1713
1714         *_validation_level = validation_level;
1715         *_validation = validation;
1716         return NT_STATUS_OK;
1717 }
1718
1719 static NTSTATUS nt_dual_auth_passdb(TALLOC_CTX *mem_ctx,
1720                                     fstring name_user,
1721                                     fstring name_domain,
1722                                     const char *pass,
1723                                     uint64_t logon_id,
1724                                     const char *client_name,
1725                                     const int client_pid,
1726                                     const struct tsocket_address *remote,
1727                                     const struct tsocket_address *local,
1728                                     uint8_t *authoritative,
1729                                     struct netr_SamInfo3 **info3)
1730 {
1731         unsigned char local_nt_response[24];
1732         uchar chal[8];
1733         DATA_BLOB chal_blob;
1734         DATA_BLOB lm_resp;
1735         DATA_BLOB nt_resp;
1736
1737         /* do password magic */
1738
1739         generate_random_buffer(chal, sizeof(chal));
1740         chal_blob = data_blob_const(chal, sizeof(chal));
1741
1742         if (lp_client_ntlmv2_auth()) {
1743                 DATA_BLOB server_chal;
1744                 DATA_BLOB names_blob;
1745                 server_chal = data_blob_const(chal, 8);
1746
1747                 /* note that the 'workgroup' here is for the local
1748                    machine.  The 'server name' must match the
1749                    'workstation' passed to the actual SamLogon call.
1750                 */
1751                 names_blob = NTLMv2_generate_names_blob(mem_ctx,
1752                                                         lp_netbios_name(),
1753                                                         lp_workgroup());
1754
1755                 if (!SMBNTLMv2encrypt(mem_ctx, name_user, name_domain,
1756                                       pass, &server_chal, &names_blob,
1757                                       &lm_resp, &nt_resp, NULL, NULL)) {
1758                         data_blob_free(&names_blob);
1759                         DEBUG(0, ("SMBNTLMv2encrypt() failed!\n"));
1760                         return NT_STATUS_NO_MEMORY;
1761                 }
1762                 data_blob_free(&names_blob);
1763         } else {
1764                 int rc;
1765                 lm_resp = data_blob_null;
1766
1767                 rc = SMBNTencrypt(pass, chal, local_nt_response);
1768                 if (rc != 0) {
1769                         DEBUG(0, ("SMBNTencrypt() failed!\n"));
1770                         return gnutls_error_to_ntstatus(rc,
1771                                     NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
1772                 }
1773
1774                 nt_resp = data_blob_talloc(mem_ctx, local_nt_response,
1775                                            sizeof(local_nt_response));
1776         }
1777
1778         return winbindd_dual_auth_passdb(talloc_tos(), 0, name_domain,
1779                                          name_user, logon_id, client_name,
1780                                          client_pid, &chal_blob, &lm_resp,
1781                                          &nt_resp, remote, local,
1782                                          true, /* interactive */
1783                                          authoritative, info3);
1784 }
1785
1786 static NTSTATUS winbindd_dual_pam_auth_samlogon(
1787         TALLOC_CTX *mem_ctx,
1788         struct winbindd_domain *domain,
1789         const char *user,
1790         const char *pass,
1791         uint64_t logon_id,
1792         const char *client_name,
1793         const int client_pid,
1794         uint32_t request_flags,
1795         const struct tsocket_address *remote,
1796         const struct tsocket_address *local,
1797         uint16_t *_validation_level,
1798         union netr_Validation **_validation)
1799 {
1800         fstring name_namespace, name_domain, name_user;
1801         NTSTATUS result;
1802         uint8_t authoritative = 0;
1803         uint32_t flags = 0;
1804         uint16_t validation_level = 0;
1805         union netr_Validation *validation = NULL;
1806         struct netr_SamBaseInfo *base_info = NULL;
1807         bool ok;
1808
1809         DEBUG(10,("winbindd_dual_pam_auth_samlogon\n"));
1810
1811         /* Parse domain and username */
1812
1813         ok = parse_domain_user(user, name_namespace, name_domain, name_user);
1814         if (!ok) {
1815                 return NT_STATUS_INVALID_PARAMETER;
1816         }
1817
1818         /*
1819          * We check against domain->name instead of
1820          * name_domain, as find_auth_domain() ->
1821          * find_domain_from_name_noinit() already decided
1822          * that we are in a child for the correct domain.
1823          *
1824          * name_domain can also be lp_realm()
1825          * we need to check against domain->name.
1826          */
1827         if (strequal(domain->name, get_global_sam_name())) {
1828                 struct netr_SamInfo3 *info3 = NULL;
1829
1830                 result = nt_dual_auth_passdb(mem_ctx, name_user, name_domain,
1831                                              pass, logon_id, client_name,
1832                                              client_pid, remote, local,
1833                                              &authoritative, &info3);
1834
1835                 /*
1836                  * We need to try the remote NETLOGON server if this is
1837                  * not authoritative (for example on the RODC).
1838                  */
1839                 if (authoritative != 0) {
1840                         if (NT_STATUS_IS_OK(result)) {
1841                                 result = map_info3_to_validation(
1842                                                 mem_ctx,
1843                                                 info3,
1844                                                 &validation_level,
1845                                                 &validation);
1846                                 TALLOC_FREE(info3);
1847                                 if (!NT_STATUS_IS_OK(result)) {
1848                                         goto done;
1849                                 }
1850                         }
1851
1852                         goto done;
1853                 }
1854         }
1855
1856         /* check authentication loop */
1857
1858         result = winbind_samlogon_retry_loop(domain,
1859                                              mem_ctx,
1860                                              0,
1861                                              name_user,
1862                                              pass,
1863                                              name_domain,
1864                                              lp_netbios_name(),
1865                                              logon_id,
1866                                              true, /* plaintext_given */
1867                                              NULL,
1868                                              data_blob_null, data_blob_null,
1869                                              true, /* interactive */
1870                                              &authoritative,
1871                                              &flags,
1872                                              &validation_level,
1873                                              &validation);
1874         if (!NT_STATUS_IS_OK(result)) {
1875                 goto done;
1876         }
1877
1878         /* handle the case where a NT4 DC does not fill in the acct_flags in
1879          * the samlogon reply info3. When accurate info3 is required by the
1880          * caller, we look up the account flags ourselves - gd */
1881
1882         switch (validation_level) {
1883         case 3:
1884                 base_info = &validation->sam3->base;
1885                 break;
1886         case 6:
1887                 base_info = &validation->sam6->base;
1888                 break;
1889         default:
1890                 DBG_ERR("Bad validation level %d", (int)validation_level);
1891                 result = NT_STATUS_INTERNAL_ERROR;
1892                 goto done;
1893         }
1894         if ((request_flags & WBFLAG_PAM_INFO3_TEXT) &&
1895             (base_info->acct_flags == 0))
1896         {
1897                 struct rpc_pipe_client *samr_pipe;
1898                 struct policy_handle samr_domain_handle, user_pol;
1899                 union samr_UserInfo *info = NULL;
1900                 NTSTATUS status_tmp, result_tmp;
1901                 uint32_t acct_flags;
1902                 struct dcerpc_binding_handle *b;
1903
1904                 status_tmp = cm_connect_sam(domain, mem_ctx, false,
1905                                             &samr_pipe, &samr_domain_handle);
1906
1907                 if (!NT_STATUS_IS_OK(status_tmp)) {
1908                         DEBUG(3, ("could not open handle to SAMR pipe: %s\n",
1909                                 nt_errstr(status_tmp)));
1910                         goto done;
1911                 }
1912
1913                 b = samr_pipe->binding_handle;
1914
1915                 status_tmp = dcerpc_samr_OpenUser(b, mem_ctx,
1916                                                   &samr_domain_handle,
1917                                                   MAXIMUM_ALLOWED_ACCESS,
1918                                                   base_info->rid,
1919                                                   &user_pol,
1920                                                   &result_tmp);
1921
1922                 if (!NT_STATUS_IS_OK(status_tmp)) {
1923                         DEBUG(3, ("could not open user handle on SAMR pipe: %s\n",
1924                                 nt_errstr(status_tmp)));
1925                         goto done;
1926                 }
1927                 if (!NT_STATUS_IS_OK(result_tmp)) {
1928                         DEBUG(3, ("could not open user handle on SAMR pipe: %s\n",
1929                                 nt_errstr(result_tmp)));
1930                         goto done;
1931                 }
1932
1933                 status_tmp = dcerpc_samr_QueryUserInfo(b, mem_ctx,
1934                                                        &user_pol,
1935                                                        16,
1936                                                        &info,
1937                                                        &result_tmp);
1938
1939                 if (any_nt_status_not_ok(status_tmp, result_tmp,
1940                                          &status_tmp)) {
1941                         DEBUG(3, ("could not query user info on SAMR pipe: %s\n",
1942                                 nt_errstr(status_tmp)));
1943                         dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
1944                         goto done;
1945                 }
1946
1947                 acct_flags = info->info16.acct_flags;
1948
1949                 if (acct_flags == 0) {
1950                         dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
1951                         goto done;
1952                 }
1953
1954                 base_info->acct_flags = acct_flags;
1955
1956                 DEBUG(10,("successfully retrieved acct_flags 0x%x\n", acct_flags));
1957
1958                 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
1959         }
1960
1961 done:
1962         if (NT_STATUS_IS_OK(result)) {
1963                 *_validation_level = validation_level;
1964                 *_validation = validation;
1965         }
1966         return result;
1967 }
1968
1969 /*
1970  * @brief build a tsocket_address for the remote address of the supplied socket
1971  *
1972  */
1973 static struct tsocket_address *get_remote_address(TALLOC_CTX *mem_ctx, int sock)
1974 {
1975         struct sockaddr_storage st = {0};
1976         struct sockaddr *sar = (struct sockaddr *)&st;
1977         socklen_t sa_len = sizeof(st);
1978         struct tsocket_address *remote = NULL;
1979         int ret = 0;
1980
1981         ret = getpeername(sock, sar, &sa_len);
1982         if (ret != 0) {
1983                 DBG_ERR("getpeername failed - %s", strerror(errno));
1984                 return NULL;
1985         }
1986         ret = tsocket_address_bsd_from_sockaddr(mem_ctx, sar, sa_len, &remote);
1987         if (ret != 0) {
1988                 DBG_ERR("tsocket_address_bsd_from_sockaddr failed - %s",
1989                         strerror(errno));
1990                 return NULL;
1991         }
1992         return remote;
1993 }
1994
1995 /*
1996  * @brief build a tsocket_address for the local address of the supplied socket
1997  *
1998  */
1999 static struct tsocket_address *get_local_address(TALLOC_CTX *mem_ctx, int sock)
2000 {
2001         struct sockaddr_storage st = {0};
2002         struct sockaddr *sar = (struct sockaddr *)&st;
2003         socklen_t sa_len = sizeof(st);
2004         struct tsocket_address *local = NULL;
2005         int ret = 0;
2006
2007         ret = getsockname(sock, sar, &sa_len);
2008         if (ret != 0) {
2009                 DBG_ERR("getsockname failed - %s", strerror(errno));
2010                 return NULL;
2011         }
2012         ret = tsocket_address_bsd_from_sockaddr(mem_ctx, sar, sa_len, &local);
2013         if (ret != 0) {
2014                 DBG_ERR("tsocket_address_bsd_from_sockaddr failed - %s",
2015                         strerror(errno));
2016                 return NULL;
2017         }
2018         return local;
2019 }
2020
2021 /*
2022  * @brief generate an authentication message in the logs.
2023  *
2024  */
2025 static void log_authentication(
2026         TALLOC_CTX *mem_ctx,
2027         const struct winbindd_domain *domain,
2028         const struct winbindd_cli_state *state,
2029         const struct timeval start_time,
2030         const uint64_t logon_id,
2031         const char *command,
2032         const char *user_name,
2033         const char *domain_name,
2034         const char *workstation,
2035         const DATA_BLOB lm_resp,
2036         const DATA_BLOB nt_resp,
2037         const struct tsocket_address *remote,
2038         const struct tsocket_address *local,
2039         NTSTATUS result)
2040 {
2041
2042         struct auth_usersupplied_info *ui = NULL;
2043         struct dom_sid *sid = NULL;
2044         struct loadparm_context *lp_ctx = NULL;
2045         struct imessaging_context *msg_ctx = NULL;
2046
2047         ui = talloc_zero(mem_ctx, struct auth_usersupplied_info);
2048         ui->logon_id = logon_id;
2049         ui->service_description = "winbind";
2050         ui->password.response.nt.length = nt_resp.length;
2051         ui->password.response.nt.data = nt_resp.data;
2052         ui->password.response.lanman.length = lm_resp.length;
2053         ui->password.response.lanman.data = lm_resp.data;
2054         if (nt_resp.length == 0 && lm_resp.length == 0) {
2055                 ui->password_state = AUTH_PASSWORD_PLAIN;
2056         } else {
2057                 ui->password_state = AUTH_PASSWORD_RESPONSE;
2058         }
2059         /*
2060          * In the event of a failure ui->auth_description will be null,
2061          * the logging code handles this correctly so it can be ignored.
2062          */
2063         ui->auth_description = talloc_asprintf(
2064                 ui,
2065                 "%s, %s, %d",
2066                 command,
2067                 state->request->client_name,
2068                 state->pid);
2069         if (ui->auth_description == NULL) {
2070                 DBG_ERR("OOM Unable to create auth_description");
2071         }
2072         ui->client.account_name = user_name;
2073         ui->client.domain_name = domain_name;
2074         ui->workstation_name = workstation;
2075         ui->remote_host = remote;
2076         ui->local_host = local;
2077
2078         sid = dom_sid_parse_talloc(
2079             ui, state->response->data.auth.info3.dom_sid);
2080         if (sid != NULL) {
2081                 sid_append_rid(sid, state->response->data.auth.info3.user_rid);
2082         }
2083
2084         if (lp_auth_event_notification()) {
2085                 lp_ctx = loadparm_init_s3(ui, loadparm_s3_helpers());
2086                 msg_ctx = imessaging_client_init(
2087                     ui, lp_ctx, global_event_context());
2088         }
2089         log_authentication_event(
2090             msg_ctx,
2091             lp_ctx,
2092             &start_time,
2093             ui,
2094             result,
2095             state->response->data.auth.info3.logon_dom,
2096             state->response->data.auth.info3.user_name,
2097             sid);
2098         TALLOC_FREE(ui);
2099 }
2100
2101 enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain,
2102                                             struct winbindd_cli_state *state)
2103 {
2104         NTSTATUS result = NT_STATUS_LOGON_FAILURE;
2105         NTSTATUS krb5_result = NT_STATUS_OK;
2106         fstring name_namespace, name_domain, name_user;
2107         char *mapped_user;
2108         fstring domain_user;
2109         uint16_t validation_level = UINT16_MAX;
2110         union netr_Validation *validation = NULL;
2111         NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL;
2112         bool ok;
2113         uint64_t logon_id = 0;
2114         const struct timeval start_time = timeval_current();
2115         const struct tsocket_address *remote = NULL;
2116         const struct tsocket_address *local = NULL;
2117
2118         /* Ensure null termination */
2119         state->request->data.auth.user[sizeof(state->request->data.auth.user)-1]='\0';
2120
2121         /* Ensure null termination */
2122         state->request->data.auth.pass[sizeof(state->request->data.auth.pass)-1]='\0';
2123
2124         /*
2125          * Generate a logon_id for this session.
2126          */
2127         logon_id = generate_random_u64();
2128         remote = get_remote_address(state->mem_ctx, state->sock);
2129         local = get_local_address(state->mem_ctx, state->sock);
2130         DEBUG(3, ("[%5lu]: dual pam auth %s\n", (unsigned long)state->pid,
2131                   state->request->data.auth.user));
2132
2133         /* Parse domain and username */
2134
2135         name_map_status = normalize_name_unmap(state->mem_ctx,
2136                                                state->request->data.auth.user,
2137                                                &mapped_user);
2138
2139         /* If the name normalization didn't actually do anything,
2140            just use the original name */
2141
2142         if (!NT_STATUS_IS_OK(name_map_status) &&
2143             !NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED))
2144         {
2145                 mapped_user = state->request->data.auth.user;
2146         }
2147
2148         ok = parse_domain_user(mapped_user,
2149                                name_namespace,
2150                                name_domain,
2151                                name_user);
2152         if (!ok) {
2153                 result = NT_STATUS_INVALID_PARAMETER;
2154                 goto process_result;
2155         }
2156
2157         if ( mapped_user != state->request->data.auth.user ) {
2158                 fstr_sprintf( domain_user, "%s%c%s", name_domain,
2159                         *lp_winbind_separator(),
2160                         name_user );
2161                 strlcpy( state->request->data.auth.user, domain_user,
2162                              sizeof(state->request->data.auth.user));
2163         }
2164
2165         if (!domain->online) {
2166                 result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
2167                 if (domain->startup) {
2168                         /* Logons are very important to users. If we're offline and
2169                            we get a request within the first 30 seconds of startup,
2170                            try very hard to find a DC and go online. */
2171
2172                         DEBUG(10,("winbindd_dual_pam_auth: domain: %s offline and auth "
2173                                 "request in startup mode.\n", domain->name ));
2174
2175                         winbindd_flush_negative_conn_cache(domain);
2176                         result = init_dc_connection(domain, false);
2177                 }
2178         }
2179
2180         DEBUG(10,("winbindd_dual_pam_auth: domain: %s last was %s\n", domain->name, domain->online ? "online":"offline"));
2181
2182         /* Check for Kerberos authentication */
2183         if (domain->online && (state->request->flags & WBFLAG_PAM_KRB5)) {
2184                 struct netr_SamInfo6 *info6 = NULL;
2185
2186                 result = winbindd_dual_pam_auth_kerberos(domain, state, &info6);
2187                 /* save for later */
2188                 krb5_result = result;
2189
2190                 if (NT_STATUS_IS_OK(result)) {
2191                         DEBUG(10,("winbindd_dual_pam_auth_kerberos succeeded\n"));
2192
2193                         result = map_info6_to_validation(state->mem_ctx,
2194                                                          info6,
2195                                                          &validation_level,
2196                                                          &validation);
2197                         TALLOC_FREE(info6);
2198                         if (!NT_STATUS_IS_OK(result)) {
2199                                 DBG_ERR("map_info6_to_validation failed\n");
2200                                 goto done;
2201                         }
2202                         goto process_result;
2203                 }
2204
2205                 DBG_DEBUG("winbindd_dual_pam_auth_kerberos failed: %s\n",
2206                           nt_errstr(result));
2207
2208                 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
2209                     NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
2210                     NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2211                         DEBUG(10,("winbindd_dual_pam_auth_kerberos setting domain to offline\n"));
2212                         set_domain_offline( domain );
2213                         goto cached_logon;
2214                 }
2215
2216                 /* there are quite some NT_STATUS errors where there is no
2217                  * point in retrying with a samlogon, we explictly have to take
2218                  * care not to increase the bad logon counter on the DC */
2219
2220                 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_DISABLED) ||
2221                     NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_EXPIRED) ||
2222                     NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_LOCKED_OUT) ||
2223                     NT_STATUS_EQUAL(result, NT_STATUS_INVALID_LOGON_HOURS) ||
2224                     NT_STATUS_EQUAL(result, NT_STATUS_INVALID_WORKSTATION) ||
2225                     NT_STATUS_EQUAL(result, NT_STATUS_LOGON_FAILURE) ||
2226                     NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER) ||
2227                     NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_EXPIRED) ||
2228                     NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_MUST_CHANGE) ||
2229                     NT_STATUS_EQUAL(result, NT_STATUS_WRONG_PASSWORD)) {
2230                         goto done;
2231                 }
2232
2233                 if (state->request->flags & WBFLAG_PAM_FALLBACK_AFTER_KRB5) {
2234                         DEBUG(3,("falling back to samlogon\n"));
2235                         goto sam_logon;
2236                 } else {
2237                         goto cached_logon;
2238                 }
2239         }
2240
2241 sam_logon:
2242         /* Check for Samlogon authentication */
2243         if (domain->online) {
2244                 struct netr_SamBaseInfo *base_info = NULL;
2245
2246                 result = winbindd_dual_pam_auth_samlogon(
2247                         state->mem_ctx, domain,
2248                         state->request->data.auth.user,
2249                         state->request->data.auth.pass,
2250                         logon_id,
2251                         state->request->client_name,
2252                         state->pid,
2253                         state->request->flags,
2254                         remote,
2255                         local,
2256                         &validation_level,
2257                         &validation);
2258
2259                 if (NT_STATUS_IS_OK(result)) {
2260                         DEBUG(10,("winbindd_dual_pam_auth_samlogon succeeded\n"));
2261
2262                         switch (validation_level) {
2263                         case 3:
2264                                 base_info = &validation->sam3->base;
2265                                 break;
2266                         case 6:
2267                                 base_info = &validation->sam6->base;
2268                                 break;
2269                         default:
2270                                 DBG_ERR("Bad validation level %d\n",
2271                                         validation_level);
2272                                 result = NT_STATUS_INTERNAL_ERROR;
2273                                 goto done;
2274                         }
2275
2276                         /* add the Krb5 err if we have one */
2277                         if ( NT_STATUS_EQUAL(krb5_result, NT_STATUS_TIME_DIFFERENCE_AT_DC ) ) {
2278                                 base_info->user_flags |= LOGON_KRB5_FAIL_CLOCK_SKEW;
2279                         }
2280
2281                         goto process_result;
2282                 }
2283
2284                 DEBUG(10,("winbindd_dual_pam_auth_samlogon failed: %s\n",
2285                           nt_errstr(result)));
2286
2287                 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
2288                     NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
2289                     NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND))
2290                 {
2291                         DEBUG(10,("winbindd_dual_pam_auth_samlogon setting domain to offline\n"));
2292                         set_domain_offline( domain );
2293                         goto cached_logon;
2294                 }
2295
2296                 if (domain->online) {
2297                         /* We're still online - fail. */
2298                         goto done;
2299                 }
2300         }
2301
2302 cached_logon:
2303         /* Check for Cached logons */
2304         if (!domain->online && (state->request->flags & WBFLAG_PAM_CACHED_LOGIN) &&
2305             lp_winbind_offline_logon()) {
2306                 struct netr_SamInfo3 *info3 = NULL;
2307
2308                 result = winbindd_dual_pam_auth_cached(domain, state, &info3);
2309
2310                 if (!NT_STATUS_IS_OK(result)) {
2311                         DEBUG(10,("winbindd_dual_pam_auth_cached failed: %s\n", nt_errstr(result)));
2312                         goto done;
2313                 }
2314                 DEBUG(10,("winbindd_dual_pam_auth_cached succeeded\n"));
2315
2316                 result = map_info3_to_validation(state->mem_ctx,
2317                                                  info3,
2318                                                  &validation_level,
2319                                                  &validation);
2320                 TALLOC_FREE(info3);
2321                 if (!NT_STATUS_IS_OK(result)) {
2322                         DBG_ERR("map_info3_to_validation failed\n");
2323                         goto done;
2324                 }
2325         }
2326
2327 process_result:
2328
2329         if (NT_STATUS_IS_OK(result)) {
2330                 struct dom_sid user_sid;
2331                 TALLOC_CTX *base_ctx = NULL;
2332                 struct netr_SamBaseInfo *base_info = NULL;
2333                 struct netr_SamInfo3 *info3 = NULL;
2334
2335                 switch (validation_level) {
2336                 case 3:
2337                         base_ctx = validation->sam3;
2338                         base_info = &validation->sam3->base;
2339                         break;
2340                 case 6:
2341                         base_ctx = validation->sam6;
2342                         base_info = &validation->sam6->base;
2343                         break;
2344                 default:
2345                         result = NT_STATUS_INTERNAL_ERROR;
2346                         goto done;
2347                 }
2348
2349                 sid_compose(&user_sid, base_info->domain_sid, base_info->rid);
2350
2351                 if (base_info->full_name.string == NULL) {
2352                         struct netr_SamInfo3 *cached_info3;
2353
2354                         cached_info3 = netsamlogon_cache_get(state->mem_ctx,
2355                                                              &user_sid);
2356                         if (cached_info3 != NULL &&
2357                             cached_info3->base.full_name.string != NULL) {
2358                                 base_info->full_name.string = talloc_strdup(
2359                                         base_ctx,
2360                                         cached_info3->base.full_name.string);
2361                                 if (base_info->full_name.string == NULL) {
2362                                         result = NT_STATUS_NO_MEMORY;
2363                                         goto done;
2364                                 }
2365                         } else {
2366
2367                                 /* this might fail so we don't check the return code */
2368                                 wcache_query_user_fullname(domain,
2369                                                 base_ctx,
2370                                                 &user_sid,
2371                                                 &base_info->full_name.string);
2372                         }
2373                 }
2374
2375                 result = map_validation_to_info3(talloc_tos(),
2376                                                  validation_level,
2377                                                  validation,
2378                                                  &info3);
2379                 if (!NT_STATUS_IS_OK(result)) {
2380                         goto done;
2381                 }
2382
2383                 wcache_invalidate_samlogon(find_domain_from_name(name_domain),
2384                                            &user_sid);
2385                 netsamlogon_cache_store(name_user, info3);
2386
2387                 /* save name_to_sid info as early as possible (only if
2388                    this is our primary domain so we don't invalidate
2389                    the cache entry by storing the seq_num for the wrong
2390                    domain). */
2391                 if ( domain->primary ) {
2392                         cache_name2sid(domain, name_domain, name_user,
2393                                        SID_NAME_USER, &user_sid);
2394                 }
2395
2396                 /* Check if the user is in the right group */
2397
2398                 result = check_info3_in_group(
2399                         info3,
2400                         state->request->data.auth.require_membership_of_sid);
2401                 if (!NT_STATUS_IS_OK(result)) {
2402                         DEBUG(3, ("User %s is not in the required group (%s), so plaintext authentication is rejected\n",
2403                                   state->request->data.auth.user,
2404                                   state->request->data.auth.require_membership_of_sid));
2405                         goto done;
2406                 }
2407
2408                 result = append_auth_data(state->mem_ctx, state->response,
2409                                           state->request->flags,
2410                                           validation_level,
2411                                           validation,
2412                                           name_domain, name_user);
2413                 if (!NT_STATUS_IS_OK(result)) {
2414                         goto done;
2415                 }
2416
2417                 if ((state->request->flags & WBFLAG_PAM_CACHED_LOGIN)
2418                     && lp_winbind_offline_logon()) {
2419
2420                         result = winbindd_store_creds(domain,
2421                                                       state->request->data.auth.user,
2422                                                       state->request->data.auth.pass,
2423                                                       info3);
2424                 }
2425
2426                 if (state->request->flags & WBFLAG_PAM_GET_PWD_POLICY) {
2427                         /*
2428                          * WBFLAG_PAM_GET_PWD_POLICY is not used within
2429                          * any Samba caller anymore.
2430                          *
2431                          * We just fake this based on the effective values
2432                          * for the user, for legacy callers.
2433                          */
2434                         fake_password_policy(state->response, &info3->base);
2435                 }
2436
2437                 result = NT_STATUS_OK;
2438         }
2439
2440 done:
2441         /* give us a more useful (more correct?) error code */
2442         if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
2443             (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
2444                 result = NT_STATUS_NO_LOGON_SERVERS;
2445         }
2446
2447         set_auth_errors(state->response, result);
2448
2449         DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, ("Plain-text authentication for user %s returned %s (PAM: %d)\n",
2450               state->request->data.auth.user,
2451               state->response->data.auth.nt_status_string,
2452               state->response->data.auth.pam_error));
2453
2454         /*
2455          * Log the winbind pam authentication, the logon_id will tie this to
2456          * any of the logons invoked from this request.
2457          */
2458         log_authentication(
2459             state->mem_ctx,
2460             domain,
2461             state,
2462             start_time,
2463             logon_id,
2464             "PAM_AUTH",
2465             name_user,
2466             name_domain,
2467             NULL,
2468             data_blob_null,
2469             data_blob_null,
2470             remote,
2471             local,
2472             result);
2473
2474         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2475 }
2476
2477 NTSTATUS winbind_dual_SamLogon(struct winbindd_domain *domain,
2478                                TALLOC_CTX *mem_ctx,
2479                                bool interactive,
2480                                uint32_t logon_parameters,
2481                                const char *name_user,
2482                                const char *name_domain,
2483                                const char *workstation,
2484                                const uint64_t logon_id,
2485                                const char* client_name,
2486                                const int client_pid,
2487                                const uint8_t chal[8],
2488                                DATA_BLOB lm_response,
2489                                DATA_BLOB nt_response,
2490                                const struct tsocket_address *remote,
2491                                const struct tsocket_address *local,
2492                                uint8_t *authoritative,
2493                                bool skip_sam,
2494                                uint32_t *flags,
2495                                uint16_t *_validation_level,
2496                                union netr_Validation **_validation)
2497 {
2498         uint16_t validation_level = 0;
2499         union netr_Validation *validation = NULL;
2500         NTSTATUS result;
2501
2502         /*
2503          * We check against domain->name instead of
2504          * name_domain, as find_auth_domain() ->
2505          * find_domain_from_name_noinit() already decided
2506          * that we are in a child for the correct domain.
2507          *
2508          * name_domain can also be lp_realm()
2509          * we need to check against domain->name.
2510          */
2511         if (!skip_sam && strequal(domain->name, get_global_sam_name())) {
2512                 DATA_BLOB chal_blob = data_blob_const(
2513                         chal, 8);
2514                 struct netr_SamInfo3 *info3 = NULL;
2515
2516                 result = winbindd_dual_auth_passdb(
2517                         talloc_tos(),
2518                         logon_parameters,
2519                         name_domain, name_user,
2520                         logon_id,
2521                         client_name,
2522                         client_pid,
2523                         &chal_blob, &lm_response, &nt_response,
2524                         remote,
2525                         local,
2526                         interactive,
2527                         authoritative,
2528                         &info3);
2529                 if (NT_STATUS_IS_OK(result)) {
2530                         result = map_info3_to_validation(mem_ctx,
2531                                                          info3,
2532                                                          &validation_level,
2533                                                          &validation);
2534                         TALLOC_FREE(info3);
2535                         if (!NT_STATUS_IS_OK(result)) {
2536                                 goto done;
2537                         }
2538                 }
2539
2540                 /*
2541                  * We need to try the remote NETLOGON server if this is
2542                  * not authoritative.
2543                  */
2544                 if (*authoritative != 0) {
2545                         *flags = 0;
2546                         goto process_result;
2547                 }
2548         }
2549
2550         result = winbind_samlogon_retry_loop(domain,
2551                                              mem_ctx,
2552                                              logon_parameters,
2553                                              name_user,
2554                                              NULL, /* password */
2555                                              name_domain,
2556                                              /* Bug #3248 - found by Stefan Burkei. */
2557                                              workstation, /* We carefully set this above so use it... */
2558                                              logon_id,
2559                                              false, /* plaintext_given */
2560                                              chal,
2561                                              lm_response,
2562                                              nt_response,
2563                                              interactive,
2564                                              authoritative,
2565                                              flags,
2566                                              &validation_level,
2567                                              &validation);
2568         if (!NT_STATUS_IS_OK(result)) {
2569                 goto done;
2570         }
2571
2572 process_result:
2573
2574         if (NT_STATUS_IS_OK(result)) {
2575                 struct dom_sid user_sid;
2576                 TALLOC_CTX *base_ctx = NULL;
2577                 struct netr_SamBaseInfo *base_info = NULL;
2578                 struct netr_SamInfo3 *info3 = NULL;
2579
2580                 switch (validation_level) {
2581                 case 3:
2582                         base_ctx = validation->sam3;
2583                         base_info = &validation->sam3->base;
2584                         break;
2585                 case 6:
2586                         base_ctx = validation->sam6;
2587                         base_info = &validation->sam6->base;
2588                         break;
2589                 default:
2590                         result = NT_STATUS_INTERNAL_ERROR;
2591                         goto done;
2592                 }
2593
2594                 sid_compose(&user_sid, base_info->domain_sid, base_info->rid);
2595
2596                 if (base_info->full_name.string == NULL) {
2597                         struct netr_SamInfo3 *cached_info3;
2598
2599                         cached_info3 = netsamlogon_cache_get(mem_ctx,
2600                                                              &user_sid);
2601                         if (cached_info3 != NULL &&
2602                             cached_info3->base.full_name.string != NULL)
2603                         {
2604                                 base_info->full_name.string = talloc_strdup(
2605                                         base_ctx,
2606                                         cached_info3->base.full_name.string);
2607                         } else {
2608
2609                                 /* this might fail so we don't check the return code */
2610                                 wcache_query_user_fullname(domain,
2611                                                 base_ctx,
2612                                                 &user_sid,
2613                                                 &base_info->full_name.string);
2614                         }
2615                 }
2616
2617                 result = map_validation_to_info3(talloc_tos(),
2618                                                  validation_level,
2619                                                  validation,
2620                                                  &info3);
2621                 if (!NT_STATUS_IS_OK(result)) {
2622                         goto done;
2623                 }
2624                 wcache_invalidate_samlogon(find_domain_from_name(name_domain),
2625                                            &user_sid);
2626                 netsamlogon_cache_store(name_user, info3);
2627                 TALLOC_FREE(info3);
2628         }
2629
2630 done:
2631
2632         /* give us a more useful (more correct?) error code */
2633         if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
2634             (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
2635                 result = NT_STATUS_NO_LOGON_SERVERS;
2636         }
2637
2638         DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
2639               ("NTLM CRAP authentication for user [%s]\\[%s] returned %s\n",
2640                name_domain,
2641                name_user,
2642                nt_errstr(result)));
2643
2644         if (!NT_STATUS_IS_OK(result)) {
2645                 return result;
2646         }
2647
2648         *_validation_level = validation_level;
2649         *_validation = validation;
2650         return NT_STATUS_OK;
2651 }
2652
2653 enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain,
2654                                                  struct winbindd_cli_state *state)
2655 {
2656         NTSTATUS result;
2657         const char *name_user = NULL;
2658         const char *name_domain = NULL;
2659         const char *workstation;
2660         uint64_t logon_id = 0;
2661         uint8_t authoritative = 0;
2662         uint32_t flags = 0;
2663         uint16_t validation_level;
2664         union netr_Validation *validation = NULL;
2665         DATA_BLOB lm_resp = { 0 }, nt_resp = { 0 };
2666         const struct timeval start_time = timeval_current();
2667         const struct tsocket_address *remote = NULL;
2668         const struct tsocket_address *local = NULL;
2669
2670         /* This is child-only, so no check for privileged access is needed
2671            anymore */
2672
2673         /* Ensure null termination */
2674         state->request->data.auth_crap.user[sizeof(state->request->data.auth_crap.user)-1]=0;
2675         state->request->data.auth_crap.domain[sizeof(state->request->data.auth_crap.domain)-1]=0;
2676
2677         name_user = state->request->data.auth_crap.user;
2678         name_domain = state->request->data.auth_crap.domain;
2679         workstation = state->request->data.auth_crap.workstation;
2680         logon_id = generate_random_u64();
2681         remote = get_remote_address(state->mem_ctx, state->sock);
2682         local = get_local_address(state->mem_ctx, state->sock);
2683
2684         DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n", (unsigned long)state->pid,
2685                   name_domain, name_user));
2686
2687         if (state->request->data.auth_crap.lm_resp_len > sizeof(state->request->data.auth_crap.lm_resp)
2688                 || state->request->data.auth_crap.nt_resp_len > sizeof(state->request->data.auth_crap.nt_resp)) {
2689                 if (!(state->request->flags & WBFLAG_BIG_NTLMV2_BLOB) ||
2690                      state->request->extra_len != state->request->data.auth_crap.nt_resp_len) {
2691                         DEBUG(0, ("winbindd_pam_auth_crap: invalid password length %u/%u\n",
2692                                   state->request->data.auth_crap.lm_resp_len,
2693                                   state->request->data.auth_crap.nt_resp_len));
2694                         result = NT_STATUS_INVALID_PARAMETER;
2695                         goto done;
2696                 }
2697         }
2698
2699         lm_resp = data_blob_talloc(state->mem_ctx, state->request->data.auth_crap.lm_resp,
2700                                         state->request->data.auth_crap.lm_resp_len);
2701
2702         if (state->request->flags & WBFLAG_BIG_NTLMV2_BLOB) {
2703                 nt_resp = data_blob_talloc(state->mem_ctx,
2704                                            state->request->extra_data.data,
2705                                            state->request->data.auth_crap.nt_resp_len);
2706         } else {
2707                 nt_resp = data_blob_talloc(state->mem_ctx,
2708                                            state->request->data.auth_crap.nt_resp,
2709                                            state->request->data.auth_crap.nt_resp_len);
2710         }
2711
2712         result = winbind_dual_SamLogon(domain,
2713                                        state->mem_ctx,
2714                                        false, /* interactive */
2715                                        state->request->data.auth_crap.logon_parameters,
2716                                        name_user,
2717                                        name_domain,
2718                                        /* Bug #3248 - found by Stefan Burkei. */
2719                                        workstation, /* We carefully set this above so use it... */
2720                                        logon_id,
2721                                        state->request->client_name,
2722                                        state->request->pid,
2723                                        state->request->data.auth_crap.chal,
2724                                        lm_resp,
2725                                        nt_resp,
2726                                        remote,
2727                                        local,
2728                                        &authoritative,
2729                                        false,
2730                                        &flags,
2731                                        &validation_level,
2732                                        &validation);
2733         if (!NT_STATUS_IS_OK(result)) {
2734                 state->response->data.auth.authoritative = authoritative;
2735                 goto done;
2736         }
2737
2738         if (NT_STATUS_IS_OK(result)) {
2739                 struct netr_SamInfo3 *info3 = NULL;
2740
2741                 result = map_validation_to_info3(state->mem_ctx,
2742                                                  validation_level,
2743                                                  validation,
2744                                                  &info3);
2745                 if (!NT_STATUS_IS_OK(result)) {
2746                         goto done;
2747                 }
2748
2749                 /* Check if the user is in the right group */
2750                 result = check_info3_in_group(
2751                         info3,
2752                         state->request->data.auth_crap.require_membership_of_sid);
2753                 if (!NT_STATUS_IS_OK(result)) {
2754                         DEBUG(3, ("User %s is not in the required group (%s), so "
2755                                   "crap authentication is rejected\n",
2756                                   state->request->data.auth_crap.user,
2757                                   state->request->data.auth_crap.require_membership_of_sid));
2758                         goto done;
2759                 }
2760
2761                 result = append_auth_data(state->mem_ctx, state->response,
2762                                           state->request->flags,
2763                                           validation_level,
2764                                           validation,
2765                                           name_domain, name_user);
2766                 if (!NT_STATUS_IS_OK(result)) {
2767                         goto done;
2768                 }
2769         }
2770
2771 done:
2772
2773         if (state->request->flags & WBFLAG_PAM_NT_STATUS_SQUASH) {
2774                 result = nt_status_squash(result);
2775         }
2776
2777         set_auth_errors(state->response, result);
2778         /*
2779          * Log the winbind pam authentication, the logon_id will tie this to
2780          * any of the logons invoked from this request.
2781          */
2782         log_authentication(
2783             state->mem_ctx,
2784             domain,
2785             state,
2786             start_time,
2787             logon_id,
2788             "NTLM_AUTH",
2789             name_user,
2790             name_domain,
2791             workstation,
2792             lm_resp,
2793             nt_resp,
2794             remote,
2795             local,
2796             result);
2797
2798         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2799 }
2800
2801 enum winbindd_result winbindd_dual_pam_chauthtok(struct winbindd_domain *contact_domain,
2802                                                  struct winbindd_cli_state *state)
2803 {
2804         char *oldpass;
2805         char *newpass = NULL;
2806         struct policy_handle dom_pol;
2807         struct rpc_pipe_client *cli = NULL;
2808         bool got_info = false;
2809         struct samr_DomInfo1 *info = NULL;
2810         struct userPwdChangeFailureInformation *reject = NULL;
2811         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
2812         fstring namespace, domain, user;
2813         struct dcerpc_binding_handle *b = NULL;
2814         bool ok;
2815
2816         ZERO_STRUCT(dom_pol);
2817
2818         DEBUG(3, ("[%5lu]: dual pam chauthtok %s\n", (unsigned long)state->pid,
2819                   state->request->data.auth.user));
2820
2821         ok = parse_domain_user(state->request->data.chauthtok.user,
2822                                namespace,
2823                                domain,
2824                                user);
2825         if (!ok) {
2826                 goto done;
2827         }
2828
2829         /* Change password */
2830
2831         oldpass = state->request->data.chauthtok.oldpass;
2832         newpass = state->request->data.chauthtok.newpass;
2833
2834         /* Initialize reject reason */
2835         state->response->data.auth.reject_reason = Undefined;
2836
2837         /* Get sam handle */
2838
2839         result = cm_connect_sam(contact_domain, state->mem_ctx, true, &cli,
2840                                 &dom_pol);
2841         if (!NT_STATUS_IS_OK(result)) {
2842                 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
2843                 goto done;
2844         }
2845
2846         b = cli->binding_handle;
2847
2848         result = rpccli_samr_chgpasswd_user3(cli, state->mem_ctx,
2849                                              user,
2850                                              newpass,
2851                                              oldpass,
2852                                              &info,
2853                                              &reject);
2854
2855         /* Windows 2003 returns NT_STATUS_PASSWORD_RESTRICTION */
2856
2857         if (NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_RESTRICTION) ) {
2858
2859                 fill_in_password_policy(state->response, info);
2860
2861                 state->response->data.auth.reject_reason =
2862                         reject->extendedFailureReason;
2863
2864                 got_info = true;
2865         }
2866
2867         /* atm the pidl generated rpccli_samr_ChangePasswordUser3 function will
2868          * return with NT_STATUS_BUFFER_TOO_SMALL for w2k dcs as w2k just
2869          * returns with 4byte error code (NT_STATUS_NOT_SUPPORTED) which is too
2870          * short to comply with the samr_ChangePasswordUser3 idl - gd */
2871
2872         /* only fallback when the chgpasswd_user3 call is not supported */
2873         if (NT_STATUS_EQUAL(result, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE) ||
2874             NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED) ||
2875             NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL) ||
2876             NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
2877
2878                 DEBUG(10,("Password change with chgpasswd_user3 failed with: %s, retrying chgpasswd_user2\n",
2879                         nt_errstr(result)));
2880
2881                 result = rpccli_samr_chgpasswd_user2(cli, state->mem_ctx, user, newpass, oldpass);
2882
2883                 /* Windows 2000 returns NT_STATUS_ACCOUNT_RESTRICTION.
2884                    Map to the same status code as Windows 2003. */
2885
2886                 if ( NT_STATUS_EQUAL(NT_STATUS_ACCOUNT_RESTRICTION, result ) ) {
2887                         result = NT_STATUS_PASSWORD_RESTRICTION;
2888                 }
2889         }
2890
2891 done:
2892
2893         if (NT_STATUS_IS_OK(result)
2894             && (state->request->flags & WBFLAG_PAM_CACHED_LOGIN)
2895             && lp_winbind_offline_logon()) {
2896                 result = winbindd_update_creds_by_name(contact_domain, user,
2897                                                        newpass);
2898                 /* Again, this happens when we login from gdm or xdm
2899                  * and the password expires, *BUT* cached crendentials
2900                  * doesn't exist. winbindd_update_creds_by_name()
2901                  * returns NT_STATUS_NO_SUCH_USER.
2902                  * This is not a failure.
2903                  * --- BoYang
2904                  * */
2905                 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER)) {
2906                         result = NT_STATUS_OK;
2907                 }
2908
2909                 if (!NT_STATUS_IS_OK(result)) {
2910                         DEBUG(10, ("Failed to store creds: %s\n",
2911                                    nt_errstr(result)));
2912                         goto process_result;
2913                 }
2914         }
2915
2916         if (!NT_STATUS_IS_OK(result) && !got_info && contact_domain) {
2917
2918                 NTSTATUS policy_ret;
2919
2920                 policy_ret = fillup_password_policy(
2921                         contact_domain, state->response);
2922
2923                 /* failure of this is non critical, it will just provide no
2924                  * additional information to the client why the change has
2925                  * failed - Guenther */
2926
2927                 if (!NT_STATUS_IS_OK(policy_ret)) {
2928                         DEBUG(10,("Failed to get password policies: %s\n", nt_errstr(policy_ret)));
2929                         goto process_result;
2930                 }
2931         }
2932
2933 process_result:
2934
2935         if (strequal(contact_domain->name, get_global_sam_name())) {
2936                 /* FIXME: internal rpc pipe does not cache handles yet */
2937                 if (b) {
2938                         if (is_valid_policy_hnd(&dom_pol)) {
2939                                 NTSTATUS _result;
2940                                 dcerpc_samr_Close(b, state->mem_ctx, &dom_pol, &_result);
2941                         }
2942                         TALLOC_FREE(cli);
2943                 }
2944         }
2945
2946         set_auth_errors(state->response, result);
2947
2948         DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
2949               ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
2950                domain,
2951                user,
2952                state->response->data.auth.nt_status_string,
2953                state->response->data.auth.pam_error));
2954
2955         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2956 }
2957
2958 enum winbindd_result winbindd_dual_pam_logoff(struct winbindd_domain *domain,
2959                                               struct winbindd_cli_state *state)
2960 {
2961         NTSTATUS result = NT_STATUS_NOT_SUPPORTED;
2962
2963         DEBUG(3, ("[%5lu]: pam dual logoff %s\n", (unsigned long)state->pid,
2964                 state->request->data.logoff.user));
2965
2966         if (!(state->request->flags & WBFLAG_PAM_KRB5)) {
2967                 result = NT_STATUS_OK;
2968                 goto process_result;
2969         }
2970
2971         if (state->request->data.logoff.krb5ccname[0] == '\0') {
2972                 result = NT_STATUS_OK;
2973                 goto process_result;
2974         }
2975
2976 #ifdef HAVE_KRB5
2977
2978         if (state->request->data.logoff.uid == (uid_t)-1) {
2979                 DEBUG(0,("winbindd_pam_logoff: invalid uid\n"));
2980                 goto process_result;
2981         }
2982
2983         /* what we need here is to find the corresponding krb5 ccache name *we*
2984          * created for a given username and destroy it */
2985
2986         if (!ccache_entry_exists(state->request->data.logoff.user)) {
2987                 result = NT_STATUS_OK;
2988                 DEBUG(10,("winbindd_pam_logoff: no entry found.\n"));
2989                 goto process_result;
2990         }
2991
2992         if (!ccache_entry_identical(state->request->data.logoff.user,
2993                                         state->request->data.logoff.uid,
2994                                         state->request->data.logoff.krb5ccname)) {
2995                 DEBUG(0,("winbindd_pam_logoff: cached entry differs.\n"));
2996                 goto process_result;
2997         }
2998
2999         result = remove_ccache(state->request->data.logoff.user);
3000         if (!NT_STATUS_IS_OK(result)) {
3001                 DEBUG(0,("winbindd_pam_logoff: failed to remove ccache: %s\n",
3002                         nt_errstr(result)));
3003                 goto process_result;
3004         }
3005
3006         /*
3007          * Remove any mlock'ed memory creds in the child
3008          * we might be using for krb5 ticket renewal.
3009          */
3010
3011         winbindd_delete_memory_creds(state->request->data.logoff.user);
3012
3013 #else
3014         result = NT_STATUS_NOT_SUPPORTED;
3015 #endif
3016
3017 process_result:
3018
3019
3020         set_auth_errors(state->response, result);
3021
3022         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
3023 }
3024
3025 /* Change user password with auth crap*/
3026
3027 enum winbindd_result winbindd_dual_pam_chng_pswd_auth_crap(struct winbindd_domain *domainSt, struct winbindd_cli_state *state)
3028 {
3029         NTSTATUS result;
3030         DATA_BLOB new_nt_password;
3031         DATA_BLOB old_nt_hash_enc;
3032         DATA_BLOB new_lm_password;
3033         DATA_BLOB old_lm_hash_enc;
3034         fstring  namespace, domain, user;
3035         struct policy_handle dom_pol;
3036         struct winbindd_domain *contact_domain = domainSt;
3037         struct rpc_pipe_client *cli = NULL;
3038         struct dcerpc_binding_handle *b = NULL;
3039
3040         ZERO_STRUCT(dom_pol);
3041
3042         /* Ensure null termination */
3043         state->request->data.chng_pswd_auth_crap.user[
3044                 sizeof(state->request->data.chng_pswd_auth_crap.user)-1]=0;
3045         state->request->data.chng_pswd_auth_crap.domain[
3046                 sizeof(state->request->data.chng_pswd_auth_crap.domain)-1]=0;
3047         domain[0] = '\0';
3048         namespace[0] = '\0';
3049         user[0] = '\0';
3050
3051         DEBUG(3, ("[%5lu]: pam change pswd auth crap domain: %s user: %s\n",
3052                   (unsigned long)state->pid,
3053                   state->request->data.chng_pswd_auth_crap.domain,
3054                   state->request->data.chng_pswd_auth_crap.user));
3055
3056         if (lp_winbind_offline_logon()) {
3057                 DEBUG(0,("Refusing password change as winbind offline logons are enabled. "));
3058                 DEBUGADD(0,("Changing passwords here would risk inconsistent logons\n"));
3059                 result = NT_STATUS_ACCESS_DENIED;
3060                 goto done;
3061         }
3062
3063         if (*state->request->data.chng_pswd_auth_crap.domain) {
3064                 fstrcpy(domain,state->request->data.chng_pswd_auth_crap.domain);
3065         } else {
3066                 bool ok;
3067
3068                 ok = parse_domain_user(state->request->data.chng_pswd_auth_crap.user,
3069                                        namespace,
3070                                        domain,
3071                                        user);
3072                 if (!ok) {
3073                         result = NT_STATUS_INVALID_PARAMETER;
3074                         goto done;
3075                 }
3076
3077                 if(!*domain) {
3078                         DEBUG(3,("no domain specified with username (%s) - "
3079                                  "failing auth\n",
3080                                  state->request->data.chng_pswd_auth_crap.user));
3081                         result = NT_STATUS_NO_SUCH_USER;
3082                         goto done;
3083                 }
3084         }
3085
3086         if (!*domain && lp_winbind_use_default_domain()) {
3087                 fstrcpy(domain,lp_workgroup());
3088         }
3089
3090         if(!*user) {
3091                 fstrcpy(user, state->request->data.chng_pswd_auth_crap.user);
3092         }
3093
3094         DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n",
3095                   (unsigned long)state->pid, domain, user));
3096
3097         /* Change password */
3098         new_nt_password = data_blob_const(
3099                 state->request->data.chng_pswd_auth_crap.new_nt_pswd,
3100                 state->request->data.chng_pswd_auth_crap.new_nt_pswd_len);
3101
3102         old_nt_hash_enc = data_blob_const(
3103                 state->request->data.chng_pswd_auth_crap.old_nt_hash_enc,
3104                 state->request->data.chng_pswd_auth_crap.old_nt_hash_enc_len);
3105
3106         if(state->request->data.chng_pswd_auth_crap.new_lm_pswd_len > 0)        {
3107                 new_lm_password = data_blob_const(
3108                         state->request->data.chng_pswd_auth_crap.new_lm_pswd,
3109                         state->request->data.chng_pswd_auth_crap.new_lm_pswd_len);
3110
3111                 old_lm_hash_enc = data_blob_const(
3112                         state->request->data.chng_pswd_auth_crap.old_lm_hash_enc,
3113                         state->request->data.chng_pswd_auth_crap.old_lm_hash_enc_len);
3114         } else {
3115                 new_lm_password = data_blob_null;
3116                 old_lm_hash_enc = data_blob_null;
3117         }
3118
3119         /* Get sam handle */
3120
3121         result = cm_connect_sam(contact_domain, state->mem_ctx, true, &cli, &dom_pol);
3122         if (!NT_STATUS_IS_OK(result)) {
3123                 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
3124                 goto done;
3125         }
3126
3127         b = cli->binding_handle;
3128
3129         result = rpccli_samr_chng_pswd_auth_crap(
3130                 cli, state->mem_ctx, user, new_nt_password, old_nt_hash_enc,
3131                 new_lm_password, old_lm_hash_enc);
3132
3133  done:
3134
3135         if (strequal(contact_domain->name, get_global_sam_name())) {
3136                 /* FIXME: internal rpc pipe does not cache handles yet */
3137                 if (b) {
3138                         if (is_valid_policy_hnd(&dom_pol)) {
3139                                 NTSTATUS _result;
3140                                 dcerpc_samr_Close(b, state->mem_ctx, &dom_pol, &_result);
3141                         }
3142                         TALLOC_FREE(cli);
3143                 }
3144         }
3145
3146         set_auth_errors(state->response, result);
3147
3148         DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
3149               ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
3150                domain, user,
3151                state->response->data.auth.nt_status_string,
3152                state->response->data.auth.pam_error));
3153
3154         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
3155 }
3156
3157 #ifdef HAVE_KRB5
3158 static NTSTATUS extract_pac_vrfy_sigs(TALLOC_CTX *mem_ctx, DATA_BLOB pac_blob,
3159                                       struct PAC_DATA **p_pac_data)
3160 {
3161         krb5_context krbctx = NULL;
3162         krb5_error_code k5ret;
3163         krb5_keytab keytab;
3164         krb5_kt_cursor cursor;
3165         krb5_keytab_entry entry;
3166         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
3167
3168         ZERO_STRUCT(entry);
3169         ZERO_STRUCT(cursor);
3170
3171         k5ret = smb_krb5_init_context_common(&krbctx);
3172         if (k5ret) {
3173                 DBG_ERR("kerberos init context failed (%s)\n",
3174                         error_message(k5ret));
3175                 status = krb5_to_nt_status(k5ret);
3176                 goto out;
3177         }
3178
3179         k5ret =  gse_krb5_get_server_keytab(krbctx, &keytab);
3180         if (k5ret) {
3181                 DEBUG(1, ("Failed to get keytab: %s\n",
3182                           error_message(k5ret)));
3183                 status = krb5_to_nt_status(k5ret);
3184                 goto out_free;
3185         }
3186
3187         k5ret = krb5_kt_start_seq_get(krbctx, keytab, &cursor);
3188         if (k5ret) {
3189                 DEBUG(1, ("Failed to start seq: %s\n",
3190                           error_message(k5ret)));
3191                 status = krb5_to_nt_status(k5ret);
3192                 goto out_keytab;
3193         }
3194
3195         k5ret = krb5_kt_next_entry(krbctx, keytab, &entry, &cursor);
3196         while (k5ret == 0) {
3197                 status = kerberos_decode_pac(mem_ctx,
3198                                              pac_blob,
3199                                              krbctx,
3200                                              NULL, /* krbtgt_keyblock */
3201                                              KRB5_KT_KEY(&entry), /* service_keyblock */
3202                                              NULL, /* client_principal */
3203                                              0, /* tgs_authtime */
3204                                              p_pac_data);
3205                 if (NT_STATUS_IS_OK(status)) {
3206                         break;
3207                 }
3208                 k5ret = smb_krb5_kt_free_entry(krbctx, &entry);
3209                 k5ret = krb5_kt_next_entry(krbctx, keytab, &entry, &cursor);
3210         }
3211
3212         k5ret = krb5_kt_end_seq_get(krbctx, keytab, &cursor);
3213         if (k5ret) {
3214                 DEBUG(1, ("Failed to end seq: %s\n",
3215                           error_message(k5ret)));
3216         }
3217 out_keytab:
3218         k5ret = krb5_kt_close(krbctx, keytab);
3219         if (k5ret) {
3220                 DEBUG(1, ("Failed to close keytab: %s\n",
3221                           error_message(k5ret)));
3222         }
3223 out_free:
3224         krb5_free_context(krbctx);
3225 out:
3226         return status;
3227 }
3228
3229 NTSTATUS winbindd_pam_auth_pac_verify(struct winbindd_cli_state *state,
3230                                       bool *p_is_trusted,
3231                                       uint16_t *p_validation_level,
3232                                       union netr_Validation **p_validation)
3233 {
3234         struct winbindd_request *req = state->request;
3235         DATA_BLOB pac_blob;
3236         struct PAC_DATA *pac_data = NULL;
3237         struct PAC_LOGON_INFO *logon_info = NULL;
3238         struct PAC_UPN_DNS_INFO *upn_dns_info = NULL;
3239         struct netr_SamInfo6 *info6 = NULL;
3240         uint16_t validation_level = 0;
3241         union netr_Validation *validation = NULL;
3242         struct netr_SamInfo3 *info3_copy = NULL;
3243         NTSTATUS result;
3244         bool is_trusted = false;
3245         uint32_t i;
3246
3247         *p_is_trusted = false;
3248         *p_validation_level = 0;
3249         *p_validation = NULL;
3250
3251         pac_blob = data_blob_const(req->extra_data.data, req->extra_len);
3252         result = extract_pac_vrfy_sigs(state->mem_ctx, pac_blob, &pac_data);
3253         if (NT_STATUS_IS_OK(result)) {
3254                 is_trusted = true;
3255         }
3256         if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
3257                 /* Try without signature verification */
3258                 result = kerberos_decode_pac(state->mem_ctx,
3259                                              pac_blob,
3260                                              NULL, /* krb5_context */
3261                                              NULL, /* krbtgt_keyblock */
3262                                              NULL, /* service_keyblock */
3263                                              NULL, /* client_principal */
3264                                              0, /* tgs_authtime */
3265                                              &pac_data);
3266         }
3267         if (!NT_STATUS_IS_OK(result)) {
3268                 DEBUG(1, ("Error during PAC signature verification: %s\n",
3269                           nt_errstr(result)));
3270                 return result;
3271         }
3272
3273         for (i=0; i < pac_data->num_buffers; i++) {
3274                 if (pac_data->buffers[i].type == PAC_TYPE_LOGON_INFO) {
3275                         logon_info = pac_data->buffers[i].info->logon_info.info;
3276                         continue;
3277                 }
3278                 if (pac_data->buffers[i].type == PAC_TYPE_UPN_DNS_INFO) {
3279                         upn_dns_info = &pac_data->buffers[i].info->upn_dns_info;
3280                         continue;
3281                 }
3282         }
3283
3284         result = create_info6_from_pac(state->mem_ctx,
3285                                        logon_info,
3286                                        upn_dns_info,
3287                                        &info6);
3288         if (!NT_STATUS_IS_OK(result)) {
3289                 return result;
3290         }
3291
3292         result = map_info6_to_validation(state->mem_ctx,
3293                                          info6,
3294                                          &validation_level,
3295                                          &validation);
3296         if (!NT_STATUS_IS_OK(result)) {
3297                 return result;
3298         }
3299
3300         result = map_validation_to_info3(state->mem_ctx,
3301                                          validation_level,
3302                                          validation,
3303                                          &info3_copy);
3304         if (!NT_STATUS_IS_OK(result)) {
3305                 return result;
3306         }
3307
3308         if (is_trusted) {
3309                 /*
3310                  * Signature verification succeeded, we can
3311                  * trust the PAC and prime the netsamlogon
3312                  * and name2sid caches. DO NOT DO THIS
3313                  * in the signature verification failed
3314                  * code path.
3315                  */
3316                 struct winbindd_domain *domain = NULL;
3317
3318                 netsamlogon_cache_store(NULL, info3_copy);
3319
3320                 /*
3321                  * We're in the parent here, so find the child
3322                  * pointer from the PAC domain name.
3323                  */
3324                 domain = find_lookup_domain_from_name(
3325                                 info3_copy->base.logon_domain.string);
3326                 if (domain && domain->primary ) {
3327                         struct dom_sid user_sid;
3328                         struct dom_sid_buf buf;
3329
3330                         sid_compose(&user_sid,
3331                                 info3_copy->base.domain_sid,
3332                                 info3_copy->base.rid);
3333
3334                         cache_name2sid_trusted(domain,
3335                                 info3_copy->base.logon_domain.string,
3336                                 info3_copy->base.account_name.string,
3337                                 SID_NAME_USER,
3338                                 &user_sid);
3339
3340                         DBG_INFO("PAC for user %s\\%s SID %s primed cache\n",
3341                                 info3_copy->base.logon_domain.string,
3342                                 info3_copy->base.account_name.string,
3343                                 dom_sid_str_buf(&user_sid, &buf));
3344                 }
3345         }
3346
3347         *p_is_trusted = is_trusted;
3348         *p_validation_level = validation_level;
3349         *p_validation = validation;
3350         return NT_STATUS_OK;
3351 }
3352 #else /* HAVE_KRB5 */
3353 NTSTATUS winbindd_pam_auth_pac_verify(struct winbindd_cli_state *state,
3354                                       bool *p_is_trusted,
3355                                       uint16_t *p_validation_level,
3356                                       union netr_Validation **p_validation);
3357 {
3358
3359         *p_is_trusted = false;
3360         *p_validation_level = 0;
3361         *p_validation = NULL;
3362         return NT_STATUS_NO_SUCH_USER;
3363 }
3364 #endif /* HAVE_KRB5 */