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