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