r4728: split up server_services into:
[gd/samba-autobuild/.git] / source4 / smb_server / request.c
index 07b2ee0575b0c99bf0197916cdbc652008200bba..f7f39f39d5925f8ddae759f5d78a381403eee224 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_free(req);
@@ -49,8 +47,6 @@ struct smbsrv_request *init_smb_request(struct smbsrv_connection *smb_conn)
 {
        struct smbsrv_request *req;
 
-       smb_conn->socket.pkt_count++;
-
        req = talloc_p(smb_conn, struct smbsrv_request);
        if (!req) {
                return NULL;
@@ -60,7 +56,14 @@ struct smbsrv_request *init_smb_request(struct smbsrv_connection *smb_conn)
 
        /* 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;
 }
 
@@ -78,9 +81,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->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;
@@ -102,6 +107,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;
@@ -112,9 +119,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, 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;
@@ -129,13 +145,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);
 
@@ -154,6 +166,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
@@ -182,7 +225,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) {
@@ -192,7 +235,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->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");
        }
@@ -247,23 +290,16 @@ void req_grow_data(struct smbsrv_request *req, uint_t new_size)
 */
 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;
 }
 
 /*
@@ -349,11 +385,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))) {
@@ -379,7 +415,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);
 
@@ -431,10 +467,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++;
@@ -458,19 +495,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, 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;
 }
@@ -488,10 +525,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;
@@ -506,18 +544,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, 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;
 }
@@ -535,7 +574,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)))) {
@@ -555,7 +594,7 @@ 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;
 
@@ -584,7 +623,7 @@ 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;
@@ -597,7 +636,7 @@ BOOL req_pull_blob(struct smbsrv_request *req, const char *src, int len, DATA_BL
 
 /* 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;
@@ -617,7 +656,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;