Unix SMB/CIFS implementation.
negprot reply code
Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Volker Lendecke 2007
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
extern enum protocol_types Protocol;
extern int max_recv;
-BOOL global_encrypted_passwords_negotiated = False;
-BOOL global_spnego_negotiated = False;
+bool global_encrypted_passwords_negotiated = False;
+bool global_spnego_negotiated = False;
struct auth_context *negprot_global_auth_context = NULL;
-static void get_challenge(char buff[8])
+static void get_challenge(uint8 buff[8])
{
NTSTATUS nt_status;
const uint8 *cryptkey;
Reply for the core protocol.
****************************************************************************/
-static int reply_corep(char *inbuf, char *outbuf)
+static void reply_corep(struct smb_request *req, uint16 choice)
{
- int outsize = set_message(inbuf,outbuf,1,0,True);
+ reply_outbuf(req, 1, 0);
+ SSVAL(req->outbuf, smb_vwv0, choice);
Protocol = PROTOCOL_CORE;
-
- return outsize;
}
/****************************************************************************
Reply for the coreplus protocol.
****************************************************************************/
-static int reply_coreplus(char *inbuf, char *outbuf)
+static void reply_coreplus(struct smb_request *req, uint16 choice)
{
int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
- int outsize = set_message(inbuf,outbuf,13,0,True);
- SSVAL(outbuf,smb_vwv5,raw); /* tell redirector we support
+
+ reply_outbuf(req, 13, 0);
+
+ SSVAL(req->outbuf,smb_vwv0,choice);
+ SSVAL(req->outbuf,smb_vwv5,raw); /* tell redirector we support
readbraw and writebraw (possibly) */
/* Reply, SMBlockread, SMBwritelock supported. */
- SCVAL(outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD);
- SSVAL(outbuf,smb_vwv1,0x1); /* user level security, don't encrypt */
-
+ SCVAL(req->outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD);
+ SSVAL(req->outbuf,smb_vwv1,0x1); /* user level security, don't
+ * encrypt */
Protocol = PROTOCOL_COREPLUS;
-
- return outsize;
}
/****************************************************************************
Reply for the lanman 1.0 protocol.
****************************************************************************/
-static int reply_lanman1(char *inbuf, char *outbuf)
+static void reply_lanman1(struct smb_request *req, uint16 choice)
{
int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
int secword=0;
if (global_encrypted_passwords_negotiated)
secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE;
- set_message(inbuf,outbuf,13,global_encrypted_passwords_negotiated?8:0,True);
- SSVAL(outbuf,smb_vwv1,secword);
+ reply_outbuf(req, 13, global_encrypted_passwords_negotiated?8:0);
+
+ SSVAL(req->outbuf,smb_vwv0,choice);
+ SSVAL(req->outbuf,smb_vwv1,secword);
/* Create a token value and add it to the outgoing packet. */
if (global_encrypted_passwords_negotiated) {
- get_challenge(smb_buf(outbuf));
- SSVAL(outbuf,smb_vwv11, 8);
+ get_challenge((uint8 *)smb_buf(req->outbuf));
+ SSVAL(req->outbuf,smb_vwv11, 8);
}
Protocol = PROTOCOL_LANMAN1;
/* Reply, SMBlockread, SMBwritelock supported. */
- SCVAL(outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD);
- SSVAL(outbuf,smb_vwv2,max_recv);
- SSVAL(outbuf,smb_vwv3,lp_maxmux()); /* maxmux */
- SSVAL(outbuf,smb_vwv4,1);
- SSVAL(outbuf,smb_vwv5,raw); /* tell redirector we support
+ SCVAL(req->outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD);
+ SSVAL(req->outbuf,smb_vwv2,max_recv);
+ SSVAL(req->outbuf,smb_vwv3,lp_maxmux()); /* maxmux */
+ SSVAL(req->outbuf,smb_vwv4,1);
+ SSVAL(req->outbuf,smb_vwv5,raw); /* tell redirector we support
readbraw writebraw (possibly) */
- SIVAL(outbuf,smb_vwv6,sys_getpid());
- SSVAL(outbuf,smb_vwv10, set_server_zone_offset(t)/60);
+ SIVAL(req->outbuf,smb_vwv6,sys_getpid());
+ SSVAL(req->outbuf,smb_vwv10, set_server_zone_offset(t)/60);
- srv_put_dos_date(outbuf,smb_vwv8,t);
+ srv_put_dos_date((char *)req->outbuf,smb_vwv8,t);
- return (smb_len(outbuf)+4);
+ return;
}
/****************************************************************************
Reply for the lanman 2.0 protocol.
****************************************************************************/
-static int reply_lanman2(char *inbuf, char *outbuf)
+static void reply_lanman2(struct smb_request *req, uint16 choice)
{
int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
int secword=0;
if (global_encrypted_passwords_negotiated)
secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE;
- set_message(inbuf,outbuf,13,global_encrypted_passwords_negotiated?8:0,True);
- SSVAL(outbuf,smb_vwv1,secword);
- SIVAL(outbuf,smb_vwv6,sys_getpid());
+ reply_outbuf(req, 13, global_encrypted_passwords_negotiated?8:0);
+
+ SSVAL(req->outbuf,smb_vwv0,choice);
+ SSVAL(req->outbuf,smb_vwv1,secword);
+ SIVAL(req->outbuf,smb_vwv6,sys_getpid());
/* Create a token value and add it to the outgoing packet. */
if (global_encrypted_passwords_negotiated) {
- get_challenge(smb_buf(outbuf));
- SSVAL(outbuf,smb_vwv11, 8);
+ get_challenge((uint8 *)smb_buf(req->outbuf));
+ SSVAL(req->outbuf,smb_vwv11, 8);
}
Protocol = PROTOCOL_LANMAN2;
/* Reply, SMBlockread, SMBwritelock supported. */
- SCVAL(outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD);
- SSVAL(outbuf,smb_vwv2,max_recv);
- SSVAL(outbuf,smb_vwv3,lp_maxmux());
- SSVAL(outbuf,smb_vwv4,1);
- SSVAL(outbuf,smb_vwv5,raw); /* readbraw and/or writebraw */
- SSVAL(outbuf,smb_vwv10, set_server_zone_offset(t)/60);
- srv_put_dos_date(outbuf,smb_vwv8,t);
-
- return (smb_len(outbuf)+4);
+ SCVAL(req->outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD);
+ SSVAL(req->outbuf,smb_vwv2,max_recv);
+ SSVAL(req->outbuf,smb_vwv3,lp_maxmux());
+ SSVAL(req->outbuf,smb_vwv4,1);
+ SSVAL(req->outbuf,smb_vwv5,raw); /* readbraw and/or writebraw */
+ SSVAL(req->outbuf,smb_vwv10, set_server_zone_offset(t)/60);
+ srv_put_dos_date((char *)req->outbuf,smb_vwv8,t);
}
/****************************************************************************
char *host_princ_s = NULL;
name_to_fqdn(myname, global_myname());
strlower_m(myname);
- asprintf(&host_princ_s, "cifs/%s@%s", myname, lp_realm());
- if (host_princ_s == NULL) {
- blob = data_blob_null;
- return blob;
+ if (asprintf(&host_princ_s, "cifs/%s@%s", myname, lp_realm())
+ == -1) {
+ return data_blob_null;
}
blob = spnego_gen_negTokenInit(guid, OIDs_krb5, host_princ_s);
SAFE_FREE(host_princ_s);
Reply for the nt protocol.
****************************************************************************/
-static int reply_nt1(char *inbuf, char *outbuf)
+static void reply_nt1(struct smb_request *req, uint16 choice)
{
/* dual names + lock_and_read + nt SMBs + remote API calls */
int capabilities = CAP_NT_FIND|CAP_LOCK_AND_READ|
int secword=0;
char *p, *q;
- BOOL negotiate_spnego = False;
+ bool negotiate_spnego = False;
time_t t = time(NULL);
+ ssize_t ret;
global_encrypted_passwords_negotiated = lp_encrypted_passwords();
WinXP sets it and Vista does not. But we have to
distinguish from NT which doesn't set it either. */
- if ( (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY) &&
- ((SVAL(inbuf, smb_flg2) & FLAGS2_UNKNOWN_BIT4) == 0) )
+ if ( (req->flags2 & FLAGS2_EXTENDED_SECURITY) &&
+ ((req->flags2 & FLAGS2_UNKNOWN_BIT4) == 0) )
{
if (get_remote_arch() != RA_SAMBA) {
set_remote_arch( RA_VISTA );
}
}
+ reply_outbuf(req,17,0);
+
/* do spnego in user level security if the client
supports it and we can do encrypted passwords */
if (global_encrypted_passwords_negotiated &&
(lp_security() != SEC_SHARE) &&
lp_use_spnego() &&
- (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
+ (req->flags2 & FLAGS2_EXTENDED_SECURITY)) {
negotiate_spnego = True;
capabilities |= CAP_EXTENDED_SECURITY;
add_to_common_flags2(FLAGS2_EXTENDED_SECURITY);
- /* Ensure FLAGS2_EXTENDED_SECURITY gets set in this reply (already
- partially constructed. */
- SSVAL(outbuf,smb_flg2, SVAL(outbuf,smb_flg2) | FLAGS2_EXTENDED_SECURITY);
+ /* Ensure FLAGS2_EXTENDED_SECURITY gets set in this reply
+ (already partially constructed. */
+ SSVAL(req->outbuf, smb_flg2,
+ req->flags2 | FLAGS2_EXTENDED_SECURITY);
}
capabilities |= CAP_NT_SMBS|CAP_RPC_REMOTE_APIS|CAP_UNICODE;
}
}
- set_message(inbuf,outbuf,17,0,True);
-
- SCVAL(outbuf,smb_vwv1,secword);
+ SSVAL(req->outbuf,smb_vwv0,choice);
+ SCVAL(req->outbuf,smb_vwv1,secword);
Protocol = PROTOCOL_NT1;
- SSVAL(outbuf,smb_vwv1+1,lp_maxmux()); /* maxmpx */
- SSVAL(outbuf,smb_vwv2+1,1); /* num vcs */
- SIVAL(outbuf,smb_vwv3+1,max_recv); /* max buffer. LOTS! */
- SIVAL(outbuf,smb_vwv5+1,0x10000); /* raw size. full 64k */
- SIVAL(outbuf,smb_vwv7+1,sys_getpid()); /* session key */
- SIVAL(outbuf,smb_vwv9+1,capabilities); /* capabilities */
- put_long_date(outbuf+smb_vwv11+1,t);
- SSVALS(outbuf,smb_vwv15+1,set_server_zone_offset(t)/60);
+ SSVAL(req->outbuf,smb_vwv1+1,lp_maxmux()); /* maxmpx */
+ SSVAL(req->outbuf,smb_vwv2+1,1); /* num vcs */
+ SIVAL(req->outbuf,smb_vwv3+1,max_recv); /* max buffer. LOTS! */
+ SIVAL(req->outbuf,smb_vwv5+1,0x10000); /* raw size. full 64k */
+ SIVAL(req->outbuf,smb_vwv7+1,sys_getpid()); /* session key */
+ SIVAL(req->outbuf,smb_vwv9+1,capabilities); /* capabilities */
+ put_long_date((char *)req->outbuf+smb_vwv11+1,t);
+ SSVALS(req->outbuf,smb_vwv15+1,set_server_zone_offset(t)/60);
- p = q = smb_buf(outbuf);
+ p = q = smb_buf(req->outbuf);
if (!negotiate_spnego) {
/* Create a token value and add it to the outgoing packet. */
if (global_encrypted_passwords_negotiated) {
+ uint8 chal[8];
/* note that we do not send a challenge at all if
we are using plaintext */
- get_challenge(p);
- SCVAL(outbuf,smb_vwv16+1,8);
- p += 8;
+ get_challenge(chal);
+ ret = message_push_blob(
+ &req->outbuf, data_blob_const(chal, sizeof(chal)));
+ if (ret == -1) {
+ DEBUG(0, ("Could not push challenge\n"));
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+ SCVAL(req->outbuf, smb_vwv16+1, ret);
+ p += ret;
+ }
+ ret = message_push_string(&req->outbuf, lp_workgroup(),
+ STR_UNICODE|STR_TERMINATE
+ |STR_NOALIGN);
+ if (ret == -1) {
+ DEBUG(0, ("Could not push challenge\n"));
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
}
- p += srvstr_push(outbuf, p, lp_workgroup(), -1,
- STR_UNICODE|STR_TERMINATE|STR_NOALIGN);
DEBUG(3,("not using SPNEGO\n"));
} else {
DATA_BLOB spnego_blob = negprot_spnego();
if (spnego_blob.data == NULL) {
- return ERROR_NT(NT_STATUS_NO_MEMORY);
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
}
- memcpy(p, spnego_blob.data, spnego_blob.length);
- p += spnego_blob.length;
+ ret = message_push_blob(&req->outbuf, spnego_blob);
+ if (ret == -1) {
+ DEBUG(0, ("Could not push spnego blob\n"));
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+ p += ret;
data_blob_free(&spnego_blob);
- SCVAL(outbuf,smb_vwv16+1, 0);
+ SCVAL(req->outbuf,smb_vwv16+1, 0);
DEBUG(3,("using SPNEGO\n"));
}
- SSVAL(outbuf,smb_vwv17, p - q); /* length of challenge+domain strings */
- set_message_end(inbuf,outbuf, p);
-
- return (smb_len(outbuf)+4);
+ SSVAL(req->outbuf,smb_vwv17, p - q); /* length of challenge+domain
+ * strings */
+
+ return;
}
/* these are the protocol lists used for auto architecture detection:
static const struct {
const char *proto_name;
const char *short_name;
- int (*proto_reply_fn)(char *, char *);
+ void (*proto_reply_fn)(struct smb_request *req, uint16 choice);
int protocol_level;
} supported_protocols[] = {
{"NT LANMAN 1.0", "NT1", reply_nt1, PROTOCOL_NT1},
conn POINTER CAN BE NULL HERE !
****************************************************************************/
-int reply_negprot(connection_struct *conn,
- char *inbuf,char *outbuf, int dum_size,
- int dum_buffsize)
+void reply_negprot(struct smb_request *req)
{
- int outsize = set_message(inbuf,outbuf,1,0,True);
- int Index=0;
+ size_t size = smb_len(req->inbuf) + 4;
int choice= -1;
int protocol;
char *p;
- int bcc = SVAL(smb_buf(inbuf),-2);
+ int bcc = SVAL(smb_buf(req->inbuf),-2);
int arch = ARCH_ALL;
+ int num_cliprotos;
+ char **cliprotos;
+ int i;
- static BOOL done_negprot = False;
+ static bool done_negprot = False;
START_PROFILE(SMBnegprot);
}
done_negprot = True;
- p = smb_buf(inbuf)+1;
- while (p < (smb_buf(inbuf) + bcc)) {
- Index++;
- DEBUG(3,("Requested protocol [%s]\n",p));
- if (strcsequal(p,"Windows for Workgroups 3.1a"))
- arch &= ( ARCH_WFWG | ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K );
- else if (strcsequal(p,"DOS LM1.2X002"))
+ if (req->inbuf[size-1] != '\0') {
+ DEBUG(0, ("negprot protocols not 0-terminated\n"));
+ reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ END_PROFILE(SMBnegprot);
+ return;
+ }
+
+ p = smb_buf(req->inbuf) + 1;
+
+ num_cliprotos = 0;
+ cliprotos = NULL;
+
+ while (p < (smb_buf(req->inbuf) + bcc)) {
+
+ char **tmp;
+
+ tmp = TALLOC_REALLOC_ARRAY(talloc_tos(), cliprotos, char *,
+ num_cliprotos+1);
+ if (tmp == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ TALLOC_FREE(cliprotos);
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ END_PROFILE(SMBnegprot);
+ return;
+ }
+
+ cliprotos = tmp;
+
+ if (pull_ascii_talloc(cliprotos, &cliprotos[num_cliprotos], p)
+ == (size_t)-1) {
+ DEBUG(0, ("pull_ascii_talloc failed\n"));
+ TALLOC_FREE(cliprotos);
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ END_PROFILE(SMBnegprot);
+ return;
+ }
+
+ DEBUG(3, ("Requested protocol [%s]\n",
+ cliprotos[num_cliprotos]));
+
+ num_cliprotos += 1;
+ p += strlen(p) + 2;
+ }
+
+ for (i=0; i<num_cliprotos; i++) {
+ if (strcsequal(cliprotos[i], "Windows for Workgroups 3.1a"))
+ arch &= ( ARCH_WFWG | ARCH_WIN95 | ARCH_WINNT
+ | ARCH_WIN2K );
+ else if (strcsequal(cliprotos[i], "DOS LM1.2X002"))
arch &= ( ARCH_WFWG | ARCH_WIN95 );
- else if (strcsequal(p,"DOS LANMAN2.1"))
+ else if (strcsequal(cliprotos[i], "DOS LANMAN2.1"))
arch &= ( ARCH_WFWG | ARCH_WIN95 );
- else if (strcsequal(p,"NT LM 0.12"))
- arch &= ( ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K | ARCH_CIFSFS);
- else if (strcsequal(p,"SMB 2.001"))
+ else if (strcsequal(cliprotos[i], "NT LM 0.12"))
+ arch &= ( ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K
+ | ARCH_CIFSFS);
+ else if (strcsequal(cliprotos[i], "SMB 2.001"))
arch = ARCH_VISTA;
- else if (strcsequal(p,"LANMAN2.1"))
+ else if (strcsequal(cliprotos[i], "LANMAN2.1"))
arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 );
- else if (strcsequal(p,"LM1.2X002"))
+ else if (strcsequal(cliprotos[i], "LM1.2X002"))
arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 );
- else if (strcsequal(p,"MICROSOFT NETWORKS 1.03"))
+ else if (strcsequal(cliprotos[i], "MICROSOFT NETWORKS 1.03"))
arch &= ARCH_WINNT;
- else if (strcsequal(p,"XENIX CORE"))
+ else if (strcsequal(cliprotos[i], "XENIX CORE"))
arch &= ( ARCH_WINNT | ARCH_OS2 );
- else if (strcsequal(p,"Samba")) {
+ else if (strcsequal(cliprotos[i], "Samba")) {
arch = ARCH_SAMBA;
break;
- } else if (strcsequal(p,"POSIX 2")) {
+ } else if (strcsequal(cliprotos[i], "POSIX 2")) {
arch = ARCH_CIFSFS;
break;
}
-
- p += strlen(p) + 2;
}
/* CIFSFS can send one arch only, NT LM 0.12. */
- if (Index == 1 && (arch & ARCH_CIFSFS)) {
+ if (i == 1 && (arch & ARCH_CIFSFS)) {
arch = ARCH_CIFSFS;
}
set_remote_arch(RA_WIN95);
break;
case ARCH_WINNT:
- if(SVAL(inbuf,smb_flg2)==FLAGS2_WIN2K_SIGNATURE)
+ if(req->flags2 == FLAGS2_WIN2K_SIGNATURE)
set_remote_arch(RA_WIN2K);
else
set_remote_arch(RA_WINNT);
/* Check for protocols, most desirable first */
for (protocol = 0; supported_protocols[protocol].proto_name; protocol++) {
- p = smb_buf(inbuf)+1;
- Index = 0;
+ i = 0;
if ((supported_protocols[protocol].protocol_level <= lp_maxprotocol()) &&
(supported_protocols[protocol].protocol_level >= lp_minprotocol()))
- while (p < (smb_buf(inbuf) + bcc)) {
- if (strequal(p,supported_protocols[protocol].proto_name))
- choice = Index;
- Index++;
- p += strlen(p) + 2;
+ while (i < num_cliprotos) {
+ if (strequal(cliprotos[i],supported_protocols[protocol].proto_name))
+ choice = i;
+ i++;
}
if(choice != -1)
break;
}
- SSVAL(outbuf,smb_vwv0,choice);
if(choice != -1) {
fstrcpy(remote_proto,supported_protocols[protocol].short_name);
reload_services(True);
- outsize = supported_protocols[protocol].proto_reply_fn(inbuf, outbuf);
+ supported_protocols[protocol].proto_reply_fn(req, choice);
DEBUG(3,("Selected protocol %s\n",supported_protocols[protocol].proto_name));
} else {
DEBUG(0,("No protocol supported !\n"));
+ reply_outbuf(req, 1, 0);
+ SSVAL(req->outbuf, smb_vwv0, choice);
}
- SSVAL(outbuf,smb_vwv0,choice);
DEBUG( 5, ( "negprot index=%d\n", choice ) );
"client negotiated a downlevel protocol");
}
+ TALLOC_FREE(cliprotos);
END_PROFILE(SMBnegprot);
- return(outsize);
+ return;
}