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