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