~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source3/winbindd/winbindd_pam.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

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