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