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