r4591: - converted the other _p talloc functions to not need _p
[jelmer/samba4-debian.git] / source / smb_server / request.c
index f4cdba79ccc7e14adc5519a6c27e5b20ca74bc90..2ac832b439dc0b8bb9fe316cca0b1d313b13438c 100644 (file)
 */
 
 #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_destroy(req->mem_ctx);
+       talloc_free(req);
 }
 
 /****************************************************************************
@@ -48,20 +46,10 @@ such as change notify and oplock break requests
 struct smbsrv_request *init_smb_request(struct smbsrv_connection *smb_conn)
 {
        struct smbsrv_request *req;
-       TALLOC_CTX *mem_ctx;
-
-       /* each request gets its own talloc context. The request
-          structure itself is also allocated inside this context, so
-          we need to allocate it before we construct the request
-       */
-       mem_ctx = talloc_init("request_context[%d]", smb_conn->connection->socket->pkt_count);
-       if (!mem_ctx) {
-               return NULL;
-       }
 
-       smb_conn->connection->socket->pkt_count++;
+       smb_conn->pkt_count++;
 
-       req = talloc(mem_ctx, sizeof(*req));
+       req = talloc_p(smb_conn, struct smbsrv_request);
        if (!req) {
                return NULL;
        }
@@ -70,8 +58,14 @@ struct smbsrv_request *init_smb_request(struct smbsrv_connection *smb_conn)
 
        /* setup the request context */
        req->smb_conn = smb_conn;
-       req->mem_ctx = mem_ctx;
-       
+
+       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;
 }
 
@@ -89,9 +83,11 @@ static void req_setup_chain_reply(struct smbsrv_request *req, uint_t wct, uint_t
        /* over allocate by a small amount */
        req->out.allocated = req->out.size + REQ_OVER_ALLOCATION; 
 
-       req->out.buffer = talloc_realloc(req->mem_ctx, 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;
@@ -113,6 +109,8 @@ static void req_setup_chain_reply(struct smbsrv_request *req, uint_t wct, uint_t
 */
 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;
@@ -123,9 +121,18 @@ void req_setup_reply(struct smbsrv_request *req, uint_t wct, uint_t buflen)
        /* over allocate by a small amount */
        req->out.allocated = req->out.size + REQ_OVER_ALLOCATION; 
 
-       req->out.buffer = talloc(req->mem_ctx, 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;
@@ -140,13 +147,9 @@ void req_setup_reply(struct smbsrv_request *req, uint_t wct, uint_t buflen)
        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);
 
@@ -165,6 +168,37 @@ void req_setup_reply(struct smbsrv_request *req, uint_t wct, uint_t buflen)
        }
 }
 
+
+/*
+  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
@@ -193,7 +227,7 @@ int req_max_data(struct smbsrv_request *req)
 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) {
@@ -203,7 +237,7 @@ static void req_grow_allocation(struct smbsrv_request *req, uint_t new_size)
 
        /* we need to realloc */
        req->out.allocated = req->out.size + delta + REQ_OVER_ALLOCATION;
-       buf2 = talloc_realloc(req->mem_ctx, 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");
        }
@@ -262,11 +296,12 @@ void req_send_reply_nosign(struct smbsrv_request *req)
                _smb_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
        }
 
-       if (write_data(req->smb_conn->connection->socket->fde->fd, req->out.buffer, req->out.size) != req->out.size) {
-               smb_panic("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;
 }
 
 /*
@@ -352,11 +387,11 @@ void req_reply_error(struct smbsrv_request *req, NTSTATUS status)
 
   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))) {
@@ -382,7 +417,7 @@ size_t req_push_str(struct smbsrv_request *req, char *dest, const char *str, int
                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);
 
@@ -398,7 +433,7 @@ size_t req_push_str(struct smbsrv_request *req, char *dest, const char *str, int
   return the number of bytes added
 */
 size_t req_append_bytes(struct smbsrv_request *req, 
-               const uint8_t *bytes, size_t byte_len)
+                       const uint8_t *bytes, size_t byte_len)
 {
        req_grow_allocation(req, byte_len + req->out.data_size);
        memcpy(req->out.data + req->out.data_size, bytes, byte_len);
@@ -434,10 +469,11 @@ size_t req_append_var_block(struct smbsrv_request *req,
   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++;
@@ -461,19 +497,19 @@ static size_t req_pull_ucs2(struct smbsrv_request *req, const char **dest, const
                }
        }
 
-       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->mem_ctx, CH_UCS2, 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;
 }
@@ -491,10 +527,11 @@ static size_t req_pull_ucs2(struct smbsrv_request *req, const char **dest, const
   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;
@@ -509,18 +546,19 @@ static size_t req_pull_ascii(struct smbsrv_request *req, const char **dest, cons
                }
        }
 
-       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->mem_ctx, 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;
 }
@@ -538,7 +576,7 @@ static size_t req_pull_ascii(struct smbsrv_request *req, const char **dest, cons
   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)))) {
@@ -558,13 +596,13 @@ size_t req_pull_string(struct smbsrv_request *req, const char **dest, const char
   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;
 
        if (PTR_DIFF(src, req->in.data) + 1 > req->in.data_size) {
                /* win2000 treats this as the NULL string! */
-               (*dest) = talloc_strdup(req->mem_ctx, "");
+               (*dest) = talloc_strdup(req, "");
                return 0;
        }
 
@@ -575,7 +613,7 @@ size_t req_pull_ascii4(struct smbsrv_request *req, const char **dest, const char
 
        ret = req_pull_string(req, dest, src, -1, flags);
        if (ret == -1) {
-               (*dest) = talloc_strdup(req->mem_ctx, "");
+               (*dest) = talloc_strdup(req, "");
                return 1;
        }
        
@@ -587,20 +625,20 @@ size_t req_pull_ascii4(struct smbsrv_request *req, const char **dest, const char
 
   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;
        }
 
-       (*blob) = data_blob_talloc(req->mem_ctx, src, len);
+       (*blob) = data_blob_talloc(req, src, len);
 
        return True;
 }
 
 /* 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;
@@ -620,7 +658,7 @@ BOOL req_data_oob(struct smbsrv_request *req, const char *ptr, uint32_t count)
 /* 
    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;