source: trunk/server/source3/smbd/sesssetup.c@ 888

Last change on this file since 888 was 862, checked in by Silvan Scherrer, 11 years ago

Samba Server: update trunk to 3.6.23

File size: 47.5 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3 handle SMBsessionsetup
4 Copyright (C) Andrew Tridgell 1998-2001
5 Copyright (C) Andrew Bartlett 2001
6 Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002
7 Copyright (C) Luke Howard 2003
8 Copyright (C) Volker Lendecke 2007
9 Copyright (C) Jeremy Allison 2007
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 "../lib/tsocket/tsocket.h"
27#include "smbd/smbd.h"
28#include "smbd/globals.h"
29#include "../libcli/auth/spnego.h"
30#include "../libcli/auth/ntlmssp.h"
31#include "ntlmssp_wrap.h"
32#include "../librpc/gen_ndr/krb5pac.h"
33#include "libads/kerberos_proto.h"
34#include "../lib/util/asn1.h"
35#include "auth.h"
36#include "messages.h"
37#include "smbprofile.h"
38
39/* For split krb5 SPNEGO blobs. */
40struct pending_auth_data {
41 struct pending_auth_data *prev, *next;
42 uint16 vuid; /* Tag for this entry. */
43 uint16 smbpid; /* Alternate tag for this entry. */
44 size_t needed_len;
45 DATA_BLOB partial_data;
46};
47
48/*
49 on a logon error possibly map the error to success if "map to guest"
50 is set approriately
51*/
52NTSTATUS do_map_to_guest(NTSTATUS status,
53 struct auth_serversupplied_info **server_info,
54 const char *user, const char *domain)
55{
56 user = user ? user : "";
57 domain = domain ? domain : "";
58
59 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
60 if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) ||
61 (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
62 DEBUG(3,("No such user %s [%s] - using guest account\n",
63 user, domain));
64 status = make_server_info_guest(NULL, server_info);
65 }
66 }
67
68 if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
69 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
70 DEBUG(3,("Registered username %s for guest access\n",
71 user));
72 status = make_server_info_guest(NULL, server_info);
73 }
74 }
75
76 return status;
77}
78
79/****************************************************************************
80 Add the standard 'Samba' signature to the end of the session setup.
81****************************************************************************/
82
83static int push_signature(uint8 **outbuf)
84{
85 char *lanman;
86 int result, tmp;
87
88 result = 0;
89
90#ifndef __OS2__
91 tmp = message_push_string(outbuf, "Unix", STR_TERMINATE);
92#else
93 tmp = message_push_string(outbuf, "eCS (OS/2)", STR_TERMINATE);
94#endif
95
96 if (tmp == -1) return -1;
97 result += tmp;
98
99 if (asprintf(&lanman, "Samba %s", samba_version_string()) != -1) {
100 tmp = message_push_string(outbuf, lanman, STR_TERMINATE);
101 SAFE_FREE(lanman);
102 }
103 else {
104 tmp = message_push_string(outbuf, "Samba", STR_TERMINATE);
105 }
106
107 if (tmp == -1) return -1;
108 result += tmp;
109
110 tmp = message_push_string(outbuf, lp_workgroup(), STR_TERMINATE);
111
112 if (tmp == -1) return -1;
113 result += tmp;
114
115 return result;
116}
117
118/****************************************************************************
119 Send a security blob via a session setup reply.
120****************************************************************************/
121
122static void reply_sesssetup_blob(struct smb_request *req,
123 DATA_BLOB blob,
124 NTSTATUS nt_status)
125{
126 if (!NT_STATUS_IS_OK(nt_status) &&
127 !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
128 reply_nterror(req, nt_status_squash(nt_status));
129 return;
130 }
131
132 nt_status = nt_status_squash(nt_status);
133 SIVAL(req->outbuf, smb_rcls, NT_STATUS_V(nt_status));
134 SSVAL(req->outbuf, smb_vwv0, 0xFF); /* no chaining possible */
135 SSVAL(req->outbuf, smb_vwv3, blob.length);
136
137 if ((message_push_blob(&req->outbuf, blob) == -1)
138 || (push_signature(&req->outbuf) == -1)) {
139 reply_nterror(req, NT_STATUS_NO_MEMORY);
140 }
141}
142
143/****************************************************************************
144 Do a 'guest' logon, getting back the
145****************************************************************************/
146
147static NTSTATUS check_guest_password(struct auth_serversupplied_info **server_info)
148{
149 struct auth_context *auth_context;
150 struct auth_usersupplied_info *user_info = NULL;
151
152 NTSTATUS nt_status;
153 static unsigned char chal[8] = { 0, };
154
155 DEBUG(3,("Got anonymous request\n"));
156
157 nt_status = make_auth_context_fixed(talloc_tos(), &auth_context, chal);
158 if (!NT_STATUS_IS_OK(nt_status)) {
159 return nt_status;
160 }
161
162 if (!make_user_info_guest(&user_info)) {
163 TALLOC_FREE(auth_context);
164 return NT_STATUS_NO_MEMORY;
165 }
166
167 nt_status = auth_context->check_ntlm_password(auth_context,
168 user_info,
169 server_info);
170 TALLOC_FREE(auth_context);
171 free_user_info(&user_info);
172 return nt_status;
173}
174
175
176#ifdef HAVE_KRB5
177
178#if 0
179/* Experiment that failed. See "only happens with a KDC" comment below. */
180/****************************************************************************
181 Cerate a clock skew error blob for a Windows client.
182****************************************************************************/
183
184static bool make_krb5_skew_error(DATA_BLOB *pblob_out)
185{
186 krb5_context context = NULL;
187 krb5_error_code kerr = 0;
188 krb5_data reply;
189 krb5_principal host_princ = NULL;
190 char *host_princ_s = NULL;
191 bool ret = False;
192
193 *pblob_out = data_blob_null;
194
195 initialize_krb5_error_table();
196 kerr = krb5_init_context(&context);
197 if (kerr) {
198 return False;
199 }
200 /* Create server principal. */
201 asprintf(&host_princ_s, "%s$@%s", global_myname(), lp_realm());
202 if (!host_princ_s) {
203 goto out;
204 }
205 strlower_m(host_princ_s);
206
207 kerr = smb_krb5_parse_name(context, host_princ_s, &host_princ);
208 if (kerr) {
209 DEBUG(10,("make_krb5_skew_error: smb_krb5_parse_name failed "
210 "for name %s: Error %s\n",
211 host_princ_s, error_message(kerr) ));
212 goto out;
213 }
214
215 kerr = smb_krb5_mk_error(context, KRB5KRB_AP_ERR_SKEW,
216 host_princ, &reply);
217 if (kerr) {
218 DEBUG(10,("make_krb5_skew_error: smb_krb5_mk_error "
219 "failed: Error %s\n",
220 error_message(kerr) ));
221 goto out;
222 }
223
224 *pblob_out = data_blob(reply.data, reply.length);
225 kerberos_free_data_contents(context,&reply);
226 ret = True;
227
228 out:
229
230 if (host_princ_s) {
231 SAFE_FREE(host_princ_s);
232 }
233 if (host_princ) {
234 krb5_free_principal(context, host_princ);
235 }
236 krb5_free_context(context);
237 return ret;
238}
239#endif
240
241/****************************************************************************
242 Reply to a session setup spnego negotiate packet for kerberos.
243****************************************************************************/
244
245static void reply_spnego_kerberos(struct smb_request *req,
246 DATA_BLOB *secblob,
247 const char *mechOID,
248 uint16 vuid,
249 bool *p_invalidate_vuid)
250{
251 TALLOC_CTX *mem_ctx;
252 DATA_BLOB ticket;
253 struct passwd *pw;
254 int sess_vuid = req->vuid;
255 NTSTATUS ret = NT_STATUS_OK;
256 DATA_BLOB ap_rep, ap_rep_wrapped, response;
257 struct auth_serversupplied_info *server_info = NULL;
258 DATA_BLOB session_key = data_blob_null;
259 uint8 tok_id[2];
260 DATA_BLOB nullblob = data_blob_null;
261 bool map_domainuser_to_guest = False;
262 bool username_was_mapped;
263 struct PAC_LOGON_INFO *logon_info = NULL;
264 struct smbd_server_connection *sconn = req->sconn;
265 char *principal;
266 char *user;
267 char *domain;
268 char *real_username;
269
270 ZERO_STRUCT(ticket);
271 ZERO_STRUCT(ap_rep);
272 ZERO_STRUCT(ap_rep_wrapped);
273 ZERO_STRUCT(response);
274
275 /* Normally we will always invalidate the intermediate vuid. */
276 *p_invalidate_vuid = True;
277
278 mem_ctx = talloc_init("reply_spnego_kerberos");
279 if (mem_ctx == NULL) {
280 reply_nterror(req, nt_status_squash(NT_STATUS_NO_MEMORY));
281 return;
282 }
283
284 if (!spnego_parse_krb5_wrap(mem_ctx, *secblob, &ticket, tok_id)) {
285 talloc_destroy(mem_ctx);
286 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
287 return;
288 }
289
290 ret = ads_verify_ticket(mem_ctx, lp_realm(), 0, &ticket,
291 &principal, &logon_info, &ap_rep,
292 &session_key, True);
293
294 data_blob_free(&ticket);
295
296 if (!NT_STATUS_IS_OK(ret)) {
297#if 0
298 /* Experiment that failed.
299 * See "only happens with a KDC" comment below. */
300
301 if (NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
302
303 /*
304 * Windows in this case returns
305 * NT_STATUS_MORE_PROCESSING_REQUIRED
306 * with a negTokenTarg blob containing an krb5_error
307 * struct ASN1 encoded containing KRB5KRB_AP_ERR_SKEW.
308 * The client then fixes its clock and continues rather
309 * than giving an error. JRA.
310 * -- Looks like this only happens with a KDC. JRA.
311 */
312
313 bool ok = make_krb5_skew_error(&ap_rep);
314 if (!ok) {
315 talloc_destroy(mem_ctx);
316 return ERROR_NT(nt_status_squash(
317 NT_STATUS_LOGON_FAILURE));
318 }
319 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
320 TOK_ID_KRB_ERROR);
321 response = spnego_gen_auth_response(&ap_rep_wrapped,
322 ret, OID_KERBEROS5_OLD);
323 reply_sesssetup_blob(conn, inbuf, outbuf, response,
324 NT_STATUS_MORE_PROCESSING_REQUIRED);
325
326 /*
327 * In this one case we don't invalidate the
328 * intermediate vuid as we're expecting the client
329 * to re-use it for the next sessionsetupX packet. JRA.
330 */
331
332 *p_invalidate_vuid = False;
333
334 data_blob_free(&ap_rep);
335 data_blob_free(&ap_rep_wrapped);
336 data_blob_free(&response);
337 talloc_destroy(mem_ctx);
338 return -1; /* already replied */
339 }
340#else
341 if (!NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
342 ret = NT_STATUS_LOGON_FAILURE;
343 }
344#endif
345 DEBUG(1,("Failed to verify incoming ticket with error %s!\n",
346 nt_errstr(ret)));
347 talloc_destroy(mem_ctx);
348 reply_nterror(req, nt_status_squash(ret));
349 return;
350 }
351
352 ret = get_user_from_kerberos_info(talloc_tos(),
353 sconn->client_id.name,
354 principal, logon_info,
355 &username_was_mapped,
356 &map_domainuser_to_guest,
357 &user, &domain,
358 &real_username, &pw);
359 if (!NT_STATUS_IS_OK(ret)) {
360 data_blob_free(&ap_rep);
361 data_blob_free(&session_key);
362 talloc_destroy(mem_ctx);
363 reply_nterror(req,nt_status_squash(NT_STATUS_LOGON_FAILURE));
364 return;
365 }
366
367 /* save the PAC data if we have it */
368 if (logon_info) {
369 netsamlogon_cache_store(user, &logon_info->info3);
370 }
371
372 /* setup the string used by %U */
373 sub_set_smb_name(real_username);
374
375 /* reload services so that the new %U is taken into account */
376 reload_services(sconn->msg_ctx, sconn->sock, True);
377
378 ret = make_server_info_krb5(mem_ctx,
379 user, domain, real_username, pw,
380 logon_info, map_domainuser_to_guest,
381 &server_info);
382 if (!NT_STATUS_IS_OK(ret)) {
383 DEBUG(1, ("make_server_info_krb5 failed!\n"));
384 data_blob_free(&ap_rep);
385 data_blob_free(&session_key);
386 TALLOC_FREE(mem_ctx);
387 reply_nterror(req, nt_status_squash(ret));
388 return;
389 }
390
391 server_info->nss_token |= username_was_mapped;
392
393 /* we need to build the token for the user. make_server_info_guest()
394 already does this */
395
396 if ( !server_info->security_token ) {
397 ret = create_local_token( server_info );
398 if ( !NT_STATUS_IS_OK(ret) ) {
399 DEBUG(10,("failed to create local token: %s\n",
400 nt_errstr(ret)));
401 data_blob_free(&ap_rep);
402 data_blob_free(&session_key);
403 TALLOC_FREE( mem_ctx );
404 TALLOC_FREE( server_info );
405 reply_nterror(req, nt_status_squash(ret));
406 return;
407 }
408 }
409
410 if (!is_partial_auth_vuid(sconn, sess_vuid)) {
411 sess_vuid = register_initial_vuid(sconn);
412 }
413
414 data_blob_free(&server_info->user_session_key);
415 /* Set the kerberos-derived session key onto the server_info */
416 server_info->user_session_key = session_key;
417 talloc_steal(server_info, session_key.data);
418
419 session_key = data_blob_null;
420
421 /* register_existing_vuid keeps the server info */
422 /* register_existing_vuid takes ownership of session_key on success,
423 * no need to free after this on success. A better interface would copy
424 * it.... */
425
426 sess_vuid = register_existing_vuid(sconn, sess_vuid,
427 server_info, nullblob, user);
428
429 reply_outbuf(req, 4, 0);
430 SSVAL(req->outbuf,smb_uid,sess_vuid);
431
432 if (sess_vuid == UID_FIELD_INVALID ) {
433 ret = NT_STATUS_LOGON_FAILURE;
434 } else {
435 /* current_user_info is changed on new vuid */
436 reload_services(sconn->msg_ctx, sconn->sock, True);
437
438 SSVAL(req->outbuf, smb_vwv3, 0);
439
440 if (server_info->guest) {
441 SSVAL(req->outbuf,smb_vwv2,1);
442 }
443
444 SSVAL(req->outbuf, smb_uid, sess_vuid);
445
446 /* Successful logon. Keep this vuid. */
447 *p_invalidate_vuid = False;
448 }
449
450 /* wrap that up in a nice GSS-API wrapping */
451 if (NT_STATUS_IS_OK(ret)) {
452 ap_rep_wrapped = spnego_gen_krb5_wrap(talloc_tos(), ap_rep,
453 TOK_ID_KRB_AP_REP);
454 } else {
455 ap_rep_wrapped = data_blob_null;
456 }
457 response = spnego_gen_auth_response(talloc_tos(), &ap_rep_wrapped, ret,
458 mechOID);
459 reply_sesssetup_blob(req, response, ret);
460
461 data_blob_free(&ap_rep);
462 data_blob_free(&ap_rep_wrapped);
463 data_blob_free(&response);
464 TALLOC_FREE(mem_ctx);
465}
466
467#endif
468
469/****************************************************************************
470 Send a session setup reply, wrapped in SPNEGO.
471 Get vuid and check first.
472 End the NTLMSSP exchange context if we are OK/complete fail
473 This should be split into two functions, one to handle each
474 leg of the NTLM auth steps.
475***************************************************************************/
476
477static void reply_spnego_ntlmssp(struct smb_request *req,
478 uint16 vuid,
479 struct auth_ntlmssp_state **auth_ntlmssp_state,
480 DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status,
481 const char *OID,
482 bool wrap)
483{
484 bool do_invalidate = true;
485 DATA_BLOB response;
486 struct auth_serversupplied_info *session_info = NULL;
487 struct smbd_server_connection *sconn = req->sconn;
488
489 if (NT_STATUS_IS_OK(nt_status)) {
490 nt_status = auth_ntlmssp_steal_session_info(talloc_tos(),
491 (*auth_ntlmssp_state), &session_info);
492 } else {
493 /* Note that this session_info won't have a session
494 * key. But for map to guest, that's exactly the right
495 * thing - we can't reasonably guess the key the
496 * client wants, as the password was wrong */
497 nt_status = do_map_to_guest(nt_status,
498 &session_info,
499 auth_ntlmssp_get_username(*auth_ntlmssp_state),
500 auth_ntlmssp_get_domain(*auth_ntlmssp_state));
501 }
502
503 reply_outbuf(req, 4, 0);
504
505 SSVAL(req->outbuf, smb_uid, vuid);
506
507 if (NT_STATUS_IS_OK(nt_status)) {
508 DATA_BLOB nullblob = data_blob_null;
509
510 if (!is_partial_auth_vuid(sconn, vuid)) {
511 nt_status = NT_STATUS_LOGON_FAILURE;
512 goto out;
513 }
514
515 /* register_existing_vuid keeps the server info */
516 if (register_existing_vuid(sconn, vuid,
517 session_info, nullblob,
518 auth_ntlmssp_get_username(*auth_ntlmssp_state)) !=
519 vuid) {
520 /* The problem is, *auth_ntlmssp_state points
521 * into the vuser this will have
522 * talloc_free()'ed in
523 * register_existing_vuid() */
524 do_invalidate = false;
525 nt_status = NT_STATUS_LOGON_FAILURE;
526 goto out;
527 }
528
529 /* current_user_info is changed on new vuid */
530 reload_services(sconn->msg_ctx, sconn->sock, True);
531
532 SSVAL(req->outbuf, smb_vwv3, 0);
533
534 if (session_info->guest) {
535 SSVAL(req->outbuf,smb_vwv2,1);
536 }
537 }
538
539 out:
540
541 if (wrap) {
542 response = spnego_gen_auth_response(talloc_tos(),
543 ntlmssp_blob,
544 nt_status, OID);
545 } else {
546 response = *ntlmssp_blob;
547 }
548
549 reply_sesssetup_blob(req, response, nt_status);
550 if (wrap) {
551 data_blob_free(&response);
552 }
553
554 /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
555 and the other end, that we are not finished yet. */
556
557 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
558 /* NB. This is *NOT* an error case. JRA */
559 if (do_invalidate) {
560 TALLOC_FREE(*auth_ntlmssp_state);
561 if (!NT_STATUS_IS_OK(nt_status)) {
562 /* Kill the intermediate vuid */
563 invalidate_vuid(sconn, vuid);
564 }
565 }
566 }
567}
568
569/****************************************************************************
570 Is this a krb5 mechanism ?
571****************************************************************************/
572
573NTSTATUS parse_spnego_mechanisms(TALLOC_CTX *ctx,
574 DATA_BLOB blob_in,
575 DATA_BLOB *pblob_out,
576 char **kerb_mechOID)
577{
578 char *OIDs[ASN1_MAX_OIDS];
579 int i;
580 NTSTATUS ret = NT_STATUS_OK;
581
582 *kerb_mechOID = NULL;
583
584 /* parse out the OIDs and the first sec blob */
585 if (!spnego_parse_negTokenInit(ctx, blob_in, OIDs, NULL, pblob_out) ||
586 (OIDs[0] == NULL)) {
587 return NT_STATUS_LOGON_FAILURE;
588 }
589
590 /* only look at the first OID for determining the mechToken --
591 according to RFC2478, we should choose the one we want
592 and renegotiate, but i smell a client bug here..
593
594 Problem observed when connecting to a member (samba box)
595 of an AD domain as a user in a Samba domain. Samba member
596 server sent back krb5/mskrb5/ntlmssp as mechtypes, but the
597 client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an
598 NTLMSSP mechtoken. --jerry */
599
600#ifdef HAVE_KRB5
601 if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
602 strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
603 *kerb_mechOID = talloc_strdup(ctx, OIDs[0]);
604 if (*kerb_mechOID == NULL) {
605 ret = NT_STATUS_NO_MEMORY;
606 }
607 }
608#endif
609
610 for (i=0;OIDs[i];i++) {
611 DEBUG(5,("parse_spnego_mechanisms: Got OID %s\n", OIDs[i]));
612 talloc_free(OIDs[i]);
613 }
614 return ret;
615}
616
617/****************************************************************************
618 Fall back from krb5 to NTLMSSP.
619****************************************************************************/
620
621static void reply_spnego_downgrade_to_ntlmssp(struct smb_request *req,
622 uint16 vuid)
623{
624 DATA_BLOB response;
625
626 reply_outbuf(req, 4, 0);
627 SSVAL(req->outbuf,smb_uid,vuid);
628
629 DEBUG(3,("reply_spnego_downgrade_to_ntlmssp: Got krb5 ticket in SPNEGO "
630 "but set to downgrade to NTLMSSP\n"));
631
632 response = spnego_gen_auth_response(talloc_tos(), NULL,
633 NT_STATUS_MORE_PROCESSING_REQUIRED,
634 OID_NTLMSSP);
635 reply_sesssetup_blob(req, response, NT_STATUS_MORE_PROCESSING_REQUIRED);
636 data_blob_free(&response);
637}
638
639/****************************************************************************
640 Reply to a session setup spnego negotiate packet.
641****************************************************************************/
642
643static void reply_spnego_negotiate(struct smb_request *req,
644 uint16 vuid,
645 DATA_BLOB blob1,
646 struct auth_ntlmssp_state **auth_ntlmssp_state)
647{
648 DATA_BLOB secblob;
649 DATA_BLOB chal;
650 char *kerb_mech = NULL;
651 NTSTATUS status;
652 struct smbd_server_connection *sconn = req->sconn;
653
654 status = parse_spnego_mechanisms(talloc_tos(),
655 blob1, &secblob, &kerb_mech);
656 if (!NT_STATUS_IS_OK(status)) {
657 /* Kill the intermediate vuid */
658 invalidate_vuid(sconn, vuid);
659 reply_nterror(req, nt_status_squash(status));
660 return;
661 }
662
663 DEBUG(3,("reply_spnego_negotiate: Got secblob of size %lu\n",
664 (unsigned long)secblob.length));
665
666#ifdef HAVE_KRB5
667 if (kerb_mech && ((lp_security()==SEC_ADS) ||
668 USE_KERBEROS_KEYTAB) ) {
669 bool destroy_vuid = True;
670 reply_spnego_kerberos(req, &secblob, kerb_mech,
671 vuid, &destroy_vuid);
672 data_blob_free(&secblob);
673 if (destroy_vuid) {
674 /* Kill the intermediate vuid */
675 invalidate_vuid(sconn, vuid);
676 }
677 TALLOC_FREE(kerb_mech);
678 return;
679 }
680#endif
681
682 TALLOC_FREE(*auth_ntlmssp_state);
683
684 if (kerb_mech) {
685 data_blob_free(&secblob);
686 /* The mechtoken is a krb5 ticket, but
687 * we need to fall back to NTLM. */
688 reply_spnego_downgrade_to_ntlmssp(req, vuid);
689 TALLOC_FREE(kerb_mech);
690 return;
691 }
692
693 status = auth_ntlmssp_start(auth_ntlmssp_state);
694 if (!NT_STATUS_IS_OK(status)) {
695 /* Kill the intermediate vuid */
696 invalidate_vuid(sconn, vuid);
697 reply_nterror(req, nt_status_squash(status));
698 return;
699 }
700
701 status = auth_ntlmssp_update(*auth_ntlmssp_state,
702 secblob, &chal);
703
704 data_blob_free(&secblob);
705
706 reply_spnego_ntlmssp(req, vuid, auth_ntlmssp_state,
707 &chal, status, OID_NTLMSSP, true);
708
709 data_blob_free(&chal);
710
711 /* already replied */
712 return;
713}
714
715/****************************************************************************
716 Reply to a session setup spnego auth packet.
717****************************************************************************/
718
719static void reply_spnego_auth(struct smb_request *req,
720 uint16 vuid,
721 DATA_BLOB blob1,
722 struct auth_ntlmssp_state **auth_ntlmssp_state)
723{
724 DATA_BLOB auth = data_blob_null;
725 DATA_BLOB auth_reply = data_blob_null;
726 DATA_BLOB secblob = data_blob_null;
727 NTSTATUS status = NT_STATUS_LOGON_FAILURE;
728 struct smbd_server_connection *sconn = req->sconn;
729
730 if (!spnego_parse_auth(talloc_tos(), blob1, &auth)) {
731#if 0
732 file_save("auth.dat", blob1.data, blob1.length);
733#endif
734 /* Kill the intermediate vuid */
735 invalidate_vuid(sconn, vuid);
736
737 reply_nterror(req, nt_status_squash(
738 NT_STATUS_LOGON_FAILURE));
739 return;
740 }
741
742 if (auth.length > 0 && auth.data[0] == ASN1_APPLICATION(0)) {
743 /* Might be a second negTokenTarg packet */
744 char *kerb_mech = NULL;
745
746 status = parse_spnego_mechanisms(talloc_tos(),
747 auth, &secblob, &kerb_mech);
748
749 if (!NT_STATUS_IS_OK(status)) {
750 /* Kill the intermediate vuid */
751 invalidate_vuid(sconn, vuid);
752 reply_nterror(req, nt_status_squash(status));
753 return;
754 }
755
756 DEBUG(3,("reply_spnego_auth: Got secblob of size %lu\n",
757 (unsigned long)secblob.length));
758#ifdef HAVE_KRB5
759 if (kerb_mech && ((lp_security()==SEC_ADS) ||
760 USE_KERBEROS_KEYTAB)) {
761 bool destroy_vuid = True;
762 reply_spnego_kerberos(req, &secblob, kerb_mech,
763 vuid, &destroy_vuid);
764 data_blob_free(&secblob);
765 data_blob_free(&auth);
766 if (destroy_vuid) {
767 /* Kill the intermediate vuid */
768 invalidate_vuid(sconn, vuid);
769 }
770 TALLOC_FREE(kerb_mech);
771 return;
772 }
773#endif
774 /* Can't blunder into NTLMSSP auth if we have
775 * a krb5 ticket. */
776
777 if (kerb_mech) {
778 /* Kill the intermediate vuid */
779 invalidate_vuid(sconn, vuid);
780 DEBUG(3,("reply_spnego_auth: network "
781 "misconfiguration, client sent us a "
782 "krb5 ticket and kerberos security "
783 "not enabled\n"));
784 reply_nterror(req, nt_status_squash(
785 NT_STATUS_LOGON_FAILURE));
786 TALLOC_FREE(kerb_mech);
787 }
788 }
789
790 /* If we get here it wasn't a negTokenTarg auth packet. */
791 data_blob_free(&secblob);
792
793 if (!*auth_ntlmssp_state) {
794 status = auth_ntlmssp_start(auth_ntlmssp_state);
795 if (!NT_STATUS_IS_OK(status)) {
796 /* Kill the intermediate vuid */
797 invalidate_vuid(sconn, vuid);
798 reply_nterror(req, nt_status_squash(status));
799 return;
800 }
801 }
802
803 status = auth_ntlmssp_update(*auth_ntlmssp_state,
804 auth, &auth_reply);
805
806 data_blob_free(&auth);
807
808 /* Don't send the mechid as we've already sent this (RFC4178). */
809
810 reply_spnego_ntlmssp(req, vuid,
811 auth_ntlmssp_state,
812 &auth_reply, status, NULL, true);
813
814 data_blob_free(&auth_reply);
815
816 /* and tell smbd that we have already replied to this packet */
817 return;
818}
819
820/****************************************************************************
821 Delete an entry on the list.
822****************************************************************************/
823
824static void delete_partial_auth(struct smbd_server_connection *sconn,
825 struct pending_auth_data *pad)
826{
827 if (!pad) {
828 return;
829 }
830 DLIST_REMOVE(sconn->smb1.pd_list, pad);
831 data_blob_free(&pad->partial_data);
832 SAFE_FREE(pad);
833}
834
835/****************************************************************************
836 Search for a partial SPNEGO auth fragment matching an smbpid.
837****************************************************************************/
838
839static struct pending_auth_data *get_pending_auth_data(
840 struct smbd_server_connection *sconn,
841 uint16_t smbpid)
842{
843 struct pending_auth_data *pad;
844/*
845 * NOTE: using the smbpid here is completely wrong...
846 * see [MS-SMB]
847 * 3.3.5.3 Receiving an SMB_COM_SESSION_SETUP_ANDX Request
848 */
849 for (pad = sconn->smb1.pd_list; pad; pad = pad->next) {
850 if (pad->smbpid == smbpid) {
851 break;
852 }
853 }
854 return pad;
855}
856
857/****************************************************************************
858 Check the size of an SPNEGO blob. If we need more return
859 NT_STATUS_MORE_PROCESSING_REQUIRED, else return NT_STATUS_OK. Don't allow
860 the blob to be more than 64k.
861****************************************************************************/
862
863static NTSTATUS check_spnego_blob_complete(struct smbd_server_connection *sconn,
864 uint16 smbpid, uint16 vuid,
865 DATA_BLOB *pblob)
866{
867 struct pending_auth_data *pad = NULL;
868 ASN1_DATA *data;
869 size_t needed_len = 0;
870
871 pad = get_pending_auth_data(sconn, smbpid);
872
873 /* Ensure we have some data. */
874 if (pblob->length == 0) {
875 /* Caller can cope. */
876 DEBUG(2,("check_spnego_blob_complete: zero blob length !\n"));
877 delete_partial_auth(sconn, pad);
878 return NT_STATUS_OK;
879 }
880
881 /* Were we waiting for more data ? */
882 if (pad) {
883 DATA_BLOB tmp_blob;
884 size_t copy_len = MIN(65536, pblob->length);
885
886 /* Integer wrap paranoia.... */
887
888 if (pad->partial_data.length + copy_len <
889 pad->partial_data.length ||
890 pad->partial_data.length + copy_len < copy_len) {
891
892 DEBUG(2,("check_spnego_blob_complete: integer wrap "
893 "pad->partial_data.length = %u, "
894 "copy_len = %u\n",
895 (unsigned int)pad->partial_data.length,
896 (unsigned int)copy_len ));
897
898 delete_partial_auth(sconn, pad);
899 return NT_STATUS_INVALID_PARAMETER;
900 }
901
902 DEBUG(10,("check_spnego_blob_complete: "
903 "pad->partial_data.length = %u, "
904 "pad->needed_len = %u, "
905 "copy_len = %u, "
906 "pblob->length = %u,\n",
907 (unsigned int)pad->partial_data.length,
908 (unsigned int)pad->needed_len,
909 (unsigned int)copy_len,
910 (unsigned int)pblob->length ));
911
912 if (pblob->length > pad->needed_len) {
913 DEBUG(2, ("subsequent security token data length %u "
914 "exceeds expected length %u\n",
915 (unsigned int)pblob->length,
916 (unsigned int)pad->needed_len));
917 }
918
919 tmp_blob = data_blob(NULL,
920 pad->partial_data.length + copy_len);
921
922 /* Concatenate the two (up to copy_len) bytes. */
923 memcpy(tmp_blob.data,
924 pad->partial_data.data,
925 pad->partial_data.length);
926 memcpy(tmp_blob.data + pad->partial_data.length,
927 pblob->data,
928 copy_len);
929
930 /* Replace the partial data. */
931 data_blob_free(&pad->partial_data);
932 pad->partial_data = tmp_blob;
933 ZERO_STRUCT(tmp_blob);
934
935 /* Are we done ? */
936 if (pblob->length >= pad->needed_len) {
937 /* Yes, replace pblob. */
938 data_blob_free(pblob);
939 *pblob = pad->partial_data;
940 ZERO_STRUCT(pad->partial_data);
941 delete_partial_auth(sconn, pad);
942 return NT_STATUS_OK;
943 }
944
945 /* Still need more data. */
946 pad->needed_len -= copy_len;
947 return NT_STATUS_MORE_PROCESSING_REQUIRED;
948 }
949
950 if ((pblob->data[0] != ASN1_APPLICATION(0)) &&
951 (pblob->data[0] != ASN1_CONTEXT(1))) {
952 /* Not something we can determine the
953 * length of.
954 */
955 return NT_STATUS_OK;
956 }
957
958 /* This is a new SPNEGO sessionsetup - see if
959 * the data given in this blob is enough.
960 */
961
962 data = asn1_init(NULL);
963 if (data == NULL) {
964 return NT_STATUS_NO_MEMORY;
965 }
966
967 asn1_load(data, *pblob);
968 if (asn1_start_tag(data, pblob->data[0])) {
969 /* asn1_start_tag checks if the given
970 length of the blob is enough to complete
971 the tag. If it returns true we know
972 there is nothing to do - the blob is
973 complete. */
974 asn1_free(data);
975 return NT_STATUS_OK;
976 }
977
978 if (data->nesting == NULL) {
979 /* Incorrect tag, allocation failed,
980 or reading the tag length failed.
981 Let the caller catch. */
982 asn1_free(data);
983 return NT_STATUS_OK;
984 }
985
986 /* Here we know asn1_start_tag() has set data->has_error to true.
987 asn1_tag_remaining() will have failed due to the given blob
988 being too short. We need to work out how short. */
989
990 /* Integer wrap paranoia.... */
991
992 if (data->nesting->taglen + data->nesting->start < data->nesting->taglen ||
993 data->nesting->taglen + data->nesting->start < data->nesting->start) {
994
995 DEBUG(2,("check_spnego_blob_complete: integer wrap "
996 "data.nesting->taglen = %u, "
997 "data.nesting->start = %u\n",
998 (unsigned int)data->nesting->taglen,
999 (unsigned int)data->nesting->start ));
1000
1001 asn1_free(data);
1002 return NT_STATUS_INVALID_PARAMETER;
1003 }
1004
1005 /* Total length of the needed asn1 is the tag length
1006 * plus the current offset. */
1007
1008 needed_len = data->nesting->taglen + data->nesting->start;
1009 asn1_free(data);
1010
1011 DEBUG(10,("check_spnego_blob_complete: needed_len = %u, "
1012 "pblob->length = %u\n",
1013 (unsigned int)needed_len,
1014 (unsigned int)pblob->length ));
1015
1016 if (needed_len <= pblob->length) {
1017 /* Nothing to do - blob is complete. */
1018 /* THIS SHOULD NOT HAPPEN - asn1_start_tag()
1019 above should have caught this !!! */
1020 DEBUG(0,("check_spnego_blob_complete: logic "
1021 "error (needed_len = %u, "
1022 "pblob->length = %u).\n",
1023 (unsigned int)needed_len,
1024 (unsigned int)pblob->length ));
1025 return NT_STATUS_OK;
1026 }
1027
1028 /* Refuse the blob if it's bigger than 64k. */
1029 if (needed_len > 65536) {
1030 DEBUG(2,("check_spnego_blob_complete: needed_len "
1031 "too large (%u)\n",
1032 (unsigned int)needed_len ));
1033 return NT_STATUS_INVALID_PARAMETER;
1034 }
1035
1036 /* We must store this blob until complete. */
1037 if (!(pad = SMB_MALLOC_P(struct pending_auth_data))) {
1038 return NT_STATUS_NO_MEMORY;
1039 }
1040 pad->needed_len = needed_len - pblob->length;
1041 pad->partial_data = data_blob(pblob->data, pblob->length);
1042 if (pad->partial_data.data == NULL) {
1043 SAFE_FREE(pad);
1044 return NT_STATUS_NO_MEMORY;
1045 }
1046 pad->smbpid = smbpid;
1047 pad->vuid = vuid;
1048 DLIST_ADD(sconn->smb1.pd_list, pad);
1049
1050 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1051}
1052
1053/****************************************************************************
1054 Reply to a session setup command.
1055 conn POINTER CAN BE NULL HERE !
1056****************************************************************************/
1057
1058static void reply_sesssetup_and_X_spnego(struct smb_request *req)
1059{
1060 const uint8 *p;
1061 DATA_BLOB blob1;
1062 size_t bufrem;
1063 char *tmp;
1064 const char *native_os;
1065 const char *native_lanman;
1066 const char *primary_domain;
1067 const char *p2;
1068 uint16 data_blob_len = SVAL(req->vwv+7, 0);
1069 enum remote_arch_types ra_type = get_remote_arch();
1070 int vuid = req->vuid;
1071 user_struct *vuser = NULL;
1072 NTSTATUS status = NT_STATUS_OK;
1073 uint16 smbpid = req->smbpid;
1074 struct smbd_server_connection *sconn = req->sconn;
1075
1076 DEBUG(3,("Doing spnego session setup\n"));
1077
1078 if (global_client_caps == 0) {
1079 global_client_caps = IVAL(req->vwv+10, 0);
1080
1081 if (!(global_client_caps & CAP_STATUS32)) {
1082 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1083 }
1084
1085 }
1086
1087 p = req->buf;
1088
1089 if (data_blob_len == 0) {
1090 /* an invalid request */
1091 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1092 return;
1093 }
1094
1095 bufrem = smbreq_bufrem(req, p);
1096 /* pull the spnego blob */
1097 blob1 = data_blob(p, MIN(bufrem, data_blob_len));
1098
1099#if 0
1100 file_save("negotiate.dat", blob1.data, blob1.length);
1101#endif
1102
1103 p2 = (char *)req->buf + blob1.length;
1104
1105 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1106 STR_TERMINATE);
1107 native_os = tmp ? tmp : "";
1108
1109 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1110 STR_TERMINATE);
1111 native_lanman = tmp ? tmp : "";
1112
1113 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1114 STR_TERMINATE);
1115 primary_domain = tmp ? tmp : "";
1116
1117 DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
1118 native_os, native_lanman, primary_domain));
1119
1120 if ( ra_type == RA_WIN2K ) {
1121 /* Vista sets neither the OS or lanman strings */
1122
1123 if ( !strlen(native_os) && !strlen(native_lanman) )
1124 set_remote_arch(RA_VISTA);
1125
1126 /* Windows 2003 doesn't set the native lanman string,
1127 but does set primary domain which is a bug I think */
1128
1129 if ( !strlen(native_lanman) ) {
1130 ra_lanman_string( primary_domain );
1131 } else {
1132 ra_lanman_string( native_lanman );
1133 }
1134 } else if ( ra_type == RA_VISTA ) {
1135 if ( strncmp(native_os, "Mac OS X", 8) == 0 ) {
1136 set_remote_arch(RA_OSX);
1137 }
1138 }
1139
1140 /* Did we get a valid vuid ? */
1141 if (!is_partial_auth_vuid(sconn, vuid)) {
1142 /* No, then try and see if this is an intermediate sessionsetup
1143 * for a large SPNEGO packet. */
1144 struct pending_auth_data *pad;
1145 pad = get_pending_auth_data(sconn, smbpid);
1146 if (pad) {
1147 DEBUG(10,("reply_sesssetup_and_X_spnego: found "
1148 "pending vuid %u\n",
1149 (unsigned int)pad->vuid ));
1150 vuid = pad->vuid;
1151 }
1152 }
1153
1154 /* Do we have a valid vuid now ? */
1155 if (!is_partial_auth_vuid(sconn, vuid)) {
1156 /* No, start a new authentication setup. */
1157 vuid = register_initial_vuid(sconn);
1158 if (vuid == UID_FIELD_INVALID) {
1159 data_blob_free(&blob1);
1160 reply_nterror(req, nt_status_squash(
1161 NT_STATUS_INVALID_PARAMETER));
1162 return;
1163 }
1164 }
1165
1166 vuser = get_partial_auth_user_struct(sconn, vuid);
1167 /* This MUST be valid. */
1168 if (!vuser) {
1169 smb_panic("reply_sesssetup_and_X_spnego: invalid vuid.");
1170 }
1171
1172 /* Large (greater than 4k) SPNEGO blobs are split into multiple
1173 * sessionsetup requests as the Windows limit on the security blob
1174 * field is 4k. Bug #4400. JRA.
1175 */
1176
1177 status = check_spnego_blob_complete(sconn, smbpid, vuid, &blob1);
1178 if (!NT_STATUS_IS_OK(status)) {
1179 /*
1180 * Pack error response, ensuring to fill NativeOS, NativeLanMan
1181 * & PrimaryDomain fields on NT_STATUS_MORE_PROCESSING_REQUIRED
1182 */
1183 reply_outbuf(req, 4, 0);
1184 reply_sesssetup_blob(req, data_blob_null, status);
1185 if (!NT_STATUS_EQUAL(status,
1186 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1187 /* Real error - kill the intermediate vuid */
1188 invalidate_vuid(sconn, vuid);
1189 }
1190 data_blob_free(&blob1);
1191 return;
1192 }
1193
1194 if (blob1.data[0] == ASN1_APPLICATION(0)) {
1195
1196 /* its a negTokenTarg packet */
1197
1198 reply_spnego_negotiate(req, vuid, blob1,
1199 &vuser->auth_ntlmssp_state);
1200 data_blob_free(&blob1);
1201 return;
1202 }
1203
1204 if (blob1.data[0] == ASN1_CONTEXT(1)) {
1205
1206 /* its a auth packet */
1207
1208 reply_spnego_auth(req, vuid, blob1,
1209 &vuser->auth_ntlmssp_state);
1210 data_blob_free(&blob1);
1211 return;
1212 }
1213
1214 if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) {
1215 DATA_BLOB chal;
1216
1217 if (!vuser->auth_ntlmssp_state) {
1218 status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state);
1219 if (!NT_STATUS_IS_OK(status)) {
1220 /* Kill the intermediate vuid */
1221 invalidate_vuid(sconn, vuid);
1222 data_blob_free(&blob1);
1223 reply_nterror(req, nt_status_squash(status));
1224 return;
1225 }
1226 }
1227
1228 status = auth_ntlmssp_update(vuser->auth_ntlmssp_state,
1229 blob1, &chal);
1230
1231 data_blob_free(&blob1);
1232
1233 reply_spnego_ntlmssp(req, vuid,
1234 &vuser->auth_ntlmssp_state,
1235 &chal, status, OID_NTLMSSP, false);
1236 data_blob_free(&chal);
1237 return;
1238 }
1239
1240 /* what sort of packet is this? */
1241 DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
1242
1243 data_blob_free(&blob1);
1244
1245 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1246}
1247
1248/****************************************************************************
1249 On new VC == 0, shutdown *all* old connections and users.
1250 It seems that only NT4.x does this. At W2K and above (XP etc.).
1251 a new session setup with VC==0 is ignored.
1252****************************************************************************/
1253
1254struct shutdown_state {
1255 const char *ip;
1256 struct messaging_context *msg_ctx;
1257};
1258
1259static int shutdown_other_smbds(const struct connections_key *key,
1260 const struct connections_data *crec,
1261 void *private_data)
1262{
1263 struct shutdown_state *state = (struct shutdown_state *)private_data;
1264
1265 DEBUG(10, ("shutdown_other_smbds: %s, %s\n",
1266 procid_str(talloc_tos(), &crec->pid), crec->addr));
1267
1268 if (!process_exists(crec->pid)) {
1269 DEBUG(10, ("process does not exist\n"));
1270 return 0;
1271 }
1272
1273 if (procid_is_me(&crec->pid)) {
1274 DEBUG(10, ("It's me\n"));
1275 return 0;
1276 }
1277
1278 if (strcmp(state->ip, crec->addr) != 0) {
1279 DEBUG(10, ("%s does not match %s\n", state->ip, crec->addr));
1280 return 0;
1281 }
1282
1283 DEBUG(1, ("shutdown_other_smbds: shutting down pid %u "
1284 "(IP %s)\n", (unsigned int)procid_to_pid(&crec->pid),
1285 state->ip));
1286
1287 messaging_send(state->msg_ctx, crec->pid, MSG_SHUTDOWN,
1288 &data_blob_null);
1289 return 0;
1290}
1291
1292static void setup_new_vc_session(struct smbd_server_connection *sconn)
1293{
1294 DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x "
1295 "compatible we would close all old resources.\n"));
1296#if 0
1297 conn_close_all();
1298 invalidate_all_vuids();
1299#endif
1300 if (lp_reset_on_zero_vc()) {
1301 char *addr;
1302 struct shutdown_state state;
1303
1304 addr = tsocket_address_inet_addr_string(
1305 sconn->remote_address, talloc_tos());
1306 if (addr == NULL) {
1307 return;
1308 }
1309 state.ip = addr;
1310 state.msg_ctx = sconn->msg_ctx;
1311 connections_forall_read(shutdown_other_smbds, &state);
1312 TALLOC_FREE(addr);
1313 }
1314}
1315
1316/****************************************************************************
1317 Reply to a session setup command.
1318****************************************************************************/
1319
1320void reply_sesssetup_and_X(struct smb_request *req)
1321{
1322 int sess_vuid;
1323 int smb_bufsize;
1324 DATA_BLOB lm_resp;
1325 DATA_BLOB nt_resp;
1326 DATA_BLOB plaintext_password;
1327 char *tmp;
1328 const char *user;
1329 fstring sub_user; /* Sanitised username for substituion */
1330 const char *domain;
1331 const char *native_os;
1332 const char *native_lanman;
1333 const char *primary_domain;
1334 struct auth_usersupplied_info *user_info = NULL;
1335 struct auth_serversupplied_info *server_info = NULL;
1336 uint16 smb_flag2 = req->flags2;
1337
1338 NTSTATUS nt_status;
1339 struct smbd_server_connection *sconn = req->sconn;
1340
1341 bool doencrypt = sconn->smb1.negprot.encrypted_passwords;
1342
1343 START_PROFILE(SMBsesssetupX);
1344
1345 ZERO_STRUCT(lm_resp);
1346 ZERO_STRUCT(nt_resp);
1347 ZERO_STRUCT(plaintext_password);
1348
1349 DEBUG(3,("wct=%d flg2=0x%x\n", req->wct, req->flags2));
1350
1351 /* a SPNEGO session setup has 12 command words, whereas a normal
1352 NT1 session setup has 13. See the cifs spec. */
1353 if (req->wct == 12 &&
1354 (req->flags2 & FLAGS2_EXTENDED_SECURITY)) {
1355
1356 if (!sconn->smb1.negprot.spnego) {
1357 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
1358 "at SPNEGO session setup when it was not "
1359 "negotiated.\n"));
1360 reply_nterror(req, nt_status_squash(
1361 NT_STATUS_LOGON_FAILURE));
1362 END_PROFILE(SMBsesssetupX);
1363 return;
1364 }
1365
1366 if (SVAL(req->vwv+4, 0) == 0) {
1367 setup_new_vc_session(req->sconn);
1368 }
1369
1370 reply_sesssetup_and_X_spnego(req);
1371 END_PROFILE(SMBsesssetupX);
1372 return;
1373 }
1374
1375 smb_bufsize = SVAL(req->vwv+2, 0);
1376
1377 if (get_Protocol() < PROTOCOL_NT1) {
1378 uint16 passlen1 = SVAL(req->vwv+7, 0);
1379
1380 /* Never do NT status codes with protocols before NT1 as we
1381 * don't get client caps. */
1382 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1383
1384 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > req->buflen)) {
1385 reply_nterror(req, nt_status_squash(
1386 NT_STATUS_INVALID_PARAMETER));
1387 END_PROFILE(SMBsesssetupX);
1388 return;
1389 }
1390
1391 if (doencrypt) {
1392 lm_resp = data_blob(req->buf, passlen1);
1393 } else {
1394 plaintext_password = data_blob(req->buf, passlen1+1);
1395 /* Ensure null termination */
1396 plaintext_password.data[passlen1] = 0;
1397 }
1398
1399 srvstr_pull_req_talloc(talloc_tos(), req, &tmp,
1400 req->buf + passlen1, STR_TERMINATE);
1401 user = tmp ? tmp : "";
1402
1403 domain = "";
1404
1405 } else {
1406 uint16 passlen1 = SVAL(req->vwv+7, 0);
1407 uint16 passlen2 = SVAL(req->vwv+8, 0);
1408 enum remote_arch_types ra_type = get_remote_arch();
1409 const uint8_t *p = req->buf;
1410 const uint8_t *save_p = req->buf;
1411 uint16 byte_count;
1412
1413
1414 if(global_client_caps == 0) {
1415 global_client_caps = IVAL(req->vwv+11, 0);
1416
1417 if (!(global_client_caps & CAP_STATUS32)) {
1418 remove_from_common_flags2(
1419 FLAGS2_32_BIT_ERROR_CODES);
1420 }
1421
1422 /* client_caps is used as final determination if
1423 * client is NT or Win95. This is needed to return
1424 * the correct error codes in some circumstances.
1425 */
1426
1427 if(ra_type == RA_WINNT || ra_type == RA_WIN2K ||
1428 ra_type == RA_WIN95) {
1429 if(!(global_client_caps & (CAP_NT_SMBS|
1430 CAP_STATUS32))) {
1431 set_remote_arch( RA_WIN95);
1432 }
1433 }
1434 }
1435
1436 if (!doencrypt) {
1437 /* both Win95 and WinNT stuff up the password
1438 * lengths for non-encrypting systems. Uggh.
1439
1440 if passlen1==24 its a win95 system, and its setting
1441 the password length incorrectly. Luckily it still
1442 works with the default code because Win95 will null
1443 terminate the password anyway
1444
1445 if passlen1>0 and passlen2>0 then maybe its a NT box
1446 and its setting passlen2 to some random value which
1447 really stuffs things up. we need to fix that one. */
1448
1449 if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 &&
1450 passlen2 != 1) {
1451 passlen2 = 0;
1452 }
1453 }
1454
1455 /* check for nasty tricks */
1456 if (passlen1 > MAX_PASS_LEN
1457 || passlen1 > smbreq_bufrem(req, p)) {
1458 reply_nterror(req, nt_status_squash(
1459 NT_STATUS_INVALID_PARAMETER));
1460 END_PROFILE(SMBsesssetupX);
1461 return;
1462 }
1463
1464 if (passlen2 > MAX_PASS_LEN
1465 || passlen2 > smbreq_bufrem(req, p+passlen1)) {
1466 reply_nterror(req, nt_status_squash(
1467 NT_STATUS_INVALID_PARAMETER));
1468 END_PROFILE(SMBsesssetupX);
1469 return;
1470 }
1471
1472 /* Save the lanman2 password and the NT md4 password. */
1473
1474 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
1475 doencrypt = False;
1476 }
1477
1478 if (doencrypt) {
1479 lm_resp = data_blob(p, passlen1);
1480 nt_resp = data_blob(p+passlen1, passlen2);
1481 } else if (lp_security() != SEC_SHARE) {
1482 /*
1483 * In share level we should ignore any passwords, so
1484 * only read them if we're not.
1485 */
1486 char *pass = NULL;
1487 bool unic= smb_flag2 & FLAGS2_UNICODE_STRINGS;
1488
1489 if (unic && (passlen2 == 0) && passlen1) {
1490 /* Only a ascii plaintext password was sent. */
1491 (void)srvstr_pull_talloc(talloc_tos(),
1492 req->inbuf,
1493 req->flags2,
1494 &pass,
1495 req->buf,
1496 passlen1,
1497 STR_TERMINATE|STR_ASCII);
1498 } else {
1499 (void)srvstr_pull_talloc(talloc_tos(),
1500 req->inbuf,
1501 req->flags2,
1502 &pass,
1503 req->buf,
1504 unic ? passlen2 : passlen1,
1505 STR_TERMINATE);
1506 }
1507 if (!pass) {
1508 reply_nterror(req, nt_status_squash(
1509 NT_STATUS_INVALID_PARAMETER));
1510 END_PROFILE(SMBsesssetupX);
1511 return;
1512 }
1513 plaintext_password = data_blob(pass, strlen(pass)+1);
1514 }
1515
1516 p += passlen1 + passlen2;
1517
1518 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1519 STR_TERMINATE);
1520 user = tmp ? tmp : "";
1521
1522 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1523 STR_TERMINATE);
1524 domain = tmp ? tmp : "";
1525
1526 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1527 STR_TERMINATE);
1528 native_os = tmp ? tmp : "";
1529
1530 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1531 STR_TERMINATE);
1532 native_lanman = tmp ? tmp : "";
1533
1534 /* not documented or decoded by Ethereal but there is one more
1535 * string in the extra bytes which is the same as the
1536 * PrimaryDomain when using extended security. Windows NT 4
1537 * and 2003 use this string to store the native lanman string.
1538 * Windows 9x does not include a string here at all so we have
1539 * to check if we have any extra bytes left */
1540
1541 byte_count = SVAL(req->vwv+13, 0);
1542 if ( PTR_DIFF(p, save_p) < byte_count) {
1543 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1544 STR_TERMINATE);
1545 primary_domain = tmp ? tmp : "";
1546 } else {
1547 primary_domain = talloc_strdup(talloc_tos(), "null");
1548 }
1549
1550 DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s] "
1551 "PrimaryDomain=[%s]\n",
1552 domain, native_os, native_lanman, primary_domain));
1553
1554 if ( ra_type == RA_WIN2K ) {
1555 if ( strlen(native_lanman) == 0 )
1556 ra_lanman_string( primary_domain );
1557 else
1558 ra_lanman_string( native_lanman );
1559 }
1560
1561 }
1562
1563 if (SVAL(req->vwv+4, 0) == 0) {
1564 setup_new_vc_session(req->sconn);
1565 }
1566
1567 DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n",
1568 domain, user, get_remote_machine_name()));
1569
1570 if (*user) {
1571 if (sconn->smb1.negprot.spnego) {
1572
1573 /* This has to be here, because this is a perfectly
1574 * valid behaviour for guest logons :-( */
1575
1576 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
1577 "at 'normal' session setup after "
1578 "negotiating spnego.\n"));
1579 reply_nterror(req, nt_status_squash(
1580 NT_STATUS_LOGON_FAILURE));
1581 END_PROFILE(SMBsesssetupX);
1582 return;
1583 }
1584 fstrcpy(sub_user, user);
1585 } else {
1586 fstrcpy(sub_user, lp_guestaccount());
1587 }
1588
1589 sub_set_smb_name(sub_user);
1590
1591 reload_services(sconn->msg_ctx, sconn->sock, True);
1592
1593 if (lp_security() == SEC_SHARE) {
1594 char *sub_user_mapped = NULL;
1595 /* In share level we should ignore any passwords */
1596
1597 data_blob_free(&lm_resp);
1598 data_blob_free(&nt_resp);
1599 data_blob_clear_free(&plaintext_password);
1600
1601 (void)map_username(talloc_tos(), sub_user, &sub_user_mapped);
1602 if (!sub_user_mapped) {
1603 reply_nterror(req, NT_STATUS_NO_MEMORY);
1604 END_PROFILE(SMBsesssetupX);
1605 return;
1606 }
1607 fstrcpy(sub_user, sub_user_mapped);
1608 add_session_user(sconn, sub_user);
1609 add_session_workgroup(sconn, domain);
1610 /* Then force it to null for the benfit of the code below */
1611 user = "";
1612 }
1613
1614 if (!*user) {
1615
1616 nt_status = check_guest_password(&server_info);
1617
1618 } else if (doencrypt) {
1619 struct auth_context *negprot_auth_context = NULL;
1620 negprot_auth_context = sconn->smb1.negprot.auth_context;
1621 if (!negprot_auth_context) {
1622 DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted "
1623 "session setup without negprot denied!\n"));
1624 reply_nterror(req, nt_status_squash(
1625 NT_STATUS_LOGON_FAILURE));
1626 END_PROFILE(SMBsesssetupX);
1627 return;
1628 }
1629 nt_status = make_user_info_for_reply_enc(&user_info, user,
1630 domain,
1631 lm_resp, nt_resp);
1632 if (NT_STATUS_IS_OK(nt_status)) {
1633 nt_status = negprot_auth_context->check_ntlm_password(
1634 negprot_auth_context,
1635 user_info,
1636 &server_info);
1637 }
1638 } else {
1639 struct auth_context *plaintext_auth_context = NULL;
1640
1641 nt_status = make_auth_context_subsystem(
1642 talloc_tos(), &plaintext_auth_context);
1643
1644 if (NT_STATUS_IS_OK(nt_status)) {
1645 uint8_t chal[8];
1646
1647 plaintext_auth_context->get_ntlm_challenge(
1648 plaintext_auth_context, chal);
1649
1650 if (!make_user_info_for_reply(&user_info,
1651 user, domain, chal,
1652 plaintext_password)) {
1653 nt_status = NT_STATUS_NO_MEMORY;
1654 }
1655
1656 if (NT_STATUS_IS_OK(nt_status)) {
1657 nt_status = plaintext_auth_context->check_ntlm_password(
1658 plaintext_auth_context,
1659 user_info,
1660 &server_info);
1661
1662 TALLOC_FREE(plaintext_auth_context);
1663 }
1664 }
1665 }
1666
1667 free_user_info(&user_info);
1668
1669 if (!NT_STATUS_IS_OK(nt_status)) {
1670 nt_status = do_map_to_guest(nt_status, &server_info,
1671 user, domain);
1672 }
1673
1674 if (!NT_STATUS_IS_OK(nt_status)) {
1675 data_blob_free(&nt_resp);
1676 data_blob_free(&lm_resp);
1677 data_blob_clear_free(&plaintext_password);
1678 reply_nterror(req, nt_status_squash(nt_status));
1679 END_PROFILE(SMBsesssetupX);
1680 return;
1681 }
1682
1683 /* Ensure we can't possible take a code path leading to a
1684 * null defref. */
1685 if (!server_info) {
1686 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1687 END_PROFILE(SMBsesssetupX);
1688 return;
1689 }
1690
1691 if (!server_info->security_token) {
1692 nt_status = create_local_token(server_info);
1693
1694 if (!NT_STATUS_IS_OK(nt_status)) {
1695 DEBUG(10, ("create_local_token failed: %s\n",
1696 nt_errstr(nt_status)));
1697 data_blob_free(&nt_resp);
1698 data_blob_free(&lm_resp);
1699 data_blob_clear_free(&plaintext_password);
1700 reply_nterror(req, nt_status_squash(nt_status));
1701 END_PROFILE(SMBsesssetupX);
1702 return;
1703 }
1704 }
1705
1706 data_blob_clear_free(&plaintext_password);
1707
1708 /* it's ok - setup a reply */
1709 reply_outbuf(req, 3, 0);
1710 if (get_Protocol() >= PROTOCOL_NT1) {
1711 push_signature(&req->outbuf);
1712 /* perhaps grab OS version here?? */
1713 }
1714
1715 if (server_info->guest) {
1716 SSVAL(req->outbuf,smb_vwv2,1);
1717 }
1718
1719 /* register the name and uid as being validated, so further connections
1720 to a uid can get through without a password, on the same VC */
1721
1722 if (lp_security() == SEC_SHARE) {
1723 sess_vuid = UID_FIELD_INVALID;
1724 TALLOC_FREE(server_info);
1725 } else {
1726 /* Ignore the initial vuid. */
1727 sess_vuid = register_initial_vuid(sconn);
1728 if (sess_vuid == UID_FIELD_INVALID) {
1729 data_blob_free(&nt_resp);
1730 data_blob_free(&lm_resp);
1731 reply_nterror(req, nt_status_squash(
1732 NT_STATUS_LOGON_FAILURE));
1733 END_PROFILE(SMBsesssetupX);
1734 return;
1735 }
1736 /* register_existing_vuid keeps the server info */
1737 sess_vuid = register_existing_vuid(sconn, sess_vuid,
1738 server_info,
1739 nt_resp.data ? nt_resp : lm_resp,
1740 sub_user);
1741 if (sess_vuid == UID_FIELD_INVALID) {
1742 data_blob_free(&nt_resp);
1743 data_blob_free(&lm_resp);
1744 reply_nterror(req, nt_status_squash(
1745 NT_STATUS_LOGON_FAILURE));
1746 END_PROFILE(SMBsesssetupX);
1747 return;
1748 }
1749
1750 /* current_user_info is changed on new vuid */
1751 reload_services(sconn->msg_ctx, sconn->sock, True);
1752 }
1753
1754 data_blob_free(&nt_resp);
1755 data_blob_free(&lm_resp);
1756
1757 SSVAL(req->outbuf,smb_uid,sess_vuid);
1758 SSVAL(req->inbuf,smb_uid,sess_vuid);
1759 req->vuid = sess_vuid;
1760
1761 if (!sconn->smb1.sessions.done_sesssetup) {
1762 sconn->smb1.sessions.max_send =
1763 MIN(sconn->smb1.sessions.max_send,smb_bufsize);
1764 }
1765 sconn->smb1.sessions.done_sesssetup = true;
1766
1767 END_PROFILE(SMBsesssetupX);
1768 chain_reply(req);
1769 return;
1770}
Note: See TracBrowser for help on using the repository browser.