Correctly check for errors in strlower_m() returns.
[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                                             realm,
650                                             uid,
651                                             time(NULL),
652                                             ticket_lifetime,
653                                             renewal_until,
654                                             false);
655
656                 if (!NT_STATUS_IS_OK(result)) {
657                         DEBUG(10,("winbindd_raw_kerberos_login: failed to add ccache to list: %s\n",
658                                 nt_errstr(result)));
659                 }
660         } else {
661
662                 /* need to delete the memory cred cache, it is not used anymore */
663
664                 krb5_ret = ads_kdestroy(cc);
665                 if (krb5_ret) {
666                         DEBUG(3,("winbindd_raw_kerberos_login: "
667                                  "could not destroy krb5 credential cache: "
668                                  "%s\n", error_message(krb5_ret)));
669                 }
670
671         }
672
673         return NT_STATUS_OK;
674
675 failed:
676
677         /* we could have created a new credential cache with a valid tgt in it
678          * but we werent able to get or verify the service ticket for this
679          * local host and therefor didn't get the PAC, we need to remove that
680          * cache entirely now */
681
682         krb5_ret = ads_kdestroy(cc);
683         if (krb5_ret) {
684                 DEBUG(3,("winbindd_raw_kerberos_login: "
685                          "could not destroy krb5 credential cache: "
686                          "%s\n", error_message(krb5_ret)));
687         }
688
689         if (!NT_STATUS_IS_OK(remove_ccache(user))) {
690                 DEBUG(3,("winbindd_raw_kerberos_login: "
691                           "could not remove ccache for user %s\n",
692                         user));
693         }
694
695         return result;
696 #else
697         return NT_STATUS_NOT_SUPPORTED;
698 #endif /* HAVE_KRB5 */
699 }
700
701 /****************************************************************
702 ****************************************************************/
703
704 bool check_request_flags(uint32_t flags)
705 {
706         uint32_t flags_edata = WBFLAG_PAM_AFS_TOKEN |
707                                WBFLAG_PAM_INFO3_TEXT |
708                                WBFLAG_PAM_INFO3_NDR;
709
710         if ( ( (flags & flags_edata) == WBFLAG_PAM_AFS_TOKEN) ||
711              ( (flags & flags_edata) == WBFLAG_PAM_INFO3_NDR) ||
712              ( (flags & flags_edata) == WBFLAG_PAM_INFO3_TEXT)||
713               !(flags & flags_edata) ) {
714                 return true;
715         }
716
717         DEBUG(1, ("check_request_flags: invalid request flags[0x%08X]\n",
718                   flags));
719
720         return false;
721 }
722
723 /****************************************************************
724 ****************************************************************/
725
726 static NTSTATUS append_auth_data(TALLOC_CTX *mem_ctx,
727                                  struct winbindd_response *resp,
728                                  uint32_t request_flags,
729                                  struct netr_SamInfo3 *info3,
730                                  const char *name_domain,
731                                  const char *name_user)
732 {
733         NTSTATUS result;
734
735         if (request_flags & WBFLAG_PAM_USER_SESSION_KEY) {
736                 memcpy(resp->data.auth.user_session_key,
737                        info3->base.key.key,
738                        sizeof(resp->data.auth.user_session_key)
739                        /* 16 */);
740         }
741
742         if (request_flags & WBFLAG_PAM_LMKEY) {
743                 memcpy(resp->data.auth.first_8_lm_hash,
744                        info3->base.LMSessKey.key,
745                        sizeof(resp->data.auth.first_8_lm_hash)
746                        /* 8 */);
747         }
748
749         if (request_flags & WBFLAG_PAM_UNIX_NAME) {
750                 result = append_unix_username(mem_ctx, resp,
751                                               info3, name_domain, name_user);
752                 if (!NT_STATUS_IS_OK(result)) {
753                         DEBUG(10,("Failed to append Unix Username: %s\n",
754                                 nt_errstr(result)));
755                         return result;
756                 }
757         }
758
759         /* currently, anything from here on potentially overwrites extra_data. */
760
761         if (request_flags & WBFLAG_PAM_INFO3_NDR) {
762                 result = append_info3_as_ndr(mem_ctx, resp, info3);
763                 if (!NT_STATUS_IS_OK(result)) {
764                         DEBUG(10,("Failed to append INFO3 (NDR): %s\n",
765                                 nt_errstr(result)));
766                         return result;
767                 }
768         }
769
770         if (request_flags & WBFLAG_PAM_INFO3_TEXT) {
771                 result = append_info3_as_txt(mem_ctx, resp, info3);
772                 if (!NT_STATUS_IS_OK(result)) {
773                         DEBUG(10,("Failed to append INFO3 (TXT): %s\n",
774                                 nt_errstr(result)));
775                         return result;
776                 }
777         }
778
779         if (request_flags & WBFLAG_PAM_AFS_TOKEN) {
780                 result = append_afs_token(mem_ctx, resp,
781                                           info3, name_domain, name_user);
782                 if (!NT_STATUS_IS_OK(result)) {
783                         DEBUG(10,("Failed to append AFS token: %s\n",
784                                 nt_errstr(result)));
785                         return result;
786                 }
787         }
788
789         return NT_STATUS_OK;
790 }
791
792 static NTSTATUS winbindd_dual_pam_auth_cached(struct winbindd_domain *domain,
793                                               struct winbindd_cli_state *state,
794                                               struct netr_SamInfo3 **info3)
795 {
796         NTSTATUS result = NT_STATUS_LOGON_FAILURE;
797         uint16 max_allowed_bad_attempts;
798         fstring name_domain, name_user;
799         struct dom_sid sid;
800         enum lsa_SidType type;
801         uchar new_nt_pass[NT_HASH_LEN];
802         const uint8 *cached_nt_pass;
803         const uint8 *cached_salt;
804         struct netr_SamInfo3 *my_info3;
805         time_t kickoff_time, must_change_time;
806         bool password_good = false;
807 #ifdef HAVE_KRB5
808         struct winbindd_tdc_domain *tdc_domain = NULL;
809 #endif
810
811         *info3 = NULL;
812
813         ZERO_STRUCTP(info3);
814
815         DEBUG(10,("winbindd_dual_pam_auth_cached\n"));
816
817         /* Parse domain and username */
818
819         parse_domain_user(state->request->data.auth.user, name_domain, name_user);
820
821
822         if (!lookup_cached_name(name_domain,
823                                 name_user,
824                                 &sid,
825                                 &type)) {
826                 DEBUG(10,("winbindd_dual_pam_auth_cached: no such user in the cache\n"));
827                 return NT_STATUS_NO_SUCH_USER;
828         }
829
830         if (type != SID_NAME_USER) {
831                 DEBUG(10,("winbindd_dual_pam_auth_cached: not a user (%s)\n", sid_type_lookup(type)));
832                 return NT_STATUS_LOGON_FAILURE;
833         }
834
835         result = winbindd_get_creds(domain,
836                                     state->mem_ctx,
837                                     &sid,
838                                     &my_info3,
839                                     &cached_nt_pass,
840                                     &cached_salt);
841         if (!NT_STATUS_IS_OK(result)) {
842                 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get creds: %s\n", nt_errstr(result)));
843                 return result;
844         }
845
846         *info3 = my_info3;
847
848         E_md4hash(state->request->data.auth.pass, new_nt_pass);
849
850         dump_data_pw("new_nt_pass", new_nt_pass, NT_HASH_LEN);
851         dump_data_pw("cached_nt_pass", cached_nt_pass, NT_HASH_LEN);
852         if (cached_salt) {
853                 dump_data_pw("cached_salt", cached_salt, NT_HASH_LEN);
854         }
855
856         if (cached_salt) {
857                 /* In this case we didn't store the nt_hash itself,
858                    but the MD5 combination of salt + nt_hash. */
859                 uchar salted_hash[NT_HASH_LEN];
860                 E_md5hash(cached_salt, new_nt_pass, salted_hash);
861
862                 password_good = (memcmp(cached_nt_pass, salted_hash,
863                                         NT_HASH_LEN) == 0);
864         } else {
865                 /* Old cached cred - direct store of nt_hash (bad bad bad !). */
866                 password_good = (memcmp(cached_nt_pass, new_nt_pass,
867                                         NT_HASH_LEN) == 0);
868         }
869
870         if (password_good) {
871
872                 /* User *DOES* know the password, update logon_time and reset
873                  * bad_pw_count */
874
875                 my_info3->base.user_flags |= NETLOGON_CACHED_ACCOUNT;
876
877                 if (my_info3->base.acct_flags & ACB_AUTOLOCK) {
878                         return NT_STATUS_ACCOUNT_LOCKED_OUT;
879                 }
880
881                 if (my_info3->base.acct_flags & ACB_DISABLED) {
882                         return NT_STATUS_ACCOUNT_DISABLED;
883                 }
884
885                 if (my_info3->base.acct_flags & ACB_WSTRUST) {
886                         return NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
887                 }
888
889                 if (my_info3->base.acct_flags & ACB_SVRTRUST) {
890                         return NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT;
891                 }
892
893                 if (my_info3->base.acct_flags & ACB_DOMTRUST) {
894                         return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT;
895                 }
896
897                 if (!(my_info3->base.acct_flags & ACB_NORMAL)) {
898                         DEBUG(0,("winbindd_dual_pam_auth_cached: whats wrong with that one?: 0x%08x\n",
899                                 my_info3->base.acct_flags));
900                         return NT_STATUS_LOGON_FAILURE;
901                 }
902
903                 kickoff_time = nt_time_to_unix(my_info3->base.kickoff_time);
904                 if (kickoff_time != 0 && time(NULL) > kickoff_time) {
905                         return NT_STATUS_ACCOUNT_EXPIRED;
906                 }
907
908                 must_change_time = nt_time_to_unix(my_info3->base.force_password_change);
909                 if (must_change_time != 0 && must_change_time < time(NULL)) {
910                         /* we allow grace logons when the password has expired */
911                         my_info3->base.user_flags |= NETLOGON_GRACE_LOGON;
912                         /* return NT_STATUS_PASSWORD_EXPIRED; */
913                         goto success;
914                 }
915
916 #ifdef HAVE_KRB5
917                 if ((state->request->flags & WBFLAG_PAM_KRB5) &&
918                     ((tdc_domain = wcache_tdc_fetch_domain(state->mem_ctx, name_domain)) != NULL) &&
919                     ((tdc_domain->trust_type & NETR_TRUST_TYPE_UPLEVEL) ||
920                     /* used to cope with the case winbindd starting without network. */
921                     !strequal(tdc_domain->domain_name, tdc_domain->dns_name))) {
922
923                         uid_t uid = -1;
924                         const char *cc = NULL;
925                         char *realm = NULL;
926                         const char *principal_s = NULL;
927                         const char *service = NULL;
928                         const char *user_ccache_file;
929
930                         uid = get_uid_from_request(state->request);
931                         if (uid == -1) {
932                                 DEBUG(0,("winbindd_dual_pam_auth_cached: invalid uid\n"));
933                                 return NT_STATUS_INVALID_PARAMETER;
934                         }
935
936                         cc = generate_krb5_ccache(state->mem_ctx,
937                                                 state->request->data.auth.krb5_cc_type,
938                                                 state->request->data.auth.uid,
939                                                 &user_ccache_file);
940                         if (cc == NULL) {
941                                 return NT_STATUS_NO_MEMORY;
942                         }
943
944                         realm = domain->alt_name;
945                         if (!strupper_m(realm)) {
946                                 return NT_STATUS_INVALID_PARAMETER;
947                         }
948
949                         principal_s = talloc_asprintf(state->mem_ctx, "%s@%s", name_user, realm);
950                         if (principal_s == NULL) {
951                                 return NT_STATUS_NO_MEMORY;
952                         }
953
954                         service = talloc_asprintf(state->mem_ctx, "%s/%s@%s", KRB5_TGS_NAME, realm, realm);
955                         if (service == NULL) {
956                                 return NT_STATUS_NO_MEMORY;
957                         }
958
959                         if (user_ccache_file != NULL) {
960
961                                 fstrcpy(state->response->data.auth.krb5ccname,
962                                         user_ccache_file);
963
964                                 result = add_ccache_to_list(principal_s,
965                                                             cc,
966                                                             service,
967                                                             state->request->data.auth.user,
968                                                             domain->alt_name,
969                                                             uid,
970                                                             time(NULL),
971                                                             time(NULL) + lp_winbind_cache_time(),
972                                                             time(NULL) + WINBINDD_PAM_AUTH_KRB5_RENEW_TIME,
973                                                             true);
974
975                                 if (!NT_STATUS_IS_OK(result)) {
976                                         DEBUG(10,("winbindd_dual_pam_auth_cached: failed "
977                                                 "to add ccache to list: %s\n",
978                                                 nt_errstr(result)));
979                                 }
980                         }
981                 }
982 #endif /* HAVE_KRB5 */
983  success:
984                 /* FIXME: we possibly should handle logon hours as well (does xp when
985                  * offline?) see auth/auth_sam.c:sam_account_ok for details */
986
987                 unix_to_nt_time(&my_info3->base.logon_time, time(NULL));
988                 my_info3->base.bad_password_count = 0;
989
990                 result = winbindd_update_creds_by_info3(domain,
991                                                         state->request->data.auth.user,
992                                                         state->request->data.auth.pass,
993                                                         my_info3);
994                 if (!NT_STATUS_IS_OK(result)) {
995                         DEBUG(1,("winbindd_dual_pam_auth_cached: failed to update creds: %s\n",
996                                 nt_errstr(result)));
997                         return result;
998                 }
999
1000                 return NT_STATUS_OK;
1001
1002         }
1003
1004         /* User does *NOT* know the correct password, modify info3 accordingly, but only if online */
1005         if (domain->online == false) {
1006                 goto failed;
1007         }
1008
1009         /* failure of this is not critical */
1010         result = get_max_bad_attempts_from_lockout_policy(domain, state->mem_ctx, &max_allowed_bad_attempts);
1011         if (!NT_STATUS_IS_OK(result)) {
1012                 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get max_allowed_bad_attempts. "
1013                           "Won't be able to honour account lockout policies\n"));
1014         }
1015
1016         /* increase counter */
1017         my_info3->base.bad_password_count++;
1018
1019         if (max_allowed_bad_attempts == 0) {
1020                 goto failed;
1021         }
1022
1023         /* lockout user */
1024         if (my_info3->base.bad_password_count >= max_allowed_bad_attempts) {
1025
1026                 uint32 password_properties;
1027
1028                 result = get_pwd_properties(domain, state->mem_ctx, &password_properties);
1029                 if (!NT_STATUS_IS_OK(result)) {
1030                         DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get password properties.\n"));
1031                 }
1032
1033                 if ((my_info3->base.rid != DOMAIN_RID_ADMINISTRATOR) ||
1034                     (password_properties & DOMAIN_PASSWORD_LOCKOUT_ADMINS)) {
1035                         my_info3->base.acct_flags |= ACB_AUTOLOCK;
1036                 }
1037         }
1038
1039 failed:
1040         result = winbindd_update_creds_by_info3(domain,
1041                                                 state->request->data.auth.user,
1042                                                 NULL,
1043                                                 my_info3);
1044
1045         if (!NT_STATUS_IS_OK(result)) {
1046                 DEBUG(0,("winbindd_dual_pam_auth_cached: failed to update creds %s\n",
1047                         nt_errstr(result)));
1048         }
1049
1050         return NT_STATUS_LOGON_FAILURE;
1051 }
1052
1053 static NTSTATUS winbindd_dual_pam_auth_kerberos(struct winbindd_domain *domain,
1054                                                 struct winbindd_cli_state *state,
1055                                                 struct netr_SamInfo3 **info3)
1056 {
1057         struct winbindd_domain *contact_domain;
1058         fstring name_domain, name_user;
1059         NTSTATUS result;
1060
1061         DEBUG(10,("winbindd_dual_pam_auth_kerberos\n"));
1062
1063         /* Parse domain and username */
1064
1065         parse_domain_user(state->request->data.auth.user, name_domain, name_user);
1066
1067         /* what domain should we contact? */
1068
1069         if ( IS_DC ) {
1070                 if (!(contact_domain = find_domain_from_name(name_domain))) {
1071                         DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
1072                                   state->request->data.auth.user, name_domain, name_user, name_domain));
1073                         result = NT_STATUS_NO_SUCH_USER;
1074                         goto done;
1075                 }
1076
1077         } else {
1078                 if (is_myname(name_domain)) {
1079                         DEBUG(3, ("Authentication for domain %s (local domain to this server) not supported at this stage\n", name_domain));
1080                         result =  NT_STATUS_NO_SUCH_USER;
1081                         goto done;
1082                 }
1083
1084                 contact_domain = find_domain_from_name(name_domain);
1085                 if (contact_domain == NULL) {
1086                         DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
1087                                   state->request->data.auth.user, name_domain, name_user, name_domain));
1088
1089                         result =  NT_STATUS_NO_SUCH_USER;
1090                         goto done;
1091                 }
1092         }
1093
1094         if (contact_domain->initialized &&
1095             contact_domain->active_directory) {
1096                 goto try_login;
1097         }
1098
1099         if (!contact_domain->initialized) {
1100                 init_dc_connection(contact_domain);
1101         }
1102
1103         if (!contact_domain->active_directory) {
1104                 DEBUG(3,("krb5 auth requested but domain is not Active Directory\n"));
1105                 return NT_STATUS_INVALID_LOGON_TYPE;
1106         }
1107 try_login:
1108         result = winbindd_raw_kerberos_login(
1109                 state->mem_ctx, contact_domain,
1110                 state->request->data.auth.user,
1111                 state->request->data.auth.pass,
1112                 state->request->data.auth.krb5_cc_type,
1113                 get_uid_from_request(state->request),
1114                 info3, state->response->data.auth.krb5ccname);
1115 done:
1116         return result;
1117 }
1118
1119 static NTSTATUS winbindd_dual_auth_passdb(TALLOC_CTX *mem_ctx,
1120                                           uint32_t logon_parameters,
1121                                           const char *domain, const char *user,
1122                                           const DATA_BLOB *challenge,
1123                                           const DATA_BLOB *lm_resp,
1124                                           const DATA_BLOB *nt_resp,
1125                                           struct netr_SamInfo3 **pinfo3)
1126 {
1127         struct auth_usersupplied_info *user_info = NULL;
1128         struct tsocket_address *local;
1129         NTSTATUS status;
1130         int rc;
1131
1132         rc = tsocket_address_inet_from_strings(mem_ctx,
1133                                                "ip",
1134                                                "127.0.0.1",
1135                                                0,
1136                                                &local);
1137         if (rc < 0) {
1138                 return NT_STATUS_NO_MEMORY;
1139         }
1140         status = make_user_info(&user_info, user, user, domain, domain,
1141                                 lp_netbios_name(), local, lm_resp, nt_resp, NULL, NULL,
1142                                 NULL, AUTH_PASSWORD_RESPONSE);
1143         if (!NT_STATUS_IS_OK(status)) {
1144                 DEBUG(10, ("make_user_info failed: %s\n", nt_errstr(status)));
1145                 return status;
1146         }
1147         user_info->logon_parameters = logon_parameters;
1148
1149         /* We don't want any more mapping of the username */
1150         user_info->mapped_state = True;
1151
1152         status = check_sam_security_info3(challenge, talloc_tos(), user_info,
1153                                           pinfo3);
1154         free_user_info(&user_info);
1155         DEBUG(10, ("Authenticaticating user %s\\%s returned %s\n", domain,
1156                    user, nt_errstr(status)));
1157         return status;
1158 }
1159
1160 static NTSTATUS winbind_samlogon_retry_loop(struct winbindd_domain *domain,
1161                                             TALLOC_CTX *mem_ctx,
1162                                             uint32_t logon_parameters,
1163                                             const char *server,
1164                                             const char *username,
1165                                             const char *domainname,
1166                                             const char *workstation,
1167                                             const uint8_t chal[8],
1168                                             DATA_BLOB lm_response,
1169                                             DATA_BLOB nt_response,
1170                                             struct netr_SamInfo3 **info3)
1171 {
1172         int attempts = 0;
1173         bool retry = false;
1174         NTSTATUS result;
1175
1176         do {
1177                 struct rpc_pipe_client *netlogon_pipe;
1178                 const struct pipe_auth_data *auth;
1179                 uint32_t neg_flags = 0;
1180
1181                 ZERO_STRUCTP(info3);
1182                 retry = false;
1183
1184                 result = cm_connect_netlogon(domain, &netlogon_pipe);
1185
1186                 if (!NT_STATUS_IS_OK(result)) {
1187                         DEBUG(3,("could not open handle to NETLOGON pipe (error: %s)\n",
1188                                   nt_errstr(result)));
1189                         if (NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT)) {
1190                                 if (attempts > 0) {
1191                                         DEBUG(3, ("This is the second problem for this "
1192                                                 "particular call, forcing the close of "
1193                                                 "this connection\n"));
1194                                         invalidate_cm_connection(&domain->conn);
1195                                 } else {
1196                                         DEBUG(3, ("First call to cm_connect_netlogon "
1197                                                 "has timed out, retrying\n"));
1198                                         continue;
1199                                 }
1200                         }
1201                         return result;
1202                 }
1203                 auth = netlogon_pipe->auth;
1204                 if (netlogon_pipe->dc) {
1205                         neg_flags = netlogon_pipe->dc->negotiate_flags;
1206                 }
1207
1208                 /* It is really important to try SamLogonEx here,
1209                  * because in a clustered environment, we want to use
1210                  * one machine account from multiple physical
1211                  * computers.
1212                  *
1213                  * With a normal SamLogon call, we must keep the
1214                  * credentials chain updated and intact between all
1215                  * users of the machine account (which would imply
1216                  * cross-node communication for every NTLM logon).
1217                  *
1218                  * (The credentials chain is not per NETLOGON pipe
1219                  * connection, but globally on the server/client pair
1220                  * by machine name).
1221                  *
1222                  * When using SamLogonEx, the credentials are not
1223                  * supplied, but the session key is implied by the
1224                  * wrapping SamLogon context.
1225                  *
1226                  *  -- abartlet 21 April 2008
1227                  *
1228                  * It's also important to use NetlogonValidationSamInfo4 (6),
1229                  * because it relies on the rpc transport encryption
1230                  * and avoids using the global netlogon schannel
1231                  * session key to en/decrypt secret information
1232                  * like the user_session_key for network logons.
1233                  *
1234                  * [MS-APDS] 3.1.5.2 NTLM Network Logon
1235                  * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
1236                  * NETLOGON_NEG_AUTHENTICATED_RPC set together
1237                  * are the indication that the server supports
1238                  * NetlogonValidationSamInfo4 (6). And it must only
1239                  * be used if "SealSecureChannel" is used.
1240                  *
1241                  * -- metze 4 February 2011
1242                  */
1243
1244                 if (auth == NULL) {
1245                         domain->can_do_validation6 = false;
1246                 } else if (auth->auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
1247                         domain->can_do_validation6 = false;
1248                 } else if (auth->auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
1249                         domain->can_do_validation6 = false;
1250                 } else if (!(neg_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
1251                         domain->can_do_validation6 = false;
1252                 } else if (!(neg_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
1253                         domain->can_do_validation6 = false;
1254                 }
1255
1256                 if (domain->can_do_samlogon_ex && domain->can_do_validation6) {
1257                         result = rpccli_netlogon_sam_network_logon_ex(
1258                                         netlogon_pipe,
1259                                         mem_ctx,
1260                                         logon_parameters,
1261                                         server,         /* server name */
1262                                         username,       /* user name */
1263                                         domainname,     /* target domain */
1264                                         workstation,    /* workstation */
1265                                         chal,
1266                                         6,
1267                                         lm_response,
1268                                         nt_response,
1269                                         info3);
1270                 } else {
1271                         result = rpccli_netlogon_sam_network_logon(
1272                                         netlogon_pipe,
1273                                         mem_ctx,
1274                                         logon_parameters,
1275                                         server,         /* server name */
1276                                         username,       /* user name */
1277                                         domainname,     /* target domain */
1278                                         workstation,    /* workstation */
1279                                         chal,
1280                                         domain->can_do_validation6 ? 6 : 3,
1281                                         lm_response,
1282                                         nt_response,
1283                                         info3);
1284                 }
1285
1286                 if (NT_STATUS_EQUAL(result, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1287
1288                         /*
1289                          * It's likely that the server also does not support
1290                          * validation level 6
1291                          */
1292                         domain->can_do_validation6 = false;
1293
1294                         if (domain->can_do_samlogon_ex) {
1295                                 DEBUG(3, ("Got a DC that can not do NetSamLogonEx, "
1296                                           "retrying with NetSamLogon\n"));
1297                                 domain->can_do_samlogon_ex = false;
1298                                 retry = true;
1299                                 continue;
1300                         }
1301
1302
1303                         /* Got DCERPC_FAULT_OP_RNG_ERROR for SamLogon
1304                          * (no Ex). This happens against old Samba
1305                          * DCs. Drop the connection.
1306                          */
1307                         invalidate_cm_connection(&domain->conn);
1308                         result = NT_STATUS_LOGON_FAILURE;
1309                         break;
1310                 }
1311
1312                 if (domain->can_do_validation6 &&
1313                     (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
1314                      NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
1315                      NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL))) {
1316                         DEBUG(3,("Got a DC that can not do validation level 6, "
1317                                   "retrying with level 3\n"));
1318                         domain->can_do_validation6 = false;
1319                         retry = true;
1320                         continue;
1321                 }
1322
1323                 /*
1324                  * we increment this after the "feature negotiation"
1325                  * for can_do_samlogon_ex and can_do_validation6
1326                  */
1327                 attempts += 1;
1328
1329                 /* We have to try a second time as cm_connect_netlogon
1330                    might not yet have noticed that the DC has killed
1331                    our connection. */
1332
1333                 if (!rpccli_is_connected(netlogon_pipe)) {
1334                         retry = true;
1335                         continue;
1336                 }
1337
1338                 /* if we get access denied, a possible cause was that we had
1339                    and open connection to the DC, but someone changed our
1340                    machine account password out from underneath us using 'net
1341                    rpc changetrustpw' */
1342
1343                 if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
1344                         DEBUG(3,("winbind_samlogon_retry_loop: sam_logon returned "
1345                                  "ACCESS_DENIED.  Maybe the trust account "
1346                                 "password was changed and we didn't know it. "
1347                                  "Killing connections to domain %s\n",
1348                                 domainname));
1349                         invalidate_cm_connection(&domain->conn);
1350                         retry = true;
1351                 }
1352
1353         } while ( (attempts < 2) && retry );
1354
1355         if (NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT)) {
1356                 DEBUG(3,("winbind_samlogon_retry_loop: sam_network_logon(ex) "
1357                                 "returned NT_STATUS_IO_TIMEOUT after the retry."
1358                                 "Killing connections to domain %s\n",
1359                         domainname));
1360                 invalidate_cm_connection(&domain->conn);
1361         }
1362         return result;
1363 }
1364
1365 static NTSTATUS winbindd_dual_pam_auth_samlogon(TALLOC_CTX *mem_ctx,
1366                                                 struct winbindd_domain *domain,
1367                                                 const char *user,
1368                                                 const char *pass,
1369                                                 uint32_t request_flags,
1370                                                 struct netr_SamInfo3 **info3)
1371 {
1372
1373         uchar chal[8];
1374         DATA_BLOB lm_resp;
1375         DATA_BLOB nt_resp;
1376         unsigned char local_nt_response[24];
1377         fstring name_domain, name_user;
1378         NTSTATUS result;
1379         struct netr_SamInfo3 *my_info3 = NULL;
1380
1381         *info3 = NULL;
1382
1383         DEBUG(10,("winbindd_dual_pam_auth_samlogon\n"));
1384
1385         /* Parse domain and username */
1386
1387         parse_domain_user(user, name_domain, name_user);
1388
1389         /* do password magic */
1390
1391         generate_random_buffer(chal, sizeof(chal));
1392
1393         if (lp_client_ntlmv2_auth()) {
1394                 DATA_BLOB server_chal;
1395                 DATA_BLOB names_blob;
1396                 server_chal = data_blob_const(chal, 8);
1397
1398                 /* note that the 'workgroup' here is for the local
1399                    machine.  The 'server name' must match the
1400                    'workstation' passed to the actual SamLogon call.
1401                 */
1402                 names_blob = NTLMv2_generate_names_blob(
1403                         mem_ctx, lp_netbios_name(), lp_workgroup());
1404
1405                 if (!SMBNTLMv2encrypt(mem_ctx, name_user, name_domain,
1406                                       pass,
1407                                       &server_chal,
1408                                       &names_blob,
1409                                       &lm_resp, &nt_resp, NULL, NULL)) {
1410                         data_blob_free(&names_blob);
1411                         DEBUG(0, ("winbindd_pam_auth: SMBNTLMv2encrypt() failed!\n"));
1412                         result = NT_STATUS_NO_MEMORY;
1413                         goto done;
1414                 }
1415                 data_blob_free(&names_blob);
1416         } else {
1417                 lm_resp = data_blob_null;
1418                 SMBNTencrypt(pass, chal, local_nt_response);
1419
1420                 nt_resp = data_blob_talloc(mem_ctx, local_nt_response,
1421                                            sizeof(local_nt_response));
1422         }
1423
1424         if (strequal(name_domain, get_global_sam_name())) {
1425                 DATA_BLOB chal_blob = data_blob_const(chal, sizeof(chal));
1426
1427                 result = winbindd_dual_auth_passdb(
1428                         mem_ctx, 0, name_domain, name_user,
1429                         &chal_blob, &lm_resp, &nt_resp, info3);
1430                 goto done;
1431         }
1432
1433         /* check authentication loop */
1434
1435         result = winbind_samlogon_retry_loop(domain,
1436                                              mem_ctx,
1437                                              0,
1438                                              domain->dcname,
1439                                              name_user,
1440                                              name_domain,
1441                                              lp_netbios_name(),
1442                                              chal,
1443                                              lm_resp,
1444                                              nt_resp,
1445                                              &my_info3);
1446         if (!NT_STATUS_IS_OK(result)) {
1447                 goto done;
1448         }
1449
1450         /* handle the case where a NT4 DC does not fill in the acct_flags in
1451          * the samlogon reply info3. When accurate info3 is required by the
1452          * caller, we look up the account flags ourselve - gd */
1453
1454         if ((request_flags & WBFLAG_PAM_INFO3_TEXT) &&
1455             NT_STATUS_IS_OK(result) && (my_info3->base.acct_flags == 0)) {
1456
1457                 struct rpc_pipe_client *samr_pipe;
1458                 struct policy_handle samr_domain_handle, user_pol;
1459                 union samr_UserInfo *info = NULL;
1460                 NTSTATUS status_tmp, result_tmp;
1461                 uint32 acct_flags;
1462                 struct dcerpc_binding_handle *b;
1463
1464                 status_tmp = cm_connect_sam(domain, mem_ctx,
1465                                             &samr_pipe, &samr_domain_handle);
1466
1467                 if (!NT_STATUS_IS_OK(status_tmp)) {
1468                         DEBUG(3, ("could not open handle to SAMR pipe: %s\n",
1469                                 nt_errstr(status_tmp)));
1470                         goto done;
1471                 }
1472
1473                 b = samr_pipe->binding_handle;
1474
1475                 status_tmp = dcerpc_samr_OpenUser(b, mem_ctx,
1476                                                   &samr_domain_handle,
1477                                                   MAXIMUM_ALLOWED_ACCESS,
1478                                                   my_info3->base.rid,
1479                                                   &user_pol,
1480                                                   &result_tmp);
1481
1482                 if (!NT_STATUS_IS_OK(status_tmp)) {
1483                         DEBUG(3, ("could not open user handle on SAMR pipe: %s\n",
1484                                 nt_errstr(status_tmp)));
1485                         goto done;
1486                 }
1487                 if (!NT_STATUS_IS_OK(result_tmp)) {
1488                         DEBUG(3, ("could not open user handle on SAMR pipe: %s\n",
1489                                 nt_errstr(result_tmp)));
1490                         goto done;
1491                 }
1492
1493                 status_tmp = dcerpc_samr_QueryUserInfo(b, mem_ctx,
1494                                                        &user_pol,
1495                                                        16,
1496                                                        &info,
1497                                                        &result_tmp);
1498
1499                 if (!NT_STATUS_IS_OK(status_tmp)) {
1500                         DEBUG(3, ("could not query user info on SAMR pipe: %s\n",
1501                                 nt_errstr(status_tmp)));
1502                         dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
1503                         goto done;
1504                 }
1505                 if (!NT_STATUS_IS_OK(result_tmp)) {
1506                         DEBUG(3, ("could not query user info on SAMR pipe: %s\n",
1507                                 nt_errstr(result_tmp)));
1508                         dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
1509                         goto done;
1510                 }
1511
1512                 acct_flags = info->info16.acct_flags;
1513
1514                 if (acct_flags == 0) {
1515                         dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
1516                         goto done;
1517                 }
1518
1519                 my_info3->base.acct_flags = acct_flags;
1520
1521                 DEBUG(10,("successfully retrieved acct_flags 0x%x\n", acct_flags));
1522
1523                 dcerpc_samr_Close(b, mem_ctx, &user_pol, &result_tmp);
1524         }
1525
1526         *info3 = my_info3;
1527 done:
1528         return result;
1529 }
1530
1531 enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain,
1532                                             struct winbindd_cli_state *state)
1533 {
1534         NTSTATUS result = NT_STATUS_LOGON_FAILURE;
1535         NTSTATUS krb5_result = NT_STATUS_OK;
1536         fstring name_domain, name_user;
1537         char *mapped_user;
1538         fstring domain_user;
1539         struct netr_SamInfo3 *info3 = NULL;
1540         NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL;
1541
1542         /* Ensure null termination */
1543         state->request->data.auth.user[sizeof(state->request->data.auth.user)-1]='\0';
1544
1545         /* Ensure null termination */
1546         state->request->data.auth.pass[sizeof(state->request->data.auth.pass)-1]='\0';
1547
1548         DEBUG(3, ("[%5lu]: dual pam auth %s\n", (unsigned long)state->pid,
1549                   state->request->data.auth.user));
1550
1551         /* Parse domain and username */
1552
1553         name_map_status = normalize_name_unmap(state->mem_ctx,
1554                                                state->request->data.auth.user,
1555                                                &mapped_user);
1556
1557         /* If the name normalization didnt' actually do anything,
1558            just use the original name */
1559
1560         if (!NT_STATUS_IS_OK(name_map_status) &&
1561             !NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED))
1562         {
1563                 mapped_user = state->request->data.auth.user;
1564         }
1565
1566         parse_domain_user(mapped_user, name_domain, name_user);
1567
1568         if ( mapped_user != state->request->data.auth.user ) {
1569                 fstr_sprintf( domain_user, "%s%c%s", name_domain,
1570                         *lp_winbind_separator(),
1571                         name_user );
1572                 strlcpy( state->request->data.auth.user, domain_user,
1573                              sizeof(state->request->data.auth.user));
1574         }
1575
1576         if (!domain->online) {
1577                 result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
1578                 if (domain->startup) {
1579                         /* Logons are very important to users. If we're offline and
1580                            we get a request within the first 30 seconds of startup,
1581                            try very hard to find a DC and go online. */
1582
1583                         DEBUG(10,("winbindd_dual_pam_auth: domain: %s offline and auth "
1584                                 "request in startup mode.\n", domain->name ));
1585
1586                         winbindd_flush_negative_conn_cache(domain);
1587                         result = init_dc_connection(domain);
1588                 }
1589         }
1590
1591         DEBUG(10,("winbindd_dual_pam_auth: domain: %s last was %s\n", domain->name, domain->online ? "online":"offline"));
1592
1593         /* Check for Kerberos authentication */
1594         if (domain->online && (state->request->flags & WBFLAG_PAM_KRB5)) {
1595
1596                 result = winbindd_dual_pam_auth_kerberos(domain, state, &info3);
1597                 /* save for later */
1598                 krb5_result = result;
1599
1600
1601                 if (NT_STATUS_IS_OK(result)) {
1602                         DEBUG(10,("winbindd_dual_pam_auth_kerberos succeeded\n"));
1603                         goto process_result;
1604                 } else {
1605                         DEBUG(10,("winbindd_dual_pam_auth_kerberos failed: %s\n", nt_errstr(result)));
1606                 }
1607
1608                 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
1609                     NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
1610                     NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1611                         DEBUG(10,("winbindd_dual_pam_auth_kerberos setting domain to offline\n"));
1612                         set_domain_offline( domain );
1613                         goto cached_logon;
1614                 }
1615
1616                 /* there are quite some NT_STATUS errors where there is no
1617                  * point in retrying with a samlogon, we explictly have to take
1618                  * care not to increase the bad logon counter on the DC */
1619
1620                 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_DISABLED) ||
1621                     NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_EXPIRED) ||
1622                     NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_LOCKED_OUT) ||
1623                     NT_STATUS_EQUAL(result, NT_STATUS_INVALID_LOGON_HOURS) ||
1624                     NT_STATUS_EQUAL(result, NT_STATUS_INVALID_WORKSTATION) ||
1625                     NT_STATUS_EQUAL(result, NT_STATUS_LOGON_FAILURE) ||
1626                     NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER) ||
1627                     NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_EXPIRED) ||
1628                     NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_MUST_CHANGE) ||
1629                     NT_STATUS_EQUAL(result, NT_STATUS_WRONG_PASSWORD)) {
1630                         goto done;
1631                 }
1632
1633                 if (state->request->flags & WBFLAG_PAM_FALLBACK_AFTER_KRB5) {
1634                         DEBUG(3,("falling back to samlogon\n"));
1635                         goto sam_logon;
1636                 } else {
1637                         goto cached_logon;
1638                 }
1639         }
1640
1641 sam_logon:
1642         /* Check for Samlogon authentication */
1643         if (domain->online) {
1644                 result = winbindd_dual_pam_auth_samlogon(
1645                         state->mem_ctx, domain,
1646                         state->request->data.auth.user,
1647                         state->request->data.auth.pass,
1648                         state->request->flags,
1649                         &info3);
1650
1651                 if (NT_STATUS_IS_OK(result)) {
1652                         DEBUG(10,("winbindd_dual_pam_auth_samlogon succeeded\n"));
1653                         /* add the Krb5 err if we have one */
1654                         if ( NT_STATUS_EQUAL(krb5_result, NT_STATUS_TIME_DIFFERENCE_AT_DC ) ) {
1655                                 info3->base.user_flags |= LOGON_KRB5_FAIL_CLOCK_SKEW;
1656                         }
1657                         goto process_result;
1658                 }
1659
1660                 DEBUG(10,("winbindd_dual_pam_auth_samlogon failed: %s\n",
1661                           nt_errstr(result)));
1662
1663                 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
1664                     NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
1665                     NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND))
1666                 {
1667                         DEBUG(10,("winbindd_dual_pam_auth_samlogon setting domain to offline\n"));
1668                         set_domain_offline( domain );
1669                         goto cached_logon;
1670                 }
1671
1672                         if (domain->online) {
1673                                 /* We're still online - fail. */
1674                                 goto done;
1675                         }
1676         }
1677
1678 cached_logon:
1679         /* Check for Cached logons */
1680         if (!domain->online && (state->request->flags & WBFLAG_PAM_CACHED_LOGIN) &&
1681             lp_winbind_offline_logon()) {
1682
1683                 result = winbindd_dual_pam_auth_cached(domain, state, &info3);
1684
1685                 if (NT_STATUS_IS_OK(result)) {
1686                         DEBUG(10,("winbindd_dual_pam_auth_cached succeeded\n"));
1687                         goto process_result;
1688                 } else {
1689                         DEBUG(10,("winbindd_dual_pam_auth_cached failed: %s\n", nt_errstr(result)));
1690                         goto done;
1691                 }
1692         }
1693
1694 process_result:
1695
1696         if (NT_STATUS_IS_OK(result)) {
1697
1698                 struct dom_sid user_sid;
1699
1700                 /* In all codepaths where result == NT_STATUS_OK info3 must have
1701                    been initialized. */
1702                 if (!info3) {
1703                         result = NT_STATUS_INTERNAL_ERROR;
1704                         goto done;
1705                 }
1706
1707                 sid_compose(&user_sid, info3->base.domain_sid,
1708                             info3->base.rid);
1709
1710                 wcache_invalidate_samlogon(find_domain_from_name(name_domain),
1711                                            &user_sid);
1712                 netsamlogon_cache_store(name_user, info3);
1713
1714                 /* save name_to_sid info as early as possible (only if
1715                    this is our primary domain so we don't invalidate
1716                    the cache entry by storing the seq_num for the wrong
1717                    domain). */
1718                 if ( domain->primary ) {
1719                         cache_name2sid(domain, name_domain, name_user,
1720                                        SID_NAME_USER, &user_sid);
1721                 }
1722
1723                 /* Check if the user is in the right group */
1724
1725                 result = check_info3_in_group(
1726                         info3,
1727                         state->request->data.auth.require_membership_of_sid);
1728                 if (!NT_STATUS_IS_OK(result)) {
1729                         DEBUG(3, ("User %s is not in the required group (%s), so plaintext authentication is rejected\n",
1730                                   state->request->data.auth.user,
1731                                   state->request->data.auth.require_membership_of_sid));
1732                         goto done;
1733                 }
1734
1735                 result = append_auth_data(state->mem_ctx, state->response,
1736                                           state->request->flags, info3,
1737                                           name_domain, name_user);
1738                 if (!NT_STATUS_IS_OK(result)) {
1739                         goto done;
1740                 }
1741
1742                 if ((state->request->flags & WBFLAG_PAM_CACHED_LOGIN)
1743                     && lp_winbind_offline_logon()) {
1744
1745                         result = winbindd_store_creds(domain,
1746                                                       state->request->data.auth.user,
1747                                                       state->request->data.auth.pass,
1748                                                       info3);
1749                 }
1750
1751                 if (state->request->flags & WBFLAG_PAM_GET_PWD_POLICY) {
1752                         struct winbindd_domain *our_domain = find_our_domain();
1753
1754                         /* This is not entirely correct I believe, but it is
1755                            consistent.  Only apply the password policy settings
1756                            too warn users for our own domain.  Cannot obtain these
1757                            from trusted DCs all the  time so don't do it at all.
1758                            -- jerry */
1759
1760                         result = NT_STATUS_NOT_SUPPORTED;
1761                         if (our_domain == domain ) {
1762                                 result = fillup_password_policy(
1763                                         our_domain, state->response);
1764                         }
1765
1766                         if (!NT_STATUS_IS_OK(result)
1767                             && !NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED) )
1768                         {
1769                                 DEBUG(10,("Failed to get password policies for domain %s: %s\n",
1770                                           domain->name, nt_errstr(result)));
1771                                 goto done;
1772                         }
1773                 }
1774
1775                 result = NT_STATUS_OK;
1776         }
1777
1778 done:
1779         /* give us a more useful (more correct?) error code */
1780         if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
1781             (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
1782                 result = NT_STATUS_NO_LOGON_SERVERS;
1783         }
1784
1785         set_auth_errors(state->response, result);
1786
1787         DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, ("Plain-text authentication for user %s returned %s (PAM: %d)\n",
1788               state->request->data.auth.user,
1789               state->response->data.auth.nt_status_string,
1790               state->response->data.auth.pam_error));
1791
1792         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
1793 }
1794
1795 enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain,
1796                                                  struct winbindd_cli_state *state)
1797 {
1798         NTSTATUS result;
1799         struct netr_SamInfo3 *info3 = NULL;
1800         const char *name_user = NULL;
1801         const char *name_domain = NULL;
1802         const char *workstation;
1803
1804         DATA_BLOB lm_resp, nt_resp;
1805
1806         /* This is child-only, so no check for privileged access is needed
1807            anymore */
1808
1809         /* Ensure null termination */
1810         state->request->data.auth_crap.user[sizeof(state->request->data.auth_crap.user)-1]=0;
1811         state->request->data.auth_crap.domain[sizeof(state->request->data.auth_crap.domain)-1]=0;
1812
1813         name_user = state->request->data.auth_crap.user;
1814         name_domain = state->request->data.auth_crap.domain;
1815         workstation = state->request->data.auth_crap.workstation;
1816
1817         DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n", (unsigned long)state->pid,
1818                   name_domain, name_user));
1819
1820         if (state->request->data.auth_crap.lm_resp_len > sizeof(state->request->data.auth_crap.lm_resp)
1821                 || state->request->data.auth_crap.nt_resp_len > sizeof(state->request->data.auth_crap.nt_resp)) {
1822                 if (!(state->request->flags & WBFLAG_BIG_NTLMV2_BLOB) ||
1823                      state->request->extra_len != state->request->data.auth_crap.nt_resp_len) {
1824                         DEBUG(0, ("winbindd_pam_auth_crap: invalid password length %u/%u\n",
1825                                   state->request->data.auth_crap.lm_resp_len,
1826                                   state->request->data.auth_crap.nt_resp_len));
1827                         result = NT_STATUS_INVALID_PARAMETER;
1828                         goto done;
1829                 }
1830         }
1831
1832         lm_resp = data_blob_talloc(state->mem_ctx, state->request->data.auth_crap.lm_resp,
1833                                         state->request->data.auth_crap.lm_resp_len);
1834
1835         if (state->request->flags & WBFLAG_BIG_NTLMV2_BLOB) {
1836                 nt_resp = data_blob_talloc(state->mem_ctx,
1837                                            state->request->extra_data.data,
1838                                            state->request->data.auth_crap.nt_resp_len);
1839         } else {
1840                 nt_resp = data_blob_talloc(state->mem_ctx,
1841                                            state->request->data.auth_crap.nt_resp,
1842                                            state->request->data.auth_crap.nt_resp_len);
1843         }
1844
1845         if (strequal(name_domain, get_global_sam_name())) {
1846                 DATA_BLOB chal_blob = data_blob_const(
1847                         state->request->data.auth_crap.chal,
1848                         sizeof(state->request->data.auth_crap.chal));
1849
1850                 result = winbindd_dual_auth_passdb(
1851                         state->mem_ctx,
1852                         state->request->data.auth_crap.logon_parameters,
1853                         name_domain, name_user,
1854                         &chal_blob, &lm_resp, &nt_resp, &info3);
1855                 goto process_result;
1856         }
1857
1858         result = winbind_samlogon_retry_loop(domain,
1859                                              state->mem_ctx,
1860                                              state->request->data.auth_crap.logon_parameters,
1861                                              domain->dcname,
1862                                              name_user,
1863                                              name_domain,
1864                                              /* Bug #3248 - found by Stefan Burkei. */
1865                                              workstation, /* We carefully set this above so use it... */
1866                                              state->request->data.auth_crap.chal,
1867                                              lm_resp,
1868                                              nt_resp,
1869                                              &info3);
1870         if (!NT_STATUS_IS_OK(result)) {
1871                 goto done;
1872         }
1873
1874 process_result:
1875
1876         if (NT_STATUS_IS_OK(result)) {
1877                 struct dom_sid user_sid;
1878
1879                 sid_compose(&user_sid, info3->base.domain_sid,
1880                             info3->base.rid);
1881                 wcache_invalidate_samlogon(find_domain_from_name(name_domain),
1882                                            &user_sid);
1883                 netsamlogon_cache_store(name_user, info3);
1884
1885                 /* Check if the user is in the right group */
1886
1887                 result = check_info3_in_group(
1888                         info3,
1889                         state->request->data.auth_crap.require_membership_of_sid);
1890                 if (!NT_STATUS_IS_OK(result)) {
1891                         DEBUG(3, ("User %s is not in the required group (%s), so "
1892                                   "crap authentication is rejected\n",
1893                                   state->request->data.auth_crap.user,
1894                                   state->request->data.auth_crap.require_membership_of_sid));
1895                         goto done;
1896                 }
1897
1898                 result = append_auth_data(state->mem_ctx, state->response,
1899                                           state->request->flags, info3,
1900                                           name_domain, name_user);
1901                 if (!NT_STATUS_IS_OK(result)) {
1902                         goto done;
1903                 }
1904         }
1905
1906 done:
1907
1908         /* give us a more useful (more correct?) error code */
1909         if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
1910             (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
1911                 result = NT_STATUS_NO_LOGON_SERVERS;
1912         }
1913
1914         if (state->request->flags & WBFLAG_PAM_NT_STATUS_SQUASH) {
1915                 result = nt_status_squash(result);
1916         }
1917
1918         set_auth_errors(state->response, result);
1919
1920         DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
1921               ("NTLM CRAP authentication for user [%s]\\[%s] returned %s (PAM: %d)\n",
1922                name_domain,
1923                name_user,
1924                state->response->data.auth.nt_status_string,
1925                state->response->data.auth.pam_error));
1926
1927         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
1928 }
1929
1930 enum winbindd_result winbindd_dual_pam_chauthtok(struct winbindd_domain *contact_domain,
1931                                                  struct winbindd_cli_state *state)
1932 {
1933         char *oldpass;
1934         char *newpass = NULL;
1935         struct policy_handle dom_pol;
1936         struct rpc_pipe_client *cli = NULL;
1937         bool got_info = false;
1938         struct samr_DomInfo1 *info = NULL;
1939         struct userPwdChangeFailureInformation *reject = NULL;
1940         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1941         fstring domain, user;
1942         struct dcerpc_binding_handle *b = NULL;
1943
1944         ZERO_STRUCT(dom_pol);
1945
1946         DEBUG(3, ("[%5lu]: dual pam chauthtok %s\n", (unsigned long)state->pid,
1947                   state->request->data.auth.user));
1948
1949         if (!parse_domain_user(state->request->data.chauthtok.user, domain, user)) {
1950                 goto done;
1951         }
1952
1953         /* Change password */
1954
1955         oldpass = state->request->data.chauthtok.oldpass;
1956         newpass = state->request->data.chauthtok.newpass;
1957
1958         /* Initialize reject reason */
1959         state->response->data.auth.reject_reason = Undefined;
1960
1961         /* Get sam handle */
1962
1963         result = cm_connect_sam(contact_domain, state->mem_ctx, &cli,
1964                                 &dom_pol);
1965         if (!NT_STATUS_IS_OK(result)) {
1966                 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
1967                 goto done;
1968         }
1969
1970         b = cli->binding_handle;
1971
1972         result = rpccli_samr_chgpasswd_user3(cli, state->mem_ctx,
1973                                              user,
1974                                              newpass,
1975                                              oldpass,
1976                                              &info,
1977                                              &reject);
1978
1979         /* Windows 2003 returns NT_STATUS_PASSWORD_RESTRICTION */
1980
1981         if (NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_RESTRICTION) ) {
1982
1983                 fill_in_password_policy(state->response, info);
1984
1985                 state->response->data.auth.reject_reason =
1986                         reject->extendedFailureReason;
1987
1988                 got_info = true;
1989         }
1990
1991         /* atm the pidl generated rpccli_samr_ChangePasswordUser3 function will
1992          * return with NT_STATUS_BUFFER_TOO_SMALL for w2k dcs as w2k just
1993          * returns with 4byte error code (NT_STATUS_NOT_SUPPORTED) which is too
1994          * short to comply with the samr_ChangePasswordUser3 idl - gd */
1995
1996         /* only fallback when the chgpasswd_user3 call is not supported */
1997         if (NT_STATUS_EQUAL(result, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE) ||
1998             NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED) ||
1999             NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL) ||
2000             NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
2001
2002                 DEBUG(10,("Password change with chgpasswd_user3 failed with: %s, retrying chgpasswd_user2\n",
2003                         nt_errstr(result)));
2004
2005                 result = rpccli_samr_chgpasswd_user2(cli, state->mem_ctx, user, newpass, oldpass);
2006
2007                 /* Windows 2000 returns NT_STATUS_ACCOUNT_RESTRICTION.
2008                    Map to the same status code as Windows 2003. */
2009
2010                 if ( NT_STATUS_EQUAL(NT_STATUS_ACCOUNT_RESTRICTION, result ) ) {
2011                         result = NT_STATUS_PASSWORD_RESTRICTION;
2012                 }
2013         }
2014
2015 done:
2016
2017         if (NT_STATUS_IS_OK(result)
2018             && (state->request->flags & WBFLAG_PAM_CACHED_LOGIN)
2019             && lp_winbind_offline_logon()) {
2020                 result = winbindd_update_creds_by_name(contact_domain, user,
2021                                                        newpass);
2022                 /* Again, this happens when we login from gdm or xdm
2023                  * and the password expires, *BUT* cached crendentials
2024                  * doesn't exist. winbindd_update_creds_by_name()
2025                  * returns NT_STATUS_NO_SUCH_USER.
2026                  * This is not a failure.
2027                  * --- BoYang
2028                  * */
2029                 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER)) {
2030                         result = NT_STATUS_OK;
2031                 }
2032
2033                 if (!NT_STATUS_IS_OK(result)) {
2034                         DEBUG(10, ("Failed to store creds: %s\n",
2035                                    nt_errstr(result)));
2036                         goto process_result;
2037                 }
2038         }
2039
2040         if (!NT_STATUS_IS_OK(result) && !got_info && contact_domain) {
2041
2042                 NTSTATUS policy_ret;
2043
2044                 policy_ret = fillup_password_policy(
2045                         contact_domain, state->response);
2046
2047                 /* failure of this is non critical, it will just provide no
2048                  * additional information to the client why the change has
2049                  * failed - Guenther */
2050
2051                 if (!NT_STATUS_IS_OK(policy_ret)) {
2052                         DEBUG(10,("Failed to get password policies: %s\n", nt_errstr(policy_ret)));
2053                         goto process_result;
2054                 }
2055         }
2056
2057 process_result:
2058
2059         if (strequal(contact_domain->name, get_global_sam_name())) {
2060                 /* FIXME: internal rpc pipe does not cache handles yet */
2061                 if (b) {
2062                         if (is_valid_policy_hnd(&dom_pol)) {
2063                                 NTSTATUS _result;
2064                                 dcerpc_samr_Close(b, state->mem_ctx, &dom_pol, &_result);
2065                         }
2066                         TALLOC_FREE(cli);
2067                 }
2068         }
2069
2070         set_auth_errors(state->response, result);
2071
2072         DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
2073               ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
2074                domain,
2075                user,
2076                state->response->data.auth.nt_status_string,
2077                state->response->data.auth.pam_error));
2078
2079         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2080 }
2081
2082 enum winbindd_result winbindd_dual_pam_logoff(struct winbindd_domain *domain,
2083                                               struct winbindd_cli_state *state)
2084 {
2085         NTSTATUS result = NT_STATUS_NOT_SUPPORTED;
2086
2087         DEBUG(3, ("[%5lu]: pam dual logoff %s\n", (unsigned long)state->pid,
2088                 state->request->data.logoff.user));
2089
2090         if (!(state->request->flags & WBFLAG_PAM_KRB5)) {
2091                 result = NT_STATUS_OK;
2092                 goto process_result;
2093         }
2094
2095         if (state->request->data.logoff.krb5ccname[0] == '\0') {
2096                 result = NT_STATUS_OK;
2097                 goto process_result;
2098         }
2099
2100 #ifdef HAVE_KRB5
2101
2102         if (state->request->data.logoff.uid < 0) {
2103                 DEBUG(0,("winbindd_pam_logoff: invalid uid\n"));
2104                 goto process_result;
2105         }
2106
2107         /* what we need here is to find the corresponding krb5 ccache name *we*
2108          * created for a given username and destroy it */
2109
2110         if (!ccache_entry_exists(state->request->data.logoff.user)) {
2111                 result = NT_STATUS_OK;
2112                 DEBUG(10,("winbindd_pam_logoff: no entry found.\n"));
2113                 goto process_result;
2114         }
2115
2116         if (!ccache_entry_identical(state->request->data.logoff.user,
2117                                         state->request->data.logoff.uid,
2118                                         state->request->data.logoff.krb5ccname)) {
2119                 DEBUG(0,("winbindd_pam_logoff: cached entry differs.\n"));
2120                 goto process_result;
2121         }
2122
2123         result = remove_ccache(state->request->data.logoff.user);
2124         if (!NT_STATUS_IS_OK(result)) {
2125                 DEBUG(0,("winbindd_pam_logoff: failed to remove ccache: %s\n",
2126                         nt_errstr(result)));
2127                 goto process_result;
2128         }
2129
2130 #else
2131         result = NT_STATUS_NOT_SUPPORTED;
2132 #endif
2133
2134 process_result:
2135
2136
2137         set_auth_errors(state->response, result);
2138
2139         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2140 }
2141
2142 /* Change user password with auth crap*/
2143
2144 enum winbindd_result winbindd_dual_pam_chng_pswd_auth_crap(struct winbindd_domain *domainSt, struct winbindd_cli_state *state)
2145 {
2146         NTSTATUS result;
2147         DATA_BLOB new_nt_password;
2148         DATA_BLOB old_nt_hash_enc;
2149         DATA_BLOB new_lm_password;
2150         DATA_BLOB old_lm_hash_enc;
2151         fstring  domain,user;
2152         struct policy_handle dom_pol;
2153         struct winbindd_domain *contact_domain = domainSt;
2154         struct rpc_pipe_client *cli = NULL;
2155         struct dcerpc_binding_handle *b = NULL;
2156
2157         ZERO_STRUCT(dom_pol);
2158
2159         /* Ensure null termination */
2160         state->request->data.chng_pswd_auth_crap.user[
2161                 sizeof(state->request->data.chng_pswd_auth_crap.user)-1]=0;
2162         state->request->data.chng_pswd_auth_crap.domain[
2163                 sizeof(state->request->data.chng_pswd_auth_crap.domain)-1]=0;
2164         *domain = 0;
2165         *user = 0;
2166
2167         DEBUG(3, ("[%5lu]: pam change pswd auth crap domain: %s user: %s\n",
2168                   (unsigned long)state->pid,
2169                   state->request->data.chng_pswd_auth_crap.domain,
2170                   state->request->data.chng_pswd_auth_crap.user));
2171
2172         if (lp_winbind_offline_logon()) {
2173                 DEBUG(0,("Refusing password change as winbind offline logons are enabled. "));
2174                 DEBUGADD(0,("Changing passwords here would risk inconsistent logons\n"));
2175                 result = NT_STATUS_ACCESS_DENIED;
2176                 goto done;
2177         }
2178
2179         if (*state->request->data.chng_pswd_auth_crap.domain) {
2180                 fstrcpy(domain,state->request->data.chng_pswd_auth_crap.domain);
2181         } else {
2182                 parse_domain_user(state->request->data.chng_pswd_auth_crap.user,
2183                                   domain, user);
2184
2185                 if(!*domain) {
2186                         DEBUG(3,("no domain specified with username (%s) - "
2187                                  "failing auth\n",
2188                                  state->request->data.chng_pswd_auth_crap.user));
2189                         result = NT_STATUS_NO_SUCH_USER;
2190                         goto done;
2191                 }
2192         }
2193
2194         if (!*domain && lp_winbind_use_default_domain()) {
2195                 fstrcpy(domain,lp_workgroup());
2196         }
2197
2198         if(!*user) {
2199                 fstrcpy(user, state->request->data.chng_pswd_auth_crap.user);
2200         }
2201
2202         DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n",
2203                   (unsigned long)state->pid, domain, user));
2204
2205         /* Change password */
2206         new_nt_password = data_blob_const(
2207                 state->request->data.chng_pswd_auth_crap.new_nt_pswd,
2208                 state->request->data.chng_pswd_auth_crap.new_nt_pswd_len);
2209
2210         old_nt_hash_enc = data_blob_const(
2211                 state->request->data.chng_pswd_auth_crap.old_nt_hash_enc,
2212                 state->request->data.chng_pswd_auth_crap.old_nt_hash_enc_len);
2213
2214         if(state->request->data.chng_pswd_auth_crap.new_lm_pswd_len > 0)        {
2215                 new_lm_password = data_blob_const(
2216                         state->request->data.chng_pswd_auth_crap.new_lm_pswd,
2217                         state->request->data.chng_pswd_auth_crap.new_lm_pswd_len);
2218
2219                 old_lm_hash_enc = data_blob_const(
2220                         state->request->data.chng_pswd_auth_crap.old_lm_hash_enc,
2221                         state->request->data.chng_pswd_auth_crap.old_lm_hash_enc_len);
2222         } else {
2223                 new_lm_password = data_blob_null;
2224                 old_lm_hash_enc = data_blob_null;
2225         }
2226
2227         /* Get sam handle */
2228
2229         result = cm_connect_sam(contact_domain, state->mem_ctx, &cli, &dom_pol);
2230         if (!NT_STATUS_IS_OK(result)) {
2231                 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
2232                 goto done;
2233         }
2234
2235         b = cli->binding_handle;
2236
2237         result = rpccli_samr_chng_pswd_auth_crap(
2238                 cli, state->mem_ctx, user, new_nt_password, old_nt_hash_enc,
2239                 new_lm_password, old_lm_hash_enc);
2240
2241  done:
2242
2243         if (strequal(contact_domain->name, get_global_sam_name())) {
2244                 /* FIXME: internal rpc pipe does not cache handles yet */
2245                 if (b) {
2246                         if (is_valid_policy_hnd(&dom_pol)) {
2247                                 NTSTATUS _result;
2248                                 dcerpc_samr_Close(b, state->mem_ctx, &dom_pol, &_result);
2249                         }
2250                         TALLOC_FREE(cli);
2251                 }
2252         }
2253
2254         set_auth_errors(state->response, result);
2255
2256         DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
2257               ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
2258                domain, user,
2259                state->response->data.auth.nt_status_string,
2260                state->response->data.auth.pam_error));
2261
2262         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2263 }