auth: Provide a way to use the auth stack for winbindd authentication
[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);
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 *domainname,
1296                                             const char *workstation,
1297                                             const uint8_t chal[8],
1298                                             DATA_BLOB lm_response,
1299                                             DATA_BLOB nt_response,
1300                                             struct netr_SamInfo3 **info3)
1301 {
1302         int attempts = 0;
1303         int netr_attempts = 0;
1304         bool retry = false;
1305         NTSTATUS result;
1306
1307         do {
1308                 struct rpc_pipe_client *netlogon_pipe;
1309                 uint8_t authoritative = 0;
1310                 uint32_t flags = 0;
1311
1312                 ZERO_STRUCTP(info3);
1313                 retry = false;
1314
1315                 result = cm_connect_netlogon(domain, &netlogon_pipe);
1316
1317                 if (!NT_STATUS_IS_OK(result)) {
1318                         DEBUG(3,("Could not open handle to NETLOGON pipe "
1319                                  "(error: %s, attempts: %d)\n",
1320                                   nt_errstr(result), netr_attempts));
1321
1322                         /* After the first retry always close the connection */
1323                         if (netr_attempts > 0) {
1324                                 DEBUG(3, ("This is again a problem for this "
1325                                           "particular call, forcing the close "
1326                                           "of this connection\n"));
1327                                 invalidate_cm_connection(&domain->conn);
1328                         }
1329
1330                         /* After the second retry failover to the next DC */
1331                         if (netr_attempts > 1) {
1332                                 /*
1333                                  * If the netlogon server is not reachable then
1334                                  * it is possible that the DC is rebuilding
1335                                  * sysvol and shutdown netlogon for that time.
1336                                  * We should failover to the next dc.
1337                                  */
1338                                 DEBUG(3, ("This is the third problem for this "
1339                                           "particular call, adding DC to the "
1340                                           "negative cache list\n"));
1341                                 add_failed_connection_entry(domain->name,
1342                                                             domain->dcname,
1343                                                             result);
1344                                 saf_delete(domain->name);
1345                         }
1346
1347                         /* Only allow 3 retries */
1348                         if (netr_attempts < 3) {
1349                                 DEBUG(3, ("The connection to netlogon "
1350                                           "failed, retrying\n"));
1351                                 netr_attempts++;
1352                                 retry = true;
1353                                 continue;
1354                         }
1355                         return result;
1356                 }
1357                 netr_attempts = 0;
1358
1359                 result = rpccli_netlogon_network_logon(domain->conn.netlogon_creds,
1360                                                 netlogon_pipe->binding_handle,
1361                                                 mem_ctx,
1362                                                 logon_parameters,
1363                                                 username,
1364                                                 domainname,
1365                                                 workstation,
1366                                                 chal,
1367                                                 lm_response,
1368                                                 nt_response,
1369                                                 &authoritative,
1370                                                 &flags,
1371                                                 info3);
1372
1373                 /*
1374                  * we increment this after the "feature negotiation"
1375                  * for can_do_samlogon_ex and can_do_validation6
1376                  */
1377                 attempts += 1;
1378
1379                 /* We have to try a second time as cm_connect_netlogon
1380                    might not yet have noticed that the DC has killed
1381                    our connection. */
1382
1383                 if (!rpccli_is_connected(netlogon_pipe)) {
1384                         retry = true;
1385                         continue;
1386                 }
1387
1388                 /* if we get access denied, a possible cause was that we had
1389                    and open connection to the DC, but someone changed our
1390                    machine account password out from underneath us using 'net
1391                    rpc changetrustpw' */
1392
1393                 if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
1394                         DEBUG(3,("winbind_samlogon_retry_loop: sam_logon returned "
1395                                  "ACCESS_DENIED.  Maybe the trust account "
1396                                 "password was changed and we didn't know it. "
1397                                  "Killing connections to domain %s\n",
1398                                 domainname));
1399                         invalidate_cm_connection(&domain->conn);
1400                         retry = true;
1401                 }
1402
1403                 if (NT_STATUS_EQUAL(result, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1404                         /*
1405                          * Got DCERPC_FAULT_OP_RNG_ERROR for SamLogon
1406                          * (no Ex). This happens against old Samba
1407                          * DCs, if LogonSamLogonEx() fails with an error
1408                          * e.g. NT_STATUS_NO_SUCH_USER or NT_STATUS_WRONG_PASSWORD.
1409                          *
1410                          * The server will log something like this:
1411                          * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
1412                          *
1413                          * This sets the whole connection into a fault_state mode
1414                          * and all following request get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
1415                          *
1416                          * This also happens to our retry with LogonSamLogonWithFlags()
1417                          * and LogonSamLogon().
1418                          *
1419                          * In order to recover from this situation, we need to
1420                          * drop the connection.
1421                          */
1422                         invalidate_cm_connection(&domain->conn);
1423                         result = NT_STATUS_LOGON_FAILURE;
1424                         break;
1425                 }
1426
1427         } while ( (attempts < 2) && retry );
1428
1429         if (NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT)) {
1430                 DEBUG(3,("winbind_samlogon_retry_loop: sam_network_logon(ex) "
1431                                 "returned NT_STATUS_IO_TIMEOUT after the retry."
1432                                 "Killing connections to domain %s\n",
1433                         domainname));
1434                 invalidate_cm_connection(&domain->conn);
1435         }
1436         return result;
1437 }
1438
1439 static NTSTATUS winbindd_dual_pam_auth_samlogon(TALLOC_CTX *mem_ctx,
1440                                                 struct winbindd_domain *domain,
1441                                                 const char *user,
1442                                                 const char *pass,
1443                                                 uint32_t request_flags,
1444                                                 struct netr_SamInfo3 **info3)
1445 {
1446
1447         uchar chal[8];
1448         DATA_BLOB lm_resp;
1449         DATA_BLOB nt_resp;
1450         unsigned char local_nt_response[24];
1451         fstring name_domain, name_user;
1452         NTSTATUS result;
1453         struct netr_SamInfo3 *my_info3 = NULL;
1454
1455         *info3 = NULL;
1456
1457         DEBUG(10,("winbindd_dual_pam_auth_samlogon\n"));
1458
1459         /* Parse domain and username */
1460
1461         parse_domain_user(user, name_domain, name_user);
1462
1463         /* do password magic */
1464
1465         generate_random_buffer(chal, sizeof(chal));
1466
1467         if (lp_client_ntlmv2_auth()) {
1468                 DATA_BLOB server_chal;
1469                 DATA_BLOB names_blob;
1470                 server_chal = data_blob_const(chal, 8);
1471
1472                 /* note that the 'workgroup' here is for the local
1473                    machine.  The 'server name' must match the
1474                    'workstation' passed to the actual SamLogon call.
1475                 */
1476                 names_blob = NTLMv2_generate_names_blob(
1477                         mem_ctx, lp_netbios_name(), lp_workgroup());
1478
1479                 if (!SMBNTLMv2encrypt(mem_ctx, name_user, name_domain,
1480                                       pass,
1481                                       &server_chal,
1482                                       &names_blob,
1483                                       &lm_resp, &nt_resp, NULL, NULL)) {
1484                         data_blob_free(&names_blob);
1485                         DEBUG(0, ("winbindd_pam_auth: SMBNTLMv2encrypt() failed!\n"));
1486                         result = NT_STATUS_NO_MEMORY;
1487                         goto done;
1488                 }
1489                 data_blob_free(&names_blob);
1490         } else {
1491                 lm_resp = data_blob_null;
1492                 SMBNTencrypt(pass, chal, local_nt_response);
1493
1494                 nt_resp = data_blob_talloc(mem_ctx, local_nt_response,
1495                                            sizeof(local_nt_response));
1496         }
1497
1498         if (strequal(name_domain, get_global_sam_name())) {
1499                 DATA_BLOB chal_blob = data_blob_const(chal, sizeof(chal));
1500
1501                 result = winbindd_dual_auth_passdb(
1502                         mem_ctx, 0, name_domain, name_user,
1503                         &chal_blob, &lm_resp, &nt_resp, info3);
1504                 goto done;
1505         }
1506
1507         /* check authentication loop */
1508
1509         result = winbind_samlogon_retry_loop(domain,
1510                                              mem_ctx,
1511                                              0,
1512                                              domain->dcname,
1513                                              name_user,
1514                                              name_domain,
1515                                              lp_netbios_name(),
1516                                              chal,
1517                                              lm_resp,
1518                                              nt_resp,
1519                                              &my_info3);
1520         if (!NT_STATUS_IS_OK(result)) {
1521                 goto done;
1522         }
1523
1524         /* handle the case where a NT4 DC does not fill in the acct_flags in
1525          * the samlogon reply info3. When accurate info3 is required by the
1526          * caller, we look up the account flags ourselve - gd */
1527
1528         if ((request_flags & WBFLAG_PAM_INFO3_TEXT) &&
1529             NT_STATUS_IS_OK(result) && (my_info3->base.acct_flags == 0)) {
1530
1531                 struct rpc_pipe_client *samr_pipe;
1532                 struct policy_handle samr_domain_handle, user_pol;
1533                 union samr_UserInfo *info = NULL;
1534                 NTSTATUS status_tmp, result_tmp;
1535                 uint32 acct_flags;
1536                 struct dcerpc_binding_handle *b;
1537
1538                 status_tmp = cm_connect_sam(domain, mem_ctx,
1539                                             &samr_pipe, &samr_domain_handle);
1540
1541                 if (!NT_STATUS_IS_OK(status_tmp)) {
1542                         DEBUG(3, ("could not open handle to SAMR pipe: %s\n",
1543                                 nt_errstr(status_tmp)));
1544                         goto done;
1545                 }
1546
1547                 b = samr_pipe->binding_handle;
1548
1549                 status_tmp = dcerpc_samr_OpenUser(b, mem_ctx,
1550                                                   &samr_domain_handle,
1551                                                   MAXIMUM_ALLOWED_ACCESS,
1552                                                   my_info3->base.rid,
1553                                                   &user_pol,
1554                                                   &result_tmp);
1555
1556                 if (!NT_STATUS_IS_OK(status_tmp)) {
1557                         DEBUG(3, ("could not open user handle on SAMR pipe: %s\n",
1558                                 nt_errstr(status_tmp)));
1559                         goto done;
1560                 }
1561                 if (!NT_STATUS_IS_OK(result_tmp)) {
1562                         DEBUG(3, ("could not open user handle on SAMR pipe: %s\n",
1563                                 nt_errstr(result_tmp)));
1564                         goto done;
1565                 }
1566
1567                 status_tmp = dcerpc_samr_QueryUserInfo(b, mem_ctx,
1568                                                        &user_pol,
1569                                                        16,
1570                                                        &info,
1571                                                        &result_tmp);
1572
1573                 if (!NT_STATUS_IS_OK(status_tmp)) {
1574                         DEBUG(3, ("could not query user info on SAMR pipe: %s\n",
1575                                 nt_errstr(status_tmp)));
1576                         dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
1577                         goto done;
1578                 }
1579                 if (!NT_STATUS_IS_OK(result_tmp)) {
1580                         DEBUG(3, ("could not query user info on SAMR pipe: %s\n",
1581                                 nt_errstr(result_tmp)));
1582                         dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
1583                         goto done;
1584                 }
1585
1586                 acct_flags = info->info16.acct_flags;
1587
1588                 if (acct_flags == 0) {
1589                         dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
1590                         goto done;
1591                 }
1592
1593                 my_info3->base.acct_flags = acct_flags;
1594
1595                 DEBUG(10,("successfully retrieved acct_flags 0x%x\n", acct_flags));
1596
1597                 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
1598         }
1599
1600         *info3 = my_info3;
1601 done:
1602         return result;
1603 }
1604
1605 enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain,
1606                                             struct winbindd_cli_state *state)
1607 {
1608         NTSTATUS result = NT_STATUS_LOGON_FAILURE;
1609         NTSTATUS krb5_result = NT_STATUS_OK;
1610         fstring name_domain, name_user;
1611         char *mapped_user;
1612         fstring domain_user;
1613         struct netr_SamInfo3 *info3 = NULL;
1614         NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL;
1615
1616         /* Ensure null termination */
1617         state->request->data.auth.user[sizeof(state->request->data.auth.user)-1]='\0';
1618
1619         /* Ensure null termination */
1620         state->request->data.auth.pass[sizeof(state->request->data.auth.pass)-1]='\0';
1621
1622         DEBUG(3, ("[%5lu]: dual pam auth %s\n", (unsigned long)state->pid,
1623                   state->request->data.auth.user));
1624
1625         /* Parse domain and username */
1626
1627         name_map_status = normalize_name_unmap(state->mem_ctx,
1628                                                state->request->data.auth.user,
1629                                                &mapped_user);
1630
1631         /* If the name normalization didnt' actually do anything,
1632            just use the original name */
1633
1634         if (!NT_STATUS_IS_OK(name_map_status) &&
1635             !NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED))
1636         {
1637                 mapped_user = state->request->data.auth.user;
1638         }
1639
1640         parse_domain_user(mapped_user, name_domain, name_user);
1641
1642         if ( mapped_user != state->request->data.auth.user ) {
1643                 fstr_sprintf( domain_user, "%s%c%s", name_domain,
1644                         *lp_winbind_separator(),
1645                         name_user );
1646                 strlcpy( state->request->data.auth.user, domain_user,
1647                              sizeof(state->request->data.auth.user));
1648         }
1649
1650         if (!domain->online) {
1651                 result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
1652                 if (domain->startup) {
1653                         /* Logons are very important to users. If we're offline and
1654                            we get a request within the first 30 seconds of startup,
1655                            try very hard to find a DC and go online. */
1656
1657                         DEBUG(10,("winbindd_dual_pam_auth: domain: %s offline and auth "
1658                                 "request in startup mode.\n", domain->name ));
1659
1660                         winbindd_flush_negative_conn_cache(domain);
1661                         result = init_dc_connection(domain);
1662                 }
1663         }
1664
1665         DEBUG(10,("winbindd_dual_pam_auth: domain: %s last was %s\n", domain->name, domain->online ? "online":"offline"));
1666
1667         /* Check for Kerberos authentication */
1668         if (domain->online && (state->request->flags & WBFLAG_PAM_KRB5)) {
1669
1670                 result = winbindd_dual_pam_auth_kerberos(domain, state, &info3);
1671                 /* save for later */
1672                 krb5_result = result;
1673
1674
1675                 if (NT_STATUS_IS_OK(result)) {
1676                         DEBUG(10,("winbindd_dual_pam_auth_kerberos succeeded\n"));
1677                         goto process_result;
1678                 } else {
1679                         DEBUG(10,("winbindd_dual_pam_auth_kerberos failed: %s\n", nt_errstr(result)));
1680                 }
1681
1682                 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
1683                     NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
1684                     NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1685                         DEBUG(10,("winbindd_dual_pam_auth_kerberos setting domain to offline\n"));
1686                         set_domain_offline( domain );
1687                         goto cached_logon;
1688                 }
1689
1690                 /* there are quite some NT_STATUS errors where there is no
1691                  * point in retrying with a samlogon, we explictly have to take
1692                  * care not to increase the bad logon counter on the DC */
1693
1694                 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_DISABLED) ||
1695                     NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_EXPIRED) ||
1696                     NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_LOCKED_OUT) ||
1697                     NT_STATUS_EQUAL(result, NT_STATUS_INVALID_LOGON_HOURS) ||
1698                     NT_STATUS_EQUAL(result, NT_STATUS_INVALID_WORKSTATION) ||
1699                     NT_STATUS_EQUAL(result, NT_STATUS_LOGON_FAILURE) ||
1700                     NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER) ||
1701                     NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_EXPIRED) ||
1702                     NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_MUST_CHANGE) ||
1703                     NT_STATUS_EQUAL(result, NT_STATUS_WRONG_PASSWORD)) {
1704                         goto done;
1705                 }
1706
1707                 if (state->request->flags & WBFLAG_PAM_FALLBACK_AFTER_KRB5) {
1708                         DEBUG(3,("falling back to samlogon\n"));
1709                         goto sam_logon;
1710                 } else {
1711                         goto cached_logon;
1712                 }
1713         }
1714
1715 sam_logon:
1716         /* Check for Samlogon authentication */
1717         if (domain->online) {
1718                 result = winbindd_dual_pam_auth_samlogon(
1719                         state->mem_ctx, domain,
1720                         state->request->data.auth.user,
1721                         state->request->data.auth.pass,
1722                         state->request->flags,
1723                         &info3);
1724
1725                 if (NT_STATUS_IS_OK(result)) {
1726                         DEBUG(10,("winbindd_dual_pam_auth_samlogon succeeded\n"));
1727                         /* add the Krb5 err if we have one */
1728                         if ( NT_STATUS_EQUAL(krb5_result, NT_STATUS_TIME_DIFFERENCE_AT_DC ) ) {
1729                                 info3->base.user_flags |= LOGON_KRB5_FAIL_CLOCK_SKEW;
1730                         }
1731                         goto process_result;
1732                 }
1733
1734                 DEBUG(10,("winbindd_dual_pam_auth_samlogon failed: %s\n",
1735                           nt_errstr(result)));
1736
1737                 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
1738                     NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
1739                     NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND))
1740                 {
1741                         DEBUG(10,("winbindd_dual_pam_auth_samlogon setting domain to offline\n"));
1742                         set_domain_offline( domain );
1743                         goto cached_logon;
1744                 }
1745
1746                         if (domain->online) {
1747                                 /* We're still online - fail. */
1748                                 goto done;
1749                         }
1750         }
1751
1752 cached_logon:
1753         /* Check for Cached logons */
1754         if (!domain->online && (state->request->flags & WBFLAG_PAM_CACHED_LOGIN) &&
1755             lp_winbind_offline_logon()) {
1756
1757                 result = winbindd_dual_pam_auth_cached(domain, state, &info3);
1758
1759                 if (NT_STATUS_IS_OK(result)) {
1760                         DEBUG(10,("winbindd_dual_pam_auth_cached succeeded\n"));
1761                         goto process_result;
1762                 } else {
1763                         DEBUG(10,("winbindd_dual_pam_auth_cached failed: %s\n", nt_errstr(result)));
1764                         goto done;
1765                 }
1766         }
1767
1768 process_result:
1769
1770         if (NT_STATUS_IS_OK(result)) {
1771
1772                 struct dom_sid user_sid;
1773
1774                 /* In all codepaths where result == NT_STATUS_OK info3 must have
1775                    been initialized. */
1776                 if (!info3) {
1777                         result = NT_STATUS_INTERNAL_ERROR;
1778                         goto done;
1779                 }
1780
1781                 sid_compose(&user_sid, info3->base.domain_sid,
1782                             info3->base.rid);
1783
1784                 wcache_invalidate_samlogon(find_domain_from_name(name_domain),
1785                                            &user_sid);
1786                 netsamlogon_cache_store(name_user, info3);
1787
1788                 /* save name_to_sid info as early as possible (only if
1789                    this is our primary domain so we don't invalidate
1790                    the cache entry by storing the seq_num for the wrong
1791                    domain). */
1792                 if ( domain->primary ) {
1793                         cache_name2sid(domain, name_domain, name_user,
1794                                        SID_NAME_USER, &user_sid);
1795                 }
1796
1797                 /* Check if the user is in the right group */
1798
1799                 result = check_info3_in_group(
1800                         info3,
1801                         state->request->data.auth.require_membership_of_sid);
1802                 if (!NT_STATUS_IS_OK(result)) {
1803                         DEBUG(3, ("User %s is not in the required group (%s), so plaintext authentication is rejected\n",
1804                                   state->request->data.auth.user,
1805                                   state->request->data.auth.require_membership_of_sid));
1806                         goto done;
1807                 }
1808
1809                 result = append_auth_data(state->mem_ctx, state->response,
1810                                           state->request->flags, info3,
1811                                           name_domain, name_user);
1812                 if (!NT_STATUS_IS_OK(result)) {
1813                         goto done;
1814                 }
1815
1816                 if ((state->request->flags & WBFLAG_PAM_CACHED_LOGIN)
1817                     && lp_winbind_offline_logon()) {
1818
1819                         result = winbindd_store_creds(domain,
1820                                                       state->request->data.auth.user,
1821                                                       state->request->data.auth.pass,
1822                                                       info3);
1823                 }
1824
1825                 if (state->request->flags & WBFLAG_PAM_GET_PWD_POLICY) {
1826                         struct winbindd_domain *our_domain = find_our_domain();
1827
1828                         /* This is not entirely correct I believe, but it is
1829                            consistent.  Only apply the password policy settings
1830                            too warn users for our own domain.  Cannot obtain these
1831                            from trusted DCs all the  time so don't do it at all.
1832                            -- jerry */
1833
1834                         result = NT_STATUS_NOT_SUPPORTED;
1835                         if (our_domain == domain ) {
1836                                 result = fillup_password_policy(
1837                                         our_domain, state->response);
1838                         }
1839
1840                         if (!NT_STATUS_IS_OK(result)
1841                             && !NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED) )
1842                         {
1843                                 DEBUG(10,("Failed to get password policies for domain %s: %s\n",
1844                                           domain->name, nt_errstr(result)));
1845                                 goto done;
1846                         }
1847                 }
1848
1849                 result = NT_STATUS_OK;
1850         }
1851
1852 done:
1853         /* give us a more useful (more correct?) error code */
1854         if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
1855             (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
1856                 result = NT_STATUS_NO_LOGON_SERVERS;
1857         }
1858
1859         set_auth_errors(state->response, result);
1860
1861         DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, ("Plain-text authentication for user %s returned %s (PAM: %d)\n",
1862               state->request->data.auth.user,
1863               state->response->data.auth.nt_status_string,
1864               state->response->data.auth.pam_error));
1865
1866         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
1867 }
1868
1869 enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain,
1870                                                  struct winbindd_cli_state *state)
1871 {
1872         NTSTATUS result;
1873         struct netr_SamInfo3 *info3 = NULL;
1874         const char *name_user = NULL;
1875         const char *name_domain = NULL;
1876         const char *workstation;
1877
1878         DATA_BLOB lm_resp, nt_resp;
1879
1880         /* This is child-only, so no check for privileged access is needed
1881            anymore */
1882
1883         /* Ensure null termination */
1884         state->request->data.auth_crap.user[sizeof(state->request->data.auth_crap.user)-1]=0;
1885         state->request->data.auth_crap.domain[sizeof(state->request->data.auth_crap.domain)-1]=0;
1886
1887         name_user = state->request->data.auth_crap.user;
1888         name_domain = state->request->data.auth_crap.domain;
1889         workstation = state->request->data.auth_crap.workstation;
1890
1891         DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n", (unsigned long)state->pid,
1892                   name_domain, name_user));
1893
1894         if (state->request->data.auth_crap.lm_resp_len > sizeof(state->request->data.auth_crap.lm_resp)
1895                 || state->request->data.auth_crap.nt_resp_len > sizeof(state->request->data.auth_crap.nt_resp)) {
1896                 if (!(state->request->flags & WBFLAG_BIG_NTLMV2_BLOB) ||
1897                      state->request->extra_len != state->request->data.auth_crap.nt_resp_len) {
1898                         DEBUG(0, ("winbindd_pam_auth_crap: invalid password length %u/%u\n",
1899                                   state->request->data.auth_crap.lm_resp_len,
1900                                   state->request->data.auth_crap.nt_resp_len));
1901                         result = NT_STATUS_INVALID_PARAMETER;
1902                         goto done;
1903                 }
1904         }
1905
1906         lm_resp = data_blob_talloc(state->mem_ctx, state->request->data.auth_crap.lm_resp,
1907                                         state->request->data.auth_crap.lm_resp_len);
1908
1909         if (state->request->flags & WBFLAG_BIG_NTLMV2_BLOB) {
1910                 nt_resp = data_blob_talloc(state->mem_ctx,
1911                                            state->request->extra_data.data,
1912                                            state->request->data.auth_crap.nt_resp_len);
1913         } else {
1914                 nt_resp = data_blob_talloc(state->mem_ctx,
1915                                            state->request->data.auth_crap.nt_resp,
1916                                            state->request->data.auth_crap.nt_resp_len);
1917         }
1918
1919         if (strequal(name_domain, get_global_sam_name())) {
1920                 DATA_BLOB chal_blob = data_blob_const(
1921                         state->request->data.auth_crap.chal,
1922                         sizeof(state->request->data.auth_crap.chal));
1923
1924                 result = winbindd_dual_auth_passdb(
1925                         state->mem_ctx,
1926                         state->request->data.auth_crap.logon_parameters,
1927                         name_domain, name_user,
1928                         &chal_blob, &lm_resp, &nt_resp, &info3);
1929                 goto process_result;
1930         }
1931
1932         result = winbind_samlogon_retry_loop(domain,
1933                                              state->mem_ctx,
1934                                              state->request->data.auth_crap.logon_parameters,
1935                                              domain->dcname,
1936                                              name_user,
1937                                              name_domain,
1938                                              /* Bug #3248 - found by Stefan Burkei. */
1939                                              workstation, /* We carefully set this above so use it... */
1940                                              state->request->data.auth_crap.chal,
1941                                              lm_resp,
1942                                              nt_resp,
1943                                              &info3);
1944         if (!NT_STATUS_IS_OK(result)) {
1945                 goto done;
1946         }
1947
1948 process_result:
1949
1950         if (NT_STATUS_IS_OK(result)) {
1951                 struct dom_sid user_sid;
1952
1953                 sid_compose(&user_sid, info3->base.domain_sid,
1954                             info3->base.rid);
1955                 wcache_invalidate_samlogon(find_domain_from_name(name_domain),
1956                                            &user_sid);
1957                 netsamlogon_cache_store(name_user, info3);
1958
1959                 /* Check if the user is in the right group */
1960
1961                 result = check_info3_in_group(
1962                         info3,
1963                         state->request->data.auth_crap.require_membership_of_sid);
1964                 if (!NT_STATUS_IS_OK(result)) {
1965                         DEBUG(3, ("User %s is not in the required group (%s), so "
1966                                   "crap authentication is rejected\n",
1967                                   state->request->data.auth_crap.user,
1968                                   state->request->data.auth_crap.require_membership_of_sid));
1969                         goto done;
1970                 }
1971
1972                 result = append_auth_data(state->mem_ctx, state->response,
1973                                           state->request->flags, info3,
1974                                           name_domain, name_user);
1975                 if (!NT_STATUS_IS_OK(result)) {
1976                         goto done;
1977                 }
1978         }
1979
1980 done:
1981
1982         /* give us a more useful (more correct?) error code */
1983         if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
1984             (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
1985                 result = NT_STATUS_NO_LOGON_SERVERS;
1986         }
1987
1988         if (state->request->flags & WBFLAG_PAM_NT_STATUS_SQUASH) {
1989                 result = nt_status_squash(result);
1990         }
1991
1992         set_auth_errors(state->response, result);
1993
1994         DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
1995               ("NTLM CRAP authentication for user [%s]\\[%s] returned %s (PAM: %d)\n",
1996                name_domain,
1997                name_user,
1998                state->response->data.auth.nt_status_string,
1999                state->response->data.auth.pam_error));
2000
2001         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2002 }
2003
2004 enum winbindd_result winbindd_dual_pam_chauthtok(struct winbindd_domain *contact_domain,
2005                                                  struct winbindd_cli_state *state)
2006 {
2007         char *oldpass;
2008         char *newpass = NULL;
2009         struct policy_handle dom_pol;
2010         struct rpc_pipe_client *cli = NULL;
2011         bool got_info = false;
2012         struct samr_DomInfo1 *info = NULL;
2013         struct userPwdChangeFailureInformation *reject = NULL;
2014         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
2015         fstring domain, user;
2016         struct dcerpc_binding_handle *b = NULL;
2017
2018         ZERO_STRUCT(dom_pol);
2019
2020         DEBUG(3, ("[%5lu]: dual pam chauthtok %s\n", (unsigned long)state->pid,
2021                   state->request->data.auth.user));
2022
2023         if (!parse_domain_user(state->request->data.chauthtok.user, domain, user)) {
2024                 goto done;
2025         }
2026
2027         /* Change password */
2028
2029         oldpass = state->request->data.chauthtok.oldpass;
2030         newpass = state->request->data.chauthtok.newpass;
2031
2032         /* Initialize reject reason */
2033         state->response->data.auth.reject_reason = Undefined;
2034
2035         /* Get sam handle */
2036
2037         result = cm_connect_sam(contact_domain, state->mem_ctx, &cli,
2038                                 &dom_pol);
2039         if (!NT_STATUS_IS_OK(result)) {
2040                 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
2041                 goto done;
2042         }
2043
2044         b = cli->binding_handle;
2045
2046         result = rpccli_samr_chgpasswd_user3(cli, state->mem_ctx,
2047                                              user,
2048                                              newpass,
2049                                              oldpass,
2050                                              &info,
2051                                              &reject);
2052
2053         /* Windows 2003 returns NT_STATUS_PASSWORD_RESTRICTION */
2054
2055         if (NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_RESTRICTION) ) {
2056
2057                 fill_in_password_policy(state->response, info);
2058
2059                 state->response->data.auth.reject_reason =
2060                         reject->extendedFailureReason;
2061
2062                 got_info = true;
2063         }
2064
2065         /* atm the pidl generated rpccli_samr_ChangePasswordUser3 function will
2066          * return with NT_STATUS_BUFFER_TOO_SMALL for w2k dcs as w2k just
2067          * returns with 4byte error code (NT_STATUS_NOT_SUPPORTED) which is too
2068          * short to comply with the samr_ChangePasswordUser3 idl - gd */
2069
2070         /* only fallback when the chgpasswd_user3 call is not supported */
2071         if (NT_STATUS_EQUAL(result, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE) ||
2072             NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED) ||
2073             NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL) ||
2074             NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
2075
2076                 DEBUG(10,("Password change with chgpasswd_user3 failed with: %s, retrying chgpasswd_user2\n",
2077                         nt_errstr(result)));
2078
2079                 result = rpccli_samr_chgpasswd_user2(cli, state->mem_ctx, user, newpass, oldpass);
2080
2081                 /* Windows 2000 returns NT_STATUS_ACCOUNT_RESTRICTION.
2082                    Map to the same status code as Windows 2003. */
2083
2084                 if ( NT_STATUS_EQUAL(NT_STATUS_ACCOUNT_RESTRICTION, result ) ) {
2085                         result = NT_STATUS_PASSWORD_RESTRICTION;
2086                 }
2087         }
2088
2089 done:
2090
2091         if (NT_STATUS_IS_OK(result)
2092             && (state->request->flags & WBFLAG_PAM_CACHED_LOGIN)
2093             && lp_winbind_offline_logon()) {
2094                 result = winbindd_update_creds_by_name(contact_domain, user,
2095                                                        newpass);
2096                 /* Again, this happens when we login from gdm or xdm
2097                  * and the password expires, *BUT* cached crendentials
2098                  * doesn't exist. winbindd_update_creds_by_name()
2099                  * returns NT_STATUS_NO_SUCH_USER.
2100                  * This is not a failure.
2101                  * --- BoYang
2102                  * */
2103                 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER)) {
2104                         result = NT_STATUS_OK;
2105                 }
2106
2107                 if (!NT_STATUS_IS_OK(result)) {
2108                         DEBUG(10, ("Failed to store creds: %s\n",
2109                                    nt_errstr(result)));
2110                         goto process_result;
2111                 }
2112         }
2113
2114         if (!NT_STATUS_IS_OK(result) && !got_info && contact_domain) {
2115
2116                 NTSTATUS policy_ret;
2117
2118                 policy_ret = fillup_password_policy(
2119                         contact_domain, state->response);
2120
2121                 /* failure of this is non critical, it will just provide no
2122                  * additional information to the client why the change has
2123                  * failed - Guenther */
2124
2125                 if (!NT_STATUS_IS_OK(policy_ret)) {
2126                         DEBUG(10,("Failed to get password policies: %s\n", nt_errstr(policy_ret)));
2127                         goto process_result;
2128                 }
2129         }
2130
2131 process_result:
2132
2133         if (strequal(contact_domain->name, get_global_sam_name())) {
2134                 /* FIXME: internal rpc pipe does not cache handles yet */
2135                 if (b) {
2136                         if (is_valid_policy_hnd(&dom_pol)) {
2137                                 NTSTATUS _result;
2138                                 dcerpc_samr_Close(b, state->mem_ctx, &dom_pol, &_result);
2139                         }
2140                         TALLOC_FREE(cli);
2141                 }
2142         }
2143
2144         set_auth_errors(state->response, result);
2145
2146         DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
2147               ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
2148                domain,
2149                user,
2150                state->response->data.auth.nt_status_string,
2151                state->response->data.auth.pam_error));
2152
2153         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2154 }
2155
2156 enum winbindd_result winbindd_dual_pam_logoff(struct winbindd_domain *domain,
2157                                               struct winbindd_cli_state *state)
2158 {
2159         NTSTATUS result = NT_STATUS_NOT_SUPPORTED;
2160
2161         DEBUG(3, ("[%5lu]: pam dual logoff %s\n", (unsigned long)state->pid,
2162                 state->request->data.logoff.user));
2163
2164         if (!(state->request->flags & WBFLAG_PAM_KRB5)) {
2165                 result = NT_STATUS_OK;
2166                 goto process_result;
2167         }
2168
2169         if (state->request->data.logoff.krb5ccname[0] == '\0') {
2170                 result = NT_STATUS_OK;
2171                 goto process_result;
2172         }
2173
2174 #ifdef HAVE_KRB5
2175
2176         if (state->request->data.logoff.uid < 0) {
2177                 DEBUG(0,("winbindd_pam_logoff: invalid uid\n"));
2178                 goto process_result;
2179         }
2180
2181         /* what we need here is to find the corresponding krb5 ccache name *we*
2182          * created for a given username and destroy it */
2183
2184         if (!ccache_entry_exists(state->request->data.logoff.user)) {
2185                 result = NT_STATUS_OK;
2186                 DEBUG(10,("winbindd_pam_logoff: no entry found.\n"));
2187                 goto process_result;
2188         }
2189
2190         if (!ccache_entry_identical(state->request->data.logoff.user,
2191                                         state->request->data.logoff.uid,
2192                                         state->request->data.logoff.krb5ccname)) {
2193                 DEBUG(0,("winbindd_pam_logoff: cached entry differs.\n"));
2194                 goto process_result;
2195         }
2196
2197         result = remove_ccache(state->request->data.logoff.user);
2198         if (!NT_STATUS_IS_OK(result)) {
2199                 DEBUG(0,("winbindd_pam_logoff: failed to remove ccache: %s\n",
2200                         nt_errstr(result)));
2201                 goto process_result;
2202         }
2203
2204         /*
2205          * Remove any mlock'ed memory creds in the child
2206          * we might be using for krb5 ticket renewal.
2207          */
2208
2209         winbindd_delete_memory_creds(state->request->data.logoff.user);
2210
2211 #else
2212         result = NT_STATUS_NOT_SUPPORTED;
2213 #endif
2214
2215 process_result:
2216
2217
2218         set_auth_errors(state->response, result);
2219
2220         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2221 }
2222
2223 /* Change user password with auth crap*/
2224
2225 enum winbindd_result winbindd_dual_pam_chng_pswd_auth_crap(struct winbindd_domain *domainSt, struct winbindd_cli_state *state)
2226 {
2227         NTSTATUS result;
2228         DATA_BLOB new_nt_password;
2229         DATA_BLOB old_nt_hash_enc;
2230         DATA_BLOB new_lm_password;
2231         DATA_BLOB old_lm_hash_enc;
2232         fstring  domain,user;
2233         struct policy_handle dom_pol;
2234         struct winbindd_domain *contact_domain = domainSt;
2235         struct rpc_pipe_client *cli = NULL;
2236         struct dcerpc_binding_handle *b = NULL;
2237
2238         ZERO_STRUCT(dom_pol);
2239
2240         /* Ensure null termination */
2241         state->request->data.chng_pswd_auth_crap.user[
2242                 sizeof(state->request->data.chng_pswd_auth_crap.user)-1]=0;
2243         state->request->data.chng_pswd_auth_crap.domain[
2244                 sizeof(state->request->data.chng_pswd_auth_crap.domain)-1]=0;
2245         *domain = 0;
2246         *user = 0;
2247
2248         DEBUG(3, ("[%5lu]: pam change pswd auth crap domain: %s user: %s\n",
2249                   (unsigned long)state->pid,
2250                   state->request->data.chng_pswd_auth_crap.domain,
2251                   state->request->data.chng_pswd_auth_crap.user));
2252
2253         if (lp_winbind_offline_logon()) {
2254                 DEBUG(0,("Refusing password change as winbind offline logons are enabled. "));
2255                 DEBUGADD(0,("Changing passwords here would risk inconsistent logons\n"));
2256                 result = NT_STATUS_ACCESS_DENIED;
2257                 goto done;
2258         }
2259
2260         if (*state->request->data.chng_pswd_auth_crap.domain) {
2261                 fstrcpy(domain,state->request->data.chng_pswd_auth_crap.domain);
2262         } else {
2263                 parse_domain_user(state->request->data.chng_pswd_auth_crap.user,
2264                                   domain, user);
2265
2266                 if(!*domain) {
2267                         DEBUG(3,("no domain specified with username (%s) - "
2268                                  "failing auth\n",
2269                                  state->request->data.chng_pswd_auth_crap.user));
2270                         result = NT_STATUS_NO_SUCH_USER;
2271                         goto done;
2272                 }
2273         }
2274
2275         if (!*domain && lp_winbind_use_default_domain()) {
2276                 fstrcpy(domain,lp_workgroup());
2277         }
2278
2279         if(!*user) {
2280                 fstrcpy(user, state->request->data.chng_pswd_auth_crap.user);
2281         }
2282
2283         DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n",
2284                   (unsigned long)state->pid, domain, user));
2285
2286         /* Change password */
2287         new_nt_password = data_blob_const(
2288                 state->request->data.chng_pswd_auth_crap.new_nt_pswd,
2289                 state->request->data.chng_pswd_auth_crap.new_nt_pswd_len);
2290
2291         old_nt_hash_enc = data_blob_const(
2292                 state->request->data.chng_pswd_auth_crap.old_nt_hash_enc,
2293                 state->request->data.chng_pswd_auth_crap.old_nt_hash_enc_len);
2294
2295         if(state->request->data.chng_pswd_auth_crap.new_lm_pswd_len > 0)        {
2296                 new_lm_password = data_blob_const(
2297                         state->request->data.chng_pswd_auth_crap.new_lm_pswd,
2298                         state->request->data.chng_pswd_auth_crap.new_lm_pswd_len);
2299
2300                 old_lm_hash_enc = data_blob_const(
2301                         state->request->data.chng_pswd_auth_crap.old_lm_hash_enc,
2302                         state->request->data.chng_pswd_auth_crap.old_lm_hash_enc_len);
2303         } else {
2304                 new_lm_password = data_blob_null;
2305                 old_lm_hash_enc = data_blob_null;
2306         }
2307
2308         /* Get sam handle */
2309
2310         result = cm_connect_sam(contact_domain, state->mem_ctx, &cli, &dom_pol);
2311         if (!NT_STATUS_IS_OK(result)) {
2312                 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
2313                 goto done;
2314         }
2315
2316         b = cli->binding_handle;
2317
2318         result = rpccli_samr_chng_pswd_auth_crap(
2319                 cli, state->mem_ctx, user, new_nt_password, old_nt_hash_enc,
2320                 new_lm_password, old_lm_hash_enc);
2321
2322  done:
2323
2324         if (strequal(contact_domain->name, get_global_sam_name())) {
2325                 /* FIXME: internal rpc pipe does not cache handles yet */
2326                 if (b) {
2327                         if (is_valid_policy_hnd(&dom_pol)) {
2328                                 NTSTATUS _result;
2329                                 dcerpc_samr_Close(b, state->mem_ctx, &dom_pol, &_result);
2330                         }
2331                         TALLOC_FREE(cli);
2332                 }
2333         }
2334
2335         set_auth_errors(state->response, result);
2336
2337         DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
2338               ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
2339                domain, user,
2340                state->response->data.auth.nt_status_string,
2341                state->response->data.auth.pam_error));
2342
2343         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2344 }
2345
2346 #ifdef HAVE_KRB5
2347 static NTSTATUS extract_pac_vrfy_sigs(TALLOC_CTX *mem_ctx, DATA_BLOB pac_blob,
2348                                       struct PAC_LOGON_INFO **logon_info)
2349 {
2350         krb5_context krbctx = NULL;
2351         krb5_error_code k5ret;
2352         krb5_keytab keytab;
2353         krb5_kt_cursor cursor;
2354         krb5_keytab_entry entry;
2355         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
2356
2357         ZERO_STRUCT(entry);
2358         ZERO_STRUCT(cursor);
2359
2360         k5ret = krb5_init_context(&krbctx);
2361         if (k5ret) {
2362                 DEBUG(1, ("Failed to initialize kerberos context: %s\n",
2363                           error_message(k5ret)));
2364                 status = krb5_to_nt_status(k5ret);
2365                 goto out;
2366         }
2367
2368         k5ret =  gse_krb5_get_server_keytab(krbctx, &keytab);
2369         if (k5ret) {
2370                 DEBUG(1, ("Failed to get keytab: %s\n",
2371                           error_message(k5ret)));
2372                 status = krb5_to_nt_status(k5ret);
2373                 goto out_free;
2374         }
2375
2376         k5ret = krb5_kt_start_seq_get(krbctx, keytab, &cursor);
2377         if (k5ret) {
2378                 DEBUG(1, ("Failed to start seq: %s\n",
2379                           error_message(k5ret)));
2380                 status = krb5_to_nt_status(k5ret);
2381                 goto out_keytab;
2382         }
2383
2384         k5ret = krb5_kt_next_entry(krbctx, keytab, &entry, &cursor);
2385         while (k5ret == 0) {
2386                 status = kerberos_pac_logon_info(mem_ctx, pac_blob,
2387                                                  krbctx, NULL,
2388                                                  KRB5_KT_KEY(&entry), NULL, 0,
2389                                                  logon_info);
2390                 if (NT_STATUS_IS_OK(status)) {
2391                         break;
2392                 }
2393                 k5ret = smb_krb5_kt_free_entry(krbctx, &entry);
2394                 k5ret = krb5_kt_next_entry(krbctx, keytab, &entry, &cursor);
2395         }
2396
2397         k5ret = krb5_kt_end_seq_get(krbctx, keytab, &cursor);
2398         if (k5ret) {
2399                 DEBUG(1, ("Failed to end seq: %s\n",
2400                           error_message(k5ret)));
2401         }
2402 out_keytab:
2403         k5ret = krb5_kt_close(krbctx, keytab);
2404         if (k5ret) {
2405                 DEBUG(1, ("Failed to close keytab: %s\n",
2406                           error_message(k5ret)));
2407         }
2408 out_free:
2409         krb5_free_context(krbctx);
2410 out:
2411         return status;
2412 }
2413
2414 NTSTATUS winbindd_pam_auth_pac_send(struct winbindd_cli_state *state,
2415                                     struct netr_SamInfo3 **info3)
2416 {
2417         struct winbindd_request *req = state->request;
2418         DATA_BLOB pac_blob;
2419         struct PAC_LOGON_INFO *logon_info = NULL;
2420         NTSTATUS result;
2421
2422         pac_blob = data_blob_const(req->extra_data.data, req->extra_len);
2423         result = extract_pac_vrfy_sigs(state->mem_ctx, pac_blob, &logon_info);
2424         if (!NT_STATUS_IS_OK(result) &&
2425             !NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
2426                 DEBUG(1, ("Error during PAC signature verification: %s\n",
2427                           nt_errstr(result)));
2428                 return result;
2429         }
2430
2431         if (logon_info) {
2432                 /* Signature verification succeeded, trust the PAC */
2433                 netsamlogon_cache_store(NULL, &logon_info->info3);
2434
2435         } else {
2436                 /* Try without signature verification */
2437                 result = kerberos_pac_logon_info(state->mem_ctx, pac_blob, NULL,
2438                                                  NULL, NULL, NULL, 0,
2439                                                  &logon_info);
2440                 if (!NT_STATUS_IS_OK(result)) {
2441                         DEBUG(10, ("Could not extract PAC: %s\n",
2442                                    nt_errstr(result)));
2443                         return result;
2444                 }
2445         }
2446
2447         *info3 = &logon_info->info3;
2448
2449         return NT_STATUS_OK;
2450 }
2451 #else /* HAVE_KRB5 */
2452 NTSTATUS winbindd_pam_auth_pac_send(struct winbindd_cli_state *state,
2453                                     struct netr_SamInfo3 **info3)
2454 {
2455         return NT_STATUS_NO_SUCH_USER;
2456 }
2457 #endif /* HAVE_KRB5 */