winbindd: kill some trailing/leading whitespace.
[kai/samba.git] / source3 / winbindd / winbindd_pam.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Winbind daemon - pam auth funcions
5
6    Copyright (C) Andrew Tridgell 2000
7    Copyright (C) Tim Potter 2001
8    Copyright (C) Andrew Bartlett 2001-2002
9    Copyright (C) Guenther Deschner 2005
10
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 3 of the License, or
14    (at your option) any later version.
15
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20
21    You should have received a copy of the GNU General Public License
22    along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 */
24
25 #include "includes.h"
26 #include "winbindd.h"
27 #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, false);
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 typedef NTSTATUS (*netlogon_fn_t)(struct rpc_pipe_client *cli,
1183                                   TALLOC_CTX *mem_ctx,
1184                                   uint32 logon_parameters,
1185                                   const char *server,
1186                                   const char *username,
1187                                   const char *domain,
1188                                   const char *workstation,
1189                                   const uint8 chal[8],
1190                                   DATA_BLOB lm_response,
1191                                   DATA_BLOB nt_response,
1192                                   struct netr_SamInfo3 **info3);
1193
1194 NTSTATUS winbindd_dual_pam_auth_samlogon(struct winbindd_domain *domain,
1195                                          struct winbindd_cli_state *state,
1196                                          struct netr_SamInfo3 **info3)
1197 {
1198
1199         struct rpc_pipe_client *netlogon_pipe;
1200         uchar chal[8];
1201         DATA_BLOB lm_resp;
1202         DATA_BLOB nt_resp;
1203         int attempts = 0;
1204         unsigned char local_lm_response[24];
1205         unsigned char local_nt_response[24];
1206         struct winbindd_domain *contact_domain;
1207         fstring name_domain, name_user;
1208         bool retry;
1209         NTSTATUS result;
1210         struct netr_SamInfo3 *my_info3 = NULL;
1211
1212         *info3 = NULL;
1213
1214         DEBUG(10,("winbindd_dual_pam_auth_samlogon\n"));
1215
1216         /* Parse domain and username */
1217
1218         parse_domain_user(state->request.data.auth.user, name_domain, name_user);
1219
1220         /* do password magic */
1221
1222
1223         generate_random_buffer(chal, 8);
1224         if (lp_client_ntlmv2_auth()) {
1225                 DATA_BLOB server_chal;
1226                 DATA_BLOB names_blob;
1227                 DATA_BLOB nt_response;
1228                 DATA_BLOB lm_response;
1229                 server_chal = data_blob_talloc(state->mem_ctx, chal, 8);
1230
1231                 /* note that the 'workgroup' here is a best guess - we don't know
1232                    the server's domain at this point.  The 'server name' is also
1233                    dodgy...
1234                 */
1235                 names_blob = NTLMv2_generate_names_blob(global_myname(), lp_workgroup());
1236
1237                 if (!SMBNTLMv2encrypt(name_user, name_domain,
1238                                       state->request.data.auth.pass,
1239                                       &server_chal,
1240                                       &names_blob,
1241                                       &lm_response, &nt_response, NULL)) {
1242                         data_blob_free(&names_blob);
1243                         data_blob_free(&server_chal);
1244                         DEBUG(0, ("winbindd_pam_auth: SMBNTLMv2encrypt() failed!\n"));
1245                         result = NT_STATUS_NO_MEMORY;
1246                         goto done;
1247                 }
1248                 data_blob_free(&names_blob);
1249                 data_blob_free(&server_chal);
1250                 lm_resp = data_blob_talloc(state->mem_ctx, lm_response.data,
1251                                            lm_response.length);
1252                 nt_resp = data_blob_talloc(state->mem_ctx, nt_response.data,
1253                                            nt_response.length);
1254                 data_blob_free(&lm_response);
1255                 data_blob_free(&nt_response);
1256
1257         } else {
1258                 if (lp_client_lanman_auth()
1259                     && SMBencrypt(state->request.data.auth.pass,
1260                                   chal,
1261                                   local_lm_response)) {
1262                         lm_resp = data_blob_talloc(state->mem_ctx,
1263                                                    local_lm_response,
1264                                                    sizeof(local_lm_response));
1265                 } else {
1266                         lm_resp = data_blob_null;
1267                 }
1268                 SMBNTencrypt(state->request.data.auth.pass,
1269                              chal,
1270                              local_nt_response);
1271
1272                 nt_resp = data_blob_talloc(state->mem_ctx,
1273                                            local_nt_response,
1274                                            sizeof(local_nt_response));
1275         }
1276
1277         /* what domain should we contact? */
1278
1279         if ( IS_DC ) {
1280                 if (!(contact_domain = find_domain_from_name(name_domain))) {
1281                         DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
1282                                   state->request.data.auth.user, name_domain, name_user, name_domain));
1283                         result = NT_STATUS_NO_SUCH_USER;
1284                         goto done;
1285                 }
1286
1287         } else {
1288                 if (is_myname(name_domain)) {
1289                         DEBUG(3, ("Authentication for domain %s (local domain to this server) not supported at this stage\n", name_domain));
1290                         result =  NT_STATUS_NO_SUCH_USER;
1291                         goto done;
1292                 }
1293
1294                 contact_domain = find_our_domain();
1295         }
1296
1297         /* check authentication loop */
1298
1299         do {
1300                 netlogon_fn_t logon_fn;
1301
1302                 ZERO_STRUCTP(my_info3);
1303                 retry = False;
1304
1305                 result = cm_connect_netlogon(contact_domain, &netlogon_pipe);
1306
1307                 if (!NT_STATUS_IS_OK(result)) {
1308                         DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
1309                         goto done;
1310                 }
1311
1312                 /* It is really important to try SamLogonEx here,
1313                  * because in a clustered environment, we want to use
1314                  * one machine account from multiple physical
1315                  * computers.
1316                  *
1317                  * With a normal SamLogon call, we must keep the
1318                  * credentials chain updated and intact between all
1319                  * users of the machine account (which would imply
1320                  * cross-node communication for every NTLM logon).
1321                  *
1322                  * (The credentials chain is not per NETLOGON pipe
1323                  * connection, but globally on the server/client pair
1324                  * by machine name).
1325                  *
1326                  * When using SamLogonEx, the credentials are not
1327                  * supplied, but the session key is implied by the
1328                  * wrapping SamLogon context.
1329                  *
1330                  *  -- abartlet 21 April 2008
1331                  */
1332
1333                 logon_fn = contact_domain->can_do_samlogon_ex
1334                         ? rpccli_netlogon_sam_network_logon_ex
1335                         : rpccli_netlogon_sam_network_logon;
1336
1337                 result = logon_fn(netlogon_pipe,
1338                                   state->mem_ctx,
1339                                   0,
1340                                   contact_domain->dcname, /* server name */
1341                                   name_user,              /* user name */
1342                                   name_domain,            /* target domain */
1343                                   global_myname(),        /* workstation */
1344                                   chal,
1345                                   lm_resp,
1346                                   nt_resp,
1347                                   &my_info3);
1348                 attempts += 1;
1349
1350                 if ((NT_STATUS_V(result) == DCERPC_FAULT_OP_RNG_ERROR)
1351                     && contact_domain->can_do_samlogon_ex) {
1352                         DEBUG(3, ("Got a DC that can not do NetSamLogonEx, "
1353                                   "retrying with NetSamLogon\n"));
1354                         contact_domain->can_do_samlogon_ex = False;
1355                         retry = True;
1356                         continue;
1357                 }
1358
1359                 /* We have to try a second time as cm_connect_netlogon
1360                    might not yet have noticed that the DC has killed
1361                    our connection. */
1362
1363                 if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)) {
1364                         retry = True;
1365                         continue;
1366                 }
1367
1368                 /* if we get access denied, a possible cause was that we had
1369                    and open connection to the DC, but someone changed our
1370                    machine account password out from underneath us using 'net
1371                    rpc changetrustpw' */
1372
1373                 if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
1374                         DEBUG(3,("winbindd_pam_auth: sam_logon returned "
1375                                  "ACCESS_DENIED.  Maybe the trust account "
1376                                 "password was changed and we didn't know it. "
1377                                  "Killing connections to domain %s\n",
1378                                 name_domain));
1379                         invalidate_cm_connection(&contact_domain->conn);
1380                         retry = True;
1381                 }
1382
1383         } while ( (attempts < 2) && retry );
1384
1385         /* handle the case where a NT4 DC does not fill in the acct_flags in
1386          * the samlogon reply info3. When accurate info3 is required by the
1387          * caller, we look up the account flags ourselve - gd */
1388
1389         if ((state->request.flags & WBFLAG_PAM_INFO3_TEXT) &&
1390             NT_STATUS_IS_OK(result) && (my_info3->base.acct_flags == 0)) {
1391
1392                 struct rpc_pipe_client *samr_pipe;
1393                 POLICY_HND samr_domain_handle, user_pol;
1394                 union samr_UserInfo *info = NULL;
1395                 NTSTATUS status_tmp;
1396                 uint32 acct_flags;
1397
1398                 status_tmp = cm_connect_sam(contact_domain, state->mem_ctx,
1399                                             &samr_pipe, &samr_domain_handle);
1400
1401                 if (!NT_STATUS_IS_OK(status_tmp)) {
1402                         DEBUG(3, ("could not open handle to SAMR pipe: %s\n",
1403                                 nt_errstr(status_tmp)));
1404                         goto done;
1405                 }
1406
1407                 status_tmp = rpccli_samr_OpenUser(samr_pipe, state->mem_ctx,
1408                                                   &samr_domain_handle,
1409                                                   MAXIMUM_ALLOWED_ACCESS,
1410                                                   my_info3->base.rid,
1411                                                   &user_pol);
1412
1413                 if (!NT_STATUS_IS_OK(status_tmp)) {
1414                         DEBUG(3, ("could not open user handle on SAMR pipe: %s\n",
1415                                 nt_errstr(status_tmp)));
1416                         goto done;
1417                 }
1418
1419                 status_tmp = rpccli_samr_QueryUserInfo(samr_pipe, state->mem_ctx,
1420                                                        &user_pol,
1421                                                        16,
1422                                                        &info);
1423
1424                 if (!NT_STATUS_IS_OK(status_tmp)) {
1425                         DEBUG(3, ("could not query user info on SAMR pipe: %s\n",
1426                                 nt_errstr(status_tmp)));
1427                         rpccli_samr_Close(samr_pipe, state->mem_ctx, &user_pol);
1428                         goto done;
1429                 }
1430
1431                 acct_flags = info->info16.acct_flags;
1432
1433                 if (acct_flags == 0) {
1434                         rpccli_samr_Close(samr_pipe, state->mem_ctx, &user_pol);
1435                         goto done;
1436                 }
1437
1438                 my_info3->base.acct_flags = acct_flags;
1439
1440                 DEBUG(10,("successfully retrieved acct_flags 0x%x\n", acct_flags));
1441
1442                 rpccli_samr_Close(samr_pipe, state->mem_ctx, &user_pol);
1443         }
1444
1445         *info3 = my_info3;
1446 done:
1447         return result;
1448 }
1449
1450 enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain,
1451                                             struct winbindd_cli_state *state)
1452 {
1453         NTSTATUS result = NT_STATUS_LOGON_FAILURE;
1454         NTSTATUS krb5_result = NT_STATUS_OK;
1455         fstring name_domain, name_user;
1456         struct netr_SamInfo3 *info3 = NULL;
1457
1458         /* Ensure null termination */
1459         state->request.data.auth.user[sizeof(state->request.data.auth.user)-1]='\0';
1460
1461         /* Ensure null termination */
1462         state->request.data.auth.pass[sizeof(state->request.data.auth.pass)-1]='\0';
1463
1464         DEBUG(3, ("[%5lu]: dual pam auth %s\n", (unsigned long)state->pid,
1465                   state->request.data.auth.user));
1466
1467         if (!check_request_flags(state->request.flags)) {
1468                 result = NT_STATUS_INVALID_PARAMETER_MIX;
1469                 goto done;
1470         }
1471
1472         /* Parse domain and username */
1473
1474         ws_name_return( state->request.data.auth.user, WB_REPLACE_CHAR );
1475
1476         parse_domain_user(state->request.data.auth.user, name_domain, name_user);
1477
1478         if (domain->online == False) {
1479                 result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
1480                 if (domain->startup) {
1481                         /* Logons are very important to users. If we're offline and
1482                            we get a request within the first 30 seconds of startup,
1483                            try very hard to find a DC and go online. */
1484
1485                         DEBUG(10,("winbindd_dual_pam_auth: domain: %s offline and auth "
1486                                 "request in startup mode.\n", domain->name ));
1487
1488                         winbindd_flush_negative_conn_cache(domain);
1489                         result = init_dc_connection(domain);
1490                 }
1491         }
1492
1493         DEBUG(10,("winbindd_dual_pam_auth: domain: %s last was %s\n", domain->name, domain->online ? "online":"offline"));
1494
1495         /* Check for Kerberos authentication */
1496         if (domain->online && (state->request.flags & WBFLAG_PAM_KRB5)) {
1497
1498                 result = winbindd_dual_pam_auth_kerberos(domain, state, &info3);
1499                 /* save for later */
1500                 krb5_result = result;
1501
1502
1503                 if (NT_STATUS_IS_OK(result)) {
1504                         DEBUG(10,("winbindd_dual_pam_auth_kerberos succeeded\n"));
1505                         goto process_result;
1506                 } else {
1507                         DEBUG(10,("winbindd_dual_pam_auth_kerberos failed: %s\n", nt_errstr(result)));
1508                 }
1509
1510                 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
1511                     NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
1512                     NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1513                         DEBUG(10,("winbindd_dual_pam_auth_kerberos setting domain to offline\n"));
1514                         set_domain_offline( domain );
1515                         goto cached_logon;
1516                 }
1517
1518                 /* there are quite some NT_STATUS errors where there is no
1519                  * point in retrying with a samlogon, we explictly have to take
1520                  * care not to increase the bad logon counter on the DC */
1521
1522                 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_DISABLED) ||
1523                     NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_EXPIRED) ||
1524                     NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_LOCKED_OUT) ||
1525                     NT_STATUS_EQUAL(result, NT_STATUS_INVALID_LOGON_HOURS) ||
1526                     NT_STATUS_EQUAL(result, NT_STATUS_INVALID_WORKSTATION) ||
1527                     NT_STATUS_EQUAL(result, NT_STATUS_LOGON_FAILURE) ||
1528                     NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER) ||
1529                     NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_EXPIRED) ||
1530                     NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_MUST_CHANGE) ||
1531                     NT_STATUS_EQUAL(result, NT_STATUS_WRONG_PASSWORD)) {
1532                         goto process_result;
1533                 }
1534
1535                 if (state->request.flags & WBFLAG_PAM_FALLBACK_AFTER_KRB5) {
1536                         DEBUG(3,("falling back to samlogon\n"));
1537                         goto sam_logon;
1538                 } else {
1539                         goto cached_logon;
1540                 }
1541         }
1542
1543 sam_logon:
1544         /* Check for Samlogon authentication */
1545         if (domain->online) {
1546                 result = winbindd_dual_pam_auth_samlogon(domain, state, &info3);
1547
1548                 if (NT_STATUS_IS_OK(result)) {
1549                         DEBUG(10,("winbindd_dual_pam_auth_samlogon succeeded\n"));
1550                         /* add the Krb5 err if we have one */
1551                         if ( NT_STATUS_EQUAL(krb5_result, NT_STATUS_TIME_DIFFERENCE_AT_DC ) ) {
1552                                 info3->base.user_flags |= LOGON_KRB5_FAIL_CLOCK_SKEW;
1553                         }
1554                         goto process_result;
1555                 }
1556
1557                 DEBUG(10,("winbindd_dual_pam_auth_samlogon failed: %s\n",
1558                           nt_errstr(result)));
1559
1560                 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
1561                     NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
1562                     NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND))
1563                 {
1564                         DEBUG(10,("winbindd_dual_pam_auth_samlogon setting domain to offline\n"));
1565                         set_domain_offline( domain );
1566                         goto cached_logon;
1567                 }
1568
1569                         if (domain->online) {
1570                                 /* We're still online - fail. */
1571                                 goto done;
1572                         }
1573         }
1574
1575 cached_logon:
1576         /* Check for Cached logons */
1577         if (!domain->online && (state->request.flags & WBFLAG_PAM_CACHED_LOGIN) &&
1578             lp_winbind_offline_logon()) {
1579
1580                 result = winbindd_dual_pam_auth_cached(domain, state, &info3);
1581
1582                 if (NT_STATUS_IS_OK(result)) {
1583                         DEBUG(10,("winbindd_dual_pam_auth_cached succeeded\n"));
1584                         goto process_result;
1585                 } else {
1586                         DEBUG(10,("winbindd_dual_pam_auth_cached failed: %s\n", nt_errstr(result)));
1587                         goto done;
1588                 }
1589         }
1590
1591 process_result:
1592
1593         if (NT_STATUS_IS_OK(result)) {
1594
1595                 DOM_SID user_sid;
1596
1597                 /* In all codepaths where result == NT_STATUS_OK info3 must have
1598                    been initialized. */
1599                 if (!info3) {
1600                         result = NT_STATUS_INTERNAL_ERROR;
1601                         goto done;
1602                 }
1603
1604                 netsamlogon_cache_store(name_user, info3);
1605                 wcache_invalidate_samlogon(find_domain_from_name(name_domain), info3);
1606
1607                 /* save name_to_sid info as early as possible (only if
1608                    this is our primary domain so we don't invalidate
1609                    the cache entry by storing the seq_num for the wrong
1610                    domain). */
1611                 if ( domain->primary ) {
1612                         sid_compose(&user_sid, info3->base.domain_sid,
1613                                     info3->base.rid);
1614                         cache_name2sid(domain, name_domain, name_user,
1615                                        SID_NAME_USER, &user_sid);
1616                 }
1617
1618                 /* Check if the user is in the right group */
1619
1620                 if (!NT_STATUS_IS_OK(result = check_info3_in_group(state->mem_ctx, info3,
1621                                         state->request.data.auth.require_membership_of_sid))) {
1622                         DEBUG(3, ("User %s is not in the required group (%s), so plaintext authentication is rejected\n",
1623                                   state->request.data.auth.user,
1624                                   state->request.data.auth.require_membership_of_sid));
1625                         goto done;
1626                 }
1627
1628                 result = append_data(state, info3, name_domain, name_user);
1629                 if (!NT_STATUS_IS_OK(result)) {
1630                         goto done;
1631                 }
1632
1633                 if ((state->request.flags & WBFLAG_PAM_CACHED_LOGIN)) {
1634
1635                         /* Store in-memory creds for single-signon using ntlm_auth. */
1636                         result = winbindd_add_memory_creds(state->request.data.auth.user,
1637                                                         get_uid_from_state(state),
1638                                                         state->request.data.auth.pass);
1639
1640                         if (!NT_STATUS_IS_OK(result)) {
1641                                 DEBUG(10,("Failed to store memory creds: %s\n", nt_errstr(result)));
1642                                 goto done;
1643                         }
1644
1645                         if (lp_winbind_offline_logon()) {
1646                                 result = winbindd_store_creds(domain,
1647                                                       state->mem_ctx,
1648                                                       state->request.data.auth.user,
1649                                                       state->request.data.auth.pass,
1650                                                       info3, NULL);
1651                                 if (!NT_STATUS_IS_OK(result)) {
1652
1653                                         /* Release refcount. */
1654                                         winbindd_delete_memory_creds(state->request.data.auth.user);
1655
1656                                         DEBUG(10,("Failed to store creds: %s\n", nt_errstr(result)));
1657                                         goto done;
1658                                 }
1659                         }
1660                 }
1661
1662
1663                 if (state->request.flags & WBFLAG_PAM_GET_PWD_POLICY) {
1664                         struct winbindd_domain *our_domain = find_our_domain();
1665
1666                         /* This is not entirely correct I believe, but it is
1667                            consistent.  Only apply the password policy settings
1668                            too warn users for our own domain.  Cannot obtain these
1669                            from trusted DCs all the  time so don't do it at all.
1670                            -- jerry */
1671
1672                         result = NT_STATUS_NOT_SUPPORTED;
1673                         if (our_domain == domain ) {
1674                                 result = fillup_password_policy(our_domain, state);
1675                         }
1676
1677                         if (!NT_STATUS_IS_OK(result)
1678                             && !NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED) )
1679                         {
1680                                 DEBUG(10,("Failed to get password policies for domain %s: %s\n",
1681                                           domain->name, nt_errstr(result)));
1682                                 goto done;
1683                         }
1684                 }
1685
1686                 result = NT_STATUS_OK;
1687         }
1688
1689 done:
1690         /* give us a more useful (more correct?) error code */
1691         if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
1692             (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
1693                 result = NT_STATUS_NO_LOGON_SERVERS;
1694         }
1695
1696         state->response.data.auth.nt_status = NT_STATUS_V(result);
1697         fstrcpy(state->response.data.auth.nt_status_string, nt_errstr(result));
1698
1699         /* we might have given a more useful error above */
1700         if (!*state->response.data.auth.error_string)
1701                 fstrcpy(state->response.data.auth.error_string, get_friendly_nt_error_msg(result));
1702         state->response.data.auth.pam_error = nt_status_to_pam(result);
1703
1704         DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, ("Plain-text authentication for user %s returned %s (PAM: %d)\n",
1705               state->request.data.auth.user,
1706               state->response.data.auth.nt_status_string,
1707               state->response.data.auth.pam_error));
1708
1709         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
1710 }
1711
1712
1713 /**********************************************************************
1714  Challenge Response Authentication Protocol
1715 **********************************************************************/
1716
1717 void winbindd_pam_auth_crap(struct winbindd_cli_state *state)
1718 {
1719         struct winbindd_domain *domain = NULL;
1720         const char *domain_name = NULL;
1721         NTSTATUS result;
1722
1723         if (!check_request_flags(state->request.flags)) {
1724                 result = NT_STATUS_INVALID_PARAMETER_MIX;
1725                 goto done;
1726         }
1727
1728         if (!state->privileged) {
1729                 char *error_string = NULL;
1730                 DEBUG(2, ("winbindd_pam_auth_crap: non-privileged access "
1731                           "denied.  !\n"));
1732                 DEBUGADD(2, ("winbindd_pam_auth_crap: Ensure permissions "
1733                              "on %s are set correctly.\n",
1734                              get_winbind_priv_pipe_dir()));
1735                 /* send a better message than ACCESS_DENIED */
1736                 error_string = talloc_asprintf(state->mem_ctx,
1737                                                "winbind client not authorized "
1738                                                "to use winbindd_pam_auth_crap."
1739                                                " Ensure permissions on %s "
1740                                                "are set correctly.",
1741                                                get_winbind_priv_pipe_dir());
1742                 fstrcpy(state->response.data.auth.error_string, error_string);
1743                 result = NT_STATUS_ACCESS_DENIED;
1744                 goto done;
1745         }
1746
1747         /* Ensure null termination */
1748         state->request.data.auth_crap.user
1749                 [sizeof(state->request.data.auth_crap.user)-1]=0;
1750         state->request.data.auth_crap.domain
1751                 [sizeof(state->request.data.auth_crap.domain)-1]=0;
1752
1753         DEBUG(3, ("[%5lu]: pam auth crap domain: [%s] user: %s\n",
1754                   (unsigned long)state->pid,
1755                   state->request.data.auth_crap.domain,
1756                   state->request.data.auth_crap.user));
1757
1758         if (*state->request.data.auth_crap.domain != '\0') {
1759                 domain_name = state->request.data.auth_crap.domain;
1760         } else if (lp_winbind_use_default_domain()) {
1761                 domain_name = lp_workgroup();
1762         }
1763
1764         if (domain_name != NULL)
1765                 domain = find_auth_domain(state, domain_name);
1766
1767         if (domain != NULL) {
1768                 sendto_domain(state, domain);
1769                 return;
1770         }
1771
1772         result = NT_STATUS_NO_SUCH_USER;
1773
1774  done:
1775         set_auth_errors(&state->response, result);
1776         DEBUG(5, ("CRAP authentication for %s\\%s returned %s (PAM: %d)\n",
1777                   state->request.data.auth_crap.domain,
1778                   state->request.data.auth_crap.user,
1779                   state->response.data.auth.nt_status_string,
1780                   state->response.data.auth.pam_error));
1781         request_error(state);
1782         return;
1783 }
1784
1785
1786 enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain,
1787                                                  struct winbindd_cli_state *state)
1788 {
1789         NTSTATUS result;
1790         struct netr_SamInfo3 *info3 = NULL;
1791         struct rpc_pipe_client *netlogon_pipe;
1792         const char *name_user = NULL;
1793         const char *name_domain = NULL;
1794         const char *workstation;
1795         struct winbindd_domain *contact_domain;
1796         int attempts = 0;
1797         bool retry;
1798
1799         DATA_BLOB lm_resp, nt_resp;
1800
1801         /* This is child-only, so no check for privileged access is needed
1802            anymore */
1803
1804         /* Ensure null termination */
1805         state->request.data.auth_crap.user[sizeof(state->request.data.auth_crap.user)-1]=0;
1806         state->request.data.auth_crap.domain[sizeof(state->request.data.auth_crap.domain)-1]=0;
1807
1808         if (!check_request_flags(state->request.flags)) {
1809                 result = NT_STATUS_INVALID_PARAMETER_MIX;
1810                 goto done;
1811         }
1812
1813         name_user = state->request.data.auth_crap.user;
1814
1815         if (*state->request.data.auth_crap.domain) {
1816                 name_domain = state->request.data.auth_crap.domain;
1817         } else if (lp_winbind_use_default_domain()) {
1818                 name_domain = lp_workgroup();
1819         } else {
1820                 DEBUG(5,("no domain specified with username (%s) - failing auth\n",
1821                          name_user));
1822                 result = NT_STATUS_NO_SUCH_USER;
1823                 goto done;
1824         }
1825
1826         DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n", (unsigned long)state->pid,
1827                   name_domain, name_user));
1828
1829         if (*state->request.data.auth_crap.workstation) {
1830                 workstation = state->request.data.auth_crap.workstation;
1831         } else {
1832                 workstation = global_myname();
1833         }
1834
1835         if (state->request.data.auth_crap.lm_resp_len > sizeof(state->request.data.auth_crap.lm_resp)
1836                 || state->request.data.auth_crap.nt_resp_len > sizeof(state->request.data.auth_crap.nt_resp)) {
1837                 DEBUG(0, ("winbindd_pam_auth_crap: invalid password length %u/%u\n",
1838                           state->request.data.auth_crap.lm_resp_len,
1839                           state->request.data.auth_crap.nt_resp_len));
1840                 result = NT_STATUS_INVALID_PARAMETER;
1841                 goto done;
1842         }
1843
1844         lm_resp = data_blob_talloc(state->mem_ctx, state->request.data.auth_crap.lm_resp,
1845                                         state->request.data.auth_crap.lm_resp_len);
1846         nt_resp = data_blob_talloc(state->mem_ctx, state->request.data.auth_crap.nt_resp,
1847                                         state->request.data.auth_crap.nt_resp_len);
1848
1849         /* what domain should we contact? */
1850
1851         if ( IS_DC ) {
1852                 if (!(contact_domain = find_domain_from_name(name_domain))) {
1853                         DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
1854                                   state->request.data.auth_crap.user, name_domain, name_user, name_domain));
1855                         result = NT_STATUS_NO_SUCH_USER;
1856                         goto done;
1857                 }
1858         } else {
1859                 if (is_myname(name_domain)) {
1860                         DEBUG(3, ("Authentication for domain %s (local domain to this server) not supported at this stage\n", name_domain));
1861                         result =  NT_STATUS_NO_SUCH_USER;
1862                         goto done;
1863                 }
1864                 contact_domain = find_our_domain();
1865         }
1866
1867         do {
1868                 netlogon_fn_t logon_fn;
1869
1870                 retry = False;
1871
1872                 netlogon_pipe = NULL;
1873                 result = cm_connect_netlogon(contact_domain, &netlogon_pipe);
1874
1875                 if (!NT_STATUS_IS_OK(result)) {
1876                         DEBUG(3, ("could not open handle to NETLOGON pipe (error: %s)\n",
1877                                   nt_errstr(result)));
1878                         goto done;
1879                 }
1880
1881                 logon_fn = contact_domain->can_do_samlogon_ex
1882                         ? rpccli_netlogon_sam_network_logon_ex
1883                         : rpccli_netlogon_sam_network_logon;
1884
1885                 result = logon_fn(netlogon_pipe,
1886                                   state->mem_ctx,
1887                                   state->request.data.auth_crap.logon_parameters,
1888                                   contact_domain->dcname,
1889                                   name_user,
1890                                   name_domain,
1891                                   /* Bug #3248 - found by Stefan Burkei. */
1892                                   workstation, /* We carefully set this above so use it... */
1893                                   state->request.data.auth_crap.chal,
1894                                   lm_resp,
1895                                   nt_resp,
1896                                   &info3);
1897
1898                 if ((NT_STATUS_V(result) == DCERPC_FAULT_OP_RNG_ERROR)
1899                     && contact_domain->can_do_samlogon_ex) {
1900                         DEBUG(3, ("Got a DC that can not do NetSamLogonEx, "
1901                                   "retrying with NetSamLogon\n"));
1902                         contact_domain->can_do_samlogon_ex = False;
1903                         retry = True;
1904                         continue;
1905                 }
1906
1907                 attempts += 1;
1908
1909                 /* We have to try a second time as cm_connect_netlogon
1910                    might not yet have noticed that the DC has killed
1911                    our connection. */
1912
1913                 if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)) {
1914                         retry = True;
1915                         continue;
1916                 }
1917
1918                 /* if we get access denied, a possible cause was that we had and open
1919                    connection to the DC, but someone changed our machine account password
1920                    out from underneath us using 'net rpc changetrustpw' */
1921
1922                 if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
1923                         DEBUG(3,("winbindd_pam_auth: sam_logon returned "
1924                                  "ACCESS_DENIED.  Maybe the trust account "
1925                                 "password was changed and we didn't know it. "
1926                                  "Killing connections to domain %s\n",
1927                                 name_domain));
1928                         invalidate_cm_connection(&contact_domain->conn);
1929                         retry = True;
1930                 }
1931
1932         } while ( (attempts < 2) && retry );
1933
1934         if (NT_STATUS_IS_OK(result)) {
1935
1936                 netsamlogon_cache_store(name_user, info3);
1937                 wcache_invalidate_samlogon(find_domain_from_name(name_domain), info3);
1938
1939                 /* Check if the user is in the right group */
1940
1941                 if (!NT_STATUS_IS_OK(result = check_info3_in_group(state->mem_ctx, info3,
1942                                                         state->request.data.auth_crap.require_membership_of_sid))) {
1943                         DEBUG(3, ("User %s is not in the required group (%s), so "
1944                                   "crap authentication is rejected\n",
1945                                   state->request.data.auth_crap.user,
1946                                   state->request.data.auth_crap.require_membership_of_sid));
1947                         goto done;
1948                 }
1949
1950                 result = append_data(state, info3, name_domain, name_user);
1951                 if (!NT_STATUS_IS_OK(result)) {
1952                         goto done;
1953                 }
1954         }
1955
1956 done:
1957
1958         /* give us a more useful (more correct?) error code */
1959         if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
1960             (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
1961                 result = NT_STATUS_NO_LOGON_SERVERS;
1962         }
1963
1964         if (state->request.flags & WBFLAG_PAM_NT_STATUS_SQUASH) {
1965                 result = nt_status_squash(result);
1966         }
1967
1968         state->response.data.auth.nt_status = NT_STATUS_V(result);
1969         fstrcpy(state->response.data.auth.nt_status_string, nt_errstr(result));
1970
1971         /* we might have given a more useful error above */
1972         if (!*state->response.data.auth.error_string) {
1973                 fstrcpy(state->response.data.auth.error_string, get_friendly_nt_error_msg(result));
1974         }
1975         state->response.data.auth.pam_error = nt_status_to_pam(result);
1976
1977         DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
1978               ("NTLM CRAP authentication for user [%s]\\[%s] returned %s (PAM: %d)\n",
1979                name_domain,
1980                name_user,
1981                state->response.data.auth.nt_status_string,
1982                state->response.data.auth.pam_error));
1983
1984         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
1985 }
1986
1987 /* Change a user password */
1988
1989 void winbindd_pam_chauthtok(struct winbindd_cli_state *state)
1990 {
1991         fstring domain, user;
1992         struct winbindd_domain *contact_domain;
1993
1994         DEBUG(3, ("[%5lu]: pam chauthtok %s\n", (unsigned long)state->pid,
1995                 state->request.data.chauthtok.user));
1996
1997         /* Setup crap */
1998
1999         ws_name_return( state->request.data.auth.user, WB_REPLACE_CHAR );
2000
2001         if (!canonicalize_username(state->request.data.chauthtok.user, domain, user)) {
2002                 set_auth_errors(&state->response, NT_STATUS_NO_SUCH_USER);
2003                 DEBUG(5, ("winbindd_pam_chauthtok: canonicalize_username %s failed with %s"
2004                           "(PAM: %d)\n",
2005                           state->request.data.auth.user,
2006                           state->response.data.auth.nt_status_string,
2007                           state->response.data.auth.pam_error));
2008                 request_error(state);
2009                 return;
2010         }
2011
2012         contact_domain = find_domain_from_name(domain);
2013         if (!contact_domain) {
2014                 set_auth_errors(&state->response, NT_STATUS_NO_SUCH_USER);
2015                 DEBUG(3, ("Cannot change password for [%s] -> [%s]\\[%s] as %s is not a trusted domain\n",
2016                           state->request.data.chauthtok.user, domain, user, domain));
2017                 request_error(state);
2018                 return;
2019         }
2020
2021         sendto_domain(state, contact_domain);
2022 }
2023
2024 enum winbindd_result winbindd_dual_pam_chauthtok(struct winbindd_domain *contact_domain,
2025                                                  struct winbindd_cli_state *state)
2026 {
2027         char *oldpass;
2028         char *newpass = NULL;
2029         POLICY_HND dom_pol;
2030         struct rpc_pipe_client *cli;
2031         bool got_info = False;
2032         struct samr_DomInfo1 *info = NULL;
2033         struct samr_ChangeReject *reject = NULL;
2034         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
2035         fstring domain, user;
2036
2037         DEBUG(3, ("[%5lu]: dual pam chauthtok %s\n", (unsigned long)state->pid,
2038                   state->request.data.auth.user));
2039
2040         if (!parse_domain_user(state->request.data.chauthtok.user, domain, user)) {
2041                 goto done;
2042         }
2043
2044         /* Change password */
2045
2046         oldpass = state->request.data.chauthtok.oldpass;
2047         newpass = state->request.data.chauthtok.newpass;
2048
2049         /* Initialize reject reason */
2050         state->response.data.auth.reject_reason = Undefined;
2051
2052         /* Get sam handle */
2053
2054         result = cm_connect_sam(contact_domain, state->mem_ctx, &cli,
2055                                 &dom_pol);
2056         if (!NT_STATUS_IS_OK(result)) {
2057                 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
2058                 goto done;
2059         }
2060
2061         result = rpccli_samr_chgpasswd_user3(cli, state->mem_ctx,
2062                                              user,
2063                                              newpass,
2064                                              oldpass,
2065                                              &info,
2066                                              &reject);
2067
2068         /* Windows 2003 returns NT_STATUS_PASSWORD_RESTRICTION */
2069
2070         if (NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_RESTRICTION) ) {
2071                 state->response.data.auth.policy.min_length_password =
2072                         info->min_password_length;
2073                 state->response.data.auth.policy.password_history =
2074                         info->password_history_length;
2075                 state->response.data.auth.policy.password_properties =
2076                         info->password_properties;
2077                 state->response.data.auth.policy.expire =
2078                         nt_time_to_unix_abs((NTTIME *)&info->max_password_age);
2079                 state->response.data.auth.policy.min_passwordage =
2080                         nt_time_to_unix_abs((NTTIME *)&info->min_password_age);
2081
2082                 state->response.data.auth.reject_reason =
2083                         reject->reason;
2084
2085                 got_info = True;
2086         }
2087
2088         /* only fallback when the chgpasswd_user3 call is not supported */
2089         if ((NT_STATUS_EQUAL(result, NT_STATUS(DCERPC_FAULT_OP_RNG_ERROR))) ||
2090                    (NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED)) ||
2091                    (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED))) {
2092
2093                 DEBUG(10,("Password change with chgpasswd_user3 failed with: %s, retrying chgpasswd_user2\n",
2094                         nt_errstr(result)));
2095
2096                 result = rpccli_samr_chgpasswd_user2(cli, state->mem_ctx, user, newpass, oldpass);
2097
2098                 /* Windows 2000 returns NT_STATUS_ACCOUNT_RESTRICTION.
2099                    Map to the same status code as Windows 2003. */
2100
2101                 if ( NT_STATUS_EQUAL(NT_STATUS_ACCOUNT_RESTRICTION, result ) ) {
2102                         result = NT_STATUS_PASSWORD_RESTRICTION;
2103                 }
2104         }
2105
2106 done:
2107
2108         if (NT_STATUS_IS_OK(result) && (state->request.flags & WBFLAG_PAM_CACHED_LOGIN)) {
2109
2110                 /* Update the single sign-on memory creds. */
2111                 result = winbindd_replace_memory_creds(state->request.data.chauthtok.user,
2112                                                         newpass);
2113
2114                 /* When we login from gdm or xdm and password expires,
2115                  * we change password, but there are no memory crendentials
2116                  * So, winbindd_replace_memory_creds() returns
2117                  * NT_STATUS_OBJECT_NAME_NOT_FOUND. This is not a failure.
2118                  * --- BoYang
2119                  * */
2120                 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
2121                         result = NT_STATUS_OK;
2122                 }
2123
2124                 if (!NT_STATUS_IS_OK(result)) {
2125                         DEBUG(10,("Failed to replace memory creds: %s\n", nt_errstr(result)));
2126                         goto process_result;
2127                 }
2128
2129                 if (lp_winbind_offline_logon()) {
2130                         result = winbindd_update_creds_by_name(contact_domain,
2131                                                          state->mem_ctx, user,
2132                                                          newpass);
2133                         /* Again, this happens when we login from gdm or xdm
2134                          * and the password expires, *BUT* cached crendentials
2135                          * doesn't exist. winbindd_update_creds_by_name()
2136                          * returns NT_STATUS_NO_SUCH_USER.
2137                          * This is not a failure.
2138                          * --- BoYang
2139                          * */
2140                         if (NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER)) {
2141                                 result = NT_STATUS_OK;
2142                         }
2143
2144                         if (!NT_STATUS_IS_OK(result)) {
2145                                 DEBUG(10,("Failed to store creds: %s\n", nt_errstr(result)));
2146                                 goto process_result;
2147                         }
2148                 }
2149         }
2150
2151         if (!NT_STATUS_IS_OK(result) && !got_info && contact_domain) {
2152
2153                 NTSTATUS policy_ret;
2154
2155                 policy_ret = fillup_password_policy(contact_domain, state);
2156
2157                 /* failure of this is non critical, it will just provide no
2158                  * additional information to the client why the change has
2159                  * failed - Guenther */
2160
2161                 if (!NT_STATUS_IS_OK(policy_ret)) {
2162                         DEBUG(10,("Failed to get password policies: %s\n", nt_errstr(policy_ret)));
2163                         goto process_result;
2164                 }
2165         }
2166
2167 process_result:
2168
2169         state->response.data.auth.nt_status = NT_STATUS_V(result);
2170         fstrcpy(state->response.data.auth.nt_status_string, nt_errstr(result));
2171         fstrcpy(state->response.data.auth.error_string, get_friendly_nt_error_msg(result));
2172         state->response.data.auth.pam_error = nt_status_to_pam(result);
2173
2174         DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
2175               ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
2176                domain,
2177                user,
2178                state->response.data.auth.nt_status_string,
2179                state->response.data.auth.pam_error));
2180
2181         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2182 }
2183
2184 void winbindd_pam_logoff(struct winbindd_cli_state *state)
2185 {
2186         struct winbindd_domain *domain;
2187         fstring name_domain, user;
2188         uid_t caller_uid = (uid_t)-1;
2189         uid_t request_uid = state->request.data.logoff.uid;
2190
2191         DEBUG(3, ("[%5lu]: pam logoff %s\n", (unsigned long)state->pid,
2192                 state->request.data.logoff.user));
2193
2194         /* Ensure null termination */
2195         state->request.data.logoff.user
2196                 [sizeof(state->request.data.logoff.user)-1]='\0';
2197
2198         state->request.data.logoff.krb5ccname
2199                 [sizeof(state->request.data.logoff.krb5ccname)-1]='\0';
2200
2201         if (request_uid == (gid_t)-1) {
2202                 goto failed;
2203         }
2204
2205         if (!canonicalize_username(state->request.data.logoff.user, name_domain, user)) {
2206                 goto failed;
2207         }
2208
2209         if ((domain = find_auth_domain(state, name_domain)) == NULL) {
2210                 goto failed;
2211         }
2212
2213         if ((sys_getpeereid(state->sock, &caller_uid)) != 0) {
2214                 DEBUG(1,("winbindd_pam_logoff: failed to check peerid: %s\n",
2215                         strerror(errno)));
2216                 goto failed;
2217         }
2218
2219         switch (caller_uid) {
2220                 case -1:
2221                         goto failed;
2222                 case 0:
2223                         /* root must be able to logoff any user - gd */
2224                         state->request.data.logoff.uid = request_uid;
2225                         break;
2226                 default:
2227                         if (caller_uid != request_uid) {
2228                                 DEBUG(1,("winbindd_pam_logoff: caller requested invalid uid\n"));
2229                                 goto failed;
2230                         }
2231                         state->request.data.logoff.uid = caller_uid;
2232                         break;
2233         }
2234
2235         sendto_domain(state, domain);
2236         return;
2237
2238  failed:
2239         set_auth_errors(&state->response, NT_STATUS_NO_SUCH_USER);
2240         DEBUG(5, ("Pam Logoff for %s returned %s "
2241                   "(PAM: %d)\n",
2242                   state->request.data.logoff.user,
2243                   state->response.data.auth.nt_status_string,
2244                   state->response.data.auth.pam_error));
2245         request_error(state);
2246         return;
2247 }
2248
2249 enum winbindd_result winbindd_dual_pam_logoff(struct winbindd_domain *domain,
2250                                               struct winbindd_cli_state *state)
2251 {
2252         NTSTATUS result = NT_STATUS_NOT_SUPPORTED;
2253
2254         DEBUG(3, ("[%5lu]: pam dual logoff %s\n", (unsigned long)state->pid,
2255                 state->request.data.logoff.user));
2256
2257         if (!(state->request.flags & WBFLAG_PAM_KRB5)) {
2258                 result = NT_STATUS_OK;
2259                 goto process_result;
2260         }
2261
2262         if (state->request.data.logoff.krb5ccname[0] == '\0') {
2263                 result = NT_STATUS_OK;
2264                 goto process_result;
2265         }
2266
2267 #ifdef HAVE_KRB5
2268
2269         if (state->request.data.logoff.uid < 0) {
2270                 DEBUG(0,("winbindd_pam_logoff: invalid uid\n"));
2271                 goto process_result;
2272         }
2273
2274         /* what we need here is to find the corresponding krb5 ccache name *we*
2275          * created for a given username and destroy it */
2276
2277         if (!ccache_entry_exists(state->request.data.logoff.user)) {
2278                 result = NT_STATUS_OK;
2279                 DEBUG(10,("winbindd_pam_logoff: no entry found.\n"));
2280                 goto process_result;
2281         }
2282
2283         if (!ccache_entry_identical(state->request.data.logoff.user,
2284                                         state->request.data.logoff.uid,
2285                                         state->request.data.logoff.krb5ccname)) {
2286                 DEBUG(0,("winbindd_pam_logoff: cached entry differs.\n"));
2287                 goto process_result;
2288         }
2289
2290         result = remove_ccache(state->request.data.logoff.user);
2291         if (!NT_STATUS_IS_OK(result)) {
2292                 DEBUG(0,("winbindd_pam_logoff: failed to remove ccache: %s\n",
2293                         nt_errstr(result)));
2294                 goto process_result;
2295         }
2296
2297 #else
2298         result = NT_STATUS_NOT_SUPPORTED;
2299 #endif
2300
2301 process_result:
2302
2303         winbindd_delete_memory_creds(state->request.data.logoff.user);
2304
2305         state->response.data.auth.nt_status = NT_STATUS_V(result);
2306         fstrcpy(state->response.data.auth.nt_status_string, nt_errstr(result));
2307         fstrcpy(state->response.data.auth.error_string, get_friendly_nt_error_msg(result));
2308         state->response.data.auth.pam_error = nt_status_to_pam(result);
2309
2310         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2311 }
2312
2313 /* Change user password with auth crap*/
2314
2315 void winbindd_pam_chng_pswd_auth_crap(struct winbindd_cli_state *state)
2316 {
2317         struct winbindd_domain *domain = NULL;
2318         const char *domain_name = NULL;
2319
2320         /* Ensure null termination */
2321         state->request.data.chng_pswd_auth_crap.user[
2322                 sizeof(state->request.data.chng_pswd_auth_crap.user)-1]=0;
2323         state->request.data.chng_pswd_auth_crap.domain[
2324                 sizeof(state->request.data.chng_pswd_auth_crap.domain)-1]=0;
2325
2326         DEBUG(3, ("[%5lu]: pam change pswd auth crap domain: %s user: %s\n",
2327                   (unsigned long)state->pid,
2328                   state->request.data.chng_pswd_auth_crap.domain,
2329                   state->request.data.chng_pswd_auth_crap.user));
2330
2331         if (*state->request.data.chng_pswd_auth_crap.domain != '\0') {
2332                 domain_name = state->request.data.chng_pswd_auth_crap.domain;
2333         } else if (lp_winbind_use_default_domain()) {
2334                 domain_name = lp_workgroup();
2335         }
2336
2337         if (domain_name != NULL)
2338                 domain = find_domain_from_name(domain_name);
2339
2340         if (domain != NULL) {
2341                 DEBUG(7, ("[%5lu]: pam auth crap changing pswd in domain: "
2342                           "%s\n", (unsigned long)state->pid,domain->name));
2343                 sendto_domain(state, domain);
2344                 return;
2345         }
2346
2347         set_auth_errors(&state->response, NT_STATUS_NO_SUCH_USER);
2348         DEBUG(5, ("CRAP change password  for %s\\%s returned %s (PAM: %d)\n",
2349                   state->request.data.chng_pswd_auth_crap.domain,
2350                   state->request.data.chng_pswd_auth_crap.user,
2351                   state->response.data.auth.nt_status_string,
2352                   state->response.data.auth.pam_error));
2353         request_error(state);
2354         return;
2355 }
2356
2357 enum winbindd_result winbindd_dual_pam_chng_pswd_auth_crap(struct winbindd_domain *domainSt, struct winbindd_cli_state *state)
2358 {
2359         NTSTATUS result;
2360         DATA_BLOB new_nt_password;
2361         DATA_BLOB old_nt_hash_enc;
2362         DATA_BLOB new_lm_password;
2363         DATA_BLOB old_lm_hash_enc;
2364         fstring  domain,user;
2365         POLICY_HND dom_pol;
2366         struct winbindd_domain *contact_domain = domainSt;
2367         struct rpc_pipe_client *cli;
2368
2369         /* Ensure null termination */
2370         state->request.data.chng_pswd_auth_crap.user[
2371                 sizeof(state->request.data.chng_pswd_auth_crap.user)-1]=0;
2372         state->request.data.chng_pswd_auth_crap.domain[
2373                 sizeof(state->request.data.chng_pswd_auth_crap.domain)-1]=0;
2374         *domain = 0;
2375         *user = 0;
2376
2377         DEBUG(3, ("[%5lu]: pam change pswd auth crap domain: %s user: %s\n",
2378                   (unsigned long)state->pid,
2379                   state->request.data.chng_pswd_auth_crap.domain,
2380                   state->request.data.chng_pswd_auth_crap.user));
2381
2382         if (lp_winbind_offline_logon()) {
2383                 DEBUG(0,("Refusing password change as winbind offline logons are enabled. "));
2384                 DEBUGADD(0,("Changing passwords here would risk inconsistent logons\n"));
2385                 result = NT_STATUS_ACCESS_DENIED;
2386                 goto done;
2387         }
2388
2389         if (*state->request.data.chng_pswd_auth_crap.domain) {
2390                 fstrcpy(domain,state->request.data.chng_pswd_auth_crap.domain);
2391         } else {
2392                 parse_domain_user(state->request.data.chng_pswd_auth_crap.user,
2393                                   domain, user);
2394
2395                 if(!*domain) {
2396                         DEBUG(3,("no domain specified with username (%s) - "
2397                                  "failing auth\n",
2398                                  state->request.data.chng_pswd_auth_crap.user));
2399                         result = NT_STATUS_NO_SUCH_USER;
2400                         goto done;
2401                 }
2402         }
2403
2404         if (!*domain && lp_winbind_use_default_domain()) {
2405                 fstrcpy(domain,(char *)lp_workgroup());
2406         }
2407
2408         if(!*user) {
2409                 fstrcpy(user, state->request.data.chng_pswd_auth_crap.user);
2410         }
2411
2412         DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n",
2413                   (unsigned long)state->pid, domain, user));
2414
2415         /* Change password */
2416         new_nt_password = data_blob_talloc(
2417                 state->mem_ctx,
2418                 state->request.data.chng_pswd_auth_crap.new_nt_pswd,
2419                 state->request.data.chng_pswd_auth_crap.new_nt_pswd_len);
2420
2421         old_nt_hash_enc = data_blob_talloc(
2422                 state->mem_ctx,
2423                 state->request.data.chng_pswd_auth_crap.old_nt_hash_enc,
2424                 state->request.data.chng_pswd_auth_crap.old_nt_hash_enc_len);
2425
2426         if(state->request.data.chng_pswd_auth_crap.new_lm_pswd_len > 0) {
2427                 new_lm_password = data_blob_talloc(
2428                         state->mem_ctx,
2429                         state->request.data.chng_pswd_auth_crap.new_lm_pswd,
2430                         state->request.data.chng_pswd_auth_crap.new_lm_pswd_len);
2431
2432                 old_lm_hash_enc = data_blob_talloc(
2433                         state->mem_ctx,
2434                         state->request.data.chng_pswd_auth_crap.old_lm_hash_enc,
2435                         state->request.data.chng_pswd_auth_crap.old_lm_hash_enc_len);
2436         } else {
2437                 new_lm_password.length = 0;
2438                 old_lm_hash_enc.length = 0;
2439         }
2440
2441         /* Get sam handle */
2442
2443         result = cm_connect_sam(contact_domain, state->mem_ctx, &cli, &dom_pol);
2444         if (!NT_STATUS_IS_OK(result)) {
2445                 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
2446                 goto done;
2447         }
2448
2449         result = rpccli_samr_chng_pswd_auth_crap(
2450                 cli, state->mem_ctx, user, new_nt_password, old_nt_hash_enc,
2451                 new_lm_password, old_lm_hash_enc);
2452
2453  done:
2454         state->response.data.auth.nt_status = NT_STATUS_V(result);
2455         fstrcpy(state->response.data.auth.nt_status_string, nt_errstr(result));
2456         fstrcpy(state->response.data.auth.error_string,
2457                 get_friendly_nt_error_msg(result));
2458         state->response.data.auth.pam_error = nt_status_to_pam(result);
2459
2460         DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
2461               ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
2462                domain, user,
2463                state->response.data.auth.nt_status_string,
2464                state->response.data.auth.pam_error));
2465
2466         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2467 }