s3-winbind: don't try to do clever thing if the username is not found while authentic...
[ddiss/samba.git] / source3 / winbindd / winbindd_pam.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Winbind daemon - pam auth funcions
5
6    Copyright (C) Andrew Tridgell 2000
7    Copyright (C) Tim Potter 2001
8    Copyright (C) Andrew Bartlett 2001-2002
9    Copyright (C) Guenther Deschner 2005
10
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 3 of the License, or
14    (at your option) any later version.
15
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20
21    You should have received a copy of the GNU General Public License
22    along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 */
24
25 #include "includes.h"
26 #include "winbindd.h"
27 #include "../libcli/auth/libcli_auth.h"
28 #include "../librpc/gen_ndr/ndr_samr_c.h"
29 #include "rpc_client/cli_pipe.h"
30 #include "rpc_client/cli_samr.h"
31 #include "../librpc/gen_ndr/ndr_netlogon.h"
32 #include "rpc_client/cli_netlogon.h"
33 #include "smb_krb5.h"
34 #include "../lib/crypto/arcfour.h"
35 #include "../libcli/security/security.h"
36 #include "ads.h"
37 #include "../librpc/gen_ndr/krb5pac.h"
38 #include "passdb/machine_sid.h"
39 #include "auth.h"
40 #include "../lib/tsocket/tsocket.h"
41
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                                           const char *domain, const char *user,
1114                                           const DATA_BLOB *challenge,
1115                                           const DATA_BLOB *lm_resp,
1116                                           const DATA_BLOB *nt_resp,
1117                                           struct netr_SamInfo3 **pinfo3)
1118 {
1119         struct auth_usersupplied_info *user_info = NULL;
1120         struct tsocket_address *local;
1121         NTSTATUS status;
1122         int rc;
1123
1124         rc = tsocket_address_inet_from_strings(mem_ctx,
1125                                                "ip",
1126                                                "127.0.0.1",
1127                                                0,
1128                                                &local);
1129         if (rc < 0) {
1130                 return NT_STATUS_NO_MEMORY;
1131         }
1132         status = make_user_info(&user_info, user, user, domain, domain,
1133                                 lp_netbios_name(), local, lm_resp, nt_resp, NULL, NULL,
1134                                 NULL, AUTH_PASSWORD_RESPONSE);
1135         if (!NT_STATUS_IS_OK(status)) {
1136                 DEBUG(10, ("make_user_info failed: %s\n", nt_errstr(status)));
1137                 return status;
1138         }
1139
1140         /* We don't want any more mapping of the username */
1141         user_info->mapped_state = True;
1142
1143         status = check_sam_security_info3(challenge, talloc_tos(), user_info,
1144                                           pinfo3);
1145         free_user_info(&user_info);
1146         DEBUG(10, ("Authenticaticating user %s\\%s returned %s\n", domain,
1147                    user, nt_errstr(status)));
1148         return status;
1149 }
1150
1151 static NTSTATUS winbind_samlogon_retry_loop(struct winbindd_domain *domain,
1152                                             TALLOC_CTX *mem_ctx,
1153                                             uint32_t logon_parameters,
1154                                             const char *server,
1155                                             const char *username,
1156                                             const char *domainname,
1157                                             const char *workstation,
1158                                             const uint8_t chal[8],
1159                                             DATA_BLOB lm_response,
1160                                             DATA_BLOB nt_response,
1161                                             struct netr_SamInfo3 **info3)
1162 {
1163         int attempts = 0;
1164         bool retry = false;
1165         NTSTATUS result;
1166
1167         do {
1168                 struct rpc_pipe_client *netlogon_pipe;
1169                 const struct pipe_auth_data *auth;
1170                 uint32_t neg_flags = 0;
1171
1172                 ZERO_STRUCTP(info3);
1173                 retry = false;
1174
1175                 result = cm_connect_netlogon(domain, &netlogon_pipe);
1176
1177                 if (!NT_STATUS_IS_OK(result)) {
1178                         DEBUG(3,("could not open handle to NETLOGON pipe (error: %s)\n",
1179                                   nt_errstr(result)));
1180                         return result;
1181                 }
1182                 auth = netlogon_pipe->auth;
1183                 if (netlogon_pipe->dc) {
1184                         neg_flags = netlogon_pipe->dc->negotiate_flags;
1185                 }
1186
1187                 /* It is really important to try SamLogonEx here,
1188                  * because in a clustered environment, we want to use
1189                  * one machine account from multiple physical
1190                  * computers.
1191                  *
1192                  * With a normal SamLogon call, we must keep the
1193                  * credentials chain updated and intact between all
1194                  * users of the machine account (which would imply
1195                  * cross-node communication for every NTLM logon).
1196                  *
1197                  * (The credentials chain is not per NETLOGON pipe
1198                  * connection, but globally on the server/client pair
1199                  * by machine name).
1200                  *
1201                  * When using SamLogonEx, the credentials are not
1202                  * supplied, but the session key is implied by the
1203                  * wrapping SamLogon context.
1204                  *
1205                  *  -- abartlet 21 April 2008
1206                  *
1207                  * It's also important to use NetlogonValidationSamInfo4 (6),
1208                  * because it relies on the rpc transport encryption
1209                  * and avoids using the global netlogon schannel
1210                  * session key to en/decrypt secret information
1211                  * like the user_session_key for network logons.
1212                  *
1213                  * [MS-APDS] 3.1.5.2 NTLM Network Logon
1214                  * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
1215                  * NETLOGON_NEG_AUTHENTICATED_RPC set together
1216                  * are the indication that the server supports
1217                  * NetlogonValidationSamInfo4 (6). And it must only
1218                  * be used if "SealSecureChannel" is used.
1219                  *
1220                  * -- metze 4 February 2011
1221                  */
1222
1223                 if (auth == NULL) {
1224                         domain->can_do_validation6 = false;
1225                 } else if (auth->auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
1226                         domain->can_do_validation6 = false;
1227                 } else if (auth->auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
1228                         domain->can_do_validation6 = false;
1229                 } else if (!(neg_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
1230                         domain->can_do_validation6 = false;
1231                 } else if (!(neg_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
1232                         domain->can_do_validation6 = false;
1233                 }
1234
1235                 if (domain->can_do_samlogon_ex) {
1236                         result = rpccli_netlogon_sam_network_logon_ex(
1237                                         netlogon_pipe,
1238                                         mem_ctx,
1239                                         logon_parameters,
1240                                         server,         /* server name */
1241                                         username,       /* user name */
1242                                         domainname,     /* target domain */
1243                                         workstation,    /* workstation */
1244                                         chal,
1245                                         domain->can_do_validation6 ? 6 : 3,
1246                                         lm_response,
1247                                         nt_response,
1248                                         info3);
1249                 } else {
1250                         result = rpccli_netlogon_sam_network_logon(
1251                                         netlogon_pipe,
1252                                         mem_ctx,
1253                                         logon_parameters,
1254                                         server,         /* server name */
1255                                         username,       /* user name */
1256                                         domainname,     /* target domain */
1257                                         workstation,    /* workstation */
1258                                         chal,
1259                                         domain->can_do_validation6 ? 6 : 3,
1260                                         lm_response,
1261                                         nt_response,
1262                                         info3);
1263                 }
1264
1265                 if (NT_STATUS_EQUAL(result, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1266
1267                         /*
1268                          * It's likely that the server also does not support
1269                          * validation level 6
1270                          */
1271                         domain->can_do_validation6 = false;
1272
1273                         if (domain->can_do_samlogon_ex) {
1274                                 DEBUG(3, ("Got a DC that can not do NetSamLogonEx, "
1275                                           "retrying with NetSamLogon\n"));
1276                                 domain->can_do_samlogon_ex = false;
1277                                 retry = true;
1278                                 continue;
1279                         }
1280
1281
1282                         /* Got DCERPC_FAULT_OP_RNG_ERROR for SamLogon
1283                          * (no Ex). This happens against old Samba
1284                          * DCs. Drop the connection.
1285                          */
1286                         invalidate_cm_connection(&domain->conn);
1287                         result = NT_STATUS_LOGON_FAILURE;
1288                         break;
1289                 }
1290
1291                 if (domain->can_do_validation6 &&
1292                     (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
1293                      NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
1294                      NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL))) {
1295                         DEBUG(3,("Got a DC that can not do validation level 6, "
1296                                   "retrying with level 3\n"));
1297                         domain->can_do_validation6 = false;
1298                         retry = true;
1299                         continue;
1300                 }
1301
1302                 /*
1303                  * we increment this after the "feature negotiation"
1304                  * for can_do_samlogon_ex and can_do_validation6
1305                  */
1306                 attempts += 1;
1307
1308                 /* We have to try a second time as cm_connect_netlogon
1309                    might not yet have noticed that the DC has killed
1310                    our connection. */
1311
1312                 if (!rpccli_is_connected(netlogon_pipe)) {
1313                         retry = true;
1314                         continue;
1315                 }
1316
1317                 /* if we get access denied, a possible cause was that we had
1318                    and open connection to the DC, but someone changed our
1319                    machine account password out from underneath us using 'net
1320                    rpc changetrustpw' */
1321
1322                 if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
1323                         DEBUG(3,("winbindd_pam_auth: sam_logon returned "
1324                                  "ACCESS_DENIED.  Maybe the trust account "
1325                                 "password was changed and we didn't know it. "
1326                                  "Killing connections to domain %s\n",
1327                                 domainname));
1328                         invalidate_cm_connection(&domain->conn);
1329                         retry = true;
1330                 }
1331
1332         } while ( (attempts < 2) && retry );
1333
1334         return result;
1335 }
1336
1337 static NTSTATUS winbindd_dual_pam_auth_samlogon(TALLOC_CTX *mem_ctx,
1338                                                 struct winbindd_domain *domain,
1339                                                 const char *user,
1340                                                 const char *pass,
1341                                                 uint32_t request_flags,
1342                                                 struct netr_SamInfo3 **info3)
1343 {
1344
1345         uchar chal[8];
1346         DATA_BLOB lm_resp;
1347         DATA_BLOB nt_resp;
1348         unsigned char local_nt_response[24];
1349         fstring name_domain, name_user;
1350         NTSTATUS result;
1351         struct netr_SamInfo3 *my_info3 = NULL;
1352
1353         *info3 = NULL;
1354
1355         DEBUG(10,("winbindd_dual_pam_auth_samlogon\n"));
1356
1357         /* Parse domain and username */
1358
1359         parse_domain_user(user, name_domain, name_user);
1360
1361         /* do password magic */
1362
1363         generate_random_buffer(chal, sizeof(chal));
1364
1365         if (lp_client_ntlmv2_auth()) {
1366                 DATA_BLOB server_chal;
1367                 DATA_BLOB names_blob;
1368                 server_chal = data_blob_const(chal, 8);
1369
1370                 /* note that the 'workgroup' here is for the local
1371                    machine.  The 'server name' must match the
1372                    'workstation' passed to the actual SamLogon call.
1373                 */
1374                 names_blob = NTLMv2_generate_names_blob(
1375                         mem_ctx, lp_netbios_name(), lp_workgroup());
1376
1377                 if (!SMBNTLMv2encrypt(mem_ctx, name_user, name_domain,
1378                                       pass,
1379                                       &server_chal,
1380                                       &names_blob,
1381                                       &lm_resp, &nt_resp, NULL, NULL)) {
1382                         data_blob_free(&names_blob);
1383                         DEBUG(0, ("winbindd_pam_auth: SMBNTLMv2encrypt() failed!\n"));
1384                         result = NT_STATUS_NO_MEMORY;
1385                         goto done;
1386                 }
1387                 data_blob_free(&names_blob);
1388         } else {
1389                 lm_resp = data_blob_null;
1390                 SMBNTencrypt(pass, chal, local_nt_response);
1391
1392                 nt_resp = data_blob_talloc(mem_ctx, local_nt_response,
1393                                            sizeof(local_nt_response));
1394         }
1395
1396         if (strequal(name_domain, get_global_sam_name())) {
1397                 DATA_BLOB chal_blob = data_blob_const(chal, sizeof(chal));
1398
1399                 result = winbindd_dual_auth_passdb(
1400                         mem_ctx, name_domain, name_user,
1401                         &chal_blob, &lm_resp, &nt_resp, info3);
1402                 goto done;
1403         }
1404
1405         /* check authentication loop */
1406
1407         result = winbind_samlogon_retry_loop(domain,
1408                                              mem_ctx,
1409                                              0,
1410                                              domain->dcname,
1411                                              name_user,
1412                                              name_domain,
1413                                              lp_netbios_name(),
1414                                              chal,
1415                                              lm_resp,
1416                                              nt_resp,
1417                                              &my_info3);
1418         if (!NT_STATUS_IS_OK(result)) {
1419                 goto done;
1420         }
1421
1422         /* handle the case where a NT4 DC does not fill in the acct_flags in
1423          * the samlogon reply info3. When accurate info3 is required by the
1424          * caller, we look up the account flags ourselve - gd */
1425
1426         if ((request_flags & WBFLAG_PAM_INFO3_TEXT) &&
1427             NT_STATUS_IS_OK(result) && (my_info3->base.acct_flags == 0)) {
1428
1429                 struct rpc_pipe_client *samr_pipe;
1430                 struct policy_handle samr_domain_handle, user_pol;
1431                 union samr_UserInfo *info = NULL;
1432                 NTSTATUS status_tmp, result_tmp;
1433                 uint32 acct_flags;
1434                 struct dcerpc_binding_handle *b;
1435
1436                 status_tmp = cm_connect_sam(domain, mem_ctx,
1437                                             &samr_pipe, &samr_domain_handle);
1438
1439                 if (!NT_STATUS_IS_OK(status_tmp)) {
1440                         DEBUG(3, ("could not open handle to SAMR pipe: %s\n",
1441                                 nt_errstr(status_tmp)));
1442                         goto done;
1443                 }
1444
1445                 b = samr_pipe->binding_handle;
1446
1447                 status_tmp = dcerpc_samr_OpenUser(b, mem_ctx,
1448                                                   &samr_domain_handle,
1449                                                   MAXIMUM_ALLOWED_ACCESS,
1450                                                   my_info3->base.rid,
1451                                                   &user_pol,
1452                                                   &result_tmp);
1453
1454                 if (!NT_STATUS_IS_OK(status_tmp)) {
1455                         DEBUG(3, ("could not open user handle on SAMR pipe: %s\n",
1456                                 nt_errstr(status_tmp)));
1457                         goto done;
1458                 }
1459                 if (!NT_STATUS_IS_OK(result_tmp)) {
1460                         DEBUG(3, ("could not open user handle on SAMR pipe: %s\n",
1461                                 nt_errstr(result_tmp)));
1462                         goto done;
1463                 }
1464
1465                 status_tmp = dcerpc_samr_QueryUserInfo(b, mem_ctx,
1466                                                        &user_pol,
1467                                                        16,
1468                                                        &info,
1469                                                        &result_tmp);
1470
1471                 if (!NT_STATUS_IS_OK(status_tmp)) {
1472                         DEBUG(3, ("could not query user info on SAMR pipe: %s\n",
1473                                 nt_errstr(status_tmp)));
1474                         dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
1475                         goto done;
1476                 }
1477                 if (!NT_STATUS_IS_OK(result_tmp)) {
1478                         DEBUG(3, ("could not query user info on SAMR pipe: %s\n",
1479                                 nt_errstr(result_tmp)));
1480                         dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
1481                         goto done;
1482                 }
1483
1484                 acct_flags = info->info16.acct_flags;
1485
1486                 if (acct_flags == 0) {
1487                         dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
1488                         goto done;
1489                 }
1490
1491                 my_info3->base.acct_flags = acct_flags;
1492
1493                 DEBUG(10,("successfully retrieved acct_flags 0x%x\n", acct_flags));
1494
1495                 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
1496         }
1497
1498         *info3 = my_info3;
1499 done:
1500         return result;
1501 }
1502
1503 enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain,
1504                                             struct winbindd_cli_state *state)
1505 {
1506         NTSTATUS result = NT_STATUS_LOGON_FAILURE;
1507         NTSTATUS krb5_result = NT_STATUS_OK;
1508         fstring name_domain, name_user;
1509         char *mapped_user;
1510         fstring domain_user;
1511         struct netr_SamInfo3 *info3 = NULL;
1512         NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL;
1513
1514         /* Ensure null termination */
1515         state->request->data.auth.user[sizeof(state->request->data.auth.user)-1]='\0';
1516
1517         /* Ensure null termination */
1518         state->request->data.auth.pass[sizeof(state->request->data.auth.pass)-1]='\0';
1519
1520         DEBUG(3, ("[%5lu]: dual pam auth %s\n", (unsigned long)state->pid,
1521                   state->request->data.auth.user));
1522
1523         /* Parse domain and username */
1524
1525         name_map_status = normalize_name_unmap(state->mem_ctx,
1526                                                state->request->data.auth.user,
1527                                                &mapped_user);
1528
1529         /* If the name normalization didnt' actually do anything,
1530            just use the original name */
1531
1532         if (!NT_STATUS_IS_OK(name_map_status) &&
1533             !NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED))
1534         {
1535                 mapped_user = state->request->data.auth.user;
1536         }
1537
1538         parse_domain_user(mapped_user, name_domain, name_user);
1539
1540         if ( mapped_user != state->request->data.auth.user ) {
1541                 fstr_sprintf( domain_user, "%s%c%s", name_domain,
1542                         *lp_winbind_separator(),
1543                         name_user );
1544                 strlcpy( state->request->data.auth.user, domain_user,
1545                              sizeof(state->request->data.auth.user));
1546         }
1547
1548         if (!domain->online) {
1549                 result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
1550                 if (domain->startup) {
1551                         /* Logons are very important to users. If we're offline and
1552                            we get a request within the first 30 seconds of startup,
1553                            try very hard to find a DC and go online. */
1554
1555                         DEBUG(10,("winbindd_dual_pam_auth: domain: %s offline and auth "
1556                                 "request in startup mode.\n", domain->name ));
1557
1558                         winbindd_flush_negative_conn_cache(domain);
1559                         result = init_dc_connection(domain);
1560                 }
1561         }
1562
1563         DEBUG(10,("winbindd_dual_pam_auth: domain: %s last was %s\n", domain->name, domain->online ? "online":"offline"));
1564
1565         /* Check for Kerberos authentication */
1566         if (domain->online && (state->request->flags & WBFLAG_PAM_KRB5)) {
1567
1568                 result = winbindd_dual_pam_auth_kerberos(domain, state, &info3);
1569                 /* save for later */
1570                 krb5_result = result;
1571
1572
1573                 if (NT_STATUS_IS_OK(result)) {
1574                         DEBUG(10,("winbindd_dual_pam_auth_kerberos succeeded\n"));
1575                         goto process_result;
1576                 } else {
1577                         DEBUG(10,("winbindd_dual_pam_auth_kerberos failed: %s\n", nt_errstr(result)));
1578                 }
1579
1580                 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
1581                     NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
1582                     NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1583                         DEBUG(10,("winbindd_dual_pam_auth_kerberos setting domain to offline\n"));
1584                         set_domain_offline( domain );
1585                         goto cached_logon;
1586                 }
1587
1588                 /* there are quite some NT_STATUS errors where there is no
1589                  * point in retrying with a samlogon, we explictly have to take
1590                  * care not to increase the bad logon counter on the DC */
1591
1592                 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_DISABLED) ||
1593                     NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_EXPIRED) ||
1594                     NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_LOCKED_OUT) ||
1595                     NT_STATUS_EQUAL(result, NT_STATUS_INVALID_LOGON_HOURS) ||
1596                     NT_STATUS_EQUAL(result, NT_STATUS_INVALID_WORKSTATION) ||
1597                     NT_STATUS_EQUAL(result, NT_STATUS_LOGON_FAILURE) ||
1598                     NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER) ||
1599                     NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_EXPIRED) ||
1600                     NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_MUST_CHANGE) ||
1601                     NT_STATUS_EQUAL(result, NT_STATUS_WRONG_PASSWORD)) {
1602                         goto done;
1603                 }
1604
1605                 if (state->request->flags & WBFLAG_PAM_FALLBACK_AFTER_KRB5) {
1606                         DEBUG(3,("falling back to samlogon\n"));
1607                         goto sam_logon;
1608                 } else {
1609                         goto cached_logon;
1610                 }
1611         }
1612
1613 sam_logon:
1614         /* Check for Samlogon authentication */
1615         if (domain->online) {
1616                 result = winbindd_dual_pam_auth_samlogon(
1617                         state->mem_ctx, domain,
1618                         state->request->data.auth.user,
1619                         state->request->data.auth.pass,
1620                         state->request->flags,
1621                         &info3);
1622
1623                 if (NT_STATUS_IS_OK(result)) {
1624                         DEBUG(10,("winbindd_dual_pam_auth_samlogon succeeded\n"));
1625                         /* add the Krb5 err if we have one */
1626                         if ( NT_STATUS_EQUAL(krb5_result, NT_STATUS_TIME_DIFFERENCE_AT_DC ) ) {
1627                                 info3->base.user_flags |= LOGON_KRB5_FAIL_CLOCK_SKEW;
1628                         }
1629                         goto process_result;
1630                 }
1631
1632                 DEBUG(10,("winbindd_dual_pam_auth_samlogon failed: %s\n",
1633                           nt_errstr(result)));
1634
1635                 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
1636                     NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
1637                     NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND))
1638                 {
1639                         DEBUG(10,("winbindd_dual_pam_auth_samlogon setting domain to offline\n"));
1640                         set_domain_offline( domain );
1641                         goto cached_logon;
1642                 }
1643
1644                         if (domain->online) {
1645                                 /* We're still online - fail. */
1646                                 goto done;
1647                         }
1648         }
1649
1650 cached_logon:
1651         /* Check for Cached logons */
1652         if (!domain->online && (state->request->flags & WBFLAG_PAM_CACHED_LOGIN) &&
1653             lp_winbind_offline_logon()) {
1654
1655                 result = winbindd_dual_pam_auth_cached(domain, state, &info3);
1656
1657                 if (NT_STATUS_IS_OK(result)) {
1658                         DEBUG(10,("winbindd_dual_pam_auth_cached succeeded\n"));
1659                         goto process_result;
1660                 } else {
1661                         DEBUG(10,("winbindd_dual_pam_auth_cached failed: %s\n", nt_errstr(result)));
1662                         goto done;
1663                 }
1664         }
1665
1666 process_result:
1667
1668         if (NT_STATUS_IS_OK(result)) {
1669
1670                 struct dom_sid user_sid;
1671
1672                 /* In all codepaths where result == NT_STATUS_OK info3 must have
1673                    been initialized. */
1674                 if (!info3) {
1675                         result = NT_STATUS_INTERNAL_ERROR;
1676                         goto done;
1677                 }
1678
1679                 sid_compose(&user_sid, info3->base.domain_sid,
1680                             info3->base.rid);
1681
1682                 wcache_invalidate_samlogon(find_domain_from_name(name_domain),
1683                                            &user_sid);
1684                 netsamlogon_cache_store(name_user, info3);
1685
1686                 /* save name_to_sid info as early as possible (only if
1687                    this is our primary domain so we don't invalidate
1688                    the cache entry by storing the seq_num for the wrong
1689                    domain). */
1690                 if ( domain->primary ) {
1691                         cache_name2sid(domain, name_domain, name_user,
1692                                        SID_NAME_USER, &user_sid);
1693                 }
1694
1695                 /* Check if the user is in the right group */
1696
1697                 result = check_info3_in_group(
1698                         info3,
1699                         state->request->data.auth.require_membership_of_sid);
1700                 if (!NT_STATUS_IS_OK(result)) {
1701                         DEBUG(3, ("User %s is not in the required group (%s), so plaintext authentication is rejected\n",
1702                                   state->request->data.auth.user,
1703                                   state->request->data.auth.require_membership_of_sid));
1704                         goto done;
1705                 }
1706
1707                 result = append_auth_data(state->mem_ctx, state->response,
1708                                           state->request->flags, info3,
1709                                           name_domain, name_user);
1710                 if (!NT_STATUS_IS_OK(result)) {
1711                         goto done;
1712                 }
1713
1714                 if ((state->request->flags & WBFLAG_PAM_CACHED_LOGIN)
1715                     && lp_winbind_offline_logon()) {
1716
1717                         result = winbindd_store_creds(domain,
1718                                                       state->request->data.auth.user,
1719                                                       state->request->data.auth.pass,
1720                                                       info3);
1721                 }
1722
1723                 if (state->request->flags & WBFLAG_PAM_GET_PWD_POLICY) {
1724                         struct winbindd_domain *our_domain = find_our_domain();
1725
1726                         /* This is not entirely correct I believe, but it is
1727                            consistent.  Only apply the password policy settings
1728                            too warn users for our own domain.  Cannot obtain these
1729                            from trusted DCs all the  time so don't do it at all.
1730                            -- jerry */
1731
1732                         result = NT_STATUS_NOT_SUPPORTED;
1733                         if (our_domain == domain ) {
1734                                 result = fillup_password_policy(
1735                                         our_domain, state->response);
1736                         }
1737
1738                         if (!NT_STATUS_IS_OK(result)
1739                             && !NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED) )
1740                         {
1741                                 DEBUG(10,("Failed to get password policies for domain %s: %s\n",
1742                                           domain->name, nt_errstr(result)));
1743                                 goto done;
1744                         }
1745                 }
1746
1747                 result = NT_STATUS_OK;
1748         }
1749
1750 done:
1751         /* give us a more useful (more correct?) error code */
1752         if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
1753             (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
1754                 result = NT_STATUS_NO_LOGON_SERVERS;
1755         }
1756
1757         set_auth_errors(state->response, result);
1758
1759         DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, ("Plain-text authentication for user %s returned %s (PAM: %d)\n",
1760               state->request->data.auth.user,
1761               state->response->data.auth.nt_status_string,
1762               state->response->data.auth.pam_error));
1763
1764         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
1765 }
1766
1767 enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain,
1768                                                  struct winbindd_cli_state *state)
1769 {
1770         NTSTATUS result;
1771         struct netr_SamInfo3 *info3 = NULL;
1772         const char *name_user = NULL;
1773         const char *name_domain = NULL;
1774         const char *workstation;
1775
1776         DATA_BLOB lm_resp, nt_resp;
1777
1778         /* This is child-only, so no check for privileged access is needed
1779            anymore */
1780
1781         /* Ensure null termination */
1782         state->request->data.auth_crap.user[sizeof(state->request->data.auth_crap.user)-1]=0;
1783         state->request->data.auth_crap.domain[sizeof(state->request->data.auth_crap.domain)-1]=0;
1784
1785         name_user = state->request->data.auth_crap.user;
1786         name_domain = state->request->data.auth_crap.domain;
1787         workstation = state->request->data.auth_crap.workstation;
1788
1789         DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n", (unsigned long)state->pid,
1790                   name_domain, name_user));
1791
1792         if (state->request->data.auth_crap.lm_resp_len > sizeof(state->request->data.auth_crap.lm_resp)
1793                 || state->request->data.auth_crap.nt_resp_len > sizeof(state->request->data.auth_crap.nt_resp)) {
1794                 if (!(state->request->flags & WBFLAG_BIG_NTLMV2_BLOB) ||
1795                      state->request->extra_len != state->request->data.auth_crap.nt_resp_len) {
1796                         DEBUG(0, ("winbindd_pam_auth_crap: invalid password length %u/%u\n",
1797                                   state->request->data.auth_crap.lm_resp_len,
1798                                   state->request->data.auth_crap.nt_resp_len));
1799                         result = NT_STATUS_INVALID_PARAMETER;
1800                         goto done;
1801                 }
1802         }
1803
1804         lm_resp = data_blob_talloc(state->mem_ctx, state->request->data.auth_crap.lm_resp,
1805                                         state->request->data.auth_crap.lm_resp_len);
1806
1807         if (state->request->flags & WBFLAG_BIG_NTLMV2_BLOB) {
1808                 nt_resp = data_blob_talloc(state->mem_ctx,
1809                                            state->request->extra_data.data,
1810                                            state->request->data.auth_crap.nt_resp_len);
1811         } else {
1812                 nt_resp = data_blob_talloc(state->mem_ctx,
1813                                            state->request->data.auth_crap.nt_resp,
1814                                            state->request->data.auth_crap.nt_resp_len);
1815         }
1816
1817         if (strequal(name_domain, get_global_sam_name())) {
1818                 DATA_BLOB chal_blob = data_blob_const(
1819                         state->request->data.auth_crap.chal,
1820                         sizeof(state->request->data.auth_crap.chal));
1821
1822                 result = winbindd_dual_auth_passdb(
1823                         state->mem_ctx, name_domain, name_user,
1824                         &chal_blob, &lm_resp, &nt_resp, &info3);
1825                 goto process_result;
1826         }
1827
1828         result = winbind_samlogon_retry_loop(domain,
1829                                              state->mem_ctx,
1830                                              state->request->data.auth_crap.logon_parameters,
1831                                              domain->dcname,
1832                                              name_user,
1833                                              name_domain,
1834                                              /* Bug #3248 - found by Stefan Burkei. */
1835                                              workstation, /* We carefully set this above so use it... */
1836                                              state->request->data.auth_crap.chal,
1837                                              lm_resp,
1838                                              nt_resp,
1839                                              &info3);
1840         if (!NT_STATUS_IS_OK(result)) {
1841                 goto done;
1842         }
1843
1844 process_result:
1845
1846         if (NT_STATUS_IS_OK(result)) {
1847                 struct dom_sid user_sid;
1848
1849                 sid_compose(&user_sid, info3->base.domain_sid,
1850                             info3->base.rid);
1851                 wcache_invalidate_samlogon(find_domain_from_name(name_domain),
1852                                            &user_sid);
1853                 netsamlogon_cache_store(name_user, info3);
1854
1855                 /* Check if the user is in the right group */
1856
1857                 result = check_info3_in_group(
1858                         info3,
1859                         state->request->data.auth_crap.require_membership_of_sid);
1860                 if (!NT_STATUS_IS_OK(result)) {
1861                         DEBUG(3, ("User %s is not in the required group (%s), so "
1862                                   "crap authentication is rejected\n",
1863                                   state->request->data.auth_crap.user,
1864                                   state->request->data.auth_crap.require_membership_of_sid));
1865                         goto done;
1866                 }
1867
1868                 result = append_auth_data(state->mem_ctx, state->response,
1869                                           state->request->flags, info3,
1870                                           name_domain, name_user);
1871                 if (!NT_STATUS_IS_OK(result)) {
1872                         goto done;
1873                 }
1874         }
1875
1876 done:
1877
1878         /* give us a more useful (more correct?) error code */
1879         if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
1880             (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
1881                 result = NT_STATUS_NO_LOGON_SERVERS;
1882         }
1883
1884         if (state->request->flags & WBFLAG_PAM_NT_STATUS_SQUASH) {
1885                 result = nt_status_squash(result);
1886         }
1887
1888         set_auth_errors(state->response, result);
1889
1890         DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
1891               ("NTLM CRAP authentication for user [%s]\\[%s] returned %s (PAM: %d)\n",
1892                name_domain,
1893                name_user,
1894                state->response->data.auth.nt_status_string,
1895                state->response->data.auth.pam_error));
1896
1897         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
1898 }
1899
1900 enum winbindd_result winbindd_dual_pam_chauthtok(struct winbindd_domain *contact_domain,
1901                                                  struct winbindd_cli_state *state)
1902 {
1903         char *oldpass;
1904         char *newpass = NULL;
1905         struct policy_handle dom_pol;
1906         struct rpc_pipe_client *cli = NULL;
1907         bool got_info = false;
1908         struct samr_DomInfo1 *info = NULL;
1909         struct userPwdChangeFailureInformation *reject = NULL;
1910         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1911         fstring domain, user;
1912         struct dcerpc_binding_handle *b = NULL;
1913
1914         ZERO_STRUCT(dom_pol);
1915
1916         DEBUG(3, ("[%5lu]: dual pam chauthtok %s\n", (unsigned long)state->pid,
1917                   state->request->data.auth.user));
1918
1919         if (!parse_domain_user(state->request->data.chauthtok.user, domain, user)) {
1920                 goto done;
1921         }
1922
1923         /* Change password */
1924
1925         oldpass = state->request->data.chauthtok.oldpass;
1926         newpass = state->request->data.chauthtok.newpass;
1927
1928         /* Initialize reject reason */
1929         state->response->data.auth.reject_reason = Undefined;
1930
1931         /* Get sam handle */
1932
1933         result = cm_connect_sam(contact_domain, state->mem_ctx, &cli,
1934                                 &dom_pol);
1935         if (!NT_STATUS_IS_OK(result)) {
1936                 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
1937                 goto done;
1938         }
1939
1940         b = cli->binding_handle;
1941
1942         result = rpccli_samr_chgpasswd_user3(cli, state->mem_ctx,
1943                                              user,
1944                                              newpass,
1945                                              oldpass,
1946                                              &info,
1947                                              &reject);
1948
1949         /* Windows 2003 returns NT_STATUS_PASSWORD_RESTRICTION */
1950
1951         if (NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_RESTRICTION) ) {
1952
1953                 fill_in_password_policy(state->response, info);
1954
1955                 state->response->data.auth.reject_reason =
1956                         reject->extendedFailureReason;
1957
1958                 got_info = true;
1959         }
1960
1961         /* atm the pidl generated rpccli_samr_ChangePasswordUser3 function will
1962          * return with NT_STATUS_BUFFER_TOO_SMALL for w2k dcs as w2k just
1963          * returns with 4byte error code (NT_STATUS_NOT_SUPPORTED) which is too
1964          * short to comply with the samr_ChangePasswordUser3 idl - gd */
1965
1966         /* only fallback when the chgpasswd_user3 call is not supported */
1967         if (NT_STATUS_EQUAL(result, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE) ||
1968             NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED) ||
1969             NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL) ||
1970             NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
1971
1972                 DEBUG(10,("Password change with chgpasswd_user3 failed with: %s, retrying chgpasswd_user2\n",
1973                         nt_errstr(result)));
1974
1975                 result = rpccli_samr_chgpasswd_user2(cli, state->mem_ctx, user, newpass, oldpass);
1976
1977                 /* Windows 2000 returns NT_STATUS_ACCOUNT_RESTRICTION.
1978                    Map to the same status code as Windows 2003. */
1979
1980                 if ( NT_STATUS_EQUAL(NT_STATUS_ACCOUNT_RESTRICTION, result ) ) {
1981                         result = NT_STATUS_PASSWORD_RESTRICTION;
1982                 }
1983         }
1984
1985 done:
1986
1987         if (NT_STATUS_IS_OK(result)
1988             && (state->request->flags & WBFLAG_PAM_CACHED_LOGIN)
1989             && lp_winbind_offline_logon()) {
1990                 result = winbindd_update_creds_by_name(contact_domain, user,
1991                                                        newpass);
1992                 /* Again, this happens when we login from gdm or xdm
1993                  * and the password expires, *BUT* cached crendentials
1994                  * doesn't exist. winbindd_update_creds_by_name()
1995                  * returns NT_STATUS_NO_SUCH_USER.
1996                  * This is not a failure.
1997                  * --- BoYang
1998                  * */
1999                 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER)) {
2000                         result = NT_STATUS_OK;
2001                 }
2002
2003                 if (!NT_STATUS_IS_OK(result)) {
2004                         DEBUG(10, ("Failed to store creds: %s\n",
2005                                    nt_errstr(result)));
2006                         goto process_result;
2007                 }
2008         }
2009
2010         if (!NT_STATUS_IS_OK(result) && !got_info && contact_domain) {
2011
2012                 NTSTATUS policy_ret;
2013
2014                 policy_ret = fillup_password_policy(
2015                         contact_domain, state->response);
2016
2017                 /* failure of this is non critical, it will just provide no
2018                  * additional information to the client why the change has
2019                  * failed - Guenther */
2020
2021                 if (!NT_STATUS_IS_OK(policy_ret)) {
2022                         DEBUG(10,("Failed to get password policies: %s\n", nt_errstr(policy_ret)));
2023                         goto process_result;
2024                 }
2025         }
2026
2027 process_result:
2028
2029         if (strequal(contact_domain->name, get_global_sam_name())) {
2030                 /* FIXME: internal rpc pipe does not cache handles yet */
2031                 if (b) {
2032                         if (is_valid_policy_hnd(&dom_pol)) {
2033                                 NTSTATUS _result;
2034                                 dcerpc_samr_Close(b, state->mem_ctx, &dom_pol, &_result);
2035                         }
2036                         TALLOC_FREE(cli);
2037                 }
2038         }
2039
2040         set_auth_errors(state->response, result);
2041
2042         DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
2043               ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
2044                domain,
2045                user,
2046                state->response->data.auth.nt_status_string,
2047                state->response->data.auth.pam_error));
2048
2049         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2050 }
2051
2052 enum winbindd_result winbindd_dual_pam_logoff(struct winbindd_domain *domain,
2053                                               struct winbindd_cli_state *state)
2054 {
2055         NTSTATUS result = NT_STATUS_NOT_SUPPORTED;
2056
2057         DEBUG(3, ("[%5lu]: pam dual logoff %s\n", (unsigned long)state->pid,
2058                 state->request->data.logoff.user));
2059
2060         if (!(state->request->flags & WBFLAG_PAM_KRB5)) {
2061                 result = NT_STATUS_OK;
2062                 goto process_result;
2063         }
2064
2065         if (state->request->data.logoff.krb5ccname[0] == '\0') {
2066                 result = NT_STATUS_OK;
2067                 goto process_result;
2068         }
2069
2070 #ifdef HAVE_KRB5
2071
2072         if (state->request->data.logoff.uid < 0) {
2073                 DEBUG(0,("winbindd_pam_logoff: invalid uid\n"));
2074                 goto process_result;
2075         }
2076
2077         /* what we need here is to find the corresponding krb5 ccache name *we*
2078          * created for a given username and destroy it */
2079
2080         if (!ccache_entry_exists(state->request->data.logoff.user)) {
2081                 result = NT_STATUS_OK;
2082                 DEBUG(10,("winbindd_pam_logoff: no entry found.\n"));
2083                 goto process_result;
2084         }
2085
2086         if (!ccache_entry_identical(state->request->data.logoff.user,
2087                                         state->request->data.logoff.uid,
2088                                         state->request->data.logoff.krb5ccname)) {
2089                 DEBUG(0,("winbindd_pam_logoff: cached entry differs.\n"));
2090                 goto process_result;
2091         }
2092
2093         result = remove_ccache(state->request->data.logoff.user);
2094         if (!NT_STATUS_IS_OK(result)) {
2095                 DEBUG(0,("winbindd_pam_logoff: failed to remove ccache: %s\n",
2096                         nt_errstr(result)));
2097                 goto process_result;
2098         }
2099
2100 #else
2101         result = NT_STATUS_NOT_SUPPORTED;
2102 #endif
2103
2104 process_result:
2105
2106
2107         set_auth_errors(state->response, result);
2108
2109         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2110 }
2111
2112 /* Change user password with auth crap*/
2113
2114 enum winbindd_result winbindd_dual_pam_chng_pswd_auth_crap(struct winbindd_domain *domainSt, struct winbindd_cli_state *state)
2115 {
2116         NTSTATUS result;
2117         DATA_BLOB new_nt_password;
2118         DATA_BLOB old_nt_hash_enc;
2119         DATA_BLOB new_lm_password;
2120         DATA_BLOB old_lm_hash_enc;
2121         fstring  domain,user;
2122         struct policy_handle dom_pol;
2123         struct winbindd_domain *contact_domain = domainSt;
2124         struct rpc_pipe_client *cli = NULL;
2125         struct dcerpc_binding_handle *b = NULL;
2126
2127         ZERO_STRUCT(dom_pol);
2128
2129         /* Ensure null termination */
2130         state->request->data.chng_pswd_auth_crap.user[
2131                 sizeof(state->request->data.chng_pswd_auth_crap.user)-1]=0;
2132         state->request->data.chng_pswd_auth_crap.domain[
2133                 sizeof(state->request->data.chng_pswd_auth_crap.domain)-1]=0;
2134         *domain = 0;
2135         *user = 0;
2136
2137         DEBUG(3, ("[%5lu]: pam change pswd auth crap domain: %s user: %s\n",
2138                   (unsigned long)state->pid,
2139                   state->request->data.chng_pswd_auth_crap.domain,
2140                   state->request->data.chng_pswd_auth_crap.user));
2141
2142         if (lp_winbind_offline_logon()) {
2143                 DEBUG(0,("Refusing password change as winbind offline logons are enabled. "));
2144                 DEBUGADD(0,("Changing passwords here would risk inconsistent logons\n"));
2145                 result = NT_STATUS_ACCESS_DENIED;
2146                 goto done;
2147         }
2148
2149         if (*state->request->data.chng_pswd_auth_crap.domain) {
2150                 fstrcpy(domain,state->request->data.chng_pswd_auth_crap.domain);
2151         } else {
2152                 parse_domain_user(state->request->data.chng_pswd_auth_crap.user,
2153                                   domain, user);
2154
2155                 if(!*domain) {
2156                         DEBUG(3,("no domain specified with username (%s) - "
2157                                  "failing auth\n",
2158                                  state->request->data.chng_pswd_auth_crap.user));
2159                         result = NT_STATUS_NO_SUCH_USER;
2160                         goto done;
2161                 }
2162         }
2163
2164         if (!*domain && lp_winbind_use_default_domain()) {
2165                 fstrcpy(domain,lp_workgroup());
2166         }
2167
2168         if(!*user) {
2169                 fstrcpy(user, state->request->data.chng_pswd_auth_crap.user);
2170         }
2171
2172         DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n",
2173                   (unsigned long)state->pid, domain, user));
2174
2175         /* Change password */
2176         new_nt_password = data_blob_const(
2177                 state->request->data.chng_pswd_auth_crap.new_nt_pswd,
2178                 state->request->data.chng_pswd_auth_crap.new_nt_pswd_len);
2179
2180         old_nt_hash_enc = data_blob_const(
2181                 state->request->data.chng_pswd_auth_crap.old_nt_hash_enc,
2182                 state->request->data.chng_pswd_auth_crap.old_nt_hash_enc_len);
2183
2184         if(state->request->data.chng_pswd_auth_crap.new_lm_pswd_len > 0)        {
2185                 new_lm_password = data_blob_const(
2186                         state->request->data.chng_pswd_auth_crap.new_lm_pswd,
2187                         state->request->data.chng_pswd_auth_crap.new_lm_pswd_len);
2188
2189                 old_lm_hash_enc = data_blob_const(
2190                         state->request->data.chng_pswd_auth_crap.old_lm_hash_enc,
2191                         state->request->data.chng_pswd_auth_crap.old_lm_hash_enc_len);
2192         } else {
2193                 new_lm_password.length = 0;
2194                 old_lm_hash_enc.length = 0;
2195         }
2196
2197         /* Get sam handle */
2198
2199         result = cm_connect_sam(contact_domain, state->mem_ctx, &cli, &dom_pol);
2200         if (!NT_STATUS_IS_OK(result)) {
2201                 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
2202                 goto done;
2203         }
2204
2205         b = cli->binding_handle;
2206
2207         result = rpccli_samr_chng_pswd_auth_crap(
2208                 cli, state->mem_ctx, user, new_nt_password, old_nt_hash_enc,
2209                 new_lm_password, old_lm_hash_enc);
2210
2211  done:
2212
2213         if (strequal(contact_domain->name, get_global_sam_name())) {
2214                 /* FIXME: internal rpc pipe does not cache handles yet */
2215                 if (b) {
2216                         if (is_valid_policy_hnd(&dom_pol)) {
2217                                 NTSTATUS _result;
2218                                 dcerpc_samr_Close(b, state->mem_ctx, &dom_pol, &_result);
2219                         }
2220                         TALLOC_FREE(cli);
2221                 }
2222         }
2223
2224         set_auth_errors(state->response, result);
2225
2226         DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
2227               ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
2228                domain, user,
2229                state->response->data.auth.nt_status_string,
2230                state->response->data.auth.pam_error));
2231
2232         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2233 }