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