CVE-2016-2111: s4:smb_server: implement "raw NTLMv2 auth" checks
[samba.git] / source4 / smb_server / smb / sesssetup.c
1
2 /* 
3    Unix SMB/CIFS implementation.
4    handle SMBsessionsetup
5    Copyright (C) Andrew Tridgell                      1998-2001
6    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2001-2005
7    Copyright (C) Jim McDonough                        2002
8    Copyright (C) Luke Howard                          2003
9    Copyright (C) Stefan Metzmacher                    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 <tevent.h>
27 #include "version.h"
28 #include "auth/gensec/gensec.h"
29 #include "auth/auth.h"
30 #include "smb_server/smb_server.h"
31 #include "smbd/service_stream.h"
32 #include "param/param.h"
33 #include "../lib/tsocket/tsocket.h"
34 #include "lib/stream/packet.h"
35
36 struct sesssetup_context {
37         struct auth4_context *auth_context;
38         struct smbsrv_request *req;
39 };
40
41 /*
42   setup the OS, Lanman and domain portions of a session setup reply
43 */
44 static void sesssetup_common_strings(struct smbsrv_request *req,
45                                      char **os, char **lanman, char **domain)
46 {
47         (*os) = talloc_asprintf(req, "Unix");
48         (*lanman) = talloc_asprintf(req, "Samba %s", SAMBA_VERSION_STRING);
49         (*domain) = talloc_asprintf(req, "%s", 
50                                     lpcfg_workgroup(req->smb_conn->lp_ctx));
51 }
52
53 static void smbsrv_sesssetup_backend_send(struct smbsrv_request *req,
54                                           union smb_sesssetup *sess,
55                                           NTSTATUS status)
56 {
57         if (NT_STATUS_IS_OK(status)) {
58                 req->smb_conn->negotiate.done_sesssetup = true;
59                 /* we need to keep the session long term */
60                 req->session = talloc_steal(req->smb_conn, req->session);
61         }
62         smbsrv_reply_sesssetup_send(req, sess, status);
63 }
64
65 static void sesssetup_old_send(struct tevent_req *subreq)
66 {
67         struct sesssetup_context *state = tevent_req_callback_data(subreq, struct sesssetup_context);
68         struct smbsrv_request *req = state->req;
69
70         union smb_sesssetup *sess = talloc_get_type(req->io_ptr, union smb_sesssetup);
71         struct auth_user_info_dc *user_info_dc = NULL;
72         struct auth_session_info *session_info;
73         struct smbsrv_session *smb_sess;
74         NTSTATUS status;
75         uint32_t flags;
76
77         status = auth_check_password_recv(subreq, req, &user_info_dc);
78         TALLOC_FREE(subreq);
79         if (!NT_STATUS_IS_OK(status)) goto failed;
80
81         flags = AUTH_SESSION_INFO_DEFAULT_GROUPS;
82         if (user_info_dc->info->authenticated) {
83                 flags |= AUTH_SESSION_INFO_AUTHENTICATED;
84         }
85         /* This references user_info_dc into session_info */
86         status = req->smb_conn->negotiate.auth_context->generate_session_info(req->smb_conn->negotiate.auth_context,
87                                                                               req,
88                                                                               user_info_dc, sess->old.in.user, 
89                                                                               flags, &session_info);
90         if (!NT_STATUS_IS_OK(status)) goto failed;
91
92         /* allocate a new session */
93         smb_sess = smbsrv_session_new(req->smb_conn, req, NULL);
94         if (!smb_sess) {
95                 status = NT_STATUS_INSUFFICIENT_RESOURCES;
96                 goto failed;
97         }
98
99         /* Ensure this is marked as a 'real' vuid, not one
100          * simply valid for the session setup leg */
101         status = smbsrv_session_sesssetup_finished(smb_sess, session_info);
102         if (!NT_STATUS_IS_OK(status)) goto failed;
103
104         /* To correctly process any AndX packet (like a tree connect)
105          * we need to fill in the session on the request here */
106         req->session = smb_sess;
107         sess->old.out.vuid = smb_sess->vuid;
108
109 failed:
110         status = nt_status_squash(status);
111         smbsrv_sesssetup_backend_send(req, sess, status);
112 }
113
114 /*
115   handler for old style session setup
116 */
117 static void sesssetup_old(struct smbsrv_request *req, union smb_sesssetup *sess)
118 {
119         struct auth_usersupplied_info *user_info = NULL;
120         struct tsocket_address *remote_address;
121         const char *remote_machine = NULL;
122         struct tevent_req *subreq;
123         struct sesssetup_context *state;
124
125         sess->old.out.vuid = 0;
126         sess->old.out.action = 0;
127
128         sesssetup_common_strings(req, 
129                                  &sess->old.out.os,
130                                  &sess->old.out.lanman,
131                                  &sess->old.out.domain);
132
133         if (!req->smb_conn->negotiate.done_sesssetup) {
134                 req->smb_conn->negotiate.max_send = sess->old.in.bufsize;
135         }
136
137         if (req->smb_conn->negotiate.calling_name) {
138                 remote_machine = req->smb_conn->negotiate.calling_name->name;
139         }
140         
141         remote_address = socket_get_remote_addr(req->smb_conn->connection->socket, req);
142         if (!remote_address) goto nomem;
143
144         if (!remote_machine) {
145                 remote_machine = tsocket_address_inet_addr_string(remote_address, req);
146                 if (!remote_machine) goto nomem;
147         }
148
149         user_info = talloc_zero(req, struct auth_usersupplied_info);
150         if (!user_info) goto nomem;
151         
152         user_info->mapped_state = false;
153         user_info->logon_parameters = 0;
154         user_info->flags = 0;
155         user_info->client.account_name = sess->old.in.user;
156         user_info->client.domain_name = sess->old.in.domain;
157         user_info->workstation_name = remote_machine;
158         user_info->remote_host = talloc_steal(user_info, remote_address);
159         
160         user_info->password_state = AUTH_PASSWORD_RESPONSE;
161         user_info->password.response.lanman = sess->old.in.password;
162         user_info->password.response.lanman.data = talloc_steal(user_info, sess->old.in.password.data);
163         user_info->password.response.nt = data_blob(NULL, 0);
164
165         state = talloc(req, struct sesssetup_context);
166         if (!state) goto nomem;
167
168         if (req->smb_conn->negotiate.auth_context) {
169                 state->auth_context = req->smb_conn->negotiate.auth_context;
170         } else {
171                 /* TODO: should we use just "anonymous" here? */
172                 NTSTATUS status = auth_context_create(state,
173                                                       req->smb_conn->connection->event.ctx,
174                                                       req->smb_conn->connection->msg_ctx,
175                                                       req->smb_conn->lp_ctx,
176                                                       &state->auth_context);
177                 if (!NT_STATUS_IS_OK(status)) {
178                         smbsrv_sesssetup_backend_send(req, sess, status);
179                         return;
180                 }
181         }
182
183         state->req = req;
184
185         subreq = auth_check_password_send(state,
186                                           req->smb_conn->connection->event.ctx,
187                                           req->smb_conn->negotiate.auth_context,
188                                           user_info);
189         if (!subreq) goto nomem;
190         tevent_req_set_callback(subreq, sesssetup_old_send, state);
191         return;
192
193 nomem:
194         smbsrv_sesssetup_backend_send(req, sess, NT_STATUS_NO_MEMORY);
195 }
196
197 static void sesssetup_nt1_send(struct tevent_req *subreq)
198 {
199         struct sesssetup_context *state = tevent_req_callback_data(subreq, struct sesssetup_context);
200         struct smbsrv_request *req = state->req;
201         union smb_sesssetup *sess = talloc_get_type(req->io_ptr, union smb_sesssetup);
202         struct auth_user_info_dc *user_info_dc = NULL;
203         struct auth_session_info *session_info;
204         struct smbsrv_session *smb_sess;
205
206         uint32_t flags;
207         NTSTATUS status;
208
209         status = auth_check_password_recv(subreq, req, &user_info_dc);
210         TALLOC_FREE(subreq);
211         if (!NT_STATUS_IS_OK(status)) goto failed;
212
213         flags = AUTH_SESSION_INFO_DEFAULT_GROUPS;
214         if (user_info_dc->info->authenticated) {
215                 flags |= AUTH_SESSION_INFO_AUTHENTICATED;
216         }
217         /* This references user_info_dc into session_info */
218         status = state->auth_context->generate_session_info(state->auth_context,
219                                                             req,
220                                                             user_info_dc,
221                                                             sess->nt1.in.user,
222                                                             flags,
223                                                             &session_info);
224         if (!NT_STATUS_IS_OK(status)) goto failed;
225
226         /* allocate a new session */
227         smb_sess = smbsrv_session_new(req->smb_conn, req, NULL);
228         if (!smb_sess) {
229                 status = NT_STATUS_INSUFFICIENT_RESOURCES;
230                 goto failed;
231         }
232
233         /* Ensure this is marked as a 'real' vuid, not one
234          * simply valid for the session setup leg */
235         status = smbsrv_session_sesssetup_finished(smb_sess, session_info);
236         if (!NT_STATUS_IS_OK(status)) goto failed;
237
238         /* To correctly process any AndX packet (like a tree connect)
239          * we need to fill in the session on the request here */
240         req->session = smb_sess;
241         sess->nt1.out.vuid = smb_sess->vuid;
242
243         if (!smbsrv_setup_signing(req->smb_conn, &session_info->session_key, &sess->nt1.in.password2)) {
244                 /* Already signing, or disabled */
245                 goto done;
246         }
247
248 done:
249         status = NT_STATUS_OK;
250 failed:
251         status = nt_status_squash(status);
252         smbsrv_sesssetup_backend_send(req, sess, status);
253 }
254
255 /*
256   handler for NT1 style session setup
257 */
258 static void sesssetup_nt1(struct smbsrv_request *req, union smb_sesssetup *sess)
259 {
260         NTSTATUS status;
261         struct auth_usersupplied_info *user_info = NULL;
262         struct tsocket_address *remote_address;
263         const char *remote_machine = NULL;
264         struct tevent_req *subreq;
265         struct sesssetup_context *state;
266         bool allow_raw = lpcfg_raw_ntlmv2_auth(req->smb_conn->lp_ctx);
267
268         sess->nt1.out.vuid = 0;
269         sess->nt1.out.action = 0;
270
271         sesssetup_common_strings(req, 
272                                  &sess->nt1.out.os,
273                                  &sess->nt1.out.lanman,
274                                  &sess->nt1.out.domain);
275
276         if (!req->smb_conn->negotiate.done_sesssetup) {
277                 req->smb_conn->negotiate.max_send = sess->nt1.in.bufsize;
278                 req->smb_conn->negotiate.client_caps = sess->nt1.in.capabilities;
279         }
280
281         state = talloc(req, struct sesssetup_context);
282         if (!state) goto nomem;
283
284         state->req = req;
285
286         if (req->smb_conn->negotiate.oid) {
287                 if (sess->nt1.in.user && *sess->nt1.in.user) {
288                         /* We can't accept a normal login, because we
289                          * don't have a challenge */
290                         status = NT_STATUS_LOGON_FAILURE;
291                         goto failed;
292                 }
293
294                 /* TODO: should we use just "anonymous" here? */
295                 status = auth_context_create(state,
296                                              req->smb_conn->connection->event.ctx,
297                                              req->smb_conn->connection->msg_ctx,
298                                              req->smb_conn->lp_ctx,
299                                              &state->auth_context);
300                 if (!NT_STATUS_IS_OK(status)) goto failed;
301         } else if (req->smb_conn->negotiate.auth_context) {
302                 state->auth_context = req->smb_conn->negotiate.auth_context;
303         } else {
304                 /* TODO: should we use just "anonymous" here? */
305                 status = auth_context_create(state,
306                                              req->smb_conn->connection->event.ctx,
307                                              req->smb_conn->connection->msg_ctx,
308                                              req->smb_conn->lp_ctx,
309                                              &state->auth_context);
310                 if (!NT_STATUS_IS_OK(status)) goto failed;
311         }
312
313         if (req->smb_conn->negotiate.calling_name) {
314                 remote_machine = req->smb_conn->negotiate.calling_name->name;
315         }
316
317         remote_address = socket_get_remote_addr(req->smb_conn->connection->socket, req);
318         if (!remote_address) goto nomem;
319
320         if (!remote_machine) {
321                 remote_machine = tsocket_address_inet_addr_string(remote_address, req);
322                 if (!remote_machine) goto nomem;
323         }
324
325         user_info = talloc_zero(req, struct auth_usersupplied_info);
326         if (!user_info) goto nomem;
327
328         user_info->mapped_state = false;
329         user_info->logon_parameters = 0;
330         user_info->flags = 0;
331         user_info->client.account_name = sess->nt1.in.user;
332         user_info->client.domain_name = sess->nt1.in.domain;
333         user_info->workstation_name = remote_machine;
334         user_info->remote_host = talloc_steal(user_info, remote_address);
335         
336         user_info->password_state = AUTH_PASSWORD_RESPONSE;
337         user_info->password.response.lanman = sess->nt1.in.password1;
338         user_info->password.response.lanman.data = talloc_steal(user_info, sess->nt1.in.password1.data);
339         user_info->password.response.nt = sess->nt1.in.password2;
340         user_info->password.response.nt.data = talloc_steal(user_info, sess->nt1.in.password2.data);
341
342         if (!allow_raw && user_info->password.response.nt.length >= 48) {
343                 /*
344                  * NTLMv2_RESPONSE has at least 48 bytes
345                  * and should only be supported via NTLMSSP.
346                  */
347                 status = NT_STATUS_INVALID_PARAMETER;
348                 goto failed;
349         }
350
351         subreq = auth_check_password_send(state,
352                                           req->smb_conn->connection->event.ctx,
353                                           state->auth_context,
354                                           user_info);
355         if (!subreq) goto nomem;
356         tevent_req_set_callback(subreq, sesssetup_nt1_send, state);
357
358         return;
359
360 nomem:
361         status = NT_STATUS_NO_MEMORY;
362 failed:
363         status = nt_status_squash(status);
364         smbsrv_sesssetup_backend_send(req, sess, status);
365 }
366
367 struct sesssetup_spnego_state {
368         struct smbsrv_request *req;
369         union smb_sesssetup *sess;
370         struct smbsrv_session *smb_sess;
371 };
372
373 static void sesssetup_spnego_send(struct tevent_req *subreq)
374 {
375         struct sesssetup_spnego_state *s = tevent_req_callback_data(subreq,
376                                            struct sesssetup_spnego_state);
377         struct smbsrv_request *req = s->req;
378         union smb_sesssetup *sess = s->sess;
379         struct smbsrv_session *smb_sess = s->smb_sess;
380         struct auth_session_info *session_info = NULL;
381         NTSTATUS status;
382         NTSTATUS skey_status;
383         DATA_BLOB session_key;
384
385         status = gensec_update_recv(subreq, req, &sess->spnego.out.secblob);
386         packet_recv_enable(req->smb_conn->packet);
387         TALLOC_FREE(subreq);
388         if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
389                 goto done;
390         } else if (!NT_STATUS_IS_OK(status)) {
391                 goto failed;
392         }
393
394         status = gensec_session_info(smb_sess->gensec_ctx, smb_sess, &session_info);
395         if (!NT_STATUS_IS_OK(status)) goto failed;
396
397         /* The session_key is only needed until the end of the smbsrv_setup_signing() call */
398         skey_status = gensec_session_key(smb_sess->gensec_ctx, req, &session_key);
399         if (NT_STATUS_IS_OK(skey_status)) {
400                 smbsrv_setup_signing(req->smb_conn, &session_key, NULL);
401         }
402
403         /* Ensure this is marked as a 'real' vuid, not one
404          * simply valid for the session setup leg */
405         status = smbsrv_session_sesssetup_finished(smb_sess, session_info);
406         if (!NT_STATUS_IS_OK(status)) goto failed;
407
408         req->session = smb_sess;
409
410 done:
411         sess->spnego.out.vuid = smb_sess->vuid;
412 failed:
413         status = nt_status_squash(status);
414         smbsrv_sesssetup_backend_send(req, sess, status);
415         if (!NT_STATUS_IS_OK(status) && 
416             !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
417                 talloc_free(smb_sess);
418         }
419 }
420
421 /*
422   handler for SPNEGO style session setup
423 */
424 static void sesssetup_spnego(struct smbsrv_request *req, union smb_sesssetup *sess)
425 {
426         NTSTATUS status;
427         struct smbsrv_session *smb_sess = NULL;
428         bool is_smb_sess_new = false;
429         struct sesssetup_spnego_state *s = NULL;
430         uint16_t vuid;
431         struct tevent_req *subreq;
432
433         sess->spnego.out.vuid = 0;
434         sess->spnego.out.action = 0;
435
436         sesssetup_common_strings(req, 
437                                  &sess->spnego.out.os,
438                                  &sess->spnego.out.lanman,
439                                  &sess->spnego.out.workgroup);
440
441         if (!req->smb_conn->negotiate.done_sesssetup) {
442                 req->smb_conn->negotiate.max_send = sess->spnego.in.bufsize;
443                 req->smb_conn->negotiate.client_caps = sess->spnego.in.capabilities;
444         }
445
446         vuid = SVAL(req->in.hdr,HDR_UID);
447
448         /* lookup an existing session */
449         if (vuid == 0) {
450                 struct gensec_security *gensec_ctx;
451
452                 status = samba_server_gensec_start(req,
453                                                    req->smb_conn->connection->event.ctx,
454                                                    req->smb_conn->connection->msg_ctx,
455                                                    req->smb_conn->lp_ctx,
456                                                    req->smb_conn->negotiate.server_credentials,
457                                                    "cifs",
458                                                    &gensec_ctx);
459                 if (!NT_STATUS_IS_OK(status)) {
460                         DEBUG(1, ("Failed to start GENSEC server code: %s\n", nt_errstr(status)));
461                         goto failed;
462                 }
463
464                 gensec_want_feature(gensec_ctx, GENSEC_FEATURE_SESSION_KEY);
465
466                 status = gensec_start_mech_by_oid(gensec_ctx, req->smb_conn->negotiate.oid);
467                 if (!NT_STATUS_IS_OK(status)) {
468                         DEBUG(1, ("Failed to start GENSEC %s server code: %s\n", 
469                                   gensec_get_name_by_oid(gensec_ctx, req->smb_conn->negotiate.oid), nt_errstr(status)));
470                         goto failed;
471                 }
472
473                 /* allocate a new session */
474                 smb_sess = smbsrv_session_new(req->smb_conn, req->smb_conn, gensec_ctx);
475                 if (!smb_sess) {
476                         status = NT_STATUS_INSUFFICIENT_RESOURCES;
477                         goto failed;
478                 }
479                 is_smb_sess_new = true;
480         } else {
481                 smb_sess = smbsrv_session_find_sesssetup(req->smb_conn, vuid);
482         }
483
484         if (!smb_sess) {
485                 status = NT_STATUS_DOS(ERRSRV, ERRbaduid);
486                 goto failed;
487         }
488
489         if (smb_sess->session_info) {
490                 status = NT_STATUS_INVALID_PARAMETER;
491                 goto failed;
492         }
493
494         if (!smb_sess->gensec_ctx) {
495                 status = NT_STATUS_INTERNAL_ERROR;
496                 DEBUG(1, ("Internal ERROR: no gensec_ctx on session: %s\n", nt_errstr(status)));
497                 goto failed;
498         }
499
500         s = talloc(req, struct sesssetup_spnego_state);
501         if (!s) goto nomem;
502         s->req          = req;
503         s->sess         = sess;
504         s->smb_sess     = smb_sess;
505
506         subreq = gensec_update_send(s,
507                                     req->smb_conn->connection->event.ctx,
508                                     smb_sess->gensec_ctx,
509                                     sess->spnego.in.secblob);
510         if (!subreq) {
511                 goto nomem;
512         }
513         /* disable receipt of more packets on this socket until we've
514            finished with the session setup. This avoids a problem with
515            crashes if we get EOF on the socket while processing a session
516            setup */
517         packet_recv_disable(req->smb_conn->packet);
518         tevent_req_set_callback(subreq, sesssetup_spnego_send, s);
519
520         return;
521
522 nomem:
523         status = NT_STATUS_NO_MEMORY;
524 failed:
525         if (is_smb_sess_new) {
526                 talloc_free(smb_sess);
527         }
528         status = nt_status_squash(status);
529         smbsrv_sesssetup_backend_send(req, sess, status);
530 }
531
532 /*
533   backend for sessionsetup call - this takes all 3 variants of the call
534 */
535 void smbsrv_sesssetup_backend(struct smbsrv_request *req,
536                               union smb_sesssetup *sess)
537 {
538         switch (sess->old.level) {
539                 case RAW_SESSSETUP_OLD:
540                         sesssetup_old(req, sess);
541                         return;
542
543                 case RAW_SESSSETUP_NT1:
544                         sesssetup_nt1(req, sess);
545                         return;
546
547                 case RAW_SESSSETUP_SPNEGO:
548                         sesssetup_spnego(req, sess);
549                         return;
550
551                 case RAW_SESSSETUP_SMB2:
552                         break;
553         }
554
555         smbsrv_sesssetup_backend_send(req, sess, NT_STATUS_INVALID_LEVEL);
556 }