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