Fix bug #9174: Empty SPNEGO packet can cause smbd to crash.
[Samba.git] / source3 / smbd / sesssetup.c
blob4f09db929ac9834dd38d69646c6ba5f087a5cede
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
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.
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.
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/>.
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"
39 /* For split krb5 SPNEGO blobs. */
40 struct 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;
49 on a logon error possibly map the error to success if "map to guest"
50 is set approriately
52 NTSTATUS do_map_to_guest(NTSTATUS status,
53 struct auth_serversupplied_info **server_info,
54 const char *user, const char *domain)
56 user = user ? user : "";
57 domain = domain ? domain : "";
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);
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);
76 return status;
79 /****************************************************************************
80 Add the standard 'Samba' signature to the end of the session setup.
81 ****************************************************************************/
83 static int push_signature(uint8 **outbuf)
85 char *lanman;
86 int result, tmp;
88 result = 0;
90 tmp = message_push_string(outbuf, "Unix", STR_TERMINATE);
92 if (tmp == -1) return -1;
93 result += tmp;
95 if (asprintf(&lanman, "Samba %s", samba_version_string()) != -1) {
96 tmp = message_push_string(outbuf, lanman, STR_TERMINATE);
97 SAFE_FREE(lanman);
99 else {
100 tmp = message_push_string(outbuf, "Samba", STR_TERMINATE);
103 if (tmp == -1) return -1;
104 result += tmp;
106 tmp = message_push_string(outbuf, lp_workgroup(), STR_TERMINATE);
108 if (tmp == -1) return -1;
109 result += tmp;
111 return result;
114 /****************************************************************************
115 Send a security blob via a session setup reply.
116 ****************************************************************************/
118 static void reply_sesssetup_blob(struct smb_request *req,
119 DATA_BLOB blob,
120 NTSTATUS nt_status)
122 if (!NT_STATUS_IS_OK(nt_status) &&
123 !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
124 reply_nterror(req, nt_status_squash(nt_status));
125 return;
128 nt_status = nt_status_squash(nt_status);
129 SIVAL(req->outbuf, smb_rcls, NT_STATUS_V(nt_status));
130 SSVAL(req->outbuf, smb_vwv0, 0xFF); /* no chaining possible */
131 SSVAL(req->outbuf, smb_vwv3, blob.length);
133 if ((message_push_blob(&req->outbuf, blob) == -1)
134 || (push_signature(&req->outbuf) == -1)) {
135 reply_nterror(req, NT_STATUS_NO_MEMORY);
139 /****************************************************************************
140 Do a 'guest' logon, getting back the
141 ****************************************************************************/
143 static NTSTATUS check_guest_password(struct auth_serversupplied_info **server_info)
145 struct auth_context *auth_context;
146 struct auth_usersupplied_info *user_info = NULL;
148 NTSTATUS nt_status;
149 static unsigned char chal[8] = { 0, };
151 DEBUG(3,("Got anonymous request\n"));
153 nt_status = make_auth_context_fixed(talloc_tos(), &auth_context, chal);
154 if (!NT_STATUS_IS_OK(nt_status)) {
155 return nt_status;
158 if (!make_user_info_guest(&user_info)) {
159 TALLOC_FREE(auth_context);
160 return NT_STATUS_NO_MEMORY;
163 nt_status = auth_context->check_ntlm_password(auth_context,
164 user_info,
165 server_info);
166 TALLOC_FREE(auth_context);
167 free_user_info(&user_info);
168 return nt_status;
172 #ifdef HAVE_KRB5
174 #if 0
175 /* Experiment that failed. See "only happens with a KDC" comment below. */
176 /****************************************************************************
177 Cerate a clock skew error blob for a Windows client.
178 ****************************************************************************/
180 static bool make_krb5_skew_error(DATA_BLOB *pblob_out)
182 krb5_context context = NULL;
183 krb5_error_code kerr = 0;
184 krb5_data reply;
185 krb5_principal host_princ = NULL;
186 char *host_princ_s = NULL;
187 bool ret = False;
189 *pblob_out = data_blob_null;
191 initialize_krb5_error_table();
192 kerr = krb5_init_context(&context);
193 if (kerr) {
194 return False;
196 /* Create server principal. */
197 asprintf(&host_princ_s, "%s$@%s", global_myname(), lp_realm());
198 if (!host_princ_s) {
199 goto out;
201 strlower_m(host_princ_s);
203 kerr = smb_krb5_parse_name(context, host_princ_s, &host_princ);
204 if (kerr) {
205 DEBUG(10,("make_krb5_skew_error: smb_krb5_parse_name failed "
206 "for name %s: Error %s\n",
207 host_princ_s, error_message(kerr) ));
208 goto out;
211 kerr = smb_krb5_mk_error(context, KRB5KRB_AP_ERR_SKEW,
212 host_princ, &reply);
213 if (kerr) {
214 DEBUG(10,("make_krb5_skew_error: smb_krb5_mk_error "
215 "failed: Error %s\n",
216 error_message(kerr) ));
217 goto out;
220 *pblob_out = data_blob(reply.data, reply.length);
221 kerberos_free_data_contents(context,&reply);
222 ret = True;
224 out:
226 if (host_princ_s) {
227 SAFE_FREE(host_princ_s);
229 if (host_princ) {
230 krb5_free_principal(context, host_princ);
232 krb5_free_context(context);
233 return ret;
235 #endif
237 /****************************************************************************
238 Reply to a session setup spnego negotiate packet for kerberos.
239 ****************************************************************************/
241 static void reply_spnego_kerberos(struct smb_request *req,
242 DATA_BLOB *secblob,
243 const char *mechOID,
244 uint16 vuid,
245 bool *p_invalidate_vuid)
247 TALLOC_CTX *mem_ctx;
248 DATA_BLOB ticket;
249 struct passwd *pw;
250 int sess_vuid = req->vuid;
251 NTSTATUS ret = NT_STATUS_OK;
252 DATA_BLOB ap_rep, ap_rep_wrapped, response;
253 struct auth_serversupplied_info *server_info = NULL;
254 DATA_BLOB session_key = data_blob_null;
255 uint8 tok_id[2];
256 DATA_BLOB nullblob = data_blob_null;
257 bool map_domainuser_to_guest = False;
258 bool username_was_mapped;
259 struct PAC_LOGON_INFO *logon_info = NULL;
260 struct smbd_server_connection *sconn = req->sconn;
261 char *principal;
262 char *user;
263 char *domain;
264 char *real_username;
266 ZERO_STRUCT(ticket);
267 ZERO_STRUCT(ap_rep);
268 ZERO_STRUCT(ap_rep_wrapped);
269 ZERO_STRUCT(response);
271 /* Normally we will always invalidate the intermediate vuid. */
272 *p_invalidate_vuid = True;
274 mem_ctx = talloc_init("reply_spnego_kerberos");
275 if (mem_ctx == NULL) {
276 reply_nterror(req, nt_status_squash(NT_STATUS_NO_MEMORY));
277 return;
280 if (!spnego_parse_krb5_wrap(mem_ctx, *secblob, &ticket, tok_id)) {
281 talloc_destroy(mem_ctx);
282 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
283 return;
286 ret = ads_verify_ticket(mem_ctx, lp_realm(), 0, &ticket,
287 &principal, &logon_info, &ap_rep,
288 &session_key, True);
290 data_blob_free(&ticket);
292 if (!NT_STATUS_IS_OK(ret)) {
293 #if 0
294 /* Experiment that failed.
295 * See "only happens with a KDC" comment below. */
297 if (NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
300 * Windows in this case returns
301 * NT_STATUS_MORE_PROCESSING_REQUIRED
302 * with a negTokenTarg blob containing an krb5_error
303 * struct ASN1 encoded containing KRB5KRB_AP_ERR_SKEW.
304 * The client then fixes its clock and continues rather
305 * than giving an error. JRA.
306 * -- Looks like this only happens with a KDC. JRA.
309 bool ok = make_krb5_skew_error(&ap_rep);
310 if (!ok) {
311 talloc_destroy(mem_ctx);
312 return ERROR_NT(nt_status_squash(
313 NT_STATUS_LOGON_FAILURE));
315 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
316 TOK_ID_KRB_ERROR);
317 response = spnego_gen_auth_response(&ap_rep_wrapped,
318 ret, OID_KERBEROS5_OLD);
319 reply_sesssetup_blob(conn, inbuf, outbuf, response,
320 NT_STATUS_MORE_PROCESSING_REQUIRED);
323 * In this one case we don't invalidate the
324 * intermediate vuid as we're expecting the client
325 * to re-use it for the next sessionsetupX packet. JRA.
328 *p_invalidate_vuid = False;
330 data_blob_free(&ap_rep);
331 data_blob_free(&ap_rep_wrapped);
332 data_blob_free(&response);
333 talloc_destroy(mem_ctx);
334 return -1; /* already replied */
336 #else
337 if (!NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
338 ret = NT_STATUS_LOGON_FAILURE;
340 #endif
341 DEBUG(1,("Failed to verify incoming ticket with error %s!\n",
342 nt_errstr(ret)));
343 talloc_destroy(mem_ctx);
344 reply_nterror(req, nt_status_squash(ret));
345 return;
348 ret = get_user_from_kerberos_info(talloc_tos(),
349 sconn->client_id.name,
350 principal, logon_info,
351 &username_was_mapped,
352 &map_domainuser_to_guest,
353 &user, &domain,
354 &real_username, &pw);
355 if (!NT_STATUS_IS_OK(ret)) {
356 data_blob_free(&ap_rep);
357 data_blob_free(&session_key);
358 talloc_destroy(mem_ctx);
359 reply_nterror(req,nt_status_squash(NT_STATUS_LOGON_FAILURE));
360 return;
363 /* save the PAC data if we have it */
364 if (logon_info) {
365 netsamlogon_cache_store(user, &logon_info->info3);
368 /* setup the string used by %U */
369 sub_set_smb_name(real_username);
371 /* reload services so that the new %U is taken into account */
372 reload_services(sconn->msg_ctx, sconn->sock, True);
374 ret = make_server_info_krb5(mem_ctx,
375 user, domain, real_username, pw,
376 logon_info, map_domainuser_to_guest,
377 &server_info);
378 if (!NT_STATUS_IS_OK(ret)) {
379 DEBUG(1, ("make_server_info_krb5 failed!\n"));
380 data_blob_free(&ap_rep);
381 data_blob_free(&session_key);
382 TALLOC_FREE(mem_ctx);
383 reply_nterror(req, nt_status_squash(ret));
384 return;
387 server_info->nss_token |= username_was_mapped;
389 /* we need to build the token for the user. make_server_info_guest()
390 already does this */
392 if ( !server_info->security_token ) {
393 ret = create_local_token( server_info );
394 if ( !NT_STATUS_IS_OK(ret) ) {
395 DEBUG(10,("failed to create local token: %s\n",
396 nt_errstr(ret)));
397 data_blob_free(&ap_rep);
398 data_blob_free(&session_key);
399 TALLOC_FREE( mem_ctx );
400 TALLOC_FREE( server_info );
401 reply_nterror(req, nt_status_squash(ret));
402 return;
406 if (!is_partial_auth_vuid(sconn, sess_vuid)) {
407 sess_vuid = register_initial_vuid(sconn);
410 data_blob_free(&server_info->user_session_key);
411 /* Set the kerberos-derived session key onto the server_info */
412 server_info->user_session_key = session_key;
413 talloc_steal(server_info, session_key.data);
415 session_key = data_blob_null;
417 /* register_existing_vuid keeps the server info */
418 /* register_existing_vuid takes ownership of session_key on success,
419 * no need to free after this on success. A better interface would copy
420 * it.... */
422 sess_vuid = register_existing_vuid(sconn, sess_vuid,
423 server_info, nullblob, user);
425 reply_outbuf(req, 4, 0);
426 SSVAL(req->outbuf,smb_uid,sess_vuid);
428 if (sess_vuid == UID_FIELD_INVALID ) {
429 ret = NT_STATUS_LOGON_FAILURE;
430 } else {
431 /* current_user_info is changed on new vuid */
432 reload_services(sconn->msg_ctx, sconn->sock, True);
434 SSVAL(req->outbuf, smb_vwv3, 0);
436 if (server_info->guest) {
437 SSVAL(req->outbuf,smb_vwv2,1);
440 SSVAL(req->outbuf, smb_uid, sess_vuid);
442 /* Successful logon. Keep this vuid. */
443 *p_invalidate_vuid = False;
446 /* wrap that up in a nice GSS-API wrapping */
447 if (NT_STATUS_IS_OK(ret)) {
448 ap_rep_wrapped = spnego_gen_krb5_wrap(talloc_tos(), ap_rep,
449 TOK_ID_KRB_AP_REP);
450 } else {
451 ap_rep_wrapped = data_blob_null;
453 response = spnego_gen_auth_response(talloc_tos(), &ap_rep_wrapped, ret,
454 mechOID);
455 reply_sesssetup_blob(req, response, ret);
457 data_blob_free(&ap_rep);
458 data_blob_free(&ap_rep_wrapped);
459 data_blob_free(&response);
460 TALLOC_FREE(mem_ctx);
463 #endif
465 /****************************************************************************
466 Send a session setup reply, wrapped in SPNEGO.
467 Get vuid and check first.
468 End the NTLMSSP exchange context if we are OK/complete fail
469 This should be split into two functions, one to handle each
470 leg of the NTLM auth steps.
471 ***************************************************************************/
473 static void reply_spnego_ntlmssp(struct smb_request *req,
474 uint16 vuid,
475 struct auth_ntlmssp_state **auth_ntlmssp_state,
476 DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status,
477 const char *OID,
478 bool wrap)
480 bool do_invalidate = true;
481 DATA_BLOB response;
482 struct auth_serversupplied_info *session_info = NULL;
483 struct smbd_server_connection *sconn = req->sconn;
485 if (NT_STATUS_IS_OK(nt_status)) {
486 nt_status = auth_ntlmssp_steal_session_info(talloc_tos(),
487 (*auth_ntlmssp_state), &session_info);
488 } else {
489 /* Note that this session_info won't have a session
490 * key. But for map to guest, that's exactly the right
491 * thing - we can't reasonably guess the key the
492 * client wants, as the password was wrong */
493 nt_status = do_map_to_guest(nt_status,
494 &session_info,
495 auth_ntlmssp_get_username(*auth_ntlmssp_state),
496 auth_ntlmssp_get_domain(*auth_ntlmssp_state));
499 reply_outbuf(req, 4, 0);
501 SSVAL(req->outbuf, smb_uid, vuid);
503 if (NT_STATUS_IS_OK(nt_status)) {
504 DATA_BLOB nullblob = data_blob_null;
506 if (!is_partial_auth_vuid(sconn, vuid)) {
507 nt_status = NT_STATUS_LOGON_FAILURE;
508 goto out;
511 /* register_existing_vuid keeps the server info */
512 if (register_existing_vuid(sconn, vuid,
513 session_info, nullblob,
514 auth_ntlmssp_get_username(*auth_ntlmssp_state)) !=
515 vuid) {
516 /* The problem is, *auth_ntlmssp_state points
517 * into the vuser this will have
518 * talloc_free()'ed in
519 * register_existing_vuid() */
520 do_invalidate = false;
521 nt_status = NT_STATUS_LOGON_FAILURE;
522 goto out;
525 /* current_user_info is changed on new vuid */
526 reload_services(sconn->msg_ctx, sconn->sock, True);
528 SSVAL(req->outbuf, smb_vwv3, 0);
530 if (session_info->guest) {
531 SSVAL(req->outbuf,smb_vwv2,1);
535 out:
537 if (wrap) {
538 response = spnego_gen_auth_response(talloc_tos(),
539 ntlmssp_blob,
540 nt_status, OID);
541 } else {
542 response = *ntlmssp_blob;
545 reply_sesssetup_blob(req, response, nt_status);
546 if (wrap) {
547 data_blob_free(&response);
550 /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
551 and the other end, that we are not finished yet. */
553 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
554 /* NB. This is *NOT* an error case. JRA */
555 if (do_invalidate) {
556 TALLOC_FREE(*auth_ntlmssp_state);
557 if (!NT_STATUS_IS_OK(nt_status)) {
558 /* Kill the intermediate vuid */
559 invalidate_vuid(sconn, vuid);
565 /****************************************************************************
566 Is this a krb5 mechanism ?
567 ****************************************************************************/
569 NTSTATUS parse_spnego_mechanisms(TALLOC_CTX *ctx,
570 DATA_BLOB blob_in,
571 DATA_BLOB *pblob_out,
572 char **kerb_mechOID)
574 char *OIDs[ASN1_MAX_OIDS];
575 int i;
576 NTSTATUS ret = NT_STATUS_OK;
578 *kerb_mechOID = NULL;
580 /* parse out the OIDs and the first sec blob */
581 if (!spnego_parse_negTokenInit(ctx, blob_in, OIDs, NULL, pblob_out) ||
582 (OIDs[0] == NULL)) {
583 return NT_STATUS_LOGON_FAILURE;
586 /* only look at the first OID for determining the mechToken --
587 according to RFC2478, we should choose the one we want
588 and renegotiate, but i smell a client bug here..
590 Problem observed when connecting to a member (samba box)
591 of an AD domain as a user in a Samba domain. Samba member
592 server sent back krb5/mskrb5/ntlmssp as mechtypes, but the
593 client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an
594 NTLMSSP mechtoken. --jerry */
596 #ifdef HAVE_KRB5
597 if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
598 strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
599 *kerb_mechOID = talloc_strdup(ctx, OIDs[0]);
600 if (*kerb_mechOID == NULL) {
601 ret = NT_STATUS_NO_MEMORY;
604 #endif
606 for (i=0;OIDs[i];i++) {
607 DEBUG(5,("parse_spnego_mechanisms: Got OID %s\n", OIDs[i]));
608 talloc_free(OIDs[i]);
610 return ret;
613 /****************************************************************************
614 Fall back from krb5 to NTLMSSP.
615 ****************************************************************************/
617 static void reply_spnego_downgrade_to_ntlmssp(struct smb_request *req,
618 uint16 vuid)
620 DATA_BLOB response;
622 reply_outbuf(req, 4, 0);
623 SSVAL(req->outbuf,smb_uid,vuid);
625 DEBUG(3,("reply_spnego_downgrade_to_ntlmssp: Got krb5 ticket in SPNEGO "
626 "but set to downgrade to NTLMSSP\n"));
628 response = spnego_gen_auth_response(talloc_tos(), NULL,
629 NT_STATUS_MORE_PROCESSING_REQUIRED,
630 OID_NTLMSSP);
631 reply_sesssetup_blob(req, response, NT_STATUS_MORE_PROCESSING_REQUIRED);
632 data_blob_free(&response);
635 /****************************************************************************
636 Reply to a session setup spnego negotiate packet.
637 ****************************************************************************/
639 static void reply_spnego_negotiate(struct smb_request *req,
640 uint16 vuid,
641 DATA_BLOB blob1,
642 struct auth_ntlmssp_state **auth_ntlmssp_state)
644 DATA_BLOB secblob;
645 DATA_BLOB chal;
646 char *kerb_mech = NULL;
647 NTSTATUS status;
648 struct smbd_server_connection *sconn = req->sconn;
650 status = parse_spnego_mechanisms(talloc_tos(),
651 blob1, &secblob, &kerb_mech);
652 if (!NT_STATUS_IS_OK(status)) {
653 /* Kill the intermediate vuid */
654 invalidate_vuid(sconn, vuid);
655 reply_nterror(req, nt_status_squash(status));
656 return;
659 DEBUG(3,("reply_spnego_negotiate: Got secblob of size %lu\n",
660 (unsigned long)secblob.length));
662 #ifdef HAVE_KRB5
663 if (kerb_mech && ((lp_security()==SEC_ADS) ||
664 USE_KERBEROS_KEYTAB) ) {
665 bool destroy_vuid = True;
666 reply_spnego_kerberos(req, &secblob, kerb_mech,
667 vuid, &destroy_vuid);
668 data_blob_free(&secblob);
669 if (destroy_vuid) {
670 /* Kill the intermediate vuid */
671 invalidate_vuid(sconn, vuid);
673 TALLOC_FREE(kerb_mech);
674 return;
676 #endif
678 TALLOC_FREE(*auth_ntlmssp_state);
680 if (kerb_mech) {
681 data_blob_free(&secblob);
682 /* The mechtoken is a krb5 ticket, but
683 * we need to fall back to NTLM. */
684 reply_spnego_downgrade_to_ntlmssp(req, vuid);
685 TALLOC_FREE(kerb_mech);
686 return;
689 status = auth_ntlmssp_start(auth_ntlmssp_state);
690 if (!NT_STATUS_IS_OK(status)) {
691 /* Kill the intermediate vuid */
692 invalidate_vuid(sconn, vuid);
693 reply_nterror(req, nt_status_squash(status));
694 return;
697 status = auth_ntlmssp_update(*auth_ntlmssp_state,
698 secblob, &chal);
700 data_blob_free(&secblob);
702 reply_spnego_ntlmssp(req, vuid, auth_ntlmssp_state,
703 &chal, status, OID_NTLMSSP, true);
705 data_blob_free(&chal);
707 /* already replied */
708 return;
711 /****************************************************************************
712 Reply to a session setup spnego auth packet.
713 ****************************************************************************/
715 static void reply_spnego_auth(struct smb_request *req,
716 uint16 vuid,
717 DATA_BLOB blob1,
718 struct auth_ntlmssp_state **auth_ntlmssp_state)
720 DATA_BLOB auth = data_blob_null;
721 DATA_BLOB auth_reply = data_blob_null;
722 DATA_BLOB secblob = data_blob_null;
723 NTSTATUS status = NT_STATUS_LOGON_FAILURE;
724 struct smbd_server_connection *sconn = req->sconn;
726 if (!spnego_parse_auth(talloc_tos(), blob1, &auth)) {
727 #if 0
728 file_save("auth.dat", blob1.data, blob1.length);
729 #endif
730 /* Kill the intermediate vuid */
731 invalidate_vuid(sconn, vuid);
733 reply_nterror(req, nt_status_squash(
734 NT_STATUS_LOGON_FAILURE));
735 return;
738 if (auth.length > 0 && auth.data[0] == ASN1_APPLICATION(0)) {
739 /* Might be a second negTokenTarg packet */
740 char *kerb_mech = NULL;
742 status = parse_spnego_mechanisms(talloc_tos(),
743 auth, &secblob, &kerb_mech);
745 if (!NT_STATUS_IS_OK(status)) {
746 /* Kill the intermediate vuid */
747 invalidate_vuid(sconn, vuid);
748 reply_nterror(req, nt_status_squash(status));
749 return;
752 DEBUG(3,("reply_spnego_auth: Got secblob of size %lu\n",
753 (unsigned long)secblob.length));
754 #ifdef HAVE_KRB5
755 if (kerb_mech && ((lp_security()==SEC_ADS) ||
756 USE_KERBEROS_KEYTAB)) {
757 bool destroy_vuid = True;
758 reply_spnego_kerberos(req, &secblob, kerb_mech,
759 vuid, &destroy_vuid);
760 data_blob_free(&secblob);
761 data_blob_free(&auth);
762 if (destroy_vuid) {
763 /* Kill the intermediate vuid */
764 invalidate_vuid(sconn, vuid);
766 TALLOC_FREE(kerb_mech);
767 return;
769 #endif
770 /* Can't blunder into NTLMSSP auth if we have
771 * a krb5 ticket. */
773 if (kerb_mech) {
774 /* Kill the intermediate vuid */
775 invalidate_vuid(sconn, vuid);
776 DEBUG(3,("reply_spnego_auth: network "
777 "misconfiguration, client sent us a "
778 "krb5 ticket and kerberos security "
779 "not enabled\n"));
780 reply_nterror(req, nt_status_squash(
781 NT_STATUS_LOGON_FAILURE));
782 TALLOC_FREE(kerb_mech);
786 /* If we get here it wasn't a negTokenTarg auth packet. */
787 data_blob_free(&secblob);
789 if (!*auth_ntlmssp_state) {
790 status = auth_ntlmssp_start(auth_ntlmssp_state);
791 if (!NT_STATUS_IS_OK(status)) {
792 /* Kill the intermediate vuid */
793 invalidate_vuid(sconn, vuid);
794 reply_nterror(req, nt_status_squash(status));
795 return;
799 status = auth_ntlmssp_update(*auth_ntlmssp_state,
800 auth, &auth_reply);
802 data_blob_free(&auth);
804 /* Don't send the mechid as we've already sent this (RFC4178). */
806 reply_spnego_ntlmssp(req, vuid,
807 auth_ntlmssp_state,
808 &auth_reply, status, NULL, true);
810 data_blob_free(&auth_reply);
812 /* and tell smbd that we have already replied to this packet */
813 return;
816 /****************************************************************************
817 Delete an entry on the list.
818 ****************************************************************************/
820 static void delete_partial_auth(struct smbd_server_connection *sconn,
821 struct pending_auth_data *pad)
823 if (!pad) {
824 return;
826 DLIST_REMOVE(sconn->smb1.pd_list, pad);
827 data_blob_free(&pad->partial_data);
828 SAFE_FREE(pad);
831 /****************************************************************************
832 Search for a partial SPNEGO auth fragment matching an smbpid.
833 ****************************************************************************/
835 static struct pending_auth_data *get_pending_auth_data(
836 struct smbd_server_connection *sconn,
837 uint16_t smbpid)
839 struct pending_auth_data *pad;
841 * NOTE: using the smbpid here is completely wrong...
842 * see [MS-SMB]
843 * 3.3.5.3 Receiving an SMB_COM_SESSION_SETUP_ANDX Request
845 for (pad = sconn->smb1.pd_list; pad; pad = pad->next) {
846 if (pad->smbpid == smbpid) {
847 break;
850 return pad;
853 /****************************************************************************
854 Check the size of an SPNEGO blob. If we need more return
855 NT_STATUS_MORE_PROCESSING_REQUIRED, else return NT_STATUS_OK. Don't allow
856 the blob to be more than 64k.
857 ****************************************************************************/
859 static NTSTATUS check_spnego_blob_complete(struct smbd_server_connection *sconn,
860 uint16 smbpid, uint16 vuid,
861 DATA_BLOB *pblob)
863 struct pending_auth_data *pad = NULL;
864 ASN1_DATA *data;
865 size_t needed_len = 0;
867 pad = get_pending_auth_data(sconn, smbpid);
869 /* Ensure we have some data. */
870 if (pblob->length == 0) {
871 /* Caller can cope. */
872 DEBUG(2,("check_spnego_blob_complete: zero blob length !\n"));
873 delete_partial_auth(sconn, pad);
874 return NT_STATUS_OK;
877 /* Were we waiting for more data ? */
878 if (pad) {
879 DATA_BLOB tmp_blob;
880 size_t copy_len = MIN(65536, pblob->length);
882 /* Integer wrap paranoia.... */
884 if (pad->partial_data.length + copy_len <
885 pad->partial_data.length ||
886 pad->partial_data.length + copy_len < copy_len) {
888 DEBUG(2,("check_spnego_blob_complete: integer wrap "
889 "pad->partial_data.length = %u, "
890 "copy_len = %u\n",
891 (unsigned int)pad->partial_data.length,
892 (unsigned int)copy_len ));
894 delete_partial_auth(sconn, pad);
895 return NT_STATUS_INVALID_PARAMETER;
898 DEBUG(10,("check_spnego_blob_complete: "
899 "pad->partial_data.length = %u, "
900 "pad->needed_len = %u, "
901 "copy_len = %u, "
902 "pblob->length = %u,\n",
903 (unsigned int)pad->partial_data.length,
904 (unsigned int)pad->needed_len,
905 (unsigned int)copy_len,
906 (unsigned int)pblob->length ));
908 tmp_blob = data_blob(NULL,
909 pad->partial_data.length + copy_len);
911 /* Concatenate the two (up to copy_len) bytes. */
912 memcpy(tmp_blob.data,
913 pad->partial_data.data,
914 pad->partial_data.length);
915 memcpy(tmp_blob.data + pad->partial_data.length,
916 pblob->data,
917 copy_len);
919 /* Replace the partial data. */
920 data_blob_free(&pad->partial_data);
921 pad->partial_data = tmp_blob;
922 ZERO_STRUCT(tmp_blob);
924 /* Are we done ? */
925 if (pblob->length >= pad->needed_len) {
926 /* Yes, replace pblob. */
927 data_blob_free(pblob);
928 *pblob = pad->partial_data;
929 ZERO_STRUCT(pad->partial_data);
930 delete_partial_auth(sconn, pad);
931 return NT_STATUS_OK;
934 /* Still need more data. */
935 pad->needed_len -= copy_len;
936 return NT_STATUS_MORE_PROCESSING_REQUIRED;
939 if ((pblob->data[0] != ASN1_APPLICATION(0)) &&
940 (pblob->data[0] != ASN1_CONTEXT(1))) {
941 /* Not something we can determine the
942 * length of.
944 return NT_STATUS_OK;
947 /* This is a new SPNEGO sessionsetup - see if
948 * the data given in this blob is enough.
951 data = asn1_init(NULL);
952 if (data == NULL) {
953 return NT_STATUS_NO_MEMORY;
956 asn1_load(data, *pblob);
957 if (asn1_start_tag(data, pblob->data[0])) {
958 /* asn1_start_tag checks if the given
959 length of the blob is enough to complete
960 the tag. If it returns true we know
961 there is nothing to do - the blob is
962 complete. */
963 asn1_free(data);
964 return NT_STATUS_OK;
967 if (data->nesting == NULL) {
968 /* Incorrect tag, allocation failed,
969 or reading the tag length failed.
970 Let the caller catch. */
971 asn1_free(data);
972 return NT_STATUS_OK;
975 /* Here we know asn1_start_tag() has set data->has_error to true.
976 asn1_tag_remaining() will have failed due to the given blob
977 being too short. We need to work out how short. */
979 /* Integer wrap paranoia.... */
981 if (data->nesting->taglen + data->nesting->start < data->nesting->taglen ||
982 data->nesting->taglen + data->nesting->start < data->nesting->start) {
984 DEBUG(2,("check_spnego_blob_complete: integer wrap "
985 "data.nesting->taglen = %u, "
986 "data.nesting->start = %u\n",
987 (unsigned int)data->nesting->taglen,
988 (unsigned int)data->nesting->start ));
990 asn1_free(data);
991 return NT_STATUS_INVALID_PARAMETER;
994 /* Total length of the needed asn1 is the tag length
995 * plus the current offset. */
997 needed_len = data->nesting->taglen + data->nesting->start;
998 asn1_free(data);
1000 DEBUG(10,("check_spnego_blob_complete: needed_len = %u, "
1001 "pblob->length = %u\n",
1002 (unsigned int)needed_len,
1003 (unsigned int)pblob->length ));
1005 if (needed_len <= pblob->length) {
1006 /* Nothing to do - blob is complete. */
1007 /* THIS SHOULD NOT HAPPEN - asn1_start_tag()
1008 above should have caught this !!! */
1009 DEBUG(0,("check_spnego_blob_complete: logic "
1010 "error (needed_len = %u, "
1011 "pblob->length = %u).\n",
1012 (unsigned int)needed_len,
1013 (unsigned int)pblob->length ));
1014 return NT_STATUS_OK;
1017 /* Refuse the blob if it's bigger than 64k. */
1018 if (needed_len > 65536) {
1019 DEBUG(2,("check_spnego_blob_complete: needed_len "
1020 "too large (%u)\n",
1021 (unsigned int)needed_len ));
1022 return NT_STATUS_INVALID_PARAMETER;
1025 /* We must store this blob until complete. */
1026 if (!(pad = SMB_MALLOC_P(struct pending_auth_data))) {
1027 return NT_STATUS_NO_MEMORY;
1029 pad->needed_len = needed_len - pblob->length;
1030 pad->partial_data = data_blob(pblob->data, pblob->length);
1031 if (pad->partial_data.data == NULL) {
1032 SAFE_FREE(pad);
1033 return NT_STATUS_NO_MEMORY;
1035 pad->smbpid = smbpid;
1036 pad->vuid = vuid;
1037 DLIST_ADD(sconn->smb1.pd_list, pad);
1039 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1042 /****************************************************************************
1043 Reply to a session setup command.
1044 conn POINTER CAN BE NULL HERE !
1045 ****************************************************************************/
1047 static void reply_sesssetup_and_X_spnego(struct smb_request *req)
1049 const uint8 *p;
1050 DATA_BLOB blob1;
1051 size_t bufrem;
1052 char *tmp;
1053 const char *native_os;
1054 const char *native_lanman;
1055 const char *primary_domain;
1056 const char *p2;
1057 uint16 data_blob_len = SVAL(req->vwv+7, 0);
1058 enum remote_arch_types ra_type = get_remote_arch();
1059 int vuid = req->vuid;
1060 user_struct *vuser = NULL;
1061 NTSTATUS status = NT_STATUS_OK;
1062 uint16 smbpid = req->smbpid;
1063 struct smbd_server_connection *sconn = req->sconn;
1065 DEBUG(3,("Doing spnego session setup\n"));
1067 if (global_client_caps == 0) {
1068 global_client_caps = IVAL(req->vwv+10, 0);
1070 if (!(global_client_caps & CAP_STATUS32)) {
1071 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1076 p = req->buf;
1078 if (data_blob_len == 0) {
1079 /* an invalid request */
1080 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1081 return;
1084 bufrem = smbreq_bufrem(req, p);
1085 /* pull the spnego blob */
1086 blob1 = data_blob(p, MIN(bufrem, data_blob_len));
1088 #if 0
1089 file_save("negotiate.dat", blob1.data, blob1.length);
1090 #endif
1092 p2 = (char *)req->buf + blob1.length;
1094 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1095 STR_TERMINATE);
1096 native_os = tmp ? tmp : "";
1098 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1099 STR_TERMINATE);
1100 native_lanman = tmp ? tmp : "";
1102 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1103 STR_TERMINATE);
1104 primary_domain = tmp ? tmp : "";
1106 DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
1107 native_os, native_lanman, primary_domain));
1109 if ( ra_type == RA_WIN2K ) {
1110 /* Vista sets neither the OS or lanman strings */
1112 if ( !strlen(native_os) && !strlen(native_lanman) )
1113 set_remote_arch(RA_VISTA);
1115 /* Windows 2003 doesn't set the native lanman string,
1116 but does set primary domain which is a bug I think */
1118 if ( !strlen(native_lanman) ) {
1119 ra_lanman_string( primary_domain );
1120 } else {
1121 ra_lanman_string( native_lanman );
1123 } else if ( ra_type == RA_VISTA ) {
1124 if ( strncmp(native_os, "Mac OS X", 8) == 0 ) {
1125 set_remote_arch(RA_OSX);
1129 /* Did we get a valid vuid ? */
1130 if (!is_partial_auth_vuid(sconn, vuid)) {
1131 /* No, then try and see if this is an intermediate sessionsetup
1132 * for a large SPNEGO packet. */
1133 struct pending_auth_data *pad;
1134 pad = get_pending_auth_data(sconn, smbpid);
1135 if (pad) {
1136 DEBUG(10,("reply_sesssetup_and_X_spnego: found "
1137 "pending vuid %u\n",
1138 (unsigned int)pad->vuid ));
1139 vuid = pad->vuid;
1143 /* Do we have a valid vuid now ? */
1144 if (!is_partial_auth_vuid(sconn, vuid)) {
1145 /* No, start a new authentication setup. */
1146 vuid = register_initial_vuid(sconn);
1147 if (vuid == UID_FIELD_INVALID) {
1148 data_blob_free(&blob1);
1149 reply_nterror(req, nt_status_squash(
1150 NT_STATUS_INVALID_PARAMETER));
1151 return;
1155 vuser = get_partial_auth_user_struct(sconn, vuid);
1156 /* This MUST be valid. */
1157 if (!vuser) {
1158 smb_panic("reply_sesssetup_and_X_spnego: invalid vuid.");
1161 /* Large (greater than 4k) SPNEGO blobs are split into multiple
1162 * sessionsetup requests as the Windows limit on the security blob
1163 * field is 4k. Bug #4400. JRA.
1166 status = check_spnego_blob_complete(sconn, smbpid, vuid, &blob1);
1167 if (!NT_STATUS_IS_OK(status)) {
1168 if (!NT_STATUS_EQUAL(status,
1169 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1170 /* Real error - kill the intermediate vuid */
1171 invalidate_vuid(sconn, vuid);
1173 data_blob_free(&blob1);
1174 reply_nterror(req, nt_status_squash(status));
1175 return;
1178 if (blob1.data[0] == ASN1_APPLICATION(0)) {
1180 /* its a negTokenTarg packet */
1182 reply_spnego_negotiate(req, vuid, blob1,
1183 &vuser->auth_ntlmssp_state);
1184 data_blob_free(&blob1);
1185 return;
1188 if (blob1.data[0] == ASN1_CONTEXT(1)) {
1190 /* its a auth packet */
1192 reply_spnego_auth(req, vuid, blob1,
1193 &vuser->auth_ntlmssp_state);
1194 data_blob_free(&blob1);
1195 return;
1198 if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) {
1199 DATA_BLOB chal;
1201 if (!vuser->auth_ntlmssp_state) {
1202 status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state);
1203 if (!NT_STATUS_IS_OK(status)) {
1204 /* Kill the intermediate vuid */
1205 invalidate_vuid(sconn, vuid);
1206 data_blob_free(&blob1);
1207 reply_nterror(req, nt_status_squash(status));
1208 return;
1212 status = auth_ntlmssp_update(vuser->auth_ntlmssp_state,
1213 blob1, &chal);
1215 data_blob_free(&blob1);
1217 reply_spnego_ntlmssp(req, vuid,
1218 &vuser->auth_ntlmssp_state,
1219 &chal, status, OID_NTLMSSP, false);
1220 data_blob_free(&chal);
1221 return;
1224 /* what sort of packet is this? */
1225 DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
1227 data_blob_free(&blob1);
1229 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1232 /****************************************************************************
1233 On new VC == 0, shutdown *all* old connections and users.
1234 It seems that only NT4.x does this. At W2K and above (XP etc.).
1235 a new session setup with VC==0 is ignored.
1236 ****************************************************************************/
1238 struct shutdown_state {
1239 const char *ip;
1240 struct messaging_context *msg_ctx;
1243 static int shutdown_other_smbds(const struct connections_key *key,
1244 const struct connections_data *crec,
1245 void *private_data)
1247 struct shutdown_state *state = (struct shutdown_state *)private_data;
1249 DEBUG(10, ("shutdown_other_smbds: %s, %s\n",
1250 procid_str(talloc_tos(), &crec->pid), crec->addr));
1252 if (!process_exists(crec->pid)) {
1253 DEBUG(10, ("process does not exist\n"));
1254 return 0;
1257 if (procid_is_me(&crec->pid)) {
1258 DEBUG(10, ("It's me\n"));
1259 return 0;
1262 if (strcmp(state->ip, crec->addr) != 0) {
1263 DEBUG(10, ("%s does not match %s\n", state->ip, crec->addr));
1264 return 0;
1267 DEBUG(1, ("shutdown_other_smbds: shutting down pid %u "
1268 "(IP %s)\n", (unsigned int)procid_to_pid(&crec->pid),
1269 state->ip));
1271 messaging_send(state->msg_ctx, crec->pid, MSG_SHUTDOWN,
1272 &data_blob_null);
1273 return 0;
1276 static void setup_new_vc_session(struct smbd_server_connection *sconn)
1278 DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x "
1279 "compatible we would close all old resources.\n"));
1280 #if 0
1281 conn_close_all();
1282 invalidate_all_vuids();
1283 #endif
1284 if (lp_reset_on_zero_vc()) {
1285 char *addr;
1286 struct shutdown_state state;
1288 addr = tsocket_address_inet_addr_string(
1289 sconn->remote_address, talloc_tos());
1290 if (addr == NULL) {
1291 return;
1293 state.ip = addr;
1294 state.msg_ctx = sconn->msg_ctx;
1295 connections_forall_read(shutdown_other_smbds, &state);
1296 TALLOC_FREE(addr);
1300 /****************************************************************************
1301 Reply to a session setup command.
1302 ****************************************************************************/
1304 void reply_sesssetup_and_X(struct smb_request *req)
1306 int sess_vuid;
1307 int smb_bufsize;
1308 DATA_BLOB lm_resp;
1309 DATA_BLOB nt_resp;
1310 DATA_BLOB plaintext_password;
1311 char *tmp;
1312 const char *user;
1313 fstring sub_user; /* Sanitised username for substituion */
1314 const char *domain;
1315 const char *native_os;
1316 const char *native_lanman;
1317 const char *primary_domain;
1318 struct auth_usersupplied_info *user_info = NULL;
1319 struct auth_serversupplied_info *server_info = NULL;
1320 uint16 smb_flag2 = req->flags2;
1322 NTSTATUS nt_status;
1323 struct smbd_server_connection *sconn = req->sconn;
1325 bool doencrypt = sconn->smb1.negprot.encrypted_passwords;
1327 START_PROFILE(SMBsesssetupX);
1329 ZERO_STRUCT(lm_resp);
1330 ZERO_STRUCT(nt_resp);
1331 ZERO_STRUCT(plaintext_password);
1333 DEBUG(3,("wct=%d flg2=0x%x\n", req->wct, req->flags2));
1335 /* a SPNEGO session setup has 12 command words, whereas a normal
1336 NT1 session setup has 13. See the cifs spec. */
1337 if (req->wct == 12 &&
1338 (req->flags2 & FLAGS2_EXTENDED_SECURITY)) {
1340 if (!sconn->smb1.negprot.spnego) {
1341 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
1342 "at SPNEGO session setup when it was not "
1343 "negotiated.\n"));
1344 reply_nterror(req, nt_status_squash(
1345 NT_STATUS_LOGON_FAILURE));
1346 END_PROFILE(SMBsesssetupX);
1347 return;
1350 if (SVAL(req->vwv+4, 0) == 0) {
1351 setup_new_vc_session(req->sconn);
1354 reply_sesssetup_and_X_spnego(req);
1355 END_PROFILE(SMBsesssetupX);
1356 return;
1359 smb_bufsize = SVAL(req->vwv+2, 0);
1361 if (get_Protocol() < PROTOCOL_NT1) {
1362 uint16 passlen1 = SVAL(req->vwv+7, 0);
1364 /* Never do NT status codes with protocols before NT1 as we
1365 * don't get client caps. */
1366 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1368 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > req->buflen)) {
1369 reply_nterror(req, nt_status_squash(
1370 NT_STATUS_INVALID_PARAMETER));
1371 END_PROFILE(SMBsesssetupX);
1372 return;
1375 if (doencrypt) {
1376 lm_resp = data_blob(req->buf, passlen1);
1377 } else {
1378 plaintext_password = data_blob(req->buf, passlen1+1);
1379 /* Ensure null termination */
1380 plaintext_password.data[passlen1] = 0;
1383 srvstr_pull_req_talloc(talloc_tos(), req, &tmp,
1384 req->buf + passlen1, STR_TERMINATE);
1385 user = tmp ? tmp : "";
1387 domain = "";
1389 } else {
1390 uint16 passlen1 = SVAL(req->vwv+7, 0);
1391 uint16 passlen2 = SVAL(req->vwv+8, 0);
1392 enum remote_arch_types ra_type = get_remote_arch();
1393 const uint8_t *p = req->buf;
1394 const uint8_t *save_p = req->buf;
1395 uint16 byte_count;
1398 if(global_client_caps == 0) {
1399 global_client_caps = IVAL(req->vwv+11, 0);
1401 if (!(global_client_caps & CAP_STATUS32)) {
1402 remove_from_common_flags2(
1403 FLAGS2_32_BIT_ERROR_CODES);
1406 /* client_caps is used as final determination if
1407 * client is NT or Win95. This is needed to return
1408 * the correct error codes in some circumstances.
1411 if(ra_type == RA_WINNT || ra_type == RA_WIN2K ||
1412 ra_type == RA_WIN95) {
1413 if(!(global_client_caps & (CAP_NT_SMBS|
1414 CAP_STATUS32))) {
1415 set_remote_arch( RA_WIN95);
1420 if (!doencrypt) {
1421 /* both Win95 and WinNT stuff up the password
1422 * lengths for non-encrypting systems. Uggh.
1424 if passlen1==24 its a win95 system, and its setting
1425 the password length incorrectly. Luckily it still
1426 works with the default code because Win95 will null
1427 terminate the password anyway
1429 if passlen1>0 and passlen2>0 then maybe its a NT box
1430 and its setting passlen2 to some random value which
1431 really stuffs things up. we need to fix that one. */
1433 if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 &&
1434 passlen2 != 1) {
1435 passlen2 = 0;
1439 /* check for nasty tricks */
1440 if (passlen1 > MAX_PASS_LEN
1441 || passlen1 > smbreq_bufrem(req, p)) {
1442 reply_nterror(req, nt_status_squash(
1443 NT_STATUS_INVALID_PARAMETER));
1444 END_PROFILE(SMBsesssetupX);
1445 return;
1448 if (passlen2 > MAX_PASS_LEN
1449 || passlen2 > smbreq_bufrem(req, p+passlen1)) {
1450 reply_nterror(req, nt_status_squash(
1451 NT_STATUS_INVALID_PARAMETER));
1452 END_PROFILE(SMBsesssetupX);
1453 return;
1456 /* Save the lanman2 password and the NT md4 password. */
1458 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
1459 doencrypt = False;
1462 if (doencrypt) {
1463 lm_resp = data_blob(p, passlen1);
1464 nt_resp = data_blob(p+passlen1, passlen2);
1465 } else if (lp_security() != SEC_SHARE) {
1467 * In share level we should ignore any passwords, so
1468 * only read them if we're not.
1470 char *pass = NULL;
1471 bool unic= smb_flag2 & FLAGS2_UNICODE_STRINGS;
1473 if (unic && (passlen2 == 0) && passlen1) {
1474 /* Only a ascii plaintext password was sent. */
1475 (void)srvstr_pull_talloc(talloc_tos(),
1476 req->inbuf,
1477 req->flags2,
1478 &pass,
1479 req->buf,
1480 passlen1,
1481 STR_TERMINATE|STR_ASCII);
1482 } else {
1483 (void)srvstr_pull_talloc(talloc_tos(),
1484 req->inbuf,
1485 req->flags2,
1486 &pass,
1487 req->buf,
1488 unic ? passlen2 : passlen1,
1489 STR_TERMINATE);
1491 if (!pass) {
1492 reply_nterror(req, nt_status_squash(
1493 NT_STATUS_INVALID_PARAMETER));
1494 END_PROFILE(SMBsesssetupX);
1495 return;
1497 plaintext_password = data_blob(pass, strlen(pass)+1);
1500 p += passlen1 + passlen2;
1502 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1503 STR_TERMINATE);
1504 user = tmp ? tmp : "";
1506 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1507 STR_TERMINATE);
1508 domain = tmp ? tmp : "";
1510 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1511 STR_TERMINATE);
1512 native_os = tmp ? tmp : "";
1514 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1515 STR_TERMINATE);
1516 native_lanman = tmp ? tmp : "";
1518 /* not documented or decoded by Ethereal but there is one more
1519 * string in the extra bytes which is the same as the
1520 * PrimaryDomain when using extended security. Windows NT 4
1521 * and 2003 use this string to store the native lanman string.
1522 * Windows 9x does not include a string here at all so we have
1523 * to check if we have any extra bytes left */
1525 byte_count = SVAL(req->vwv+13, 0);
1526 if ( PTR_DIFF(p, save_p) < byte_count) {
1527 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1528 STR_TERMINATE);
1529 primary_domain = tmp ? tmp : "";
1530 } else {
1531 primary_domain = talloc_strdup(talloc_tos(), "null");
1534 DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s] "
1535 "PrimaryDomain=[%s]\n",
1536 domain, native_os, native_lanman, primary_domain));
1538 if ( ra_type == RA_WIN2K ) {
1539 if ( strlen(native_lanman) == 0 )
1540 ra_lanman_string( primary_domain );
1541 else
1542 ra_lanman_string( native_lanman );
1547 if (SVAL(req->vwv+4, 0) == 0) {
1548 setup_new_vc_session(req->sconn);
1551 DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n",
1552 domain, user, get_remote_machine_name()));
1554 if (*user) {
1555 if (sconn->smb1.negprot.spnego) {
1557 /* This has to be here, because this is a perfectly
1558 * valid behaviour for guest logons :-( */
1560 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
1561 "at 'normal' session setup after "
1562 "negotiating spnego.\n"));
1563 reply_nterror(req, nt_status_squash(
1564 NT_STATUS_LOGON_FAILURE));
1565 END_PROFILE(SMBsesssetupX);
1566 return;
1568 fstrcpy(sub_user, user);
1569 } else {
1570 fstrcpy(sub_user, lp_guestaccount());
1573 sub_set_smb_name(sub_user);
1575 reload_services(sconn->msg_ctx, sconn->sock, True);
1577 if (lp_security() == SEC_SHARE) {
1578 char *sub_user_mapped = NULL;
1579 /* In share level we should ignore any passwords */
1581 data_blob_free(&lm_resp);
1582 data_blob_free(&nt_resp);
1583 data_blob_clear_free(&plaintext_password);
1585 (void)map_username(talloc_tos(), sub_user, &sub_user_mapped);
1586 if (!sub_user_mapped) {
1587 reply_nterror(req, NT_STATUS_NO_MEMORY);
1588 END_PROFILE(SMBsesssetupX);
1589 return;
1591 fstrcpy(sub_user, sub_user_mapped);
1592 add_session_user(sconn, sub_user);
1593 add_session_workgroup(sconn, domain);
1594 /* Then force it to null for the benfit of the code below */
1595 user = "";
1598 if (!*user) {
1600 nt_status = check_guest_password(&server_info);
1602 } else if (doencrypt) {
1603 struct auth_context *negprot_auth_context = NULL;
1604 negprot_auth_context = sconn->smb1.negprot.auth_context;
1605 if (!negprot_auth_context) {
1606 DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted "
1607 "session setup without negprot denied!\n"));
1608 reply_nterror(req, nt_status_squash(
1609 NT_STATUS_LOGON_FAILURE));
1610 END_PROFILE(SMBsesssetupX);
1611 return;
1613 nt_status = make_user_info_for_reply_enc(&user_info, user,
1614 domain,
1615 lm_resp, nt_resp);
1616 if (NT_STATUS_IS_OK(nt_status)) {
1617 nt_status = negprot_auth_context->check_ntlm_password(
1618 negprot_auth_context,
1619 user_info,
1620 &server_info);
1622 } else {
1623 struct auth_context *plaintext_auth_context = NULL;
1625 nt_status = make_auth_context_subsystem(
1626 talloc_tos(), &plaintext_auth_context);
1628 if (NT_STATUS_IS_OK(nt_status)) {
1629 uint8_t chal[8];
1631 plaintext_auth_context->get_ntlm_challenge(
1632 plaintext_auth_context, chal);
1634 if (!make_user_info_for_reply(&user_info,
1635 user, domain, chal,
1636 plaintext_password)) {
1637 nt_status = NT_STATUS_NO_MEMORY;
1640 if (NT_STATUS_IS_OK(nt_status)) {
1641 nt_status = plaintext_auth_context->check_ntlm_password(
1642 plaintext_auth_context,
1643 user_info,
1644 &server_info);
1646 TALLOC_FREE(plaintext_auth_context);
1651 free_user_info(&user_info);
1653 if (!NT_STATUS_IS_OK(nt_status)) {
1654 nt_status = do_map_to_guest(nt_status, &server_info,
1655 user, domain);
1658 if (!NT_STATUS_IS_OK(nt_status)) {
1659 data_blob_free(&nt_resp);
1660 data_blob_free(&lm_resp);
1661 data_blob_clear_free(&plaintext_password);
1662 reply_nterror(req, nt_status_squash(nt_status));
1663 END_PROFILE(SMBsesssetupX);
1664 return;
1667 /* Ensure we can't possible take a code path leading to a
1668 * null defref. */
1669 if (!server_info) {
1670 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1671 END_PROFILE(SMBsesssetupX);
1672 return;
1675 if (!server_info->security_token) {
1676 nt_status = create_local_token(server_info);
1678 if (!NT_STATUS_IS_OK(nt_status)) {
1679 DEBUG(10, ("create_local_token failed: %s\n",
1680 nt_errstr(nt_status)));
1681 data_blob_free(&nt_resp);
1682 data_blob_free(&lm_resp);
1683 data_blob_clear_free(&plaintext_password);
1684 reply_nterror(req, nt_status_squash(nt_status));
1685 END_PROFILE(SMBsesssetupX);
1686 return;
1690 data_blob_clear_free(&plaintext_password);
1692 /* it's ok - setup a reply */
1693 reply_outbuf(req, 3, 0);
1694 if (get_Protocol() >= PROTOCOL_NT1) {
1695 push_signature(&req->outbuf);
1696 /* perhaps grab OS version here?? */
1699 if (server_info->guest) {
1700 SSVAL(req->outbuf,smb_vwv2,1);
1703 /* register the name and uid as being validated, so further connections
1704 to a uid can get through without a password, on the same VC */
1706 if (lp_security() == SEC_SHARE) {
1707 sess_vuid = UID_FIELD_INVALID;
1708 TALLOC_FREE(server_info);
1709 } else {
1710 /* Ignore the initial vuid. */
1711 sess_vuid = register_initial_vuid(sconn);
1712 if (sess_vuid == UID_FIELD_INVALID) {
1713 data_blob_free(&nt_resp);
1714 data_blob_free(&lm_resp);
1715 reply_nterror(req, nt_status_squash(
1716 NT_STATUS_LOGON_FAILURE));
1717 END_PROFILE(SMBsesssetupX);
1718 return;
1720 /* register_existing_vuid keeps the server info */
1721 sess_vuid = register_existing_vuid(sconn, sess_vuid,
1722 server_info,
1723 nt_resp.data ? nt_resp : lm_resp,
1724 sub_user);
1725 if (sess_vuid == UID_FIELD_INVALID) {
1726 data_blob_free(&nt_resp);
1727 data_blob_free(&lm_resp);
1728 reply_nterror(req, nt_status_squash(
1729 NT_STATUS_LOGON_FAILURE));
1730 END_PROFILE(SMBsesssetupX);
1731 return;
1734 /* current_user_info is changed on new vuid */
1735 reload_services(sconn->msg_ctx, sconn->sock, True);
1738 data_blob_free(&nt_resp);
1739 data_blob_free(&lm_resp);
1741 SSVAL(req->outbuf,smb_uid,sess_vuid);
1742 SSVAL(req->inbuf,smb_uid,sess_vuid);
1743 req->vuid = sess_vuid;
1745 if (!sconn->smb1.sessions.done_sesssetup) {
1746 sconn->smb1.sessions.max_send =
1747 MIN(sconn->smb1.sessions.max_send,smb_bufsize);
1749 sconn->smb1.sessions.done_sesssetup = true;
1751 END_PROFILE(SMBsesssetupX);
1752 chain_reply(req);
1753 return;