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