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 2 of the License, or
+ 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,
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"
#include "auth/credentials/credentials.h"
+#include "auth/auth.h"
#include "auth/gensec/gensec.h"
+#include "libcli/raw/libcliraw.h"
+#include "libcli/raw/raw_proto.h"
#include "libcli/smb2/smb2.h"
#include "libcli/smb2/smb2_calls.h"
#include "smb_server/smb_server.h"
-#include "smb_server/service_smb_proto.h"
#include "smb_server/smb2/smb2_server.h"
#include "smbd/service_stream.h"
+#include "param/param.h"
static NTSTATUS smb2srv_negprot_secblob(struct smb2srv_request *req, DATA_BLOB *_blob)
{
NTSTATUS nt_status;
struct cli_credentials *server_credentials;
- nt_status = gensec_server_start(req,
- req->smb_conn->connection->event.ctx,
- req->smb_conn->connection->msg_ctx,
- &gensec_security);
- if (!NT_STATUS_IS_OK(nt_status)) {
- DEBUG(0, ("Failed to start GENSEC: %s\n", nt_errstr(nt_status)));
- smbsrv_terminate_connection(req->smb_conn, "Failed to start GENSEC\n");
- return nt_status;
- }
-
server_credentials = cli_credentials_init(req);
if (!server_credentials) {
smbsrv_terminate_connection(req->smb_conn, "Failed to init server credentials\n");
return NT_STATUS_NO_MEMORY;
}
- cli_credentials_set_conf(server_credentials);
- nt_status = cli_credentials_set_machine_account(server_credentials);
+ cli_credentials_set_conf(server_credentials, req->smb_conn->lp_ctx);
+ nt_status = cli_credentials_set_machine_account(server_credentials, req->smb_conn->lp_ctx);
if (!NT_STATUS_IS_OK(nt_status)) {
DEBUG(10, ("Failed to obtain server credentials, perhaps a standalone server?: %s\n", nt_errstr(nt_status)));
talloc_free(server_credentials);
req->smb_conn->negotiate.server_credentials = talloc_steal(req->smb_conn, server_credentials);
+ nt_status = samba_server_gensec_start(req,
+ req->smb_conn->connection->event.ctx,
+ req->smb_conn->connection->msg_ctx,
+ req->smb_conn->lp_ctx,
+ server_credentials,
+ "cifs",
+ &gensec_security);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(0, ("Failed to start GENSEC: %s\n", nt_errstr(nt_status)));
+ smbsrv_terminate_connection(req->smb_conn, "Failed to start GENSEC\n");
+ return nt_status;
+ }
+
gensec_set_target_service(gensec_security, "cifs");
gensec_set_credentials(gensec_security, server_credentials);
NTSTATUS status;
struct timeval current_time;
struct timeval boot_time;
+ uint16_t i;
+ uint16_t dialect = 0;
+
+ /* we only do one dialect for now */
+ if (io->in.dialect_count < 1) {
+ return NT_STATUS_NOT_SUPPORTED;
+ }
+ for (i=0; i < io->in.dialect_count; i++) {
+ dialect = io->in.dialects[i];
+ if (dialect == SMB2_DIALECT_REVISION_202) {
+ break;
+ }
+ }
+ if (dialect != SMB2_DIALECT_REVISION_202) {
+ DEBUG(0,("Got unexpected SMB2 dialect %u\n", dialect));
+ return NT_STATUS_NOT_SUPPORTED;
+ }
req->smb_conn->negotiate.protocol = PROTOCOL_SMB2;
current_time = timeval_current(); /* TODO: handle timezone?! */
boot_time = timeval_current(); /* TODO: fix me */
- io->out._pad = 0;
- io->out.unknown2 = 0x06;
- ZERO_STRUCT(io->out.sessid);
- io->out.unknown3 = 0x0d;
- io->out.unknown4 = 0x00;
- io->out.unknown5 = 0x01;
- io->out.unknown6 = 0x01;
- io->out.unknown7 = 0x01;
- io->out.current_time = timeval_to_nttime(¤t_time);
- io->out.boot_time = timeval_to_nttime(&boot_time);
+ ZERO_STRUCT(io->out);
+ switch (lpcfg_server_signing(req->smb_conn->lp_ctx)) {
+ case SMB_SIGNING_OFF:
+ io->out.security_mode = 0;
+ break;
+ case SMB_SIGNING_SUPPORTED:
+ case SMB_SIGNING_AUTO:
+ io->out.security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED;
+ break;
+ case SMB_SIGNING_REQUIRED:
+ io->out.security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED;
+ /* force signing on immediately */
+ req->smb_conn->smb2_signing_required = true;
+ break;
+ }
+ io->out.dialect_revision = dialect;
+ io->out.capabilities = 0;
+ io->out.max_transact_size = lpcfg_parm_ulong(req->smb_conn->lp_ctx, NULL,
+ "smb2", "max transaction size", 0x10000);
+ io->out.max_read_size = lpcfg_parm_ulong(req->smb_conn->lp_ctx, NULL,
+ "smb2", "max read size", 0x10000);
+ io->out.max_write_size = lpcfg_parm_ulong(req->smb_conn->lp_ctx, NULL,
+ "smb2", "max write size", 0x10000);
+ io->out.system_time = timeval_to_nttime(¤t_time);
+ io->out.server_start_time = timeval_to_nttime(&boot_time);
+ io->out.reserved2 = 0;
status = smb2srv_negprot_secblob(req, &io->out.secblob);
NT_STATUS_NOT_OK_RETURN(status);
- io->out.unknown9 = 0x204d4c20;
return NT_STATUS_OK;
}
return;
}
- status = smb2srv_setup_reply(req, 0x40, True, io->out.secblob.length);
+ status = smb2srv_setup_reply(req, 0x40, true, io->out.secblob.length);
if (!NT_STATUS_IS_OK(status)) {
smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
talloc_free(req);
return;
}
- SSVAL(req->out.body, 0x02, io->out._pad);
- SIVAL(req->out.body, 0x04, io->out.unknown2);
- memcpy(req->out.body+0x08, io->out.sessid, 16);
- SIVAL(req->out.body, 0x18, io->out.unknown3);
- SSVAL(req->out.body, 0x1C, io->out.unknown4);
- SIVAL(req->out.body, 0x1E, io->out.unknown5);
- SIVAL(req->out.body, 0x22, io->out.unknown6);
- SSVAL(req->out.body, 0x26, io->out.unknown7);
- push_nttime(req->out.body, 0x28, io->out.current_time);
- push_nttime(req->out.body, 0x30, io->out.boot_time);
+ SSVAL(req->out.body, 0x02, io->out.security_mode);
+ SIVAL(req->out.body, 0x04, io->out.dialect_revision);
+ SIVAL(req->out.body, 0x06, io->out.reserved);
+ status = smbcli_push_guid(req->out.body, 0x08, &io->out.server_guid);
+ if (!NT_STATUS_IS_OK(status)) {
+ smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
+ talloc_free(req);
+ return;
+ }
+ SIVAL(req->out.body, 0x18, io->out.capabilities);
+ SIVAL(req->out.body, 0x1C, io->out.max_transact_size);
+ SIVAL(req->out.body, 0x20, io->out.max_read_size);
+ SIVAL(req->out.body, 0x24, io->out.max_write_size);
+ push_nttime(req->out.body, 0x28, io->out.system_time);
+ push_nttime(req->out.body, 0x30, io->out.server_start_time);
+ SIVAL(req->out.body, 0x3C, io->out.reserved2);
status = smb2_push_o16s16_blob(&req->out, 0x38, io->out.secblob);
if (!NT_STATUS_IS_OK(status)) {
smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
return;
}
- SIVAL(req->out.body, 0x3C, io->out.unknown9);
-
smb2srv_send_reply(req);
}
void smb2srv_negprot_recv(struct smb2srv_request *req)
{
struct smb2_negprot *io;
+ int i;
if (req->in.body_size < 0x26) {
- smb2srv_send_error(req, NT_STATUS_FOOBAR);
+ smbsrv_terminate_connection(req->smb_conn, "Bad body size in SMB2 negprot");
return;
}
return;
}
- io->in.unknown1 = SVAL(req->in.body, 0x02);
- memcpy(io->in.unknown2, req->in.body + 0x04, 0x20);
- io->in.unknown3 = SVAL(req->in.body, 0x24);
+ io->in.dialect_count = SVAL(req->in.body, 0x02);
+ io->in.security_mode = SVAL(req->in.body, 0x04);
+ io->in.reserved = SVAL(req->in.body, 0x06);
+ io->in.capabilities = IVAL(req->in.body, 0x08);
+ req->status = smbcli_pull_guid(req->in.body, 0xC, &io->in.client_guid);
+ if (!NT_STATUS_IS_OK(req->status)) {
+ smbsrv_terminate_connection(req->smb_conn, "Bad GUID in SMB2 negprot");
+ talloc_free(req);
+ return;
+ }
+ io->in.start_time = smbcli_pull_nttime(req->in.body, 0x1C);
+
+ io->in.dialects = talloc_array(req, uint16_t, io->in.dialect_count);
+ if (io->in.dialects == NULL) {
+ smbsrv_terminate_connection(req->smb_conn, nt_errstr(NT_STATUS_NO_MEMORY));
+ talloc_free(req);
+ return;
+ }
+ for (i=0;i<io->in.dialect_count;i++) {
+ io->in.dialects[i] = SVAL(req->in.body, 0x24+i*2);
+ }
req->status = smb2srv_negprot_backend(req, io);
}
/*
- * reply to a SMB negprot request with dialect "SMB 2.001"
+ * reply to a SMB negprot request with dialect "SMB 2.002"
*/
void smb2srv_reply_smb_negprot(struct smbsrv_request *smb_req)
{
struct smb2srv_request *req;
uint32_t body_fixed_size = 0x26;
- /* create a fake SMB2 negprot request */
req = talloc_zero(smb_req->smb_conn, struct smb2srv_request);
if (!req) goto nomem;
req->smb_conn = smb_req->smb_conn;
req->in.size = NBT_HDR_SIZE+SMB2_HDR_BODY+body_fixed_size;
req->in.allocated = req->in.size;
- req->in.buffer = talloc_size(req, req->in.allocated);
+ req->in.buffer = talloc_array(req, uint8_t, req->in.allocated);
if (!req->in.buffer) goto nomem;
req->in.hdr = req->in.buffer + NBT_HDR_SIZE;
req->in.body = req->in.hdr + SMB2_HDR_BODY;
req->in.body_size = body_fixed_size;
req->in.dynamic = NULL;
- SIVAL(req->in.hdr, 0, SMB2_MAGIC);
- SSVAL(req->in.hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
- SSVAL(req->in.hdr, SMB2_HDR_PAD1, 0);
- SIVAL(req->in.hdr, SMB2_HDR_STATUS, 0);
- SSVAL(req->in.hdr, SMB2_HDR_OPCODE, SMB2_OP_NEGPROT);
- SSVAL(req->in.hdr, SMB2_HDR_UNKNOWN1,0);
- SIVAL(req->in.hdr, SMB2_HDR_FLAGS, 0);
- SIVAL(req->in.hdr, SMB2_HDR_UNKNOWN2,0);
- SBVAL(req->in.hdr, SMB2_HDR_SEQNUM, 0);
- SIVAL(req->in.hdr, SMB2_HDR_PID, 0);
- SIVAL(req->in.hdr, SMB2_HDR_TID, 0);
- SBVAL(req->in.hdr, SMB2_HDR_UID, 0);
- memset(req->in.hdr+SMB2_HDR_SIG, 0, 16);
+ smb2srv_setup_bufinfo(req);
+
+ SIVAL(req->in.hdr, 0, SMB2_MAGIC);
+ SSVAL(req->in.hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
+ SSVAL(req->in.hdr, SMB2_HDR_EPOCH, 0);
+ SIVAL(req->in.hdr, SMB2_HDR_STATUS, 0);
+ SSVAL(req->in.hdr, SMB2_HDR_OPCODE, SMB2_OP_NEGPROT);
+ SSVAL(req->in.hdr, SMB2_HDR_CREDIT, 0);
+ SIVAL(req->in.hdr, SMB2_HDR_FLAGS, 0);
+ SIVAL(req->in.hdr, SMB2_HDR_NEXT_COMMAND, 0);
+ SBVAL(req->in.hdr, SMB2_HDR_MESSAGE_ID, 0);
+ SIVAL(req->in.hdr, SMB2_HDR_PID, 0);
+ SIVAL(req->in.hdr, SMB2_HDR_TID, 0);
+ SBVAL(req->in.hdr, SMB2_HDR_SESSION_ID, 0);
+ memset(req->in.hdr+SMB2_HDR_SIGNATURE, 0, 16);
/* this seems to be a bug, they use 0x24 but the length is 0x26 */
SSVAL(req->in.body, 0x00, 0x24);
SSVAL(req->in.body, 0x02, 1);
memset(req->in.body+0x04, 0, 32);
- SSVAL(req->in.body, 0x24, 0);
+ SSVAL(req->in.body, 0x24, SMB2_DIALECT_REVISION_202);
smb2srv_negprot_recv(req);
return;