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
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
-
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
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, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
+#include "smbd/smbd.h"
#include "smbd/globals.h"
#include "../libcli/auth/spnego.h"
+#include "serverid.h"
+#include "auth.h"
+#include "messages.h"
+#include "smbprofile.h"
+#include "auth/gensec/gensec.h"
+#include "../libcli/smb/smb_signing.h"
extern fstring remote_proto;
}
DEBUG(10, ("get challenge: creating negprot_global_auth_context\n"));
- nt_status = make_auth_context_subsystem(
- &sconn->smb1.negprot.auth_context);
+ nt_status = make_auth4_context(
+ sconn, &sconn->smb1.negprot.auth_context);
if (!NT_STATUS_IS_OK(nt_status)) {
DEBUG(0, ("make_auth_context_subsystem returned %s",
nt_errstr(nt_status)));
sconn->smb1.negprot.auth_context, buff);
}
-/****************************************************************************
- Reply for the core protocol.
-****************************************************************************/
-
-static void reply_corep(struct smb_request *req, uint16 choice)
-{
- reply_outbuf(req, 1, 0);
- SSVAL(req->outbuf, smb_vwv0, choice);
-
- set_Protocol(PROTOCOL_CORE);
-}
-
-/****************************************************************************
- Reply for the coreplus protocol.
-****************************************************************************/
-
-static void reply_coreplus(struct smb_request *req, uint16 choice)
-{
- int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
-
- 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(req->outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD);
- SSVAL(req->outbuf,smb_vwv1,0x1); /* user level security, don't
- * encrypt */
- set_Protocol(PROTOCOL_COREPLUS);
-}
-
/****************************************************************************
Reply for the lanman 1.0 protocol.
****************************************************************************/
sconn->smb1.negprot.encrypted_passwords = lp_encrypted_passwords();
- if (lp_security()>=SEC_USER) {
- secword |= NEGOTIATE_SECURITY_USER_LEVEL;
- }
+ secword |= NEGOTIATE_SECURITY_USER_LEVEL;
if (sconn->smb1.negprot.encrypted_passwords) {
secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE;
}
SSVAL(req->outbuf,smb_vwv11, 8);
}
- set_Protocol(PROTOCOL_LANMAN1);
+ smbXsrv_connection_init_tables(req->sconn->conn, PROTOCOL_LANMAN1);
/* Reply, SMBlockread, SMBwritelock supported. */
- SCVAL(req->outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD);
- SSVAL(req->outbuf,smb_vwv2,sconn->smb1.negprot.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
+ SCVAL(req->outbuf,smb_flg, FLAG_REPLY|FLAG_SUPPORT_LOCKREAD);
+ SSVAL(req->outbuf,smb_vwv2, sconn->smb1.negprot.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(req->outbuf,smb_vwv6,sys_getpid());
+ SIVAL(req->outbuf,smb_vwv6, getpid());
SSVAL(req->outbuf,smb_vwv10, set_server_zone_offset(t)/60);
srv_put_dos_date((char *)req->outbuf,smb_vwv8,t);
struct smbd_server_connection *sconn = req->sconn;
sconn->smb1.negprot.encrypted_passwords = lp_encrypted_passwords();
-
- if (lp_security()>=SEC_USER) {
- secword |= NEGOTIATE_SECURITY_USER_LEVEL;
- }
+
+ secword |= NEGOTIATE_SECURITY_USER_LEVEL;
if (sconn->smb1.negprot.encrypted_passwords) {
secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE;
}
reply_outbuf(req, 13, sconn->smb1.negprot.encrypted_passwords?8:0);
- SSVAL(req->outbuf,smb_vwv0,choice);
- SSVAL(req->outbuf,smb_vwv1,secword);
- SIVAL(req->outbuf,smb_vwv6,sys_getpid());
+ SSVAL(req->outbuf,smb_vwv0, choice);
+ SSVAL(req->outbuf,smb_vwv1, secword);
+ SIVAL(req->outbuf,smb_vwv6, getpid());
/* Create a token value and add it to the outgoing packet. */
if (sconn->smb1.negprot.encrypted_passwords) {
SSVAL(req->outbuf,smb_vwv11, 8);
}
- set_Protocol(PROTOCOL_LANMAN2);
+ smbXsrv_connection_init_tables(req->sconn->conn, PROTOCOL_LANMAN2);
/* Reply, SMBlockread, SMBwritelock supported. */
SCVAL(req->outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD);
DATA_BLOB blob_out = data_blob_null;
nstring dos_name;
fstring unix_name;
+ NTSTATUS status;
#ifdef DEVELOPER
size_t slen;
#endif
- const char *OIDs_krb5[] = {OID_KERBEROS5,
- OID_KERBEROS5_OLD,
- OID_NTLMSSP,
- NULL};
- const char *OIDs_plain[] = {OID_NTLMSSP, NULL};
+ struct gensec_security *gensec_security;
+
+ /* See if we can get an SPNEGO blob */
+ status = auth_generic_prepare(talloc_tos(),
+ sconn->remote_address,
+ &gensec_security);
+ if (NT_STATUS_IS_OK(status)) {
+ status = gensec_start_mech_by_oid(gensec_security, GENSEC_OID_SPNEGO);
+ if (NT_STATUS_IS_OK(status)) {
+ status = gensec_update(gensec_security, ctx,
+ NULL, data_blob_null, &blob);
+ /* If we get the list of OIDs, the 'OK' answer
+ * is NT_STATUS_MORE_PROCESSING_REQUIRED */
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ DEBUG(0, ("Failed to start SPNEGO handler for negprot OID list!\n"));
+ blob = data_blob_null;
+ }
+ }
+ TALLOC_FREE(gensec_security);
+ }
sconn->smb1.negprot.spnego = true;
+
/* strangely enough, NT does not sent the single OID NTLMSSP when
not a ADS member, it sends no OIDs at all
*/
- if (lp_security() != SEC_ADS && !USE_KERBEROS_KEYTAB) {
-#if 0
- /* Code for PocketPC client */
- blob = data_blob(guid, 16);
-#else
- /* Code for standalone WXP client */
- blob = spnego_gen_negTokenInit(OIDs_plain, "NONE");
-#endif
- } else {
- fstring myname;
- char *host_princ_s = NULL;
- name_to_fqdn(myname, global_myname());
- strlower_m(myname);
- if (asprintf(&host_princ_s, "cifs/%s@%s", myname, lp_realm())
- == -1) {
- return data_blob_null;
- }
- blob = spnego_gen_negTokenInit(OIDs_krb5, host_princ_s);
- SAFE_FREE(host_princ_s);
+ if (blob.length == 0 || blob.data == NULL) {
+ return data_blob_null;
}
blob_out = data_blob_talloc(ctx, NULL, 16 + blob.length);
memset(blob_out.data, '\0', 16);
- safe_strcpy(unix_name, global_myname(), sizeof(unix_name)-1);
- strlower_m(unix_name);
+ checked_strlcpy(unix_name, lp_netbios_name(), sizeof(unix_name));
+ (void)strlower_m(unix_name);
push_ascii_nstring(dos_name, unix_name);
- safe_strcpy((char *)blob_out.data, dos_name, 16);
+ strlcpy((char *)blob_out.data, dos_name, 17);
#ifdef DEVELOPER
/* Fix valgrind 'uninitialized bytes' issue. */
slen = strlen(dos_name);
- if (slen < sizeof(16)) {
+ if (slen < 16) {
memset(blob_out.data+slen, '\0', 16 - slen);
}
#endif
CAP_LEVEL_II_OPLOCKS;
int secword=0;
- char *p, *q;
bool negotiate_spnego = False;
- time_t t = time(NULL);
+ struct timespec ts;
ssize_t ret;
struct smbd_server_connection *sconn = req->sconn;
+ bool signing_enabled = false;
+ bool signing_required = false;
sconn->smb1.negprot.encrypted_passwords = lp_encrypted_passwords();
distinguish from NT which doesn't set it either. */
if ( (req->flags2 & FLAGS2_EXTENDED_SECURITY) &&
- ((req->flags2 & FLAGS2_UNKNOWN_BIT4) == 0) )
+ ((req->flags2 & FLAGS2_SMB_SECURITY_SIGNATURES_REQUIRED) == 0) )
{
if (get_remote_arch() != RA_SAMBA) {
set_remote_arch( RA_VISTA );
/* do spnego in user level security if the client
supports it and we can do encrypted passwords */
-
+
if (sconn->smb1.negprot.encrypted_passwords &&
- (lp_security() != SEC_SHARE) &&
lp_use_spnego() &&
(req->flags2 & FLAGS2_EXTENDED_SECURITY)) {
negotiate_spnego = True;
SSVAL(req->outbuf, smb_flg2,
req->flags2 | FLAGS2_EXTENDED_SECURITY);
}
-
- capabilities |= CAP_NT_SMBS|CAP_RPC_REMOTE_APIS|CAP_UNICODE;
+
+ capabilities |= CAP_NT_SMBS|CAP_RPC_REMOTE_APIS;
+
+ if (lp_unicode()) {
+ capabilities |= CAP_UNICODE;
+ }
if (lp_unix_extensions()) {
capabilities |= CAP_UNIX;
}
-
+
if (lp_large_readwrite() && (SMB_OFF_T_BITS == 64))
capabilities |= CAP_LARGE_READX|CAP_LARGE_WRITEX|CAP_W2K_SMBS;
-
+
if (SMB_OFF_T_BITS == 64)
capabilities |= CAP_LARGE_FILES;
if (lp_readraw() && lp_writeraw())
capabilities |= CAP_RAW_MODE;
-
+
if (lp_nt_status_support())
capabilities |= CAP_STATUS32;
-
+
if (lp_host_msdfs())
capabilities |= CAP_DFS;
-
- if (lp_security() >= SEC_USER) {
- secword |= NEGOTIATE_SECURITY_USER_LEVEL;
- }
+
+ secword |= NEGOTIATE_SECURITY_USER_LEVEL;
if (sconn->smb1.negprot.encrypted_passwords) {
secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE;
}
- if (lp_server_signing()) {
- if (lp_security() >= SEC_USER) {
- secword |= NEGOTIATE_SECURITY_SIGNATURES_ENABLED;
- /* No raw mode with smb signing. */
- capabilities &= ~CAP_RAW_MODE;
- if (lp_server_signing() == Required)
- secword |=NEGOTIATE_SECURITY_SIGNATURES_REQUIRED;
- srv_set_signing_negotiated(sconn);
- } else {
- DEBUG(0,("reply_nt1: smb signing is incompatible with share level security !\n"));
- if (lp_server_signing() == Required) {
- exit_server_cleanly("reply_nt1: smb signing required and share level security selected.");
- }
+ signing_enabled = smb_signing_is_allowed(req->sconn->smb1.signing_state);
+ signing_required = smb_signing_is_mandatory(req->sconn->smb1.signing_state);
+
+ if (signing_enabled) {
+ secword |= NEGOTIATE_SECURITY_SIGNATURES_ENABLED;
+ /* No raw mode with smb signing. */
+ capabilities &= ~CAP_RAW_MODE;
+ if (signing_required) {
+ secword |=NEGOTIATE_SECURITY_SIGNATURES_REQUIRED;
}
}
SSVAL(req->outbuf,smb_vwv0,choice);
SCVAL(req->outbuf,smb_vwv1,secword);
-
- set_Protocol(PROTOCOL_NT1);
-
- SSVAL(req->outbuf,smb_vwv1+1,lp_maxmux()); /* maxmpx */
- SSVAL(req->outbuf,smb_vwv2+1,1); /* num vcs */
+
+ smbXsrv_connection_init_tables(req->sconn->conn, PROTOCOL_NT1);
+
+ SSVAL(req->outbuf,smb_vwv1+1, lp_maxmux()); /* maxmpx */
+ SSVAL(req->outbuf,smb_vwv2+1, 1); /* num vcs */
SIVAL(req->outbuf,smb_vwv3+1,
sconn->smb1.negprot.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(req->outbuf);
+ SIVAL(req->outbuf,smb_vwv5+1, 0x10000); /* raw size. full 64k */
+ SIVAL(req->outbuf,smb_vwv7+1, getpid()); /* session key */
+ SIVAL(req->outbuf,smb_vwv9+1, capabilities); /* capabilities */
+ clock_gettime(CLOCK_REALTIME,&ts);
+ put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER,(char *)req->outbuf+smb_vwv11+1,ts);
+ SSVALS(req->outbuf,smb_vwv15+1,set_server_zone_offset(ts.tv_sec)/60);
+
if (!negotiate_spnego) {
/* Create a token value and add it to the outgoing packet. */
if (sconn->smb1.negprot.encrypted_passwords) {
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"));
+ DEBUG(0, ("Could not push workgroup string\n"));
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+ ret = message_push_string(&req->outbuf, lp_netbios_name(),
+ STR_UNICODE|STR_TERMINATE
+ |STR_NOALIGN);
+ if (ret == -1) {
+ DEBUG(0, ("Could not push netbios name string\n"));
reply_nterror(req, NT_STATUS_NO_MEMORY);
return;
}
reply_nterror(req, NT_STATUS_NO_MEMORY);
return;
}
- p += ret;
data_blob_free(&spnego_blob);
SCVAL(req->outbuf,smb_vwv16+1, 0);
DEBUG(3,("using SPNEGO\n"));
}
-
- SSVAL(req->outbuf,smb_vwv17, p - q); /* length of challenge+domain
- * strings */
return;
}
* tim@fsg.com 09/29/95
* Win2K added by matty 17/7/99
*/
-
+
#define ARCH_WFWG 0x3 /* This is a fudge because WfWg is like Win95 */
#define ARCH_WIN95 0x2
#define ARCH_WINNT 0x4
#define ARCH_SAMBA 0x20
#define ARCH_CIFSFS 0x40
#define ARCH_VISTA 0x8C /* Vista is like XP/2K */
-
+
#define ARCH_ALL 0x7F
-
+
/* List of supported protocols, most desired first */
static const struct {
const char *proto_name;
void (*proto_reply_fn)(struct smb_request *req, uint16 choice);
int protocol_level;
} supported_protocols[] = {
- {"SMB 2.002", "SMB2", reply_smb2002, PROTOCOL_SMB2},
+ {"SMB 2.???", "SMB2_FF", reply_smb20ff, PROTOCOL_SMB2_10},
+ {"SMB 2.002", "SMB2_02", reply_smb2002, PROTOCOL_SMB2_02},
{"NT LANMAN 1.0", "NT1", reply_nt1, PROTOCOL_NT1},
{"NT LM 0.12", "NT1", reply_nt1, PROTOCOL_NT1},
{"POSIX 2", "NT1", reply_nt1, PROTOCOL_NT1},
{"DOS LM1.2X002", "LANMAN2", reply_lanman2, PROTOCOL_LANMAN2},
{"LANMAN1.0", "LANMAN1", reply_lanman1, PROTOCOL_LANMAN1},
{"MICROSOFT NETWORKS 3.0", "LANMAN1", reply_lanman1, PROTOCOL_LANMAN1},
- {"MICROSOFT NETWORKS 1.03", "COREPLUS", reply_coreplus, PROTOCOL_COREPLUS},
- {"PC NETWORK PROGRAM 1.0", "CORE", reply_corep, PROTOCOL_CORE},
{NULL,NULL,NULL,0},
};
char **tmp;
- tmp = TALLOC_REALLOC_ARRAY(talloc_tos(), cliprotos, char *,
+ tmp = talloc_realloc(talloc_tos(), cliprotos, char *,
num_cliprotos+1);
if (tmp == NULL) {
DEBUG(0, ("talloc failed\n"));
set_remote_arch(RA_UNKNOWN);
break;
}
-
+
/* possibly reload - change of architecture */
- reload_services(True);
-
+ reload_services(sconn, conn_snum_used, true);
+
/* moved from the netbios session setup code since we don't have that
when the client connects to port 445. Of course there is a small
window where we are listening to messages -- jerry */
- serverid_register(sconn_server_id(sconn),
+ serverid_register(messaging_server_id(sconn->msg_ctx),
FLAG_MSG_GENERAL|FLAG_MSG_SMBD
|FLAG_MSG_PRINT_GENERAL);
-
+
/* Check for protocols, most desirable first */
for (protocol = 0; supported_protocols[protocol].proto_name; protocol++) {
i = 0;
- if ((supported_protocols[protocol].protocol_level <= lp_maxprotocol()) &&
- (supported_protocols[protocol].protocol_level >= lp_minprotocol()))
+ if ((supported_protocols[protocol].protocol_level <= lp_srv_maxprotocol()) &&
+ (supported_protocols[protocol].protocol_level >= lp_srv_minprotocol()))
while (i < num_cliprotos) {
if (strequal(cliprotos[i],supported_protocols[protocol].proto_name))
choice = i;
if(choice != -1)
break;
}
-
+
if(choice != -1) {
fstrcpy(remote_proto,supported_protocols[protocol].short_name);
- reload_services(True);
+ reload_services(sconn, conn_snum_used, true);
supported_protocols[protocol].proto_reply_fn(req, choice);
DEBUG(3,("Selected protocol %s\n",supported_protocols[protocol].proto_name));
} else {
reply_outbuf(req, 1, 0);
SSVAL(req->outbuf, smb_vwv0, choice);
}
-
+
DEBUG( 5, ( "negprot index=%d\n", choice ) );
- if ((lp_server_signing() == Required) && (get_Protocol() < PROTOCOL_NT1)) {
+ if ((lp_server_signing() == SMB_SIGNING_REQUIRED)
+ && (get_Protocol() < PROTOCOL_NT1)) {
exit_server_cleanly("SMB signing is required and "
"client negotiated a downlevel protocol");
}
TALLOC_FREE(cliprotos);
+
+ if (lp_async_smb_echo_handler() && (get_Protocol() < PROTOCOL_SMB2_02) &&
+ !fork_echo_handler(sconn)) {
+ exit_server("Failed to fork echo handler");
+ }
+
END_PROFILE(SMBnegprot);
return;
}