The branch, master has been updated via 8f93068 s3: Add smb_request_done via 2c1caf5 s3: Remove unused smb_request->done via 3a7bc3a s3: Remove unused smb_request->chain_outbuf via 572bc64 s3: Remove "req_wct_ofs()" via 12068d4 s3: Fix the read&x offset within a chain via 11d087a s3: Remove chain_reply via 3b2c9be s3: Replace chain_reply via c9870a6 s3: Add a new set of andx chain handling routines via 90b33a0 s3: Make sure the andX chains are ended correctly from a28a740 s3: Fix a 64-bit warning
http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit 8f93068cf8fc3d282e0975cc5cbdcd2098b10d52 Author: Volker Lendecke <v...@samba.org> Date: Sun Mar 4 12:10:04 2012 +0100 s3: Add smb_request_done This is used to enable async chained command sequences. A synchronous reply_xxx command does not need to take are anymore about and_x chaining. The async commands (pipe r/w at this moment) must do so however. When finished, they must inform the main chain engine that they are finished with a smb_request_done call. Autobuild-User: Volker Lendecke <v...@samba.org> Autobuild-Date: Sat Mar 10 17:14:05 CET 2012 on sn-devel-104 commit 2c1caf5fcb002f5a4e049fcb812c98c435d0f2c9 Author: Volker Lendecke <v...@samba.org> Date: Sat Mar 3 00:59:56 2012 +0100 s3: Remove unused smb_request->done commit 3a7bc3abb837b8c9df2c156440eb8a6f7e60c8d9 Author: Volker Lendecke <v...@samba.org> Date: Sat Mar 3 00:34:27 2012 +0100 s3: Remove unused smb_request->chain_outbuf commit 572bc64b594d0d30cb64976579a55e74f01800d2 Author: Volker Lendecke <v...@samba.org> Date: Sat Mar 3 00:33:15 2012 +0100 s3: Remove "req_wct_ofs()" This is fixed up in construct_reply_chain commit 12068d4aaca0579b58bbb121df4d1e947f8ea032 Author: Volker Lendecke <v...@samba.org> Date: Wed Feb 29 23:44:36 2012 +0100 s3: Fix the read&x offset within a chain commit 11d087aa04f436147e7a9dd1748a43bde24de8e3 Author: Volker Lendecke <v...@samba.org> Date: Tue Feb 28 01:21:44 2012 +0100 s3: Remove chain_reply <insert your favourite tombstone ascii art here> commit 3b2c9bebc0aa08fe9a65afe5870bea490c5fb33a Author: Volker Lendecke <v...@samba.org> Date: Tue Feb 28 00:56:10 2012 +0100 s3: Replace chain_reply This is a new implementation of our andx handling code. The old code was quite involved in that it was called from within the reply_ handlers. This leads to pretty complex faking of smb_request structures to give them the same environment, independent of whether they are called directly or from within chain_reply. chain_reply needs to go because it blocks really async handling of chained requests. commit c9870a62f5d8865e67ae519db3f8e890afb6ee70 Author: Volker Lendecke <v...@samba.org> Date: Tue Feb 28 00:19:48 2012 +0100 s3: Add a new set of andx chain handling routines This is in preparation of getting rid of chain_reply. commit 90b33a05e967e9e29c4584bed188ef6fa5a3fbf0 Author: Volker Lendecke <v...@samba.org> Date: Sun Feb 26 16:49:09 2012 +0100 s3: Make sure the andX chains are ended correctly Normally chain_reply took care of this. This will go away soon. ----------------------------------------------------------------------- Summary of changes: source3/Makefile.in | 3 +- source3/include/smb.h | 12 +- source3/smbd/blocking.c | 11 +- source3/smbd/nttrans.c | 9 +- source3/smbd/pipes.c | 20 +- source3/smbd/process.c | 638 ++++++++++++++++++++++++--------------- source3/smbd/proto.h | 15 +- source3/smbd/reply.c | 23 +- source3/smbd/sesssetup.c | 5 +- source3/torture/cmd_vfs.c | 2 + source3/torture/vfstest.h | 3 + source3/torture/vfstest_chain.c | 342 +++++++++++++++++++++ source3/wscript_build | 3 +- 13 files changed, 804 insertions(+), 282 deletions(-) create mode 100644 source3/torture/vfstest_chain.c Changeset truncated at 500 lines: diff --git a/source3/Makefile.in b/source3/Makefile.in index 2b0002b..dc02b6a 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -1299,7 +1299,8 @@ PDBTEST_OBJ = torture/pdbtest.o $(PARAM_OBJ) $(LIBSMB_OBJ) $(KRBCLIENT_OBJ) \ $(SMBLDAP_OBJ) $(POPT_LIB_OBJ) \ $(LIBMSRPC_OBJ) $(LIBMSRPC_GEN_OBJ) -VFSTEST_OBJ = torture/cmd_vfs.o torture/vfstest.o $(SMBD_OBJ_BASE) $(READLINE_OBJ) +VFSTEST_OBJ = torture/cmd_vfs.o torture/vfstest.o $(SMBD_OBJ_BASE) $(READLINE_OBJ) \ + torture/vfstest_chain.o LOG2PCAP_OBJ = utils/log2pcaphex.o diff --git a/source3/include/smb.h b/source3/include/smb.h index d93f30d..382926c 100644 --- a/source3/include/smb.h +++ b/source3/include/smb.h @@ -481,17 +481,10 @@ struct smb_request { struct files_struct *chain_fsp; /* - * Here we collect the outbufs from the chain handlers - */ - uint8_t *chain_outbuf; - - /* * state information for async smb handling */ void *async_priv; - bool done; - /* * Back pointer to smb2 request. */ @@ -502,6 +495,11 @@ struct smb_request { * under privilege. */ struct privilege_paths *priv_paths; + + /* + * Request list for chained requests, we're part of it. + */ + struct smb_request **chain; }; /* Defines for the sent_oplock_break field above. */ diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c index 6496e43..d512b96 100644 --- a/source3/smbd/blocking.c +++ b/source3/smbd/blocking.c @@ -271,6 +271,8 @@ static void reply_lockingX_success(struct blocking_lock_record *blr) struct smb_request *req = blr->req; reply_outbuf(req, 2, 0); + SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */ + SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */ /* * As this message is a lockingX call we must handle @@ -280,7 +282,14 @@ static void reply_lockingX_success(struct blocking_lock_record *blr) * that here and must set up the chain info manually. */ - chain_reply(req); + if (!srv_send_smb(req->sconn, + (char *)req->outbuf, + true, req->seqnum+1, + IS_CONN_ENCRYPTED(req->conn)||req->encrypted, + &req->pcd)) { + exit_server_cleanly("construct_reply: srv_send_smb failed."); + } + TALLOC_FREE(req->outbuf); } diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index cfa048b..fc52ee5 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -352,6 +352,9 @@ static void do_ntcreate_pipe_open(connection_struct *conn, reply_outbuf(req, 34, 0); } + SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */ + SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */ + p = (char *)req->outbuf + smb_vwv2; p++; SSVAL(p,0,pnum); @@ -379,8 +382,6 @@ static void do_ntcreate_pipe_open(connection_struct *conn, } DEBUG(5,("do_ntcreate_pipe_open: open pipe = %s\n", fname)); - - chain_reply(req); } struct case_semantics_state { @@ -634,6 +635,9 @@ void reply_ntcreate_and_X(struct smb_request *req) reply_outbuf(req, 34, 0); } + SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */ + SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */ + p = (char *)req->outbuf + smb_vwv2; SCVAL(p, 0, oplock_granted); @@ -728,7 +732,6 @@ void reply_ntcreate_and_X(struct smb_request *req) DEBUG(5,("reply_ntcreate_and_X: fnum = %d, open name = %s\n", fsp->fnum, smb_fname_str_dbg(smb_fname))); - chain_reply(req); out: END_PROFILE(SMBntcreateX); return; diff --git a/source3/smbd/pipes.c b/source3/smbd/pipes.c index 9e5dfc3..c3a5cb3 100644 --- a/source3/smbd/pipes.c +++ b/source3/smbd/pipes.c @@ -146,6 +146,9 @@ void reply_open_pipe_and_X(connection_struct *conn, struct smb_request *req) /* Prepare the reply */ reply_outbuf(req, 15, 0); + SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */ + SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */ + /* Mark the opened file as an existing named pipe in message mode. */ SSVAL(req->outbuf,smb_vwv9,2); SSVAL(req->outbuf,smb_vwv10,0xc700); @@ -156,9 +159,6 @@ void reply_open_pipe_and_X(connection_struct *conn, struct smb_request *req) SIVAL(req->outbuf, smb_vwv6, 0); /* size */ SSVAL(req->outbuf, smb_vwv8, 0); /* rmode */ SSVAL(req->outbuf, smb_vwv11, 0x0001); - - chain_reply(req); - return; } /**************************************************************************** @@ -354,18 +354,20 @@ static void pipe_write_andx_done(struct tevent_req *subreq) reply_outbuf(req, 6, 0); + SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */ + SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */ + nwritten = (state->pipe_start_message_raw ? nwritten + 2 : nwritten); SSVAL(req->outbuf,smb_vwv2,nwritten); DEBUG(3,("writeX-IPC nwritten=%d\n", (int)nwritten)); done: - chain_reply(req); /* * We must free here as the ownership of req was * moved to the connection struct in reply_pipe_write_and_X(). */ - TALLOC_FREE(req); + smb_request_done(req); } /**************************************************************************** @@ -417,6 +419,9 @@ void reply_pipe_read_and_X(struct smb_request *req) state->smb_mincnt = SVAL(req->vwv+6, 0); reply_outbuf(req, 12, state->smb_maxcnt); + SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */ + SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */ + data = (uint8_t *)smb_buf(req->outbuf); /* @@ -474,7 +479,7 @@ static void pipe_read_andx_done(struct tevent_req *subreq) SSVAL(req->outbuf,smb_vwv5,nread); SSVAL(req->outbuf,smb_vwv6, - req_wct_ofs(req) + (smb_wct - 4) /* offset from smb header to wct */ + 1 /* the wct field */ + 12 * sizeof(uint16_t) /* vwv */ + 2); /* the buflen field */ @@ -484,10 +489,9 @@ static void pipe_read_andx_done(struct tevent_req *subreq) state->smb_mincnt, state->smb_maxcnt, (int)nread)); done: - chain_reply(req); /* * We must free here as the ownership of req was * moved to the connection struct in reply_pipe_read_and_X(). */ - TALLOC_FREE(req); + smb_request_done(req); } diff --git a/source3/smbd/process.c b/source3/smbd/process.c index f87eccf..8b15ac8 100644 --- a/source3/smbd/process.c +++ b/source3/smbd/process.c @@ -60,6 +60,7 @@ static void construct_reply_common(struct smb_request *req, const char *inbuf, char *outbuf); static struct pending_message_list *get_deferred_open_message_smb( struct smbd_server_connection *sconn, uint64_t mid); +static bool smb_splice_chain(uint8_t **poutbuf, const uint8_t *andx_buf); static bool smbd_lock_socket_internal(struct smbd_server_connection *sconn) { @@ -537,10 +538,9 @@ static bool init_smb_request(struct smb_request *req, req->sconn = sconn; req->conn = conn_find(sconn,req->tid); req->chain_fsp = NULL; - req->chain_outbuf = NULL; - req->done = false; req->smb2req = NULL; req->priv_paths = NULL; + req->chain = NULL; smb_init_perfcount_data(&req->pcd); /* Ensure we have at least wct words and 2 bytes of bcc. */ @@ -1537,11 +1537,6 @@ static void construct_reply(struct smbd_server_connection *sconn, conn = switch_message(req->cmd, req); - if (req->done) { - TALLOC_FREE(req); - return; - } - if (req->outbuf == NULL) { return; } @@ -1563,6 +1558,162 @@ static void construct_reply(struct smbd_server_connection *sconn, return; } +static void construct_reply_chain(struct smbd_server_connection *sconn, + char *inbuf, int size, uint32_t seqnum, + bool encrypted, + struct smb_perfcount_data *deferred_pcd) +{ + struct smb_request **reqs = NULL; + struct smb_request *req; + unsigned num_reqs; + bool ok; + + ok = smb1_parse_chain(talloc_tos(), (uint8_t *)inbuf, sconn, encrypted, + seqnum, &reqs, &num_reqs); + if (!ok) { + char errbuf[smb_size]; + error_packet(errbuf, 0, 0, NT_STATUS_INVALID_PARAMETER, + __LINE__, __FILE__); + if (!srv_send_smb(sconn, errbuf, true, seqnum, encrypted, + NULL)) { + exit_server_cleanly("construct_reply_chain: " + "srv_send_smb failed."); + } + return; + } + + req = reqs[0]; + req->inbuf = (uint8_t *)talloc_move(reqs, &inbuf); + + req->conn = switch_message(req->cmd, req); + + if (req->outbuf == NULL) { + /* + * Request has suspended itself, will come + * back here. + */ + return; + } + smb_request_done(req); +} + +/* + * To be called from an async SMB handler that is potentially chained + * when it is finished for shipping. + */ + +void smb_request_done(struct smb_request *req) +{ + struct smb_request **reqs = NULL; + struct smb_request *first_req; + size_t i, num_reqs, next_index; + NTSTATUS status; + + if (req->chain == NULL) { + first_req = req; + goto shipit; + } + + reqs = req->chain; + num_reqs = talloc_array_length(reqs); + + for (i=0; i<num_reqs; i++) { + if (reqs[i] == req) { + break; + } + } + if (i == num_reqs) { + /* + * Invalid chain, should not happen + */ + status = NT_STATUS_INTERNAL_ERROR; + goto error; + } + next_index = i+1; + + while ((next_index < num_reqs) && (IVAL(req->outbuf, smb_rcls) == 0)) { + struct smb_request *next = reqs[next_index]; + + next->vuid = SVAL(req->outbuf, smb_uid); + next->tid = SVAL(req->outbuf, smb_tid); + next->conn = conn_find(req->sconn, req->tid); + next->chain_fsp = req->chain_fsp; + next->inbuf = (uint8_t *)req->inbuf; + + req = next; + req->conn = switch_message(req->cmd, req); + + if (req->outbuf == NULL) { + /* + * Request has suspended itself, will come + * back here. + */ + return; + } + next_index += 1; + } + + first_req = reqs[0]; + + for (i=1; i<next_index; i++) { + bool ok; + + ok = smb_splice_chain(&first_req->outbuf, reqs[i]->outbuf); + if (!ok) { + status = NT_STATUS_INTERNAL_ERROR; + goto error; + } + } + + SSVAL(first_req->outbuf, smb_uid, SVAL(req->outbuf, smb_uid)); + SSVAL(first_req->outbuf, smb_tid, SVAL(req->outbuf, smb_tid)); + + /* + * This scary statement intends to set the + * FLAGS2_32_BIT_ERROR_CODES flg2 field in first_req->outbuf + * to the value last_req->outbuf carries + */ + SSVAL(first_req->outbuf, smb_flg2, + (SVAL(first_req->outbuf, smb_flg2) & ~FLAGS2_32_BIT_ERROR_CODES) + |(SVAL(req->outbuf, smb_flg2) & FLAGS2_32_BIT_ERROR_CODES)); + + /* + * Transfer the error codes from the subrequest to the main one + */ + SSVAL(first_req->outbuf, smb_rcls, SVAL(req->outbuf, smb_rcls)); + SSVAL(first_req->outbuf, smb_err, SVAL(req->outbuf, smb_err)); + + _smb_setlen_large( + first_req->outbuf, talloc_get_size(first_req->outbuf) - 4); + +shipit: + if (!srv_send_smb(first_req->sconn, + (char *)first_req->outbuf, + true, first_req->seqnum+1, + IS_CONN_ENCRYPTED(req->conn)||first_req->encrypted, + &first_req->pcd)) { + exit_server_cleanly("construct_reply_chain: srv_send_smb " + "failed."); + } + TALLOC_FREE(req); /* non-chained case */ + TALLOC_FREE(reqs); /* chained case */ + return; + +error: + { + char errbuf[smb_size]; + error_packet(errbuf, 0, 0, status, __LINE__, __FILE__); + if (!srv_send_smb(req->sconn, errbuf, true, + req->seqnum+1, req->encrypted, + NULL)) { + exit_server_cleanly("construct_reply_chain: " + "srv_send_smb failed."); + } + } + TALLOC_FREE(req); /* non-chained case */ + TALLOC_FREE(reqs); /* chained case */ +} + /**************************************************************************** Process an smb from the client ****************************************************************************/ @@ -1623,8 +1774,14 @@ static void process_smb(struct smbd_server_connection *sconn, show_msg((char *)inbuf); - construct_reply(sconn, (char *)inbuf, nread, unread_bytes, seqnum, - encrypted, deferred_pcd); + if ((unread_bytes == 0) && smb1_is_chain(inbuf)) { + construct_reply_chain(sconn, (char *)inbuf, nread, + seqnum, encrypted, deferred_pcd); + } else { + construct_reply(sconn, (char *)inbuf, nread, unread_bytes, + seqnum, encrypted, deferred_pcd); + } + sconn->trans_num++; done: @@ -1702,40 +1859,6 @@ void construct_reply_common_req(struct smb_request *req, char *outbuf) construct_reply_common(req, (const char *)req->inbuf, outbuf); } -/* - * How many bytes have we already accumulated up to the current wct field - * offset? - */ - -size_t req_wct_ofs(struct smb_request *req) -{ - size_t buf_size; - - if (req->chain_outbuf == NULL) { - return smb_wct - 4; - } - buf_size = talloc_get_size(req->chain_outbuf); - if ((buf_size % 4) != 0) { - buf_size += (4 - (buf_size % 4)); - } - return buf_size - 4; -} - -/* - * Hack around reply_nterror & friends not being aware of chained requests, - * generating illegal (i.e. wct==0) chain replies. - */ - -static void fixup_chain_error_packet(struct smb_request *req) -{ - uint8_t *outbuf = req->outbuf; - req->outbuf = NULL; - reply_outbuf(req, 2, 0); - memcpy(req->outbuf, outbuf, smb_wct); - TALLOC_FREE(outbuf); - SCVAL(req->outbuf, smb_vwv0, 0xff); -} - /** * @brief Find the smb_cmd offset of the last command pushed * @param[in] buf The buffer we're building up @@ -1862,6 +1985,38 @@ static bool smb_splice_chain(uint8_t **poutbuf, const uint8_t *andx_buf) */ memcpy(outbuf + ofs, vwv, sizeof(uint16_t) * wct); + + /* + * HACK ALERT + * + * Read&X has an offset into its data buffer at + * vwv[6]. reply_read_andx has no idea anymore that it's + * running from within a chain, so we have to fix up the + * offset here. + * + * Although it looks disgusting at this place, I want to keep + * it here. The alternative would be to push knowledge about + * the andx chain down into read&x again. + */ + + if (smb_command == SMBreadX) { + uint8_t *bytes_addr; + + if (wct < 7) { + /* + * Invalid read&x response + */ + return false; + } + + bytes_addr = outbuf + ofs /* vwv start */ + + sizeof(uint16_t) * wct /* vwv array */ + + sizeof(uint16_t); /* bcc */ + + SSVAL(outbuf + ofs, 6 * sizeof(uint16_t), + bytes_addr - outbuf - 4); + } + ofs += sizeof(uint16_t) * wct; /* @@ -1880,257 +2035,244 @@ static bool smb_splice_chain(uint8_t **poutbuf, const uint8_t *andx_buf) return true; } -/**************************************************************************** - Construct a chained reply and add it to the already made reply -****************************************************************************/ - -- Samba Shared Repository