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