From bd11daed0aacc906c79b307dd7754341e4ebaeb2 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 12 Sep 2011 05:12:50 +0200 Subject: [PATCH 01/14] s3:smbd: remember the client unix capabilities on the connection metze --- source3/smbd/globals.h | 7 ++++ source3/smbd/trans2.c | 80 ++++++++++++++++++++++------------------------- 2 files changed, 44 insertions(+), 43 deletions(-) diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h index 92532c2..4d95453 100644 --- a/source3/smbd/globals.h +++ b/source3/smbd/globals.h @@ -532,6 +532,13 @@ struct smbd_server_connection { } negprot; struct { + uint16_t client_major; + uint16_t client_minor; + uint32_t client_cap_low; + uint32_t client_cap_high; + } unix_info; + + struct { bool done_sesssetup; /* * Size of data we can send to client. Set diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 881dced..8d34828 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -3539,6 +3539,7 @@ static void call_trans2setfsinfo(connection_struct *conn, char **ppdata, int total_data, unsigned int max_data_bytes) { + struct smbd_server_connection *sconn = req->sconn; char *pdata = *ppdata; char *params = *pparams; uint16 info_level; @@ -3579,54 +3580,47 @@ static void call_trans2setfsinfo(connection_struct *conn, switch(info_level) { case SMB_SET_CIFS_UNIX_INFO: - { - uint16 client_unix_major; - uint16 client_unix_minor; - uint32 client_unix_cap_low; - uint32 client_unix_cap_high; - - if (!lp_unix_extensions()) { - reply_nterror(req, - NT_STATUS_INVALID_LEVEL); - return; - } + if (!lp_unix_extensions()) { + reply_nterror(req, + NT_STATUS_INVALID_LEVEL); + return; + } - /* There should be 12 bytes of capabilities set. */ - if (total_data < 8) { - reply_nterror( - req, - NT_STATUS_INVALID_PARAMETER); - return; - } - client_unix_major = SVAL(pdata,0); - client_unix_minor = SVAL(pdata,2); - client_unix_cap_low = IVAL(pdata,4); - client_unix_cap_high = IVAL(pdata,8); - /* Just print these values for now. */ - DEBUG(10,("call_trans2setfsinfo: set unix info. major = %u, minor = %u \ -cap_low = 0x%x, cap_high = 0x%x\n", - (unsigned int)client_unix_major, - (unsigned int)client_unix_minor, - (unsigned int)client_unix_cap_low, - (unsigned int)client_unix_cap_high )); - - /* Here is where we must switch to posix pathname processing... */ - if (client_unix_cap_low & CIFS_UNIX_POSIX_PATHNAMES_CAP) { - lp_set_posix_pathnames(); - mangle_change_to_posix(); - } + /* There should be 12 bytes of capabilities set. */ + if (total_data < 8) { + reply_nterror( + req, + NT_STATUS_INVALID_PARAMETER); + return; + } + sconn->smb1.unix_info.client_major = SVAL(pdata,0); + sconn->smb1.unix_info.client_minor = SVAL(pdata,2); + sconn->smb1.unix_info.client_cap_low = IVAL(pdata,4); + sconn->smb1.unix_info.client_cap_high = IVAL(pdata,8); + /* Just print these values for now. */ + DEBUG(10,("call_trans2setfsinfo: set unix_info info. major = %u, minor = %u \ +cap_low = 0x%x, cap_highn", + (unsigned int)sconn->smb1.unix_info.client_major, + (unsigned int)sconn->smb1.unix_info.client_minor, + (unsigned int)sconn->smb1.unix_info.client_cap_low, + (unsigned int)sconn->smb1.unix_info.client_cap_high)); + + /* Here is where we must switch to posix pathname processing... */ + if (sconn->smb1.unix_info.client_cap_low & CIFS_UNIX_POSIX_PATHNAMES_CAP) { + lp_set_posix_pathnames(); + mangle_change_to_posix(); + } - if ((client_unix_cap_low & CIFS_UNIX_FCNTL_LOCKS_CAP) && - !(client_unix_cap_low & CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP)) { - /* Client that knows how to do posix locks, - * but not posix open/mkdir operations. Set a - * default type for read/write checks. */ + if ((sconn->smb1.unix_info.client_cap_low & CIFS_UNIX_FCNTL_LOCKS_CAP) && + !(sconn->smb1.unix_info.client_cap_low & CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP)) { + /* Client that knows how to do posix locks, + * but not posix open/mkdir operations. Set a + * default type for read/write checks. */ - lp_set_posix_default_cifsx_readwrite_locktype(POSIX_LOCK); + lp_set_posix_default_cifsx_readwrite_locktype(POSIX_LOCK); - } - break; } + break; case SMB_REQUEST_TRANSPORT_ENCRYPTION: { -- 1.7.4.1 From 8170ac41172a173903368636ee778b21fa243140 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sat, 10 Sep 2011 11:02:02 +0200 Subject: [PATCH 02/14] s3:smbd: SMB ReadX with size > 0xffff should only possible for samba clients. Windows 2008 R2 (and others) ignore the high bits for the read size. Unless we're using the unix extentions and the client uses CIFS_UNIX_LARGE_READ_CAP, we should also ignore the high bits. But we still need to support old "smbclient" binaries and have to check if the client is "Samba". metze --- source3/smbd/reply.c | 11 ++++++++++- 1 files changed, 10 insertions(+), 1 deletions(-) diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index 6f2f281..0adc4e8 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -3738,6 +3738,7 @@ nosendfile_read: void reply_read_and_X(struct smb_request *req) { + struct smbd_server_connection *sconn = req->sconn; connection_struct *conn = req->conn; files_struct *fsp; SMB_OFF_T startpos; @@ -3776,7 +3777,15 @@ void reply_read_and_X(struct smb_request *req) return; } - if (global_client_caps & CAP_LARGE_READX) { + if ((sconn->smb1.unix_info.client_cap_low & CIFS_UNIX_LARGE_READ_CAP) || + (get_remote_arch() == RA_SAMBA)) { + /* + * This is Samba only behavior (up to Samba 3.6)! + * + * Windows 2008 R2 ignores the upper_size, + * so we do unless unix extentions are active + * or "smbclient" is talking to us. + */ size_t upper_size = SVAL(req->vwv+7, 0); smb_maxcnt |= (upper_size<<16); if (upper_size > 1) { -- 1.7.4.1 From 36db2b5b879f5a2e219607ccebb3b02f2e2f95a6 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 12 Sep 2011 04:45:22 +0200 Subject: [PATCH 03/14] s3:libsmb: let cli_read/write_max_bufsize() return the max number of possible bytes They should return what's possible on the wire. --- source3/include/client.h | 9 ---- source3/libsmb/clireadwrite.c | 91 +++++++++++++++++++++++++--------------- 2 files changed, 57 insertions(+), 43 deletions(-) diff --git a/source3/include/client.h b/source3/include/client.h index 9eae222..5ad07f8 100644 --- a/source3/include/client.h +++ b/source3/include/client.h @@ -22,16 +22,7 @@ #ifndef _CLIENT_H #define _CLIENT_H -/* the client asks for a smaller buffer to save ram and also to get more - overlap on the wire. This size gives us a nice read/write size, which - will be a multiple of the page size on almost any system */ #define CLI_BUFFER_SIZE (0xFFFF) -#define CLI_SAMBA_MAX_LARGE_READX_SIZE (127*1024) /* Works for Samba servers */ -#define CLI_SAMBA_MAX_LARGE_WRITEX_SIZE (127*1024) /* Works for Samba servers */ -#define CLI_WINDOWS_MAX_LARGE_READX_SIZE ((64*1024)-2) /* Windows servers are broken.... */ -#define CLI_WINDOWS_MAX_LARGE_WRITEX_SIZE ((64*1024)-2) /* Windows servers are broken.... */ -#define CLI_SAMBA_MAX_POSIX_LARGE_READX_SIZE (0xFFFF00) /* 24-bit len. */ -#define CLI_SAMBA_MAX_POSIX_LARGE_WRITEX_SIZE (0xFFFF00) /* 24-bit len. */ /* * These definitions depend on smb.h diff --git a/source3/libsmb/clireadwrite.c b/source3/libsmb/clireadwrite.c index 2fe41b4..9b38c93 100644 --- a/source3/libsmb/clireadwrite.c +++ b/source3/libsmb/clireadwrite.c @@ -28,25 +28,44 @@ ****************************************************************************/ static size_t cli_read_max_bufsize(struct cli_state *cli) { - size_t data_offset = smb_size - 4; size_t wct = 12; + bool broken_server = false; + size_t data_offset; + size_t useable_space = cli->max_xmit; - size_t useable_space; + data_offset = HDR_VWV; + data_offset += wct * sizeof(uint16_t); + data_offset += sizeof(uint16_t); /* byte count */ + data_offset += 1; /* pad */ - if (!client_is_signing_on(cli) && !cli_encryption_on(cli) - && (cli->server_posix_capabilities & CIFS_UNIX_LARGE_READ_CAP)) { - return CLI_SAMBA_MAX_POSIX_LARGE_READX_SIZE; - } - if (cli_state_capabilities(cli) & CAP_LARGE_READX) { - return cli->is_samba - ? CLI_SAMBA_MAX_LARGE_READX_SIZE - : CLI_WINDOWS_MAX_LARGE_READX_SIZE; + if (cli->server_posix_capabilities & CIFS_UNIX_LARGE_READ_CAP) { + useable_space = 0xFFFFFF; + + if (client_is_signing_on(cli)) { + useable_space = cli->max_xmit; + } + + if (cli_encryption_on(cli)) { + useable_space = cli->max_xmit; + } + } else if (cli_state_capabilities(cli) & CAP_LARGE_READX) { + broken_server = true; + useable_space = 0x1FFFF; + /* + * Note: CAP_LARGE_READX also works with signing + */ } - data_offset += wct * sizeof(uint16_t); - data_offset += 1; /* pad */ + useable_space -= data_offset; - useable_space = cli->max_xmit - data_offset; + if (broken_server) { + /* + * CAP_LARGE_READX is a bit broken, + * as the high bits of the size are ignored + * so the max size if 0xffff. + */ + useable_space = MIN(useable_space, UINT16_MAX); + } return useable_space; } @@ -58,35 +77,39 @@ static size_t cli_write_max_bufsize(struct cli_state *cli, uint16_t write_mode, uint8_t wct) { - if (write_mode == 0 && - !client_is_signing_on(cli) && - !cli_encryption_on(cli) && - (cli->server_posix_capabilities & CIFS_UNIX_LARGE_WRITE_CAP) && - (cli_state_capabilities(cli) & CAP_LARGE_FILES)) { - /* Only do massive writes if we can do them direct - * with no signing or encrypting - not on a pipe. */ - return CLI_SAMBA_MAX_POSIX_LARGE_WRITEX_SIZE; - } + size_t data_offset; + size_t useable_space = cli->max_xmit; + + data_offset = HDR_VWV; + data_offset += wct * sizeof(uint16_t); + data_offset += sizeof(uint16_t); /* byte count */ + data_offset += 1; /* pad */ - if (cli->is_samba) { - return CLI_SAMBA_MAX_LARGE_WRITEX_SIZE; + if (cli->server_posix_capabilities & CIFS_UNIX_LARGE_WRITE_CAP) { + useable_space = 0xFFFFFF; + } else if (cli_state_capabilities(cli) & CAP_LARGE_FILES) { + useable_space = 0x1FFFF; } - if (((cli_state_capabilities(cli) & CAP_LARGE_WRITEX) == 0) - || client_is_signing_on(cli) - || strequal(cli->dev, "LPT1:")) { - size_t data_offset = smb_size - 4; - size_t useable_space; + if (write_mode != 0) { + useable_space = cli->max_xmit; + } - data_offset += wct * sizeof(uint16_t); - data_offset += 1; /* pad */ + if (client_is_signing_on(cli)) { + useable_space = cli->max_xmit; + } - useable_space = cli->max_xmit - data_offset; + if (cli_encryption_on(cli)) { + useable_space = cli->max_xmit; + } - return useable_space; + if (strequal(cli->dev, "LPT1:")) { + useable_space = cli->max_xmit; } - return CLI_WINDOWS_MAX_LARGE_WRITEX_SIZE; + useable_space -= data_offset; + + return useable_space; } struct cli_read_andx_state { -- 1.7.4.1 From 03ce4ffd9320c40dc83b22c853f3f6d9aa15861b Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 12 Sep 2011 04:48:25 +0200 Subject: [PATCH 04/14] s3:libsmb: align chunk_size for cli_pull/push() to a page size of 1024 bytes metze --- source3/libsmb/clireadwrite.c | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-) diff --git a/source3/libsmb/clireadwrite.c b/source3/libsmb/clireadwrite.c index 9b38c93..bedb41c 100644 --- a/source3/libsmb/clireadwrite.c +++ b/source3/libsmb/clireadwrite.c @@ -476,6 +476,7 @@ struct tevent_req *cli_pull_send(TALLOC_CTX *mem_ctx, struct tevent_req *req; struct cli_pull_state *state; int i; + size_t page_size = 1024; req = tevent_req_create(mem_ctx, &state, struct cli_pull_state); if (req == NULL) { @@ -501,6 +502,9 @@ struct tevent_req *cli_pull_send(TALLOC_CTX *mem_ctx, } state->chunk_size = cli_read_max_bufsize(cli); + if (state->chunk_size > page_size) { + state->chunk_size &= ~(page_size - 1); + } state->num_reqs = MAX(window_size/state->chunk_size, 1); state->num_reqs = MIN(state->num_reqs, cli->max_mux); @@ -1167,6 +1171,7 @@ struct tevent_req *cli_push_send(TALLOC_CTX *mem_ctx, struct event_context *ev, struct tevent_req *req; struct cli_push_state *state; uint32_t i; + size_t page_size = 1024; req = tevent_req_create(mem_ctx, &state, struct cli_push_state); if (req == NULL) { @@ -1184,6 +1189,9 @@ struct tevent_req *cli_push_send(TALLOC_CTX *mem_ctx, struct event_context *ev, state->next_offset = start_offset; state->chunk_size = cli_write_max_bufsize(cli, mode, 14); + if (state->chunk_size > page_size) { + state->chunk_size &= ~(page_size - 1); + } if (window_size == 0) { window_size = cli->max_mux * state->chunk_size; -- 1.7.4.1 From 877749dbed6c40af58e735170dc4e8127e3f2af6 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 12 Sep 2011 05:19:35 +0200 Subject: [PATCH 05/14] s3:libsmb: remove unused cli->is_samba metze --- source3/include/client.h | 1 - source3/libsmb/cliconnect.c | 23 +---------------------- source3/torture/torture.c | 8 -------- 3 files changed, 1 insertions(+), 31 deletions(-) diff --git a/source3/include/client.h b/source3/include/client.h index 5ad07f8..b21d32a 100644 --- a/source3/include/client.h +++ b/source3/include/client.h @@ -75,7 +75,6 @@ struct cli_state { size_t max_mux; int initialised; int win95; - bool is_samba; bool is_guestlogin; uint32 capabilities; /* What the server offered. */ diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index fbbeb02..4597a8a 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -316,9 +316,6 @@ static void cli_session_setup_lanman2_done(struct tevent_req *subreq) } p += ret; - if (strstr(cli->server_type, "Samba")) { - cli->is_samba = True; - } status = cli_set_username(cli, state->user); if (tevent_req_nterror(req, status)) { return; @@ -544,10 +541,6 @@ static void cli_session_setup_guest_done(struct tevent_req *subreq) } p += ret; - if (strstr(cli->server_type, "Samba")) { - cli->is_samba = True; - } - status = cli_set_username(cli, ""); if (!NT_STATUS_IS_OK(status)) { tevent_req_nterror(req, status); @@ -755,9 +748,7 @@ static void cli_session_setup_plain_done(struct tevent_req *subreq) if (tevent_req_nterror(req, status)) { return; } - if (strstr(cli->server_type, "Samba")) { - cli->is_samba = True; - } + tevent_req_done(req); } @@ -1104,10 +1095,6 @@ static void cli_session_setup_nt1_done(struct tevent_req *subreq) } p += ret; - if (strstr(cli->server_type, "Samba")) { - cli->is_samba = True; - } - status = cli_set_username(cli, state->user); if (tevent_req_nterror(req, status)) { return; @@ -1355,10 +1342,6 @@ static void cli_sesssetup_blob_done(struct tevent_req *subreq) } p += ret; - if (strstr(cli->server_type, "Samba")) { - cli->is_samba = True; - } - if (state->blob.length != 0) { /* * More to send @@ -2069,10 +2052,6 @@ NTSTATUS cli_session_setup(struct cli_state *cli, } } - if (strstr(cli->server_type, "Samba")) { - cli->is_samba = True; - } - return NT_STATUS_OK; } diff --git a/source3/torture/torture.c b/source3/torture/torture.c index 0cba5c7..e80cf23 100644 --- a/source3/torture/torture.c +++ b/source3/torture/torture.c @@ -981,14 +981,6 @@ static bool run_readwritelarge_internal(int max_xmit_k) cli1->max_xmit = max_xmit_k*1024; - if (signing_state == Required) { - /* Horrible cheat to force - multiple signed outstanding - packets against a Samba server. - */ - cli1->is_samba = false; - } - printf("starting readwritelarge_internal\n"); cli_unlink(cli1, lockfname, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN); -- 1.7.4.1 From 71aac668bd6a40f73d2aea32ac495c33897550e2 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 8 Sep 2011 15:41:29 +0200 Subject: [PATCH 06/14] s3:libsmb: make sure we always set cli->capabilities at the end of cli_negprot_done() If the server doesn't support PROTOCOL_NT1 we should reset the negotiated capabilities to 0. metze --- source3/libsmb/cliconnect.c | 9 ++++++--- 1 files changed, 6 insertions(+), 3 deletions(-) diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index 4597a8a..0200ada 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -2584,6 +2584,7 @@ static void cli_negprot_done(struct tevent_req *subreq) NTSTATUS status; uint16_t protnum; uint8_t *inbuf; + uint32_t server_capabilities = 0; status = cli_smb_recv(subreq, state, &inbuf, 1, &wct, &vwv, &num_bytes, &bytes); @@ -2634,13 +2635,13 @@ static void cli_negprot_done(struct tevent_req *subreq) ts = interpret_long_date(((char *)(vwv+11))+1); cli->servertime = ts.tv_sec; cli->secblob = data_blob(bytes, num_bytes); - cli->capabilities = IVAL(vwv + 9, 1); - if (cli_state_capabilities(cli) & CAP_RAW_MODE) { + server_capabilities = IVAL(vwv + 9, 1); + if (server_capabilities & CAP_RAW_MODE) { cli->readbraw_supported = True; cli->writebraw_supported = True; } /* work out if they sent us a workgroup */ - if (!(cli_state_capabilities(cli) & CAP_EXTENDED_SECURITY) && + if (!(server_capabilities & CAP_EXTENDED_SECURITY) && smb_buflen(inbuf) > 8) { ssize_t ret; status = smb_bytes_talloc_string( @@ -2708,6 +2709,8 @@ static void cli_negprot_done(struct tevent_req *subreq) cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE); + cli->capabilities = server_capabilities; + /* a way to force ascii SMB */ if (cli->force_ascii) { cli->capabilities &= ~CAP_UNICODE; -- 1.7.4.1 From 708e65e7c6ce59a8d5657065722b706115d71aef Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 8 Sep 2011 15:50:25 +0200 Subject: [PATCH 07/14] s3:libsmb: no need to reset capabilities in cli_session_setup_lanman2() This is only used cli->protocol < PROTOCOL_NT1, in which case cli_negprot_done() has already reset cli->capabilities. metze --- source3/libsmb/cliconnect.c | 10 ---------- 1 files changed, 0 insertions(+), 10 deletions(-) diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index 0200ada..e69017f 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -133,16 +133,6 @@ static struct tevent_req *cli_session_setup_lanman2_send( vwv = state->vwv; /* - * LANMAN servers predate NT status codes and Unicode and - * ignore those smb flags so we must disable the corresponding - * default capabilities that would otherwise cause the Unicode - * and NT Status flags to be set (and even returned by the - * server) - */ - - cli->capabilities &= ~(CAP_UNICODE | CAP_STATUS32); - - /* * if in share level security then don't send a password now */ if (!(cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL)) { -- 1.7.4.1 From 376c900cb40b23d36fc0ff5ae107d6a54584f4ea Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 8 Sep 2011 16:09:35 +0200 Subject: [PATCH 08/14] s3:libsmb: calculate all SMB1 capabilities we want to support for the connection We should do this at startup in cli_state_create() and later calculate the negotiated capabilities in cli_negprot_done(). metze --- source3/libsmb/clientgen.c | 26 ++++++++++++++++++++++++-- 1 files changed, 24 insertions(+), 2 deletions(-) diff --git a/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c index bae80ef..80b3466 100644 --- a/source3/libsmb/clientgen.c +++ b/source3/libsmb/clientgen.c @@ -197,8 +197,6 @@ struct cli_state *cli_state_create(TALLOC_CTX *mem_ctx, cli->use_spnego = lp_client_use_spnego(); - cli->capabilities = CAP_UNICODE | CAP_STATUS32 | CAP_DFS; - /* Set the CLI_FORCE_DOSERR environment variable to test client routines using DOS errors instead of STATUS32 ones. This intended only as a temporary hack. */ @@ -279,6 +277,30 @@ struct cli_state *cli_state_create(TALLOC_CTX *mem_ctx, goto error; } + cli->capabilities = 0; + cli->capabilities |= CAP_LARGE_FILES; + cli->capabilities |= CAP_NT_SMBS | CAP_RPC_REMOTE_APIS; + cli->capabilities |= CAP_LOCK_AND_READ | CAP_NT_FIND; + cli->capabilities |= CAP_DFS | CAP_W2K_SMBS; + cli->capabilities |= CAP_LARGE_READX|CAP_LARGE_WRITEX; + cli->capabilities |= CAP_LWIO; + + if (!cli->force_dos_errors) { + cli->capabilities |= CAP_STATUS32; + } + + if (!cli->force_ascii) { + cli->capabilities |= CAP_UNICODE; + } + + if (cli->use_spnego) { + cli->capabilities |= CAP_EXTENDED_SECURITY; + } + + if (cli->use_level_II_oplocks) { + cli->capabilities |= CAP_LEVEL_II_OPLOCKS; + } + cli->conn.outgoing = tevent_queue_create(cli, "cli_outgoing"); if (cli->conn.outgoing == NULL) { goto error; -- 1.7.4.1 From 12989fa2bd4d43cdf2e0722e40936a7481077be0 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 8 Sep 2011 16:06:05 +0200 Subject: [PATCH 09/14] s3:include: add some masks for SMB1 CAP_* flags The flags are devided into 3 sections: - client only flags - flags used in both directions - server only flags metze --- source3/include/smb.h | 25 +++++++++++++++++++++++++ 1 files changed, 25 insertions(+), 0 deletions(-) diff --git a/source3/include/smb.h b/source3/include/smb.h index c88b3fd..75008fe 100644 --- a/source3/include/smb.h +++ b/source3/include/smb.h @@ -1239,6 +1239,31 @@ http://msdn.microsoft.com/en-us/library/cc246334(PROT.13).aspx #define CAP_DYNAMIC_REAUTH 0x20000000 #define CAP_EXTENDED_SECURITY 0x80000000 +#define SMB_CAP_BOTH_MASK ( \ + CAP_UNICODE | \ + CAP_NT_SMBS | \ + CAP_STATUS32 | \ + CAP_LEVEL_II_OPLOCKS | \ + CAP_EXTENDED_SECURITY | \ + 0) +#define SMB_CAP_SERVER_MASK ( \ + CAP_RAW_MODE | \ + CAP_MPX_MODE | \ + CAP_LARGE_FILES | \ + CAP_RPC_REMOTE_APIS | \ + CAP_LOCK_AND_READ | \ + CAP_NT_FIND | \ + CAP_DFS | \ + CAP_W2K_SMBS | \ + CAP_LARGE_READX | \ + CAP_LARGE_WRITEX | \ + CAP_LWIO | \ + CAP_UNIX | \ + 0) +#define SMB_CAP_CLIENT_MASK ( \ + CAP_DYNAMIC_REAUTH | \ + 0) + /* printing types */ enum printing_types {PRINT_BSD,PRINT_SYSV,PRINT_AIX,PRINT_HPUX, PRINT_QNX,PRINT_PLP,PRINT_LPRNG,PRINT_SOFTQ, -- 1.7.4.1 From 1f6b2985b5c28b9ab83ccfb40ad4115718d1dd20 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 8 Sep 2011 16:14:51 +0200 Subject: [PATCH 10/14] s3:libsmb: calculate the negotiated SMB1 capabilities in cli_negprot_done() We calculate the negotiated capabilities based on the mask for: - client only flags - flags used in both directions - server only flags metze --- source3/libsmb/cliconnect.c | 18 ++++++++++++------ 1 files changed, 12 insertions(+), 6 deletions(-) diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index e69017f..f410913 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -2574,6 +2574,7 @@ static void cli_negprot_done(struct tevent_req *subreq) NTSTATUS status; uint16_t protnum; uint8_t *inbuf; + uint32_t both_capabilities; uint32_t server_capabilities = 0; status = cli_smb_recv(subreq, state, &inbuf, 1, &wct, &vwv, @@ -2699,12 +2700,17 @@ static void cli_negprot_done(struct tevent_req *subreq) cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE); - cli->capabilities = server_capabilities; - - /* a way to force ascii SMB */ - if (cli->force_ascii) { - cli->capabilities &= ~CAP_UNICODE; - } + /* + * Now calculate the negotiated capabilities + * based on the mask for: + * - client only flags + * - flags used in both directions + * - server only flags + */ + both_capabilities = cli->capabilities & server_capabilities; + cli->capabilities = cli->capabilities & SMB_CAP_CLIENT_MASK; + cli->capabilities |= both_capabilities & SMB_CAP_BOTH_MASK; + cli->capabilities |= server_capabilities & SMB_CAP_SERVER_MASK; tevent_req_done(req); } -- 1.7.4.1 From a2a2d2e937d3d0c9e6a620a36e8ce5c14f35a310 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 8 Sep 2011 16:39:14 +0200 Subject: [PATCH 11/14] s3:libsmb: make use of SMB_CAP_BOTH/CLIENT_MASK in cli_session_setup_capabilities() This matches a w2k3 client. metze --- source3/libsmb/cliconnect.c | 38 +++++++++++++++++++++++++------------- 1 files changed, 25 insertions(+), 13 deletions(-) diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index f410913..1088a6e 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -356,18 +356,31 @@ static NTSTATUS cli_session_setup_lanman2(struct cli_state *cli, const char *use Work out suitable capabilities to offer the server. ****************************************************************************/ -static uint32 cli_session_setup_capabilities(struct cli_state *cli) +static uint32_t cli_session_setup_capabilities(struct cli_state *cli, + uint32_t sesssetup_capabilities) { - uint32 capabilities = CAP_NT_SMBS; + uint32_t client_capabilities = cli_state_capabilities(cli); - if (!cli->force_dos_errors) - capabilities |= CAP_STATUS32; + /* + * We only send capabilities based on the mask for: + * - client only flags + * - flags used in both directions + * + * We do not echo the server only flags. + */ + client_capabilities &= (SMB_CAP_BOTH_MASK | SMB_CAP_CLIENT_MASK); - if (cli->use_level_II_oplocks) - capabilities |= CAP_LEVEL_II_OPLOCKS; + /* + * Session Setup specific flags CAP_DYNAMIC_REAUTH + * and CAP_EXTENDED_SECURITY are passed by the caller. + * We need that in order to do guest logins even if + * CAP_EXTENDED_SECURITY is negotiated. + */ + client_capabilities &= ~(CAP_DYNAMIC_REAUTH|CAP_EXTENDED_SECURITY); + sesssetup_capabilities &= (CAP_DYNAMIC_REAUTH|CAP_EXTENDED_SECURITY); + client_capabilities |= sesssetup_capabilities; - capabilities |= (cli_state_capabilities(cli) & (CAP_UNICODE|CAP_LARGE_FILES|CAP_LARGE_READX|CAP_LARGE_WRITEX|CAP_DFS)); - return capabilities; + return client_capabilities; } /**************************************************************************** @@ -411,7 +424,7 @@ struct tevent_req *cli_session_setup_guest_create(TALLOC_CTX *mem_ctx, SSVAL(vwv+8, 0, 0); SSVAL(vwv+9, 0, 0); SSVAL(vwv+10, 0, 0); - SIVAL(vwv+11, 0, cli_session_setup_capabilities(cli)); + SIVAL(vwv+11, 0, cli_session_setup_capabilities(cli, 0)); bytes = talloc_array(state, uint8_t, 0); @@ -626,7 +639,7 @@ static struct tevent_req *cli_session_setup_plain_send( SSVAL(vwv+8, 0, 0); SSVAL(vwv+9, 0, 0); SSVAL(vwv+10, 0, 0); - SIVAL(vwv+11, 0, cli_session_setup_capabilities(cli)); + SIVAL(vwv+11, 0, cli_session_setup_capabilities(cli, 0)); bytes = talloc_array(state, uint8_t, 0); bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), pass, strlen(pass)+1, @@ -971,7 +984,7 @@ static struct tevent_req *cli_session_setup_nt1_send( SSVAL(vwv+8, 0, nt_response.length); SSVAL(vwv+9, 0, 0); SSVAL(vwv+10, 0, 0); - SIVAL(vwv+11, 0, cli_session_setup_capabilities(cli)); + SIVAL(vwv+11, 0, cli_session_setup_capabilities(cli, 0)); bytes = talloc_array(state, uint8_t, lm_response.length + nt_response.length); @@ -1223,8 +1236,7 @@ static bool cli_sesssetup_blob_next(struct cli_sesssetup_blob_state *state, SSVAL(state->vwv+8, 0, 0); SSVAL(state->vwv+9, 0, 0); SIVAL(state->vwv+10, 0, - cli_session_setup_capabilities(state->cli) - | CAP_EXTENDED_SECURITY); + cli_session_setup_capabilities(state->cli, CAP_EXTENDED_SECURITY)); state->buf = (uint8_t *)talloc_memdup(state, state->blob.data, thistime); -- 1.7.4.1 From 29480c8132866f4321e2e7a58f3658983cbd880f Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 8 Sep 2011 17:24:02 +0200 Subject: [PATCH 12/14] s3:torture/run_oplock4: don't set cli->use_level_II_oplocks Doing this after the session setup is pointless, as that's the only place where we tell the server we support level II oplocks. metze --- source3/torture/torture.c | 3 --- 1 files changed, 0 insertions(+), 3 deletions(-) diff --git a/source3/torture/torture.c b/source3/torture/torture.c index e80cf23..b0235df 100644 --- a/source3/torture/torture.c +++ b/source3/torture/torture.c @@ -3757,10 +3757,7 @@ static bool run_oplock4(int dummy) } cli1->use_oplocks = true; - cli1->use_level_II_oplocks = true; - cli2->use_oplocks = true; - cli2->use_level_II_oplocks = true; status = cli_open(cli1, fname, O_RDWR, DENY_NONE, &fnum1); if (!NT_STATUS_IS_OK(status)) { -- 1.7.4.1 From 3e34bf9046744772a00c08fbfd20a12e5e5e5124 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 8 Sep 2011 17:28:29 +0200 Subject: [PATCH 13/14] s3:libsmb: use CAP_EXTENDED_SECURITY instead of cli->use_spnego cli->capabilities contains the negotiated capabilities. metze --- source3/libsmb/clientgen.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c index 80b3466..be103ad 100644 --- a/source3/libsmb/clientgen.c +++ b/source3/libsmb/clientgen.c @@ -90,7 +90,7 @@ void cli_setup_packet_buf(struct cli_state *cli, char *buf) flags2 |= FLAGS2_DFS_PATHNAMES; if (cli_state_capabilities(cli) & CAP_STATUS32) flags2 |= FLAGS2_32_BIT_ERROR_CODES; - if (cli->use_spnego) + if (cli_state_capabilities(cli) & CAP_EXTENDED_SECURITY) flags2 |= FLAGS2_EXTENDED_SECURITY; SSVAL(buf,smb_flg2, flags2); } -- 1.7.4.1 From 46a466fb51c8dcb5ce0352827bfa94aa1d6c5988 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 8 Sep 2011 17:29:58 +0200 Subject: [PATCH 14/14] s3:libsmb: use local variables in cli_state_create() We don't need to keep use_spnego, use_level_II_oplocks, force_dos_errors and force_ascii within struct cli_state. metze --- source3/include/client.h | 4 ---- source3/libsmb/cliconnect.c | 5 ----- source3/libsmb/clientgen.c | 26 ++++++++++++++------------ 3 files changed, 14 insertions(+), 21 deletions(-) diff --git a/source3/include/client.h b/source3/include/client.h index b21d32a..0f1e2a3 100644 --- a/source3/include/client.h +++ b/source3/include/client.h @@ -96,15 +96,11 @@ struct cli_state { bool use_kerberos; bool fallback_after_kerberos; - bool use_spnego; bool use_ccache; bool got_kerberos_mechanism; /* Server supports krb5 in SPNEGO. */ bool use_oplocks; /* should we use oplocks? */ - bool use_level_II_oplocks; /* should we use level II oplocks? */ - bool force_dos_errors; - bool force_ascii; bool case_sensitive; /* False by default. */ /* Where (if anywhere) this is mounted under DFS. */ diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index 1088a6e..1eda8a8 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -2539,9 +2539,6 @@ struct tevent_req *cli_negprot_send(TALLOC_CTX *mem_ctx, } state->cli = cli; - if (cli_state_protocol(cli) < PROTOCOL_NT1) - cli->use_spnego = False; - /* setup the protocol strings */ for (numprots=0; numprots < ARRAY_SIZE(prots); numprots++) { uint8_t c = 2; @@ -2690,7 +2687,6 @@ static void cli_negprot_done(struct tevent_req *subreq) return; } - cli->use_spnego = False; cli->sec_mode = SVAL(vwv + 1, 0); cli->max_xmit = SVAL(vwv + 2, 0); cli->max_mux = SVAL(vwv + 3, 0); @@ -2705,7 +2701,6 @@ static void cli_negprot_done(struct tevent_req *subreq) cli->secblob = data_blob(bytes, num_bytes); } else { /* the old core protocol */ - cli->use_spnego = False; cli->sec_mode = 0; cli->serverzone = get_time_zone(time(NULL)); } diff --git a/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c index be103ad..b23bba3 100644 --- a/source3/libsmb/clientgen.c +++ b/source3/libsmb/clientgen.c @@ -173,6 +173,10 @@ struct cli_state *cli_state_create(TALLOC_CTX *mem_ctx, bool mandatory_signing; socklen_t ss_length; int ret; + bool use_spnego = lp_client_use_spnego(); + bool force_dos_errors = false; + bool force_ascii = false; + bool use_level_II_oplocks = false; /* Check the effective uid - make sure we are not setuid */ if (is_setuid_root()) { @@ -195,27 +199,25 @@ struct cli_state *cli_state_create(TALLOC_CTX *mem_ctx, cli->max_xmit = CLI_BUFFER_SIZE+4; cli->case_sensitive = false; - cli->use_spnego = lp_client_use_spnego(); - /* Set the CLI_FORCE_DOSERR environment variable to test client routines using DOS errors instead of STATUS32 ones. This intended only as a temporary hack. */ if (getenv("CLI_FORCE_DOSERR")) { - cli->force_dos_errors = true; + force_dos_errors = true; } if (flags & CLI_FULL_CONNECTION_FORCE_DOS_ERRORS) { - cli->force_dos_errors = true; + force_dos_errors = true; } if (getenv("CLI_FORCE_ASCII")) { - cli->force_ascii = true; + force_ascii = true; } if (flags & CLI_FULL_CONNECTION_FORCE_ASCII) { - cli->force_ascii = true; + force_ascii = true; } if (flags & CLI_FULL_CONNECTION_DONT_SPNEGO) { - cli->use_spnego = false; + use_spnego = false; } else if (flags & CLI_FULL_CONNECTION_USE_KERBEROS) { cli->use_kerberos = true; } @@ -232,7 +234,7 @@ struct cli_state *cli_state_create(TALLOC_CTX *mem_ctx, cli->use_oplocks = true; } if (flags & CLI_FULL_CONNECTION_LEVEL_II_OPLOCKS) { - cli->use_level_II_oplocks = true; + use_level_II_oplocks = true; } if (signing_state == Undefined) { @@ -285,19 +287,19 @@ struct cli_state *cli_state_create(TALLOC_CTX *mem_ctx, cli->capabilities |= CAP_LARGE_READX|CAP_LARGE_WRITEX; cli->capabilities |= CAP_LWIO; - if (!cli->force_dos_errors) { + if (!force_dos_errors) { cli->capabilities |= CAP_STATUS32; } - if (!cli->force_ascii) { + if (!force_ascii) { cli->capabilities |= CAP_UNICODE; } - if (cli->use_spnego) { + if (use_spnego) { cli->capabilities |= CAP_EXTENDED_SECURITY; } - if (cli->use_level_II_oplocks) { + if (use_level_II_oplocks) { cli->capabilities |= CAP_LEVEL_II_OPLOCKS; } -- 1.7.4.1