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