s3-rpc_client: Move client pipe functions to own header.
[samba.git] / source3 / auth / auth_netlogond.c
1 /*
2    Unix SMB/CIFS implementation.
3    Authenticate against a netlogon pipe listening on a unix domain socket
4    Copyright (C) Volker Lendecke 2008
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "../libcli/auth/libcli_auth.h"
22 #include "../librpc/gen_ndr/ndr_netlogon.h"
23 #include "librpc/gen_ndr/ndr_schannel.h"
24 #include "rpc_client/cli_pipe.h"
25 #include "rpc_client/cli_netlogon.h"
26 #include "secrets.h"
27 #include "tldap.h"
28 #include "tldap_util.h"
29
30 #undef DBGC_CLASS
31 #define DBGC_CLASS DBGC_AUTH
32
33 static bool secrets_store_local_schannel_creds(
34         const struct netlogon_creds_CredentialState *creds)
35 {
36         DATA_BLOB blob;
37         enum ndr_err_code ndr_err;
38         bool ret;
39
40         ndr_err = ndr_push_struct_blob(
41                 &blob, talloc_tos(), creds,
42                 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
43         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
44                 DEBUG(10, ("ndr_push_netlogon_creds_CredentialState failed: "
45                            "%s\n", ndr_errstr(ndr_err)));
46                 return false;
47         }
48         ret = secrets_store(SECRETS_LOCAL_SCHANNEL_KEY,
49                             blob.data, blob.length);
50         data_blob_free(&blob);
51         return ret;
52 }
53
54 static struct netlogon_creds_CredentialState *
55 secrets_fetch_local_schannel_creds(TALLOC_CTX *mem_ctx)
56 {
57         struct netlogon_creds_CredentialState *creds;
58         enum ndr_err_code ndr_err;
59         DATA_BLOB blob;
60
61         blob.data = (uint8_t *)secrets_fetch(SECRETS_LOCAL_SCHANNEL_KEY,
62                                              &blob.length);
63         if (blob.data == NULL) {
64                 DEBUG(10, ("secrets_fetch failed\n"));
65                 return NULL;
66         }
67
68         creds = talloc(mem_ctx, struct netlogon_creds_CredentialState);
69         if (creds == NULL) {
70                 DEBUG(10, ("talloc failed\n"));
71                 SAFE_FREE(blob.data);
72                 return NULL;
73         }
74         ndr_err = ndr_pull_struct_blob(
75                 &blob, creds, creds,
76                 (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
77         SAFE_FREE(blob.data);
78         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
79                 DEBUG(10, ("ndr_pull_netlogon_creds_CredentialState failed: "
80                            "%s\n", ndr_errstr(ndr_err)));
81                 TALLOC_FREE(creds);
82                 return NULL;
83         }
84
85         return creds;
86 }
87
88 static NTSTATUS netlogond_validate(TALLOC_CTX *mem_ctx,
89                                    const struct auth_context *auth_context,
90                                    const char *ncalrpc_sockname,
91                                    struct netlogon_creds_CredentialState *creds,
92                                    const struct auth_usersupplied_info *user_info,
93                                    struct netr_SamInfo3 **pinfo3,
94                                    NTSTATUS *schannel_bind_result)
95 {
96         struct rpc_pipe_client *p = NULL;
97         struct pipe_auth_data *auth = NULL;
98         struct netr_SamInfo3 *info3 = NULL;
99         NTSTATUS status;
100
101         *schannel_bind_result = NT_STATUS_OK;
102
103         status = rpc_pipe_open_ncalrpc(talloc_tos(), ncalrpc_sockname,
104                                        &ndr_table_netlogon.syntax_id, &p);
105         if (!NT_STATUS_IS_OK(status)) {
106                 DEBUG(10, ("rpc_pipe_open_ncalrpc failed: %s\n",
107                            nt_errstr(status)));
108                 return status;
109         }
110
111         p->dc = creds;
112
113         status = rpccli_schannel_bind_data(p, lp_workgroup(),
114                                            DCERPC_AUTH_LEVEL_PRIVACY,
115                                            p->dc, &auth);
116         if (!NT_STATUS_IS_OK(status)) {
117                 DEBUG(10, ("rpccli_schannel_bind_data failed: %s\n",
118                            nt_errstr(status)));
119                 TALLOC_FREE(p);
120                 return status;
121         }
122
123         status = rpc_pipe_bind(p, auth);
124         if (!NT_STATUS_IS_OK(status)) {
125                 DEBUG(10, ("rpc_pipe_bind failed: %s\n", nt_errstr(status)));
126                 TALLOC_FREE(p);
127                 *schannel_bind_result = status;
128                 return status;
129         }
130
131         status = rpccli_netlogon_sam_network_logon_ex(
132                 p, p,
133                 user_info->logon_parameters,           /* flags such as 'allow
134                                                         * workstation logon' */
135                 global_myname(),                       /* server name */
136                 user_info->client.account_name,        /* user name logging on. */
137                 user_info->client.domain_name,         /* domain name */
138                 user_info->workstation_name,           /* workstation name */
139                 (uchar *)auth_context->challenge.data, /* 8 byte challenge. */
140                 3,                                     /* validation level */
141                 user_info->password.response.lanman,   /* lanman 24 byte response */
142                 user_info->password.response.nt,       /* nt 24 byte response */
143                 &info3);                               /* info3 out */
144
145         DEBUG(10, ("rpccli_netlogon_sam_network_logon_ex returned %s\n",
146                    nt_errstr(status)));
147
148         if (!NT_STATUS_IS_OK(status)) {
149                 TALLOC_FREE(p);
150                 return status;
151         }
152
153         *pinfo3 = talloc_move(mem_ctx, &info3);
154
155         TALLOC_FREE(p);
156         return NT_STATUS_OK;
157 }
158
159 static NTSTATUS get_ldapi_ctx(TALLOC_CTX *mem_ctx, struct tldap_context **pld)
160 {
161         struct tldap_context *ld;
162         struct sockaddr_un addr;
163         char *sockaddr;
164         int fd;
165         NTSTATUS status;
166         int res;
167
168         sockaddr = talloc_asprintf(talloc_tos(), "/%s/ldap_priv/ldapi",
169                                    lp_private_dir());
170         if (sockaddr == NULL) {
171                 DEBUG(10, ("talloc failed\n"));
172                 return NT_STATUS_NO_MEMORY;
173         }
174
175         ZERO_STRUCT(addr);
176         addr.sun_family = AF_UNIX;
177         strncpy(addr.sun_path, sockaddr, sizeof(addr.sun_path));
178         TALLOC_FREE(sockaddr);
179
180         status = open_socket_out((struct sockaddr_storage *)(void *)&addr,
181                                  0, 0, &fd);
182         if (!NT_STATUS_IS_OK(status)) {
183                 DEBUG(10, ("Could not connect to %s: %s\n", addr.sun_path,
184                            nt_errstr(status)));
185                 return status;
186         }
187         set_blocking(fd, false);
188
189         ld = tldap_context_create(mem_ctx, fd);
190         if (ld == NULL) {
191                 close(fd);
192                 return NT_STATUS_NO_MEMORY;
193         }
194         res = tldap_fetch_rootdse(ld);
195         if (res != TLDAP_SUCCESS) {
196                 DEBUG(10, ("tldap_fetch_rootdse failed: %s\n",
197                            tldap_errstr(talloc_tos(), ld, res)));
198                 TALLOC_FREE(ld);
199                 return NT_STATUS_LDAP(res);
200         }
201         *pld = ld;
202         return NT_STATUS_OK;;
203 }
204
205 static NTSTATUS mymachinepw(uint8_t pwd[16])
206 {
207         TALLOC_CTX *frame = talloc_stackframe();
208         struct tldap_context *ld;
209         struct tldap_message *rootdse, **msg;
210         const char *attrs[1] = { "unicodePwd" };
211         char *default_nc, *myname;
212         int rc, num_msg;
213         DATA_BLOB pwdblob;
214         NTSTATUS status;
215
216         status = get_ldapi_ctx(talloc_tos(), &ld);
217         if (!NT_STATUS_IS_OK(status)) {
218                 goto fail;
219         }
220         rootdse = tldap_rootdse(ld);
221         if (rootdse == NULL) {
222                 DEBUG(10, ("Could not get rootdse\n"));
223                 status = NT_STATUS_INTERNAL_ERROR;
224                 goto fail;
225         }
226         default_nc = tldap_talloc_single_attribute(
227                 rootdse, "defaultNamingContext", talloc_tos());
228         if (default_nc == NULL) {
229                 DEBUG(10, ("Could not get defaultNamingContext\n"));
230                 status = NT_STATUS_NO_MEMORY;
231                 goto fail;
232         }
233         DEBUG(10, ("default_nc = %s\n", default_nc));
234
235         myname = talloc_asprintf_strupper_m(talloc_tos(), "%s$",
236                                             global_myname());
237         if (myname == NULL) {
238                 DEBUG(10, ("talloc failed\n"));
239                 status = NT_STATUS_NO_MEMORY;
240                 goto fail;
241         }
242
243         rc = tldap_search_fmt(
244                 ld, default_nc, TLDAP_SCOPE_SUB, attrs, ARRAY_SIZE(attrs), 0,
245                 talloc_tos(), &msg,
246                 "(&(sAMAccountName=%s)(objectClass=computer))", myname);
247         if (rc != TLDAP_SUCCESS) {
248                 DEBUG(10, ("Could not retrieve our account: %s\n",
249                            tldap_errstr(talloc_tos(), ld, rc)));
250                 status = NT_STATUS_LDAP(rc);
251                 goto fail;
252         }
253         num_msg = talloc_array_length(msg);
254         if (num_msg != 1) {
255                 DEBUG(10, ("Got %d accounts, expected one\n", num_msg));
256                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
257                 goto fail;
258         }
259         if (!tldap_get_single_valueblob(msg[0], "unicodePwd", &pwdblob)) {
260                 char *dn = NULL;
261                 tldap_entry_dn(msg[0], &dn);
262                 DEBUG(10, ("No unicodePwd attribute in %s\n",
263                            dn ? dn : "<unknown DN>"));
264                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
265                 goto fail;
266         }
267         if (pwdblob.length != 16) {
268                 DEBUG(10, ("Password hash hash has length %d, expected 16\n",
269                            (int)pwdblob.length));
270                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
271                 goto fail;
272         }
273         memcpy(pwd, pwdblob.data, 16);
274
275 fail:
276         TALLOC_FREE(frame);
277         return status;
278 }
279
280 static NTSTATUS check_netlogond_security(const struct auth_context *auth_context,
281                                          void *my_private_data,
282                                          TALLOC_CTX *mem_ctx,
283                                          const struct auth_usersupplied_info *user_info,
284                                          struct auth_serversupplied_info **server_info)
285 {
286         TALLOC_CTX *frame = talloc_stackframe();
287         struct netr_SamInfo3 *info3 = NULL;
288         struct rpc_pipe_client *p = NULL;
289         struct pipe_auth_data *auth = NULL;
290         uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
291         uint8_t machine_password[16];
292         struct netlogon_creds_CredentialState *creds;
293         NTSTATUS schannel_bind_result, status;
294         struct named_mutex *mutex = NULL;
295         const char *ncalrpcsock;
296
297         DEBUG(10, ("Check auth for: [%s]\n", user_info->mapped.account_name));
298
299         ncalrpcsock = lp_parm_const_string(
300                 GLOBAL_SECTION_SNUM, "auth_netlogond", "socket", NULL);
301
302         if (ncalrpcsock == NULL) {
303                 ncalrpcsock = talloc_asprintf(talloc_tos(), "%s/%s",
304                                               get_dyn_NCALRPCDIR(), "DEFAULT");
305         }
306
307         if (ncalrpcsock == NULL) {
308                 status = NT_STATUS_NO_MEMORY;
309                 goto done;
310         }
311
312         creds = secrets_fetch_local_schannel_creds(talloc_tos());
313         if (creds == NULL) {
314                 goto new_key;
315         }
316
317         status = netlogond_validate(talloc_tos(), auth_context, ncalrpcsock,
318                                     creds, user_info, &info3,
319                                     &schannel_bind_result);
320
321         DEBUG(10, ("netlogond_validate returned %s\n", nt_errstr(status)));
322
323         if (NT_STATUS_IS_OK(status)) {
324                 goto okay;
325         }
326
327         if (NT_STATUS_IS_OK(schannel_bind_result)) {
328                 /*
329                  * This is a real failure from the DC
330                  */
331                 goto done;
332         }
333
334  new_key:
335
336         mutex = grab_named_mutex(talloc_tos(), "LOCAL_SCHANNEL_KEY", 60);
337         if (mutex == NULL) {
338                 DEBUG(10, ("Could not get mutex LOCAL_SCHANNEL_KEY\n"));
339                 status = NT_STATUS_ACCESS_DENIED;
340                 goto done;
341         }
342
343         DEBUG(10, ("schannel bind failed, setting up new key\n"));
344
345         status = rpc_pipe_open_ncalrpc(talloc_tos(), ncalrpcsock,
346                                        &ndr_table_netlogon.syntax_id, &p);
347
348         if (!NT_STATUS_IS_OK(status)) {
349                 DEBUG(10, ("rpc_pipe_open_ncalrpc failed: %s\n",
350                            nt_errstr(status)));
351                 goto done;
352         }
353
354         status = rpccli_anon_bind_data(p, &auth);
355         if (!NT_STATUS_IS_OK(status)) {
356                 DEBUG(10, ("rpccli_anon_bind_data failed: %s\n",
357                            nt_errstr(status)));
358                 goto done;
359         }
360
361         status = rpc_pipe_bind(p, auth);
362         if (!NT_STATUS_IS_OK(status)) {
363                 DEBUG(10, ("rpc_pipe_bind failed: %s\n", nt_errstr(status)));
364                 goto done;
365         }
366
367         status = mymachinepw(machine_password);
368         if (!NT_STATUS_IS_OK(status)) {
369                 DEBUG(10, ("mymachinepw failed: %s\n", nt_errstr(status)));
370                 goto done;
371         }
372
373         DEBUG(10, ("machinepw "));
374         dump_data(10, machine_password, 16);
375
376         status = rpccli_netlogon_setup_creds(
377                 p, global_myname(), lp_workgroup(), global_myname(),
378                 global_myname(), machine_password, SEC_CHAN_BDC, &neg_flags);
379
380         if (!NT_STATUS_IS_OK(status)) {
381                 DEBUG(10, ("rpccli_netlogon_setup_creds failed: %s\n",
382                            nt_errstr(status)));
383                 goto done;
384         }
385
386         secrets_store_local_schannel_creds(p->dc);
387
388         /*
389          * Retry the authentication with the mutex held. This way nobody else
390          * can step on our toes.
391          */
392
393         status = netlogond_validate(talloc_tos(), auth_context, ncalrpcsock,
394                                     p->dc, user_info, &info3,
395                                     &schannel_bind_result);
396
397         TALLOC_FREE(p);
398
399         DEBUG(10, ("netlogond_validate returned %s\n", nt_errstr(status)));
400
401         if (!NT_STATUS_IS_OK(status)) {
402                 goto done;
403         }
404
405  okay:
406
407         status = make_server_info_info3(mem_ctx, user_info->client.account_name,
408                                         user_info->mapped.domain_name, server_info,
409                                         info3);
410         if (!NT_STATUS_IS_OK(status)) {
411                 DEBUG(10, ("make_server_info_info3 failed: %s\n",
412                            nt_errstr(status)));
413                 TALLOC_FREE(frame);
414                 return status;
415         }
416
417         status = NT_STATUS_OK;
418
419  done:
420         TALLOC_FREE(frame);
421         return status;
422 }
423
424 /* module initialisation */
425 static NTSTATUS auth_init_netlogond(struct auth_context *auth_context,
426                                     const char *param,
427                                     auth_methods **auth_method)
428 {
429         struct auth_methods *result;
430
431         result = TALLOC_ZERO_P(auth_context, struct auth_methods);
432         if (result == NULL) {
433                 return NT_STATUS_NO_MEMORY;
434         }
435         result->name = "netlogond";
436         result->auth = check_netlogond_security;
437
438         *auth_method = result;
439         return NT_STATUS_OK;
440 }
441
442 NTSTATUS auth_netlogond_init(void)
443 {
444         smb_register_auth(AUTH_INTERFACE_VERSION, "netlogond",
445                           auth_init_netlogond);
446         return NT_STATUS_OK;
447 }