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