r6369: update release notes
[Samba.git] / source / smbd / sesssetup.c
blob9fbf0b1d51ddb488102ff8f65e95ed944ab4b701
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
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "includes.h"
26 uint32 global_client_caps = 0;
28 extern BOOL global_encrypted_passwords_negotiated;
29 extern BOOL global_spnego_negotiated;
30 extern enum protocol_types Protocol;
31 extern int max_send;
32 extern struct auth_context *negprot_global_auth_context;
34 static struct auth_ntlmssp_state *global_ntlmssp_state;
37 on a logon error possibly map the error to success if "map to guest"
38 is set approriately
40 static NTSTATUS do_map_to_guest(NTSTATUS status, auth_serversupplied_info **server_info,
41 const char *user, const char *domain)
43 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
44 if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) ||
45 (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
46 DEBUG(3,("No such user %s [%s] - using guest account\n",
47 user, domain));
48 status = make_server_info_guest(server_info);
52 if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
53 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
54 DEBUG(3,("Registered username %s for guest access\n",user));
55 status = make_server_info_guest(server_info);
59 return status;
62 /****************************************************************************
63 Add the standard 'Samba' signature to the end of the session setup.
64 ****************************************************************************/
66 static int add_signature(char *outbuf, char *p)
68 char *start = p;
69 fstring lanman;
71 fstr_sprintf( lanman, "Samba %s", SAMBA_VERSION_STRING);
73 p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);
74 p += srvstr_push(outbuf, p, lanman, -1, STR_TERMINATE);
75 p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
77 return PTR_DIFF(p, start);
80 /****************************************************************************
81 Send a security blob via a session setup reply.
82 ****************************************************************************/
84 static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf,
85 DATA_BLOB blob, NTSTATUS nt_status)
87 char *p;
89 set_message(outbuf,4,0,True);
91 nt_status = nt_status_squash(nt_status);
92 SIVAL(outbuf, smb_rcls, NT_STATUS_V(nt_status));
93 SSVAL(outbuf, smb_vwv0, 0xFF); /* no chaining possible */
94 SSVAL(outbuf, smb_vwv3, blob.length);
95 p = smb_buf(outbuf);
97 /* should we cap this? */
98 memcpy(p, blob.data, blob.length);
99 p += blob.length;
101 p += add_signature( outbuf, p );
103 set_message_end(outbuf,p);
105 return send_smb(smbd_server_fd(),outbuf);
108 /****************************************************************************
109 Do a 'guest' logon, getting back the
110 ****************************************************************************/
112 static NTSTATUS check_guest_password(auth_serversupplied_info **server_info)
114 struct auth_context *auth_context;
115 auth_usersupplied_info *user_info = NULL;
117 NTSTATUS nt_status;
118 unsigned char chal[8];
120 ZERO_STRUCT(chal);
122 DEBUG(3,("Got anonymous request\n"));
124 if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context, chal))) {
125 return nt_status;
128 if (!make_user_info_guest(&user_info)) {
129 (auth_context->free)(&auth_context);
130 return NT_STATUS_NO_MEMORY;
133 nt_status = auth_context->check_ntlm_password(auth_context, user_info, server_info);
134 (auth_context->free)(&auth_context);
135 free_user_info(&user_info);
136 return nt_status;
140 #ifdef HAVE_KRB5
141 /****************************************************************************
142 reply to a session setup spnego negotiate packet for kerberos
143 ****************************************************************************/
144 static int reply_spnego_kerberos(connection_struct *conn,
145 char *inbuf, char *outbuf,
146 int length, int bufsize,
147 DATA_BLOB *secblob)
149 DATA_BLOB ticket;
150 char *client, *p, *domain;
151 fstring netbios_domain_name;
152 struct passwd *pw;
153 char *user;
154 int sess_vuid;
155 NTSTATUS ret;
156 DATA_BLOB auth_data;
157 DATA_BLOB ap_rep, ap_rep_wrapped, response;
158 auth_serversupplied_info *server_info = NULL;
159 DATA_BLOB session_key = data_blob(NULL, 0);
160 uint8 tok_id[2];
161 DATA_BLOB nullblob = data_blob(NULL, 0);
162 fstring real_username;
164 ZERO_STRUCT(ticket);
165 ZERO_STRUCT(auth_data);
166 ZERO_STRUCT(ap_rep);
167 ZERO_STRUCT(ap_rep_wrapped);
168 ZERO_STRUCT(response);
170 if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
171 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
174 ret = ads_verify_ticket(lp_realm(), &ticket, &client, &auth_data, &ap_rep, &session_key);
176 data_blob_free(&ticket);
178 if (!NT_STATUS_IS_OK(ret)) {
179 DEBUG(1,("Failed to verify incoming ticket!\n"));
180 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
183 data_blob_free(&auth_data);
185 DEBUG(3,("Ticket name is [%s]\n", client));
187 p = strchr_m(client, '@');
188 if (!p) {
189 DEBUG(3,("Doesn't look like a valid principal\n"));
190 data_blob_free(&ap_rep);
191 data_blob_free(&session_key);
192 SAFE_FREE(client);
193 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
196 *p = 0;
197 if (!strequal(p+1, lp_realm())) {
198 DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
199 if (!lp_allow_trusted_domains()) {
200 data_blob_free(&ap_rep);
201 data_blob_free(&session_key);
202 SAFE_FREE(client);
203 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
207 /* this gives a fully qualified user name (ie. with full realm).
208 that leads to very long usernames, but what else can we do? */
210 domain = p+1;
213 /* If we have winbind running, we can (and must) shorten the
214 username by using the short netbios name. Otherwise we will
215 have inconsistent user names. With Kerberos, we get the
216 fully qualified realm, with ntlmssp we get the short
217 name. And even w2k3 does use ntlmssp if you for example
218 connect to an ip address. */
220 struct winbindd_request wb_request;
221 struct winbindd_response wb_response;
222 NSS_STATUS wb_result;
224 ZERO_STRUCT(wb_request);
225 ZERO_STRUCT(wb_response);
227 DEBUG(10, ("Mapping [%s] to short name\n", domain));
229 fstrcpy(wb_request.domain_name, domain);
231 wb_result = winbindd_request(WINBINDD_DOMAIN_INFO,
232 &wb_request, &wb_response);
234 if (wb_result == NSS_STATUS_SUCCESS) {
236 fstrcpy(netbios_domain_name,
237 wb_response.data.domain_info.name);
238 domain = netbios_domain_name;
240 DEBUG(10, ("Mapped to [%s]\n", domain));
241 } else {
242 DEBUG(3, ("Could not find short name -- winbind "
243 "not running?\n"));
247 asprintf(&user, "%s%c%s", domain, *lp_winbind_separator(), client);
249 /* lookup the passwd struct, create a new user if necessary */
251 map_username( user );
253 pw = smb_getpwnam( user, real_username, True );
255 if (!pw) {
256 DEBUG(1,("Username %s is invalid on this system\n",user));
257 SAFE_FREE(user);
258 SAFE_FREE(client);
259 data_blob_free(&ap_rep);
260 data_blob_free(&session_key);
261 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
264 /* setup the string used by %U */
266 sub_set_smb_name( real_username );
267 reload_services(True);
269 if (!NT_STATUS_IS_OK(ret = make_server_info_pw(&server_info, real_username, pw)))
271 DEBUG(1,("make_server_info_from_pw failed!\n"));
272 SAFE_FREE(user);
273 SAFE_FREE(client);
274 data_blob_free(&ap_rep);
275 data_blob_free(&session_key);
276 return ERROR_NT(ret);
279 /* make_server_info_pw does not set the domain. Without this we end up
280 * with the local netbios name in substitutions for %D. */
282 if (server_info->sam_account != NULL) {
283 pdb_set_domain(server_info->sam_account, domain, PDB_SET);
286 /* register_vuid keeps the server info */
287 /* register_vuid takes ownership of session_key, no need to free after this.
288 A better interface would copy it.... */
289 sess_vuid = register_vuid(server_info, session_key, nullblob, client);
291 SAFE_FREE(user);
292 SAFE_FREE(client);
294 if (sess_vuid == -1) {
295 ret = NT_STATUS_LOGON_FAILURE;
296 } else {
297 /* current_user_info is changed on new vuid */
298 reload_services( True );
300 set_message(outbuf,4,0,True);
301 SSVAL(outbuf, smb_vwv3, 0);
303 if (server_info->guest) {
304 SSVAL(outbuf,smb_vwv2,1);
307 SSVAL(outbuf, smb_uid, sess_vuid);
309 if (!server_info->guest && !srv_signing_started()) {
310 /* We need to start the signing engine
311 * here but a W2K client sends the old
312 * "BSRSPYL " signature instead of the
313 * correct one. Subsequent packets will
314 * be correct.
316 srv_check_sign_mac(inbuf, False);
320 /* wrap that up in a nice GSS-API wrapping */
321 if (NT_STATUS_IS_OK(ret)) {
322 ap_rep_wrapped = spnego_gen_krb5_wrap(
323 ap_rep,
324 CONST_ADD(const uint8 *, TOK_ID_KRB_AP_REP));
325 } else {
326 ap_rep_wrapped = data_blob(NULL, 0);
328 response = spnego_gen_auth_response(&ap_rep_wrapped, ret, OID_KERBEROS5_OLD);
329 reply_sesssetup_blob(conn, outbuf, response, ret);
331 data_blob_free(&ap_rep);
332 data_blob_free(&ap_rep_wrapped);
333 data_blob_free(&response);
335 return -1; /* already replied */
337 #endif
339 /****************************************************************************
340 Send a session setup reply, wrapped in SPNEGO.
341 Get vuid and check first.
342 End the NTLMSSP exchange context if we are OK/complete fail
343 ***************************************************************************/
345 static BOOL reply_spnego_ntlmssp(connection_struct *conn, char *inbuf, char *outbuf,
346 AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
347 DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status)
349 BOOL ret;
350 DATA_BLOB response;
351 struct auth_serversupplied_info *server_info = NULL;
353 if (NT_STATUS_IS_OK(nt_status)) {
354 server_info = (*auth_ntlmssp_state)->server_info;
355 } else {
356 nt_status = do_map_to_guest(nt_status,
357 &server_info,
358 (*auth_ntlmssp_state)->ntlmssp_state->user,
359 (*auth_ntlmssp_state)->ntlmssp_state->domain);
362 if (NT_STATUS_IS_OK(nt_status)) {
363 int sess_vuid;
364 DATA_BLOB nullblob = data_blob(NULL, 0);
365 DATA_BLOB session_key = data_blob((*auth_ntlmssp_state)->ntlmssp_state->session_key.data, (*auth_ntlmssp_state)->ntlmssp_state->session_key.length);
367 /* register_vuid keeps the server info */
368 sess_vuid = register_vuid(server_info, session_key, nullblob, (*auth_ntlmssp_state)->ntlmssp_state->user);
369 (*auth_ntlmssp_state)->server_info = NULL;
371 if (sess_vuid == -1) {
372 nt_status = NT_STATUS_LOGON_FAILURE;
373 } else {
375 /* current_user_info is changed on new vuid */
376 reload_services( True );
378 set_message(outbuf,4,0,True);
379 SSVAL(outbuf, smb_vwv3, 0);
381 if (server_info->guest) {
382 SSVAL(outbuf,smb_vwv2,1);
385 SSVAL(outbuf,smb_uid,sess_vuid);
387 if (!server_info->guest && !srv_signing_started()) {
388 /* We need to start the signing engine
389 * here but a W2K client sends the old
390 * "BSRSPYL " signature instead of the
391 * correct one. Subsequent packets will
392 * be correct.
395 srv_check_sign_mac(inbuf, False);
400 response = spnego_gen_auth_response(ntlmssp_blob, nt_status, OID_NTLMSSP);
401 ret = reply_sesssetup_blob(conn, outbuf, response, nt_status);
402 data_blob_free(&response);
404 /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
405 and the other end, that we are not finished yet. */
407 if (!ret || !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
408 auth_ntlmssp_end(auth_ntlmssp_state);
411 return ret;
414 /****************************************************************************
415 Reply to a session setup spnego negotiate packet.
416 ****************************************************************************/
418 static int reply_spnego_negotiate(connection_struct *conn,
419 char *inbuf,
420 char *outbuf,
421 int length, int bufsize,
422 DATA_BLOB blob1)
424 char *OIDs[ASN1_MAX_OIDS];
425 DATA_BLOB secblob;
426 int i;
427 DATA_BLOB chal;
428 #ifdef HAVE_KRB5
429 BOOL got_kerberos_mechanism = False;
430 #endif
431 NTSTATUS nt_status;
433 /* parse out the OIDs and the first sec blob */
434 if (!parse_negTokenTarg(blob1, OIDs, &secblob)) {
435 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
438 /* only look at the first OID for determining the mechToken --
439 accoirding to RFC2478, we should choose the one we want
440 and renegotiate, but i smell a client bug here..
442 Problem observed when connecting to a member (samba box)
443 of an AD domain as a user in a Samba domain. Samba member
444 server sent back krb5/mskrb5/ntlmssp as mechtypes, but the
445 client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an
446 NTLMSSP mechtoken. --jerry */
448 #ifdef HAVE_KRB5
449 if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
450 strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
451 got_kerberos_mechanism = True;
453 #endif
455 for (i=0;OIDs[i];i++) {
456 DEBUG(3,("Got OID %s\n", OIDs[i]));
457 free(OIDs[i]);
459 DEBUG(3,("Got secblob of size %lu\n", (unsigned long)secblob.length));
461 #ifdef HAVE_KRB5
462 if (got_kerberos_mechanism && (SEC_ADS == lp_security())) {
463 int ret = reply_spnego_kerberos(conn, inbuf, outbuf,
464 length, bufsize, &secblob);
465 data_blob_free(&secblob);
466 return ret;
468 #endif
470 if (global_ntlmssp_state) {
471 auth_ntlmssp_end(&global_ntlmssp_state);
474 nt_status = auth_ntlmssp_start(&global_ntlmssp_state);
475 if (!NT_STATUS_IS_OK(nt_status)) {
476 return ERROR_NT(nt_status);
479 nt_status = auth_ntlmssp_update(global_ntlmssp_state,
480 secblob, &chal);
482 data_blob_free(&secblob);
484 reply_spnego_ntlmssp(conn, inbuf, outbuf, &global_ntlmssp_state,
485 &chal, nt_status);
487 data_blob_free(&chal);
489 /* already replied */
490 return -1;
493 /****************************************************************************
494 Reply to a session setup spnego auth packet.
495 ****************************************************************************/
497 static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
498 int length, int bufsize,
499 DATA_BLOB blob1)
501 DATA_BLOB auth, auth_reply;
502 NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
504 if (!spnego_parse_auth(blob1, &auth)) {
505 #if 0
506 file_save("auth.dat", blob1.data, blob1.length);
507 #endif
508 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
511 if (!global_ntlmssp_state) {
512 /* auth before negotiatiate? */
513 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
516 nt_status = auth_ntlmssp_update(global_ntlmssp_state,
517 auth, &auth_reply);
519 data_blob_free(&auth);
521 reply_spnego_ntlmssp(conn, inbuf, outbuf, &global_ntlmssp_state,
522 &auth_reply, nt_status);
524 data_blob_free(&auth_reply);
526 /* and tell smbd that we have already replied to this packet */
527 return -1;
530 /****************************************************************************
531 Reply to a session setup command.
532 ****************************************************************************/
534 static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,
535 char *outbuf,
536 int length,int bufsize)
538 uint8 *p;
539 DATA_BLOB blob1;
540 int ret;
541 size_t bufrem;
542 fstring native_os, native_lanman, primary_domain;
543 char *p2;
544 uint16 data_blob_len = SVAL(inbuf, smb_vwv7);
545 enum remote_arch_types ra_type = get_remote_arch();
547 DEBUG(3,("Doing spnego session setup\n"));
549 if (global_client_caps == 0) {
550 global_client_caps = IVAL(inbuf,smb_vwv10);
552 if (!(global_client_caps & CAP_STATUS32)) {
553 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
558 p = (uint8 *)smb_buf(inbuf);
560 if (data_blob_len == 0) {
561 /* an invalid request */
562 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
565 bufrem = smb_bufrem(inbuf, p);
566 /* pull the spnego blob */
567 blob1 = data_blob(p, MIN(bufrem, data_blob_len));
569 #if 0
570 file_save("negotiate.dat", blob1.data, blob1.length);
571 #endif
573 p2 = inbuf + smb_vwv13 + data_blob_len;
574 p2 += srvstr_pull_buf(inbuf, native_os, p2, sizeof(native_os), STR_TERMINATE);
575 p2 += srvstr_pull_buf(inbuf, native_lanman, p2, sizeof(native_lanman), STR_TERMINATE);
576 p2 += srvstr_pull_buf(inbuf, primary_domain, p2, sizeof(primary_domain), STR_TERMINATE);
577 DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
578 native_os, native_lanman, primary_domain));
580 if ( ra_type == RA_WIN2K ) {
581 /* Windows 2003 doesn't set the native lanman string,
582 but does set primary domain which is a bug I think */
584 if ( !strlen(native_lanman) )
585 ra_lanman_string( primary_domain );
586 else
587 ra_lanman_string( native_lanman );
590 if (blob1.data[0] == ASN1_APPLICATION(0)) {
591 /* its a negTokenTarg packet */
592 ret = reply_spnego_negotiate(conn, inbuf, outbuf, length, bufsize, blob1);
593 data_blob_free(&blob1);
594 return ret;
597 if (blob1.data[0] == ASN1_CONTEXT(1)) {
598 /* its a auth packet */
599 ret = reply_spnego_auth(conn, inbuf, outbuf, length, bufsize, blob1);
600 data_blob_free(&blob1);
601 return ret;
604 /* what sort of packet is this? */
605 DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
607 data_blob_free(&blob1);
609 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
612 /****************************************************************************
613 On new VC == 0, shutdown *all* old connections and users.
614 It seems that only NT4.x does this. At W2K and above (XP etc.).
615 a new session setup with VC==0 is ignored.
616 ****************************************************************************/
618 static void setup_new_vc_session(void)
620 DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x compatible we would close all old resources.\n"));
621 #if 0
622 conn_close_all();
623 invalidate_all_vuids();
624 #endif
627 /****************************************************************************
628 Reply to a session setup command.
629 ****************************************************************************/
631 int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
632 int length,int bufsize)
634 int sess_vuid;
635 int smb_bufsize;
636 DATA_BLOB lm_resp;
637 DATA_BLOB nt_resp;
638 DATA_BLOB plaintext_password;
639 fstring user;
640 fstring sub_user; /* Sainitised username for substituion */
641 fstring domain;
642 fstring native_os;
643 fstring native_lanman;
644 fstring primary_domain;
645 static BOOL done_sesssetup = False;
647 auth_usersupplied_info *user_info = NULL;
648 auth_serversupplied_info *server_info = NULL;
650 NTSTATUS nt_status;
652 BOOL doencrypt = global_encrypted_passwords_negotiated;
654 DATA_BLOB session_key;
656 START_PROFILE(SMBsesssetupX);
658 ZERO_STRUCT(lm_resp);
659 ZERO_STRUCT(nt_resp);
660 ZERO_STRUCT(plaintext_password);
662 DEBUG(3,("wct=%d flg2=0x%x\n", CVAL(inbuf, smb_wct), SVAL(inbuf, smb_flg2)));
664 /* a SPNEGO session setup has 12 command words, whereas a normal
665 NT1 session setup has 13. See the cifs spec. */
666 if (CVAL(inbuf, smb_wct) == 12 &&
667 (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
668 if (!global_spnego_negotiated) {
669 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt at SPNEGO session setup when it was not negoitiated.\n"));
670 return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
673 if (SVAL(inbuf,smb_vwv4) == 0) {
674 setup_new_vc_session();
676 return reply_sesssetup_and_X_spnego(conn, inbuf, outbuf, length, bufsize);
679 smb_bufsize = SVAL(inbuf,smb_vwv2);
681 if (Protocol < PROTOCOL_NT1) {
682 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
684 /* Never do NT status codes with protocols before NT1 as we don't get client caps. */
685 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
687 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > smb_bufrem(inbuf, smb_buf(inbuf)))) {
688 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
691 if (doencrypt) {
692 lm_resp = data_blob(smb_buf(inbuf), passlen1);
693 } else {
694 plaintext_password = data_blob(smb_buf(inbuf), passlen1+1);
695 /* Ensure null termination */
696 plaintext_password.data[passlen1] = 0;
699 srvstr_pull_buf(inbuf, user, smb_buf(inbuf)+passlen1, sizeof(user), STR_TERMINATE);
700 *domain = 0;
702 } else {
703 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
704 uint16 passlen2 = SVAL(inbuf,smb_vwv8);
705 enum remote_arch_types ra_type = get_remote_arch();
706 char *p = smb_buf(inbuf);
707 char *save_p = smb_buf(inbuf);
708 uint16 byte_count;
711 if(global_client_caps == 0) {
712 global_client_caps = IVAL(inbuf,smb_vwv11);
714 if (!(global_client_caps & CAP_STATUS32)) {
715 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
718 /* client_caps is used as final determination if client is NT or Win95.
719 This is needed to return the correct error codes in some
720 circumstances.
723 if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) {
724 if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) {
725 set_remote_arch( RA_WIN95);
730 if (!doencrypt) {
731 /* both Win95 and WinNT stuff up the password lengths for
732 non-encrypting systems. Uggh.
734 if passlen1==24 its a win95 system, and its setting the
735 password length incorrectly. Luckily it still works with the
736 default code because Win95 will null terminate the password
737 anyway
739 if passlen1>0 and passlen2>0 then maybe its a NT box and its
740 setting passlen2 to some random value which really stuffs
741 things up. we need to fix that one. */
743 if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1)
744 passlen2 = 0;
747 /* check for nasty tricks */
748 if (passlen1 > MAX_PASS_LEN || passlen1 > smb_bufrem(inbuf, p)) {
749 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
752 if (passlen2 > MAX_PASS_LEN || passlen2 > smb_bufrem(inbuf, p+passlen1)) {
753 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
756 /* Save the lanman2 password and the NT md4 password. */
758 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
759 doencrypt = False;
762 if (doencrypt) {
763 lm_resp = data_blob(p, passlen1);
764 nt_resp = data_blob(p+passlen1, passlen2);
765 } else {
766 pstring pass;
767 BOOL unic=SVAL(inbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS;
769 #if 0
770 /* This was the previous fix. Not sure if it's still valid. JRA. */
771 if ((ra_type == RA_WINNT) && (passlen2 == 0) && unic && passlen1) {
772 /* NT4.0 stuffs up plaintext unicode password lengths... */
773 srvstr_pull(inbuf, pass, smb_buf(inbuf) + 1,
774 sizeof(pass), passlen1, STR_TERMINATE);
775 #endif
777 if (unic && (passlen2 == 0) && passlen1) {
778 /* Only a ascii plaintext password was sent. */
779 srvstr_pull(inbuf, pass, smb_buf(inbuf), sizeof(pass),
780 passlen1, STR_TERMINATE|STR_ASCII);
781 } else {
782 srvstr_pull(inbuf, pass, smb_buf(inbuf),
783 sizeof(pass), unic ? passlen2 : passlen1,
784 STR_TERMINATE);
786 plaintext_password = data_blob(pass, strlen(pass)+1);
789 p += passlen1 + passlen2;
790 p += srvstr_pull_buf(inbuf, user, p, sizeof(user), STR_TERMINATE);
791 p += srvstr_pull_buf(inbuf, domain, p, sizeof(domain), STR_TERMINATE);
792 p += srvstr_pull_buf(inbuf, native_os, p, sizeof(native_os), STR_TERMINATE);
793 p += srvstr_pull_buf(inbuf, native_lanman, p, sizeof(native_lanman), STR_TERMINATE);
795 /* not documented or decoded by Ethereal but there is one more string
796 in the extra bytes which is the same as the PrimaryDomain when using
797 extended security. Windows NT 4 and 2003 use this string to store
798 the native lanman string. Windows 9x does not include a string here
799 at all so we have to check if we have any extra bytes left */
801 byte_count = SVAL(inbuf, smb_vwv13);
802 if ( PTR_DIFF(p, save_p) < byte_count)
803 p += srvstr_pull_buf(inbuf, primary_domain, p, sizeof(primary_domain), STR_TERMINATE);
804 else
805 fstrcpy( primary_domain, "null" );
807 DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
808 domain, native_os, native_lanman, primary_domain));
810 if ( ra_type == RA_WIN2K ) {
811 if ( strlen(native_lanman) == 0 )
812 ra_lanman_string( primary_domain );
813 else
814 ra_lanman_string( native_lanman );
819 if (SVAL(inbuf,smb_vwv4) == 0) {
820 setup_new_vc_session();
823 DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, get_remote_machine_name()));
825 if (*user) {
826 if (global_spnego_negotiated) {
828 /* This has to be here, because this is a perfectly valid behaviour for guest logons :-( */
830 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt at 'normal' session setup after negotiating spnego.\n"));
831 return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
833 fstrcpy(sub_user, user);
835 /* setup the string used by %U */
836 sub_set_smb_name(user);
837 } else {
838 fstrcpy(sub_user, lp_guestaccount());
841 sub_set_smb_name(sub_user);
843 reload_services(True);
845 if (lp_security() == SEC_SHARE) {
846 /* in share level we should ignore any passwords */
848 data_blob_free(&lm_resp);
849 data_blob_free(&nt_resp);
850 data_blob_clear_free(&plaintext_password);
852 map_username(sub_user);
853 add_session_user(sub_user);
854 /* Then force it to null for the benfit of the code below */
855 *user = 0;
858 if (!*user) {
860 nt_status = check_guest_password(&server_info);
862 } else if (doencrypt) {
863 if (!negprot_global_auth_context) {
864 DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted session setup without negprot denied!\n"));
865 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
867 nt_status = make_user_info_for_reply_enc(&user_info, user, domain,
868 lm_resp, nt_resp);
869 if (NT_STATUS_IS_OK(nt_status)) {
870 nt_status = negprot_global_auth_context->check_ntlm_password(negprot_global_auth_context,
871 user_info,
872 &server_info);
874 } else {
875 struct auth_context *plaintext_auth_context = NULL;
876 const uint8 *chal;
877 if (NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&plaintext_auth_context))) {
878 chal = plaintext_auth_context->get_ntlm_challenge(plaintext_auth_context);
880 if (!make_user_info_for_reply(&user_info,
881 user, domain, chal,
882 plaintext_password)) {
883 nt_status = NT_STATUS_NO_MEMORY;
886 if (NT_STATUS_IS_OK(nt_status)) {
887 nt_status = plaintext_auth_context->check_ntlm_password(plaintext_auth_context,
888 user_info,
889 &server_info);
891 (plaintext_auth_context->free)(&plaintext_auth_context);
896 free_user_info(&user_info);
898 if (!NT_STATUS_IS_OK(nt_status)) {
899 nt_status = do_map_to_guest(nt_status, &server_info, user, domain);
902 if (!NT_STATUS_IS_OK(nt_status)) {
903 data_blob_free(&nt_resp);
904 data_blob_free(&lm_resp);
905 data_blob_clear_free(&plaintext_password);
906 return ERROR_NT(nt_status_squash(nt_status));
909 if (server_info->user_session_key.data) {
910 session_key = data_blob(server_info->user_session_key.data, server_info->user_session_key.length);
911 } else {
912 session_key = data_blob(NULL, 0);
915 data_blob_clear_free(&plaintext_password);
917 /* it's ok - setup a reply */
918 set_message(outbuf,3,0,True);
919 if (Protocol >= PROTOCOL_NT1) {
920 char *p = smb_buf( outbuf );
921 p += add_signature( outbuf, p );
922 set_message_end( outbuf, p );
923 /* perhaps grab OS version here?? */
926 if (server_info->guest) {
927 SSVAL(outbuf,smb_vwv2,1);
930 /* register the name and uid as being validated, so further connections
931 to a uid can get through without a password, on the same VC */
933 /* register_vuid keeps the server info */
934 sess_vuid = register_vuid(server_info, session_key, nt_resp.data ? nt_resp : lm_resp, sub_user);
935 data_blob_free(&nt_resp);
936 data_blob_free(&lm_resp);
938 if (sess_vuid == -1) {
939 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
942 /* current_user_info is changed on new vuid */
943 reload_services( True );
945 if (!server_info->guest && !srv_signing_started() && !srv_check_sign_mac(inbuf, True)) {
946 exit_server("reply_sesssetup_and_X: bad smb signature");
949 SSVAL(outbuf,smb_uid,sess_vuid);
950 SSVAL(inbuf,smb_uid,sess_vuid);
952 if (!done_sesssetup)
953 max_send = MIN(max_send,smb_bufsize);
955 done_sesssetup = True;
957 END_PROFILE(SMBsesssetupX);
958 return chain_reply(inbuf,outbuf,length,bufsize);