*/
#include "includes.h"
+#include "events.h"
+#include "dlinklist.h"
+#include "smb_server/smb_server.h"
+
/* we over allocate the data buffer to prevent too many realloc calls */
-#define REQ_OVER_ALLOCATION 256
+#define REQ_OVER_ALLOCATION 0
/* destroy a request structure */
void req_destroy(struct smbsrv_request *req)
{
- /* the request might be marked protected. This is done by the
- * SMBecho code for example */
- if (req->control_flags & REQ_CONTROL_PROTECTED) {
- return;
- }
-
/* ahh, its so nice to destroy a complex structure in such a
* simple way! */
talloc_free(req);
{
struct smbsrv_request *req;
- smb_conn->socket.pkt_count++;
-
req = talloc_p(smb_conn, struct smbsrv_request);
if (!req) {
return NULL;
/* setup the request context */
req->smb_conn = smb_conn;
-
+
+ req->async_states = talloc_p(req, struct ntvfs_async_state);
+ if (!req->async_states) {
+ talloc_free(req);
+ return NULL;
+ }
+ req->async_states->state = 0;
+
return req;
}
/* over allocate by a small amount */
req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
- req->out.buffer = talloc_realloc(req->out.buffer, req->out.allocated);
+ req->out.buffer = talloc_realloc(req, req->out.buffer,
+ uint8_t, req->out.allocated);
if (!req->out.buffer) {
smbsrv_terminate_connection(req->smb_conn, "allocation failed");
+ return;
}
req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
*/
void req_setup_reply(struct smbsrv_request *req, uint_t wct, uint_t buflen)
{
+ uint16_t flags2;
+
if (req->chain_count != 0) {
req_setup_chain_reply(req, wct, buflen);
return;
/* over allocate by a small amount */
req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
- req->out.buffer = talloc(req, req->out.allocated);
+ req->out.buffer = talloc_size(req, req->out.allocated);
if (!req->out.buffer) {
smbsrv_terminate_connection(req->smb_conn, "allocation failed");
+ return;
+ }
+
+ flags2 = FLAGS2_LONG_PATH_COMPONENTS |
+ FLAGS2_EXTENDED_ATTRIBUTES |
+ FLAGS2_IS_LONG_NAME;
+ flags2 |= (req->flags2 & (FLAGS2_UNICODE_STRINGS|FLAGS2_EXTENDED_SECURITY));
+ if (req->smb_conn->negotiate.client_caps & CAP_STATUS32) {
+ flags2 |= FLAGS2_32_BIT_ERROR_CODES;
}
req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
SCVAL(req->out.hdr, HDR_WCT, wct);
SSVAL(req->out.vwv, VWV(wct), buflen);
-
memcpy(req->out.hdr, "\377SMB", 4);
SCVAL(req->out.hdr,HDR_FLG, FLAG_REPLY | FLAG_CASELESS_PATHNAMES);
- SSVAL(req->out.hdr,HDR_FLG2,
- (req->flags2 & FLAGS2_UNICODE_STRINGS) |
- FLAGS2_LONG_PATH_COMPONENTS | FLAGS2_32_BIT_ERROR_CODES | FLAGS2_EXTENDED_SECURITY);
-
+ SSVAL(req->out.hdr,HDR_FLG2, flags2);
SSVAL(req->out.hdr,HDR_PIDHIGH,0);
memset(req->out.hdr + HDR_SS_FIELD, 0, 10);
}
}
+
+/*
+ setup a copy of a request, used when the server needs to send
+ more than one reply for a single request packet
+*/
+struct smbsrv_request *req_setup_secondary(struct smbsrv_request *old_req)
+{
+ struct smbsrv_request *req;
+ ptrdiff_t diff;
+
+ req = talloc_memdup(old_req, old_req, sizeof(struct smbsrv_request));
+ if (req == NULL) {
+ return NULL;
+ }
+
+ req->out.buffer = talloc_memdup(req, req->out.buffer, req->out.allocated);
+ if (req->out.buffer == NULL) {
+ talloc_free(req);
+ return NULL;
+ }
+
+ diff = req->out.buffer - old_req->out.buffer;
+
+ req->out.hdr += diff;
+ req->out.vwv += diff;
+ req->out.data += diff;
+ req->out.ptr += diff;
+
+ return req;
+}
+
/*
work out the maximum data size we will allow for this reply, given
the negotiated max_xmit. The basic reply packet must be setup before
static void req_grow_allocation(struct smbsrv_request *req, uint_t new_size)
{
int delta;
- char *buf2;
+ uint8_t *buf2;
delta = new_size - req->out.data_size;
if (delta + req->out.size <= req->out.allocated) {
/* we need to realloc */
req->out.allocated = req->out.size + delta + REQ_OVER_ALLOCATION;
- buf2 = talloc_realloc(req->out.buffer, req->out.allocated);
+ buf2 = talloc_realloc(req, req->out.buffer, uint8_t, req->out.allocated);
if (buf2 == NULL) {
smb_panic("out of memory in req_grow_allocation");
}
*/
void req_send_reply_nosign(struct smbsrv_request *req)
{
- NTSTATUS status;
- DATA_BLOB tmp_blob;
- size_t sendlen;
-
if (req->out.size > NBT_HDR_SIZE) {
_smb_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
}
- tmp_blob.data = req->out.buffer;
- tmp_blob.length = req->out.size;
-
- status = socket_send(req->smb_conn->connection->socket, req, &tmp_blob, &sendlen, SOCKET_FLAG_BLOCK);
- if (!NT_STATUS_IS_OK(status) || (req->out.size != sendlen)) {
- smbsrv_terminate_connection(req->smb_conn, "failed to send reply\n");
- }
+ /* add the request to the list of requests that need to be
+ sent to the client, then mark the socket event structure
+ ready for write events */
+ DLIST_ADD_END(req->smb_conn->pending_send, req, struct smbsrv_request *);
- req_destroy(req);
+ req->smb_conn->connection->event.fde->flags |= EVENT_FD_WRITE;
}
/*
if dest_len is -1 then no limit applies
*/
-size_t req_push_str(struct smbsrv_request *req, char *dest, const char *str, int dest_len, uint_t flags)
+size_t req_push_str(struct smbsrv_request *req, uint8_t *dest, const char *str, int dest_len, uint_t flags)
{
size_t len;
uint_t grow_size;
- char *buf0;
+ uint8_t *buf0;
const int max_bytes_per_char = 3;
if (!(flags & (STR_ASCII|STR_UNICODE))) {
dest = req->out.buffer + PTR_DIFF(dest, buf0);
}
- len = push_string(req->out.hdr, dest, str, len, flags);
+ len = push_string(dest, str, len, flags);
grow_size = len + PTR_DIFF(dest, req->out.data);
on failure zero is returned and *dest is set to NULL, otherwise the number
of bytes consumed in the packet is returned
*/
-static size_t req_pull_ucs2(struct smbsrv_request *req, const char **dest, const char *src, int byte_len, uint_t flags)
+static size_t req_pull_ucs2(struct smbsrv_request *req, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
{
int src_len, src_len2, alignment=0;
ssize_t ret;
+ char *dest2;
if (!(flags & STR_NOALIGN) && ucs2_align(req->in.buffer, src, flags)) {
src++;
}
}
- src_len2 = strnlen_w((const smb_ucs2_t *)src, src_len/2) * 2;
-
- if (src_len2 <= src_len - 2) {
- /* include the termination if we didn't reach the end of the packet */
- src_len2 += 2;
+ src_len2 = utf16_len_n(src, src_len);
+ if (src_len2 == 0) {
+ *dest = talloc_strdup(req, "");
+ return src_len2 + alignment;
}
- ret = convert_string_talloc(req, CH_UTF16, CH_UNIX, src, src_len2, (const void **)dest);
+ ret = convert_string_talloc(req, CH_UTF16, CH_UNIX, src, src_len2, (void **)&dest2);
if (ret == -1) {
*dest = NULL;
return 0;
}
+ *dest = dest2;
return src_len2 + alignment;
}
on failure zero is returned and *dest is set to NULL, otherwise the number
of bytes consumed in the packet is returned
*/
-static size_t req_pull_ascii(struct smbsrv_request *req, const char **dest, const char *src, int byte_len, uint_t flags)
+static size_t req_pull_ascii(struct smbsrv_request *req, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
{
int src_len, src_len2;
ssize_t ret;
+ char *dest2;
if (flags & STR_NO_RANGE_CHECK) {
src_len = byte_len;
}
}
- src_len2 = strnlen(src, src_len);
+ src_len2 = strnlen((const char *)src, src_len);
if (src_len2 <= src_len - 1) {
/* include the termination if we didn't reach the end of the packet */
src_len2++;
}
- ret = convert_string_talloc(req, CH_DOS, CH_UNIX, src, src_len2, (const void **)dest);
+ ret = convert_string_talloc(req, CH_DOS, CH_UNIX, src, src_len2, (void **)&dest2);
if (ret == -1) {
*dest = NULL;
return 0;
}
+ *dest = dest2;
return src_len2;
}
on failure zero is returned and *dest is set to NULL, otherwise the number
of bytes consumed in the packet is returned
*/
-size_t req_pull_string(struct smbsrv_request *req, const char **dest, const char *src, int byte_len, uint_t flags)
+size_t req_pull_string(struct smbsrv_request *req, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
{
if (!(flags & STR_ASCII) &&
(((flags & STR_UNICODE) || (req->flags2 & FLAGS2_UNICODE_STRINGS)))) {
on failure *dest is set to the zero length string. This seems to
match win2000 behaviour
*/
-size_t req_pull_ascii4(struct smbsrv_request *req, const char **dest, const char *src, uint_t flags)
+size_t req_pull_ascii4(struct smbsrv_request *req, const char **dest, const uint8_t *src, uint_t flags)
{
ssize_t ret;
return False if any part is outside the data portion of the packet
*/
-BOOL req_pull_blob(struct smbsrv_request *req, const char *src, int len, DATA_BLOB *blob)
+BOOL req_pull_blob(struct smbsrv_request *req, const uint8_t *src, int len, DATA_BLOB *blob)
{
if (len != 0 && req_data_oob(req, src, len)) {
return False;
/* check that a lump of data in a request is within the bounds of the data section of
the packet */
-BOOL req_data_oob(struct smbsrv_request *req, const char *ptr, uint32_t count)
+BOOL req_data_oob(struct smbsrv_request *req, const uint8_t *ptr, uint32_t count)
{
if (count == 0) {
return False;
/*
pull an open file handle from a packet, taking account of the chained_fnum
*/
-uint16_t req_fnum(struct smbsrv_request *req, const char *base, uint_t offset)
+uint16_t req_fnum(struct smbsrv_request *req, const uint8_t *base, uint_t offset)
{
if (req->chained_fnum != -1) {
return req->chained_fnum;