~lefteris-nikoltsios/+junk/samba-lp1016895

« back to all changes in this revision

Viewing changes to source3/auth/auth_netlogond.c

  • Committer: Package Import Robot
  • Author(s): Chuck Short
  • Date: 2011-12-21 13:18:04 UTC
  • mfrom: (0.39.21 sid)
  • Revision ID: package-import@ubuntu.com-20111221131804-xtlr39wx6njehxxr
Tags: 2:3.6.1-3ubuntu1
* Merge from Debian testing.  Remaining changes:
  + debian/patches/VERSION.patch:
    - set SAMBA_VERSION_SUFFIX to Ubuntu.
  + debian/patches/error-trans.fix-276472:
    - Add the translation of Unix Error code -ENOTSUP to NT Error Code
    - NT_STATUS_NOT_SUPPORTED to prevent the Permission denied error.
  + debian/smb.conf:
    - add "(Samba, Ubuntu)" to server string.
    - comment out the default [homes] share, and add a comment about
      "valid users = %S" to show users how to restrict access to
      \\server\username to only username.
    - Set 'usershare allow guests', so that usershare admins are 
      allowed to create public shares in addition to authenticated
      ones.
    - add map to guest = Bad user, maps bad username to guest access.
  + debian/samba-common.config:
    - Do not change priority to high if dhclient3 is installed.
    - Use priority medium instead of high for the workgroup question.
  + debian/control:
    - Don't build against or suggest ctdb.
    - Add dependency on samba-common-bin to samba.
  + Add ufw integration:
    - Created debian/samba.ufw.profile
    - debian/rules, debian/samba.dirs, debian/samba.files: install
      profile
    - debian/control: have samba suggest ufw
  + Add apport hook:
    - Created debian/source_samba.py.
    - debian/rules, debian/samba.dirs, debian/samba-common-bin.files: install
  + Switch to upstart:
    - Add debian/samba.{nmbd,smbd}.upstart.
  + debian/samba.logrotate, debian/samba-common.dhcp, debian/samba.if-up:
    - Make them upstart compatible
  + debian/samba.postinst: 
    - Avoid scary pdbedit warnings on first import.
  + debian/samba-common.postinst: Add more informative error message for
    the case where smb.conf was manually deleted
  + debian/patches/fix-debuglevel-name-conflict.patch: don't use 'debug_level'
    as a global variable name in an NSS module 
  + Dropped:
    - debian/patches/error-trans.fix-276472
    - debian/patches/fix-debuglevel-name-conflict.patch

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
*/
19
19
 
20
20
#include "includes.h"
 
21
#include "auth.h"
21
22
#include "../libcli/auth/libcli_auth.h"
 
23
#include "../librpc/gen_ndr/ndr_netlogon.h"
 
24
#include "librpc/gen_ndr/ndr_schannel.h"
 
25
#include "rpc_client/cli_pipe.h"
 
26
#include "rpc_client/cli_netlogon.h"
 
27
#include "secrets.h"
 
28
#include "tldap.h"
 
29
#include "tldap_util.h"
22
30
 
23
31
#undef DBGC_CLASS
24
32
#define DBGC_CLASS DBGC_AUTH
25
33
 
 
34
static bool secrets_store_local_schannel_creds(
 
35
        const struct netlogon_creds_CredentialState *creds)
 
36
{
 
37
        DATA_BLOB blob;
 
38
        enum ndr_err_code ndr_err;
 
39
        bool ret;
 
40
 
 
41
        ndr_err = ndr_push_struct_blob(
 
42
                &blob, talloc_tos(), creds,
 
43
                (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
 
44
        if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 
45
                DEBUG(10, ("ndr_push_netlogon_creds_CredentialState failed: "
 
46
                           "%s\n", ndr_errstr(ndr_err)));
 
47
                return false;
 
48
        }
 
49
        ret = secrets_store(SECRETS_LOCAL_SCHANNEL_KEY,
 
50
                            blob.data, blob.length);
 
51
        data_blob_free(&blob);
 
52
        return ret;
 
53
}
 
54
 
 
55
static struct netlogon_creds_CredentialState *
 
56
secrets_fetch_local_schannel_creds(TALLOC_CTX *mem_ctx)
 
57
{
 
58
        struct netlogon_creds_CredentialState *creds;
 
59
        enum ndr_err_code ndr_err;
 
60
        DATA_BLOB blob;
 
61
 
 
62
        blob.data = (uint8_t *)secrets_fetch(SECRETS_LOCAL_SCHANNEL_KEY,
 
63
                                             &blob.length);
 
64
        if (blob.data == NULL) {
 
65
                DEBUG(10, ("secrets_fetch failed\n"));
 
66
                return NULL;
 
67
        }
 
68
 
 
69
        creds = talloc(mem_ctx, struct netlogon_creds_CredentialState);
 
70
        if (creds == NULL) {
 
71
                DEBUG(10, ("talloc failed\n"));
 
72
                SAFE_FREE(blob.data);
 
73
                return NULL;
 
74
        }
 
75
        ndr_err = ndr_pull_struct_blob(
 
76
                &blob, creds, creds,
 
77
                (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
 
78
        SAFE_FREE(blob.data);
 
79
        if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 
80
                DEBUG(10, ("ndr_pull_netlogon_creds_CredentialState failed: "
 
81
                           "%s\n", ndr_errstr(ndr_err)));
 
82
                TALLOC_FREE(creds);
 
83
                return NULL;
 
84
        }
 
85
 
 
86
        return creds;
 
87
}
 
88
 
26
89
static NTSTATUS netlogond_validate(TALLOC_CTX *mem_ctx,
27
90
                                   const struct auth_context *auth_context,
28
91
                                   const char *ncalrpc_sockname,
29
 
                                   uint8_t schannel_key[16],
30
 
                                   const auth_usersupplied_info *user_info,
 
92
                                   struct netlogon_creds_CredentialState *creds,
 
93
                                   const struct auth_usersupplied_info *user_info,
31
94
                                   struct netr_SamInfo3 **pinfo3,
32
95
                                   NTSTATUS *schannel_bind_result)
33
96
{
34
97
        struct rpc_pipe_client *p = NULL;
35
 
        struct cli_pipe_auth_data *auth = NULL;
 
98
        struct pipe_auth_data *auth = NULL;
36
99
        struct netr_SamInfo3 *info3 = NULL;
37
100
        NTSTATUS status;
38
101
 
46
109
                return status;
47
110
        }
48
111
 
49
 
        /*
50
 
         * We have to fake a struct dcinfo, so that
51
 
         * rpccli_netlogon_sam_network_logon_ex can decrypt the session keys.
52
 
         */
53
 
 
54
 
        p->dc = netlogon_creds_client_init_session_key(p, schannel_key);
55
 
        if (p->dc == NULL) {
56
 
                DEBUG(0, ("talloc failed\n"));
57
 
                TALLOC_FREE(p);
58
 
                return NT_STATUS_NO_MEMORY;
59
 
        }
 
112
        p->dc = creds;
60
113
 
61
114
        status = rpccli_schannel_bind_data(p, lp_workgroup(),
62
115
                                           DCERPC_AUTH_LEVEL_PRIVACY,
78
131
 
79
132
        status = rpccli_netlogon_sam_network_logon_ex(
80
133
                p, p,
81
 
                user_info->logon_parameters,/* flags such as 'allow
82
 
                                             * workstation logon' */
83
 
                global_myname(),            /* server name */
84
 
                user_info->smb_name,        /* user name logging on. */
85
 
                user_info->client_domain,   /* domain name */
86
 
                user_info->wksta_name,      /* workstation name */
 
134
                user_info->logon_parameters,           /* flags such as 'allow
 
135
                                                        * workstation logon' */
 
136
                global_myname(),                       /* server name */
 
137
                user_info->client.account_name,        /* user name logging on. */
 
138
                user_info->client.domain_name,         /* domain name */
 
139
                user_info->workstation_name,           /* workstation name */
87
140
                (uchar *)auth_context->challenge.data, /* 8 byte challenge. */
88
 
                3,                          /* validation level */
89
 
                user_info->lm_resp,         /* lanman 24 byte response */
90
 
                user_info->nt_resp,         /* nt 24 byte response */
91
 
                &info3);                    /* info3 out */
 
141
                3,                                     /* validation level */
 
142
                user_info->password.response.lanman,   /* lanman 24 byte response */
 
143
                user_info->password.response.nt,       /* nt 24 byte response */
 
144
                &info3);                               /* info3 out */
92
145
 
93
146
        DEBUG(10, ("rpccli_netlogon_sam_network_logon_ex returned %s\n",
94
147
                   nt_errstr(status)));
104
157
        return NT_STATUS_OK;
105
158
}
106
159
 
107
 
static char *mymachinepw(TALLOC_CTX *mem_ctx)
108
 
{
109
 
        fstring pwd;
110
 
        const char *script;
111
 
        char *to_free = NULL;
112
 
        ssize_t nread;
113
 
        int ret, fd;
114
 
 
115
 
        script = lp_parm_const_string(
116
 
                GLOBAL_SECTION_SNUM, "auth_netlogond", "machinepwscript",
117
 
                NULL);
118
 
 
119
 
        if (script == NULL) {
120
 
                to_free = talloc_asprintf(talloc_tos(), "%s/%s",
121
 
                                          get_dyn_SBINDIR(), "mymachinepw");
122
 
                script = to_free;
123
 
        }
124
 
        if (script == NULL) {
125
 
                return NULL;
126
 
        }
127
 
 
128
 
        ret = smbrun(script, &fd);
129
 
        DEBUG(ret ? 0 : 3, ("mymachinepw: Running the command `%s' gave %d\n",
130
 
                            script, ret));
131
 
        TALLOC_FREE(to_free);
132
 
 
133
 
        if (ret != 0) {
134
 
                return NULL;
135
 
        }
136
 
 
137
 
        nread = read(fd, pwd, sizeof(pwd)-1);
138
 
        close(fd);
139
 
 
140
 
        if (nread <= 0) {
141
 
                DEBUG(3, ("mymachinepwd: Could not read password\n"));
142
 
                return NULL;
143
 
        }
144
 
 
145
 
        pwd[nread] = '\0';
146
 
 
147
 
        if (pwd[nread-1] == '\n') {
148
 
                pwd[nread-1] = '\0';
149
 
        }
150
 
 
151
 
        return talloc_strdup(mem_ctx, pwd);
 
160
static NTSTATUS get_ldapi_ctx(TALLOC_CTX *mem_ctx, struct tldap_context **pld)
 
161
{
 
162
        struct tldap_context *ld;
 
163
        struct sockaddr_un addr;
 
164
        char *sockaddr;
 
165
        int fd;
 
166
        NTSTATUS status;
 
167
        int res;
 
168
 
 
169
        sockaddr = talloc_asprintf(talloc_tos(), "/%s/ldap_priv/ldapi",
 
170
                                   lp_private_dir());
 
171
        if (sockaddr == NULL) {
 
172
                DEBUG(10, ("talloc failed\n"));
 
173
                return NT_STATUS_NO_MEMORY;
 
174
        }
 
175
 
 
176
        ZERO_STRUCT(addr);
 
177
        addr.sun_family = AF_UNIX;
 
178
        strncpy(addr.sun_path, sockaddr, sizeof(addr.sun_path));
 
179
        TALLOC_FREE(sockaddr);
 
180
 
 
181
        status = open_socket_out((struct sockaddr_storage *)(void *)&addr,
 
182
                                 0, 0, &fd);
 
183
        if (!NT_STATUS_IS_OK(status)) {
 
184
                DEBUG(10, ("Could not connect to %s: %s\n", addr.sun_path,
 
185
                           nt_errstr(status)));
 
186
                return status;
 
187
        }
 
188
        set_blocking(fd, false);
 
189
 
 
190
        ld = tldap_context_create(mem_ctx, fd);
 
191
        if (ld == NULL) {
 
192
                close(fd);
 
193
                return NT_STATUS_NO_MEMORY;
 
194
        }
 
195
        res = tldap_fetch_rootdse(ld);
 
196
        if (res != TLDAP_SUCCESS) {
 
197
                DEBUG(10, ("tldap_fetch_rootdse failed: %s\n",
 
198
                           tldap_errstr(talloc_tos(), ld, res)));
 
199
                TALLOC_FREE(ld);
 
200
                return NT_STATUS_LDAP(res);
 
201
        }
 
202
        *pld = ld;
 
203
        return NT_STATUS_OK;;
 
204
}
 
205
 
 
206
static NTSTATUS mymachinepw(uint8_t pwd[16])
 
207
{
 
208
        TALLOC_CTX *frame = talloc_stackframe();
 
209
        struct tldap_context *ld = NULL;
 
210
        struct tldap_message *rootdse, **msg;
 
211
        const char *attrs[1] = { "unicodePwd" };
 
212
        char *default_nc, *myname;
 
213
        int rc, num_msg;
 
214
        DATA_BLOB pwdblob;
 
215
        NTSTATUS status;
 
216
 
 
217
        status = get_ldapi_ctx(talloc_tos(), &ld);
 
218
        if (!NT_STATUS_IS_OK(status)) {
 
219
                goto fail;
 
220
        }
 
221
        rootdse = tldap_rootdse(ld);
 
222
        if (rootdse == NULL) {
 
223
                DEBUG(10, ("Could not get rootdse\n"));
 
224
                status = NT_STATUS_INTERNAL_ERROR;
 
225
                goto fail;
 
226
        }
 
227
        default_nc = tldap_talloc_single_attribute(
 
228
                rootdse, "defaultNamingContext", talloc_tos());
 
229
        if (default_nc == NULL) {
 
230
                DEBUG(10, ("Could not get defaultNamingContext\n"));
 
231
                status = NT_STATUS_NO_MEMORY;
 
232
                goto fail;
 
233
        }
 
234
        DEBUG(10, ("default_nc = %s\n", default_nc));
 
235
 
 
236
        myname = talloc_asprintf_strupper_m(talloc_tos(), "%s$",
 
237
                                            global_myname());
 
238
        if (myname == NULL) {
 
239
                DEBUG(10, ("talloc failed\n"));
 
240
                status = NT_STATUS_NO_MEMORY;
 
241
                goto fail;
 
242
        }
 
243
 
 
244
        rc = tldap_search_fmt(
 
245
                ld, default_nc, TLDAP_SCOPE_SUB, attrs, ARRAY_SIZE(attrs), 0,
 
246
                talloc_tos(), &msg,
 
247
                "(&(sAMAccountName=%s)(objectClass=computer))", myname);
 
248
        if (rc != TLDAP_SUCCESS) {
 
249
                DEBUG(10, ("Could not retrieve our account: %s\n",
 
250
                           tldap_errstr(talloc_tos(), ld, rc)));
 
251
                status = NT_STATUS_LDAP(rc);
 
252
                goto fail;
 
253
        }
 
254
        num_msg = talloc_array_length(msg);
 
255
        if (num_msg != 1) {
 
256
                DEBUG(10, ("Got %d accounts, expected one\n", num_msg));
 
257
                status = NT_STATUS_INTERNAL_DB_CORRUPTION;
 
258
                goto fail;
 
259
        }
 
260
        if (!tldap_get_single_valueblob(msg[0], "unicodePwd", &pwdblob)) {
 
261
                char *dn = NULL;
 
262
                tldap_entry_dn(msg[0], &dn);
 
263
                DEBUG(10, ("No unicodePwd attribute in %s\n",
 
264
                           dn ? dn : "<unknown DN>"));
 
265
                status = NT_STATUS_INTERNAL_DB_CORRUPTION;
 
266
                goto fail;
 
267
        }
 
268
        if (pwdblob.length != 16) {
 
269
                DEBUG(10, ("Password hash hash has length %d, expected 16\n",
 
270
                           (int)pwdblob.length));
 
271
                status = NT_STATUS_INTERNAL_DB_CORRUPTION;
 
272
                goto fail;
 
273
        }
 
274
        memcpy(pwd, pwdblob.data, 16);
 
275
 
 
276
fail:
 
277
        TALLOC_FREE(frame);
 
278
        return status;
152
279
}
153
280
 
154
281
static NTSTATUS check_netlogond_security(const struct auth_context *auth_context,
155
282
                                         void *my_private_data,
156
283
                                         TALLOC_CTX *mem_ctx,
157
 
                                         const auth_usersupplied_info *user_info,
158
 
                                         auth_serversupplied_info **server_info)
 
284
                                         const struct auth_usersupplied_info *user_info,
 
285
                                         struct auth_serversupplied_info **server_info)
159
286
{
160
287
        TALLOC_CTX *frame = talloc_stackframe();
161
288
        struct netr_SamInfo3 *info3 = NULL;
162
289
        struct rpc_pipe_client *p = NULL;
163
 
        struct cli_pipe_auth_data *auth = NULL;
 
290
        struct pipe_auth_data *auth = NULL;
164
291
        uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
165
 
        char *plaintext_machinepw = NULL;
166
292
        uint8_t machine_password[16];
167
 
        uint8_t schannel_key[16];
 
293
        struct netlogon_creds_CredentialState *creds;
168
294
        NTSTATUS schannel_bind_result, status;
169
295
        struct named_mutex *mutex = NULL;
170
296
        const char *ncalrpcsock;
171
297
 
 
298
        DEBUG(10, ("Check auth for: [%s]\n", user_info->mapped.account_name));
 
299
 
172
300
        ncalrpcsock = lp_parm_const_string(
173
301
                GLOBAL_SECTION_SNUM, "auth_netlogond", "socket", NULL);
174
302
 
182
310
                goto done;
183
311
        }
184
312
 
185
 
        if (!secrets_fetch_local_schannel_key(schannel_key)) {
 
313
        creds = secrets_fetch_local_schannel_creds(talloc_tos());
 
314
        if (creds == NULL) {
186
315
                goto new_key;
187
316
        }
188
317
 
189
318
        status = netlogond_validate(talloc_tos(), auth_context, ncalrpcsock,
190
 
                                    schannel_key, user_info, &info3,
 
319
                                    creds, user_info, &info3,
191
320
                                    &schannel_bind_result);
192
321
 
193
322
        DEBUG(10, ("netlogond_validate returned %s\n", nt_errstr(status)));
236
365
                goto done;
237
366
        }
238
367
 
239
 
        plaintext_machinepw = mymachinepw(talloc_tos());
240
 
        if (plaintext_machinepw == NULL) {
241
 
                status = NT_STATUS_NO_MEMORY;
 
368
        status = mymachinepw(machine_password);
 
369
        if (!NT_STATUS_IS_OK(status)) {
 
370
                DEBUG(10, ("mymachinepw failed: %s\n", nt_errstr(status)));
242
371
                goto done;
243
372
        }
244
373
 
245
 
        E_md4hash(plaintext_machinepw, machine_password);
246
 
 
247
 
        TALLOC_FREE(plaintext_machinepw);
 
374
        DEBUG(10, ("machinepw "));
 
375
        dump_data(10, machine_password, 16);
248
376
 
249
377
        status = rpccli_netlogon_setup_creds(
250
378
                p, global_myname(), lp_workgroup(), global_myname(),
256
384
                goto done;
257
385
        }
258
386
 
259
 
        memcpy(schannel_key, p->dc->session_key, 16);
260
 
        secrets_store_local_schannel_key(schannel_key);
261
 
 
262
 
        TALLOC_FREE(p);
 
387
        secrets_store_local_schannel_creds(p->dc);
263
388
 
264
389
        /*
265
390
         * Retry the authentication with the mutex held. This way nobody else
267
392
         */
268
393
 
269
394
        status = netlogond_validate(talloc_tos(), auth_context, ncalrpcsock,
270
 
                                    schannel_key, user_info, &info3,
 
395
                                    p->dc, user_info, &info3,
271
396
                                    &schannel_bind_result);
272
397
 
 
398
        TALLOC_FREE(p);
 
399
 
273
400
        DEBUG(10, ("netlogond_validate returned %s\n", nt_errstr(status)));
274
401
 
275
402
        if (!NT_STATUS_IS_OK(status)) {
278
405
 
279
406
 okay:
280
407
 
281
 
        status = make_server_info_info3(mem_ctx, user_info->smb_name,
282
 
                                        user_info->domain, server_info,
 
408
        status = make_server_info_info3(mem_ctx, user_info->client.account_name,
 
409
                                        user_info->mapped.domain_name, server_info,
283
410
                                        info3);
284
411
        if (!NT_STATUS_IS_OK(status)) {
285
412
                DEBUG(10, ("make_server_info_info3 failed: %s\n",
300
427
                                    const char *param,
301
428
                                    auth_methods **auth_method)
302
429
{
303
 
        if (!make_auth_methods(auth_context, auth_method)) {
 
430
        struct auth_methods *result;
 
431
 
 
432
        result = TALLOC_ZERO_P(auth_context, struct auth_methods);
 
433
        if (result == NULL) {
304
434
                return NT_STATUS_NO_MEMORY;
305
435
        }
 
436
        result->name = "netlogond";
 
437
        result->auth = check_netlogond_security;
306
438
 
307
 
        (*auth_method)->name = "netlogond";
308
 
        (*auth_method)->auth = check_netlogond_security;
 
439
        *auth_method = result;
309
440
        return NT_STATUS_OK;
310
441
}
311
442