r7372: abartet's patch for BUG 2391 (segv caused by free a static pointer)
[Samba/gbeck.git] / source / smbd / sesssetup.c
blob6f963fc603c10308f6d7b5e243738ebbd23093c5
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 static struct auth_ntlmssp_state *global_ntlmssp_state;
31 on a logon error possibly map the error to success if "map to guest"
32 is set approriately
34 static NTSTATUS do_map_to_guest(NTSTATUS status, auth_serversupplied_info **server_info,
35 const char *user, const char *domain)
37 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
38 if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) ||
39 (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
40 DEBUG(3,("No such user %s [%s] - using guest account\n",
41 user, domain));
42 status = make_server_info_guest(server_info);
46 if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
47 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
48 DEBUG(3,("Registered username %s for guest access\n",user));
49 status = make_server_info_guest(server_info);
53 return status;
56 /****************************************************************************
57 Add the standard 'Samba' signature to the end of the session setup.
58 ****************************************************************************/
60 static int add_signature(char *outbuf, char *p)
62 char *start = p;
63 fstring lanman;
65 fstr_sprintf( lanman, "Samba %s", SAMBA_VERSION_STRING);
67 p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);
68 p += srvstr_push(outbuf, p, lanman, -1, STR_TERMINATE);
69 p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
71 return PTR_DIFF(p, start);
74 /****************************************************************************
75 Send a security blob via a session setup reply.
76 ****************************************************************************/
78 static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf,
79 DATA_BLOB blob, NTSTATUS nt_status)
81 char *p;
83 set_message(outbuf,4,0,True);
85 nt_status = nt_status_squash(nt_status);
86 SIVAL(outbuf, smb_rcls, NT_STATUS_V(nt_status));
87 SSVAL(outbuf, smb_vwv0, 0xFF); /* no chaining possible */
88 SSVAL(outbuf, smb_vwv3, blob.length);
89 p = smb_buf(outbuf);
91 /* should we cap this? */
92 memcpy(p, blob.data, blob.length);
93 p += blob.length;
95 p += add_signature( outbuf, p );
97 set_message_end(outbuf,p);
99 return send_smb(smbd_server_fd(),outbuf);
102 /****************************************************************************
103 Do a 'guest' logon, getting back the
104 ****************************************************************************/
106 static NTSTATUS check_guest_password(auth_serversupplied_info **server_info)
108 struct auth_context *auth_context;
109 auth_usersupplied_info *user_info = NULL;
111 NTSTATUS nt_status;
112 unsigned char chal[8];
114 ZERO_STRUCT(chal);
116 DEBUG(3,("Got anonymous request\n"));
118 if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context, chal))) {
119 return nt_status;
122 if (!make_user_info_guest(&user_info)) {
123 (auth_context->free)(&auth_context);
124 return NT_STATUS_NO_MEMORY;
127 nt_status = auth_context->check_ntlm_password(auth_context, user_info, server_info);
128 (auth_context->free)(&auth_context);
129 free_user_info(&user_info);
130 return nt_status;
134 #ifdef HAVE_KRB5
135 /****************************************************************************
136 reply to a session setup spnego negotiate packet for kerberos
137 ****************************************************************************/
138 static int reply_spnego_kerberos(connection_struct *conn,
139 char *inbuf, char *outbuf,
140 int length, int bufsize,
141 DATA_BLOB *secblob)
143 DATA_BLOB ticket;
144 char *client, *p, *domain;
145 fstring netbios_domain_name;
146 struct passwd *pw;
147 char *user;
148 int sess_vuid;
149 NTSTATUS ret;
150 DATA_BLOB auth_data;
151 DATA_BLOB ap_rep, ap_rep_wrapped, response;
152 auth_serversupplied_info *server_info = NULL;
153 DATA_BLOB session_key = data_blob(NULL, 0);
154 uint8 tok_id[2];
155 DATA_BLOB nullblob = data_blob(NULL, 0);
156 fstring real_username;
158 ZERO_STRUCT(ticket);
159 ZERO_STRUCT(auth_data);
160 ZERO_STRUCT(ap_rep);
161 ZERO_STRUCT(ap_rep_wrapped);
162 ZERO_STRUCT(response);
164 if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
165 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
168 ret = ads_verify_ticket(lp_realm(), &ticket, &client, &auth_data, &ap_rep, &session_key);
170 data_blob_free(&ticket);
172 if (!NT_STATUS_IS_OK(ret)) {
173 DEBUG(1,("Failed to verify incoming ticket!\n"));
174 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
177 data_blob_free(&auth_data);
179 DEBUG(3,("Ticket name is [%s]\n", client));
181 p = strchr_m(client, '@');
182 if (!p) {
183 DEBUG(3,("Doesn't look like a valid principal\n"));
184 data_blob_free(&ap_rep);
185 data_blob_free(&session_key);
186 SAFE_FREE(client);
187 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
190 *p = 0;
191 if (!strequal(p+1, lp_realm())) {
192 DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
193 if (!lp_allow_trusted_domains()) {
194 data_blob_free(&ap_rep);
195 data_blob_free(&session_key);
196 SAFE_FREE(client);
197 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
201 /* this gives a fully qualified user name (ie. with full realm).
202 that leads to very long usernames, but what else can we do? */
204 domain = p+1;
207 /* If we have winbind running, we can (and must) shorten the
208 username by using the short netbios name. Otherwise we will
209 have inconsistent user names. With Kerberos, we get the
210 fully qualified realm, with ntlmssp we get the short
211 name. And even w2k3 does use ntlmssp if you for example
212 connect to an ip address. */
214 struct winbindd_request wb_request;
215 struct winbindd_response wb_response;
216 NSS_STATUS wb_result;
218 ZERO_STRUCT(wb_request);
219 ZERO_STRUCT(wb_response);
221 DEBUG(10, ("Mapping [%s] to short name\n", domain));
223 fstrcpy(wb_request.domain_name, domain);
225 wb_result = winbindd_request(WINBINDD_DOMAIN_INFO,
226 &wb_request, &wb_response);
228 if (wb_result == NSS_STATUS_SUCCESS) {
230 fstrcpy(netbios_domain_name,
231 wb_response.data.domain_info.name);
232 domain = netbios_domain_name;
234 DEBUG(10, ("Mapped to [%s]\n", domain));
235 } else {
236 DEBUG(3, ("Could not find short name -- winbind "
237 "not running?\n"));
241 asprintf(&user, "%s%c%s", domain, *lp_winbind_separator(), client);
243 /* lookup the passwd struct, create a new user if necessary */
245 map_username( user );
247 pw = smb_getpwnam( user, real_username, True );
249 if (!pw) {
250 DEBUG(1,("Username %s is invalid on this system\n",user));
251 SAFE_FREE(user);
252 SAFE_FREE(client);
253 data_blob_free(&ap_rep);
254 data_blob_free(&session_key);
255 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
258 /* setup the string used by %U */
260 sub_set_smb_name( real_username );
261 reload_services(True);
263 if (!NT_STATUS_IS_OK(ret = make_server_info_pw(&server_info, real_username, pw)))
265 DEBUG(1,("make_server_info_from_pw failed!\n"));
266 SAFE_FREE(user);
267 SAFE_FREE(client);
268 data_blob_free(&ap_rep);
269 data_blob_free(&session_key);
270 passwd_free(&pw);
271 return ERROR_NT(ret);
273 passwd_free(&pw);
275 /* make_server_info_pw does not set the domain. Without this we end up
276 * with the local netbios name in substitutions for %D. */
278 if (server_info->sam_account != NULL) {
279 pdb_set_domain(server_info->sam_account, domain, PDB_SET);
282 /* register_vuid keeps the server info */
283 /* register_vuid takes ownership of session_key, no need to free after this.
284 A better interface would copy it.... */
285 sess_vuid = register_vuid(server_info, session_key, nullblob, client);
287 SAFE_FREE(user);
288 SAFE_FREE(client);
290 if (sess_vuid == -1) {
291 ret = NT_STATUS_LOGON_FAILURE;
292 } else {
293 /* current_user_info is changed on new vuid */
294 reload_services( True );
296 set_message(outbuf,4,0,True);
297 SSVAL(outbuf, smb_vwv3, 0);
299 if (server_info->guest) {
300 SSVAL(outbuf,smb_vwv2,1);
303 SSVAL(outbuf, smb_uid, sess_vuid);
305 if (!server_info->guest && !srv_signing_started()) {
306 /* We need to start the signing engine
307 * here but a W2K client sends the old
308 * "BSRSPYL " signature instead of the
309 * correct one. Subsequent packets will
310 * be correct.
312 srv_check_sign_mac(inbuf, False);
316 /* wrap that up in a nice GSS-API wrapping */
317 if (NT_STATUS_IS_OK(ret)) {
318 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep, TOK_ID_KRB_AP_REP);
319 } else {
320 ap_rep_wrapped = data_blob(NULL, 0);
322 response = spnego_gen_auth_response(&ap_rep_wrapped, ret, OID_KERBEROS5_OLD);
323 reply_sesssetup_blob(conn, outbuf, response, ret);
325 data_blob_free(&ap_rep);
326 data_blob_free(&ap_rep_wrapped);
327 data_blob_free(&response);
329 return -1; /* already replied */
331 #endif
333 /****************************************************************************
334 Send a session setup reply, wrapped in SPNEGO.
335 Get vuid and check first.
336 End the NTLMSSP exchange context if we are OK/complete fail
337 ***************************************************************************/
339 static BOOL reply_spnego_ntlmssp(connection_struct *conn, char *inbuf, char *outbuf,
340 AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
341 DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status)
343 BOOL ret;
344 DATA_BLOB response;
345 struct auth_serversupplied_info *server_info = NULL;
347 if (NT_STATUS_IS_OK(nt_status)) {
348 server_info = (*auth_ntlmssp_state)->server_info;
349 } else {
350 nt_status = do_map_to_guest(nt_status,
351 &server_info,
352 (*auth_ntlmssp_state)->ntlmssp_state->user,
353 (*auth_ntlmssp_state)->ntlmssp_state->domain);
356 if (NT_STATUS_IS_OK(nt_status)) {
357 int sess_vuid;
358 DATA_BLOB nullblob = data_blob(NULL, 0);
359 DATA_BLOB session_key = data_blob((*auth_ntlmssp_state)->ntlmssp_state->session_key.data, (*auth_ntlmssp_state)->ntlmssp_state->session_key.length);
361 /* register_vuid keeps the server info */
362 sess_vuid = register_vuid(server_info, session_key, nullblob, (*auth_ntlmssp_state)->ntlmssp_state->user);
363 (*auth_ntlmssp_state)->server_info = NULL;
365 if (sess_vuid == -1) {
366 nt_status = NT_STATUS_LOGON_FAILURE;
367 } else {
369 /* current_user_info is changed on new vuid */
370 reload_services( True );
372 set_message(outbuf,4,0,True);
373 SSVAL(outbuf, smb_vwv3, 0);
375 if (server_info->guest) {
376 SSVAL(outbuf,smb_vwv2,1);
379 SSVAL(outbuf,smb_uid,sess_vuid);
381 if (!server_info->guest && !srv_signing_started()) {
382 /* We need to start the signing engine
383 * here but a W2K client sends the old
384 * "BSRSPYL " signature instead of the
385 * correct one. Subsequent packets will
386 * be correct.
389 srv_check_sign_mac(inbuf, False);
394 response = spnego_gen_auth_response(ntlmssp_blob, nt_status, OID_NTLMSSP);
395 ret = reply_sesssetup_blob(conn, outbuf, response, nt_status);
396 data_blob_free(&response);
398 /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
399 and the other end, that we are not finished yet. */
401 if (!ret || !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
402 auth_ntlmssp_end(auth_ntlmssp_state);
405 return ret;
408 /****************************************************************************
409 Reply to a session setup spnego negotiate packet.
410 ****************************************************************************/
412 static int reply_spnego_negotiate(connection_struct *conn,
413 char *inbuf,
414 char *outbuf,
415 int length, int bufsize,
416 DATA_BLOB blob1)
418 char *OIDs[ASN1_MAX_OIDS];
419 DATA_BLOB secblob;
420 int i;
421 DATA_BLOB chal;
422 #ifdef HAVE_KRB5
423 BOOL got_kerberos_mechanism = False;
424 #endif
425 NTSTATUS nt_status;
427 /* parse out the OIDs and the first sec blob */
428 if (!parse_negTokenTarg(blob1, OIDs, &secblob)) {
429 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
432 /* only look at the first OID for determining the mechToken --
433 accoirding to RFC2478, we should choose the one we want
434 and renegotiate, but i smell a client bug here..
436 Problem observed when connecting to a member (samba box)
437 of an AD domain as a user in a Samba domain. Samba member
438 server sent back krb5/mskrb5/ntlmssp as mechtypes, but the
439 client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an
440 NTLMSSP mechtoken. --jerry */
442 #ifdef HAVE_KRB5
443 if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
444 strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
445 got_kerberos_mechanism = True;
447 #endif
449 for (i=0;OIDs[i];i++) {
450 DEBUG(3,("Got OID %s\n", OIDs[i]));
451 free(OIDs[i]);
453 DEBUG(3,("Got secblob of size %lu\n", (unsigned long)secblob.length));
455 #ifdef HAVE_KRB5
456 if (got_kerberos_mechanism && (SEC_ADS == lp_security())) {
457 int ret = reply_spnego_kerberos(conn, inbuf, outbuf,
458 length, bufsize, &secblob);
459 data_blob_free(&secblob);
460 return ret;
462 #endif
464 if (global_ntlmssp_state) {
465 auth_ntlmssp_end(&global_ntlmssp_state);
468 nt_status = auth_ntlmssp_start(&global_ntlmssp_state);
469 if (!NT_STATUS_IS_OK(nt_status)) {
470 return ERROR_NT(nt_status);
473 nt_status = auth_ntlmssp_update(global_ntlmssp_state,
474 secblob, &chal);
476 data_blob_free(&secblob);
478 reply_spnego_ntlmssp(conn, inbuf, outbuf, &global_ntlmssp_state,
479 &chal, nt_status);
481 data_blob_free(&chal);
483 /* already replied */
484 return -1;
487 /****************************************************************************
488 Reply to a session setup spnego auth packet.
489 ****************************************************************************/
491 static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
492 int length, int bufsize,
493 DATA_BLOB blob1)
495 DATA_BLOB auth, auth_reply;
496 NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
498 if (!spnego_parse_auth(blob1, &auth)) {
499 #if 0
500 file_save("auth.dat", blob1.data, blob1.length);
501 #endif
502 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
505 if (!global_ntlmssp_state) {
506 /* auth before negotiatiate? */
507 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
510 nt_status = auth_ntlmssp_update(global_ntlmssp_state,
511 auth, &auth_reply);
513 data_blob_free(&auth);
515 reply_spnego_ntlmssp(conn, inbuf, outbuf, &global_ntlmssp_state,
516 &auth_reply, nt_status);
518 data_blob_free(&auth_reply);
520 /* and tell smbd that we have already replied to this packet */
521 return -1;
524 /****************************************************************************
525 Reply to a session setup command.
526 ****************************************************************************/
528 static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,
529 char *outbuf,
530 int length,int bufsize)
532 uint8 *p;
533 DATA_BLOB blob1;
534 int ret;
535 size_t bufrem;
536 fstring native_os, native_lanman, primary_domain;
537 char *p2;
538 uint16 data_blob_len = SVAL(inbuf, smb_vwv7);
539 enum remote_arch_types ra_type = get_remote_arch();
541 DEBUG(3,("Doing spnego session setup\n"));
543 if (global_client_caps == 0) {
544 global_client_caps = IVAL(inbuf,smb_vwv10);
546 if (!(global_client_caps & CAP_STATUS32)) {
547 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
552 p = (uint8 *)smb_buf(inbuf);
554 if (data_blob_len == 0) {
555 /* an invalid request */
556 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
559 bufrem = smb_bufrem(inbuf, p);
560 /* pull the spnego blob */
561 blob1 = data_blob(p, MIN(bufrem, data_blob_len));
563 #if 0
564 file_save("negotiate.dat", blob1.data, blob1.length);
565 #endif
567 p2 = inbuf + smb_vwv13 + data_blob_len;
568 p2 += srvstr_pull_buf(inbuf, native_os, p2, sizeof(native_os), STR_TERMINATE);
569 p2 += srvstr_pull_buf(inbuf, native_lanman, p2, sizeof(native_lanman), STR_TERMINATE);
570 p2 += srvstr_pull_buf(inbuf, primary_domain, p2, sizeof(primary_domain), STR_TERMINATE);
571 DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
572 native_os, native_lanman, primary_domain));
574 if ( ra_type == RA_WIN2K ) {
575 /* Windows 2003 doesn't set the native lanman string,
576 but does set primary domain which is a bug I think */
578 if ( !strlen(native_lanman) )
579 ra_lanman_string( primary_domain );
580 else
581 ra_lanman_string( native_lanman );
584 if (blob1.data[0] == ASN1_APPLICATION(0)) {
585 /* its a negTokenTarg packet */
586 ret = reply_spnego_negotiate(conn, inbuf, outbuf, length, bufsize, blob1);
587 data_blob_free(&blob1);
588 return ret;
591 if (blob1.data[0] == ASN1_CONTEXT(1)) {
592 /* its a auth packet */
593 ret = reply_spnego_auth(conn, inbuf, outbuf, length, bufsize, blob1);
594 data_blob_free(&blob1);
595 return ret;
598 /* what sort of packet is this? */
599 DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
601 data_blob_free(&blob1);
603 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
606 /****************************************************************************
607 On new VC == 0, shutdown *all* old connections and users.
608 It seems that only NT4.x does this. At W2K and above (XP etc.).
609 a new session setup with VC==0 is ignored.
610 ****************************************************************************/
612 static void setup_new_vc_session(void)
614 DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x compatible we would close all old resources.\n"));
615 #if 0
616 conn_close_all();
617 invalidate_all_vuids();
618 #endif
621 /****************************************************************************
622 Reply to a session setup command.
623 ****************************************************************************/
625 int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
626 int length,int bufsize)
628 int sess_vuid;
629 int smb_bufsize;
630 DATA_BLOB lm_resp;
631 DATA_BLOB nt_resp;
632 DATA_BLOB plaintext_password;
633 fstring user;
634 fstring sub_user; /* Sainitised username for substituion */
635 fstring domain;
636 fstring native_os;
637 fstring native_lanman;
638 fstring primary_domain;
639 static BOOL done_sesssetup = False;
640 extern BOOL global_encrypted_passwords_negotiated;
641 extern BOOL global_spnego_negotiated;
642 extern enum protocol_types Protocol;
643 extern int max_send;
645 auth_usersupplied_info *user_info = NULL;
646 extern struct auth_context *negprot_global_auth_context;
647 auth_serversupplied_info *server_info = NULL;
649 NTSTATUS nt_status;
651 BOOL doencrypt = global_encrypted_passwords_negotiated;
653 DATA_BLOB session_key;
655 START_PROFILE(SMBsesssetupX);
657 ZERO_STRUCT(lm_resp);
658 ZERO_STRUCT(nt_resp);
659 ZERO_STRUCT(plaintext_password);
661 DEBUG(3,("wct=%d flg2=0x%x\n", CVAL(inbuf, smb_wct), SVAL(inbuf, smb_flg2)));
663 /* a SPNEGO session setup has 12 command words, whereas a normal
664 NT1 session setup has 13. See the cifs spec. */
665 if (CVAL(inbuf, smb_wct) == 12 &&
666 (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
667 if (!global_spnego_negotiated) {
668 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt at SPNEGO session setup when it was not negoitiated.\n"));
669 return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
672 if (SVAL(inbuf,smb_vwv4) == 0) {
673 setup_new_vc_session();
675 return reply_sesssetup_and_X_spnego(conn, inbuf, outbuf, length, bufsize);
678 smb_bufsize = SVAL(inbuf,smb_vwv2);
680 if (Protocol < PROTOCOL_NT1) {
681 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
683 /* Never do NT status codes with protocols before NT1 as we don't get client caps. */
684 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
686 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > smb_bufrem(inbuf, smb_buf(inbuf)))) {
687 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
690 if (doencrypt) {
691 lm_resp = data_blob(smb_buf(inbuf), passlen1);
692 } else {
693 plaintext_password = data_blob(smb_buf(inbuf), passlen1+1);
694 /* Ensure null termination */
695 plaintext_password.data[passlen1] = 0;
698 srvstr_pull_buf(inbuf, user, smb_buf(inbuf)+passlen1, sizeof(user), STR_TERMINATE);
699 *domain = 0;
701 } else {
702 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
703 uint16 passlen2 = SVAL(inbuf,smb_vwv8);
704 enum remote_arch_types ra_type = get_remote_arch();
705 char *p = smb_buf(inbuf);
706 char *save_p = smb_buf(inbuf);
707 uint16 byte_count;
710 if(global_client_caps == 0) {
711 global_client_caps = IVAL(inbuf,smb_vwv11);
713 if (!(global_client_caps & CAP_STATUS32)) {
714 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
717 /* client_caps is used as final determination if client is NT or Win95.
718 This is needed to return the correct error codes in some
719 circumstances.
722 if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) {
723 if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) {
724 set_remote_arch( RA_WIN95);
729 if (!doencrypt) {
730 /* both Win95 and WinNT stuff up the password lengths for
731 non-encrypting systems. Uggh.
733 if passlen1==24 its a win95 system, and its setting the
734 password length incorrectly. Luckily it still works with the
735 default code because Win95 will null terminate the password
736 anyway
738 if passlen1>0 and passlen2>0 then maybe its a NT box and its
739 setting passlen2 to some random value which really stuffs
740 things up. we need to fix that one. */
742 if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1)
743 passlen2 = 0;
746 /* check for nasty tricks */
747 if (passlen1 > MAX_PASS_LEN || passlen1 > smb_bufrem(inbuf, p)) {
748 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
751 if (passlen2 > MAX_PASS_LEN || passlen2 > smb_bufrem(inbuf, p+passlen1)) {
752 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
755 /* Save the lanman2 password and the NT md4 password. */
757 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
758 doencrypt = False;
761 if (doencrypt) {
762 lm_resp = data_blob(p, passlen1);
763 nt_resp = data_blob(p+passlen1, passlen2);
764 } else {
765 pstring pass;
766 BOOL unic=SVAL(inbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS;
768 #if 0
769 /* This was the previous fix. Not sure if it's still valid. JRA. */
770 if ((ra_type == RA_WINNT) && (passlen2 == 0) && unic && passlen1) {
771 /* NT4.0 stuffs up plaintext unicode password lengths... */
772 srvstr_pull(inbuf, pass, smb_buf(inbuf) + 1,
773 sizeof(pass), passlen1, STR_TERMINATE);
774 #endif
776 if (unic && (passlen2 == 0) && passlen1) {
777 /* Only a ascii plaintext password was sent. */
778 srvstr_pull(inbuf, pass, smb_buf(inbuf), sizeof(pass),
779 passlen1, STR_TERMINATE|STR_ASCII);
780 } else {
781 srvstr_pull(inbuf, pass, smb_buf(inbuf),
782 sizeof(pass), unic ? passlen2 : passlen1,
783 STR_TERMINATE);
785 plaintext_password = data_blob(pass, strlen(pass)+1);
788 p += passlen1 + passlen2;
789 p += srvstr_pull_buf(inbuf, user, p, sizeof(user), STR_TERMINATE);
790 p += srvstr_pull_buf(inbuf, domain, p, sizeof(domain), STR_TERMINATE);
791 p += srvstr_pull_buf(inbuf, native_os, p, sizeof(native_os), STR_TERMINATE);
792 p += srvstr_pull_buf(inbuf, native_lanman, p, sizeof(native_lanman), STR_TERMINATE);
794 /* not documented or decoded by Ethereal but there is one more string
795 in the extra bytes which is the same as the PrimaryDomain when using
796 extended security. Windows NT 4 and 2003 use this string to store
797 the native lanman string. Windows 9x does not include a string here
798 at all so we have to check if we have any extra bytes left */
800 byte_count = SVAL(inbuf, smb_vwv13);
801 if ( PTR_DIFF(p, save_p) < byte_count)
802 p += srvstr_pull_buf(inbuf, primary_domain, p, sizeof(primary_domain), STR_TERMINATE);
803 else
804 fstrcpy( primary_domain, "null" );
806 DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
807 domain, native_os, native_lanman, primary_domain));
809 if ( ra_type == RA_WIN2K ) {
810 if ( strlen(native_lanman) == 0 )
811 ra_lanman_string( primary_domain );
812 else
813 ra_lanman_string( native_lanman );
818 if (SVAL(inbuf,smb_vwv4) == 0) {
819 setup_new_vc_session();
822 DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, get_remote_machine_name()));
824 if (*user) {
825 if (global_spnego_negotiated) {
827 /* This has to be here, because this is a perfectly valid behaviour for guest logons :-( */
829 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt at 'normal' session setup after negotiating spnego.\n"));
830 return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
832 fstrcpy(sub_user, user);
834 /* setup the string used by %U */
835 sub_set_smb_name(user);
836 } else {
837 fstrcpy(sub_user, lp_guestaccount());
840 sub_set_smb_name(sub_user);
842 reload_services(True);
844 if (lp_security() == SEC_SHARE) {
845 /* in share level we should ignore any passwords */
847 data_blob_free(&lm_resp);
848 data_blob_free(&nt_resp);
849 data_blob_clear_free(&plaintext_password);
851 map_username(sub_user);
852 add_session_user(sub_user);
853 /* Then force it to null for the benfit of the code below */
854 *user = 0;
857 if (!*user) {
859 nt_status = check_guest_password(&server_info);
861 } else if (doencrypt) {
862 if (!negprot_global_auth_context) {
863 DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted session setup without negprot denied!\n"));
864 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
866 nt_status = make_user_info_for_reply_enc(&user_info, user, domain,
867 lm_resp, nt_resp);
868 if (NT_STATUS_IS_OK(nt_status)) {
869 nt_status = negprot_global_auth_context->check_ntlm_password(negprot_global_auth_context,
870 user_info,
871 &server_info);
873 } else {
874 struct auth_context *plaintext_auth_context = NULL;
875 const uint8 *chal;
876 if (NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&plaintext_auth_context))) {
877 chal = plaintext_auth_context->get_ntlm_challenge(plaintext_auth_context);
879 if (!make_user_info_for_reply(&user_info,
880 user, domain, chal,
881 plaintext_password)) {
882 nt_status = NT_STATUS_NO_MEMORY;
885 if (NT_STATUS_IS_OK(nt_status)) {
886 nt_status = plaintext_auth_context->check_ntlm_password(plaintext_auth_context,
887 user_info,
888 &server_info);
890 (plaintext_auth_context->free)(&plaintext_auth_context);
895 free_user_info(&user_info);
897 if (!NT_STATUS_IS_OK(nt_status)) {
898 nt_status = do_map_to_guest(nt_status, &server_info, user, domain);
901 if (!NT_STATUS_IS_OK(nt_status)) {
902 data_blob_free(&nt_resp);
903 data_blob_free(&lm_resp);
904 data_blob_clear_free(&plaintext_password);
905 return ERROR_NT(nt_status_squash(nt_status));
908 if (server_info->user_session_key.data) {
909 session_key = data_blob(server_info->user_session_key.data, server_info->user_session_key.length);
910 } else {
911 session_key = data_blob(NULL, 0);
914 data_blob_clear_free(&plaintext_password);
916 /* it's ok - setup a reply */
917 set_message(outbuf,3,0,True);
918 if (Protocol >= PROTOCOL_NT1) {
919 char *p = smb_buf( outbuf );
920 p += add_signature( outbuf, p );
921 set_message_end( outbuf, p );
922 /* perhaps grab OS version here?? */
925 if (server_info->guest) {
926 SSVAL(outbuf,smb_vwv2,1);
929 /* register the name and uid as being validated, so further connections
930 to a uid can get through without a password, on the same VC */
932 /* register_vuid keeps the server info */
933 sess_vuid = register_vuid(server_info, session_key, nt_resp.data ? nt_resp : lm_resp, sub_user);
934 data_blob_free(&nt_resp);
935 data_blob_free(&lm_resp);
937 if (sess_vuid == -1) {
938 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
941 /* current_user_info is changed on new vuid */
942 reload_services( True );
944 if (!server_info->guest && !srv_signing_started() && !srv_check_sign_mac(inbuf, True)) {
945 exit_server("reply_sesssetup_and_X: bad smb signature");
948 SSVAL(outbuf,smb_uid,sess_vuid);
949 SSVAL(inbuf,smb_uid,sess_vuid);
951 if (!done_sesssetup)
952 max_send = MIN(max_send,smb_bufsize);
954 done_sesssetup = True;
956 END_PROFILE(SMBsesssetupX);
957 return chain_reply(inbuf,outbuf,length,bufsize);