preliminary smb support

This commit is contained in:
Kelvin Sherlock 2014-08-20 14:00:02 -04:00
parent 103048b2db
commit f3cf2ac338
5 changed files with 376 additions and 1 deletions

4
main.c
View File

@ -277,6 +277,10 @@ int main(int argc, char **argv)
{
do_http(url, &components);
}
else if (components.schemeType == SCHEME_SMB)
{
do_smb(url, &components);
}
else
{
fprintf(stderr, "Unsupported scheme.\n");

View File

@ -1,7 +1,7 @@
CFLAGS += $(DEFINES) -v -w
OBJS = main.o gopher.o url.o connection.o readline2.o scheme.o ftype.o \
mime.o setftype.o s16debug.o common.o http.o http.utils.o \
dictionary.o options.o time.o
dictionary.o options.o time.o smb.o
gopher: $(OBJS)
$(CC) $(LDFLAGS) $(OBJS) $(LDLIBS) -o $@
@ -28,6 +28,7 @@ options.o: options.c options.h
gopher.o: gopher.c url.h connection.h options.h
http.o: http.c url.h connection.h options.h
http.utils.o: http.utils.c
smb.o: smb.c smb.h url.h connection.h options.h
data.o: data.c data.h
dictionary.o: dictionary.c dictionary.h

View File

@ -55,6 +55,7 @@ int CloseLoop(Connection *connection);
#ifdef __url_h__
int do_gopher(const char *url, URLComponents *components);
int do_http(const char *url, URLComponents *components);
int do_smb(const char *url, URLComponents *components);
#endif
#ifdef __TYPES__

201
smb.c Normal file
View File

@ -0,0 +1,201 @@
#pragma optimize 79
#pragma noroot
#include <GSOS.h>
#include <Memory.h>
#include <MiscTool.h>
#include <tcpip.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <stdint.h>
#include <unistd.h>
#include "url.h"
#include "connection.h"
#include "readline2.h"
#include "options.h"
#include "s16debug.h"
#include "prototypes.h"
#include "smb.h"
static struct smb2_header_sync header;
Handle read_response(Word ipid)
{
static srBuff sr;
static rrBuff rb;
// read an smb response. Check the first 4 bytes for the message length.
uint32_t size = 0;
uint8_t nbthead[4];
LongWord qtick;
Word terr;
qtick = GetTick() + 30 * 60;
for(;;)
{
TCPIPPoll();
terr = TCPIPStatusTCP(ipid, &sr);
if (sr.srRcvQueued >= 4) break;
/*
* the only reasonable error is if the connection is closing.
* that's ok if there's still pending data (handled above)
*/
if (terr) return (Handle)0;
if (GetTick() >= qtick)
{
fprintf(stderr, "Read timed out.\n");
return (Handle)0;
}
}
terr = TCPIPReadTCP(ipid, 0, (Ref)&nbthead, 4, &rb);
if (nbthead[0] != 0) return (Handle)0;
size = nbthead[3];
size |= nbthead[2] << 8;
size |= nbthead[1] << 16;
for(;;)
{
TCPIPPoll();
terr = TCPIPStatusTCP(ipid, &sr);
if (sr.srRcvQueued >= size) break;
if (GetTick() >= qtick)
{
fprintf(stderr, "Read timed out.\n");
return (Handle)0;
}
}
terr = TCPIPReadTCP(ipid, 2, (Ref)0, size, &rb);
return rb.rrBuffHandle;
}
int negotiate(Word ipid)
{
static struct smb2_negotiate_request req;
static uint16_t dialects[] = { 0x0202 };
uint8_t nbthead[4];
uint32_t size = 0;
memset(&header, 0, sizeof(header));
memset(&req, 0, sizeof(req));
header.protocol_id = SMB2_MAGIC; // '\xfeSMB';
header.structure_size = 64;
header.command = SMB2_NEGOTIATE;
req.structure_size = 36;
req.dialect_count = 1; // ?
req.security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED;
req.capabilities = 0;
//req.dialects[0] = 0x202; // smb 2.002
// http://support.microsoft.com/kb/204279
size = sizeof(header) + sizeof(req) + sizeof(dialects);
nbthead[0] = 0;
nbthead[1] = size >> 16;
nbthead[2] = size >> 8;
nbthead[3] = size;
TCPIPWriteTCP(ipid, (dataPtr)nbthead, sizeof(nbthead), false, false);
TCPIPWriteTCP(ipid, (dataPtr)&header, sizeof(header), false, false);
TCPIPWriteTCP(ipid, (dataPtr)&req, sizeof(req), false, false);
TCPIPWriteTCP(ipid, (dataPtr)&dialects, sizeof(dialects), true, false);
// push.
// read a response...
return 0;
}
int do_smb(char *url, URLComponents *components)
{
static Connection connection;
LongWord qtick;
char *host;
Word err;
Word terr;
Word ok;
FILE *file;
if (!components->portNumber) components->portNumber = 445;
host = URLComponentGetCMalloc(url, components, URLComponentHost);
if (!host)
{
fprintf(stderr, "URL `%s': no host.", url);
return -1;
}
ok = ConnectLoop(host, components->portNumber, &connection);
if (!ok)
{
free(host);
if (file != stdout) fclose(file);
return -1;
}
ok = negotiate(connection.ipid);
if (ok) return ok;
qtick = GetTick() + 30 * 60;
for(;;)
{
static srBuff sr;
TCPIPPoll();
terr = TCPIPStatusTCP(connection.ipid, &sr);
if (sr.srRcvQueued > 0) break;
if (GetTick() >= qtick)
{
fprintf(stderr, "Read timed out.\n");
return -1;
}
}
CloseLoop(&connection);
free(host);
return 0;
}

168
smb.h Normal file
View File

@ -0,0 +1,168 @@
#ifndef __SMB_H__
#define __SMB_H__
#include <stdint.h>
#define SMB2_MAGIC 0x424d53fe
// commands
enum {
SMB2_NEGOTIATE = 0x0000,
SMB2_SESSION_SETUP = 0x0001,
SMB2_LOGOFF = 0x0002,
SMB2_TREE_CONNECT = 0x0003,
SMB2_TREE_DISCONNECT = 0x0004,
SMB2_CREATE = 0x0005,
SMB2_CLOSE = 0x0006,
SMB2_FLUSH = 0x0007,
SMB2_READ = 0x0008,
SMB2_WRITE = 0x0009,
SMB2_LOCK = 0x000A,
SMB2_IOCTL = 0x000B,
SMB2_CANCEL = 0x000C,
SMB2_ECHO = 0x000D,
SMB2_QUERY_DIRECTORY = 0x000E,
SMB2_CHANGE_NOTIFY = 0x000F,
SMB2_QUERY_INFO = 0x0010,
SMB2_SET_INFO = 0x0011,
SMB2_OPLOCK_BREAK = 0x0012
};
// flags
enum {
SMB2_FLAGS_SERVER_TO_REDIR = 0x00000001,
SMB2_FLAGS_ASYNC_COMMAND = 0x00000002,
SMB2_FLAGS_RELATED_OPERATIONS = 0x00000004,
SMB2_FLAGS_SIGNED = 0x00000008
// integer overflow
/*
SMB2_FLAGS_DFS_OPERATIONS = 0x10000000,
SMB2_FLAGS_REPLAY_OPERATION = 0x20000000
*/
};
#define SMB2_FLAGS_DFS_OPERATIONS 0x10000000
#define SMB2_FLAGS_REPLAY_OPERATION 0x20000000
// symlink error response flags.
enum {
SYMLINK_FLAG_RELATIVE = 0x00000001
};
// negotiate flags
enum {
SMB2_NEGOTIATE_SIGNING_ENABLED = 0x0001,
SMB2_NEGOTIATE_SIGNING_REQUIRED = 0x0002,
SMB2_GLOBAL_CAP_DFS = 0x00000001,
SMB2_GLOBAL_CAP_LEASING = 0x00000002,
SMB2_GLOBAL_CAP_LARGE_MTU = 0x00000004,
SMB2_GLOBAL_CAP_MULTI_CHANNEL = 0x00000008,
SMB2_GLOBAL_CAP_PERSISTENT_HANDLES = 0x00000010,
SMB2_GLOBAL_CAP_DIRECTORY_LEASING = 0x00000020,
SMB2_GLOBAL_CAP_ENCRYPTION = 0x00000040
};
// session setup flags
enum {
SMB2_SESSION_FLAG_BINDING = 0x01
};
// session setup response flags
enum {
SMB2_SESSION_FLAG_IS_GUEST = 0x0001,
SMB2_SESSION_FLAG_IS_NULL = 0x0002,
SMB2_SESSION_FLAG_ENCRYPT_DATA = 0x0004
};
typedef struct smb2_header_sync {
uint32_t protocol_id;
uint16_t structure_size;
uint16_t credit_charge;
uint32_t status;
uint16_t command;
uint16_t credit; // _request / _response
uint32_t flags;
uint32_t next_command;
uint32_t message_id[2]; // uint64_t
uint32_t reserved;
uint32_t tree_id;
uint32_t session_id[2]; // uint64_t
uint8_t signature[16];
} smb2_header_sync;
typedef struct smb2_error_response {
uint16_t structure_size;
uint16_t reserved;
uint32_t bytecount;
//uint8_t error_data[1]; // variable.
} smb2_error_response;
typedef struct smb2_negotiate_request {
uint16_t structure_size;
uint16_t dialect_count;
uint16_t security_mode;
uint16_t reserved;
uint32_t capabilities;
uint8_t client_guid[16];
uint32_t client_start_time[2];
//uint16_t dialects[1]; // variable sized.
} smb2_negotiate_request;
typedef struct smb2_negotiate_response {
uint16_t structure_size;
uint16_t security_mode;
uint16_t dialect_revision;
uint16_t reserved;
uint8_t server_guid[16];
uint32_t capabilities;
uint32_t max_transact_size;
uint32_t max_read_size;
uint32_t max_write_size;
uint32_t server_start_time[2];
uint16_t security_buffer_offset;
uint16_t security_buffer_length;
uint32_t reserved2;
//uint8_t buffer[1]; // variable
} smb2_negotiate_response;
typedef struct smb2_session_setup_request {
uint16_t structure_size;
uint8_t flags;
uint8_t security_mode;
uint32_t capabilities;
uint32_t channel;
uint16_t security_buffer_offset;
uint16_t security_buffer_length;
uint32_t previous_session_id[2];
//uint8t_t buffer[1]; // variable
} smb2_sessions_setup_request;
typedef struct smb2_session_setup_response {
uint16_t structure_size;
uint16_t session_flags;
uint16_t security_buffer_offset;
uint16_t security_buffer_length;
//uint8t_t buffer[1]; // variable
} smb2_session_setup_response;
typedef struct smb2_logoff_request {
uint16_t structure_size;
uint16_t reserved;
} smb2_logoff_request;
typedef struct smb2_logoff_response {
uint16_t structure_size;
uint16_t reserved;
} smb2_logoff_response;
#endif