summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/smbd/process.c288
-rw-r--r--source3/smbd/server.c288
2 files changed, 288 insertions, 288 deletions
diff --git a/source3/smbd/process.c b/source3/smbd/process.c
index 1c8d8a6e76..eca51a74a3 100644
--- a/source3/smbd/process.c
+++ b/source3/smbd/process.c
@@ -22,6 +22,7 @@
extern struct auth_context *negprot_global_auth_context;
extern int smb_echo_count;
+extern int smb_read_error;
const int total_buffer_size = (BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE + SAFETY_MARGIN);
@@ -44,6 +45,293 @@ SIG_ATOMIC_T got_sig_term = 0;
extern bool global_machine_password_needs_changing;
extern int max_send;
+/* Socket functions for smbd packet processing. */
+
+static bool valid_packet_size(len)
+{
+ /*
+ * A WRITEX with CAP_LARGE_WRITEX can be 64k worth of data plus 65 bytes
+ * of header. Don't print the error if this fits.... JRA.
+ */
+
+ if (len > (BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE)) {
+ DEBUG(0,("Invalid packet length! (%lu bytes).\n",
+ (unsigned long)len));
+ if (len > BUFFER_SIZE + (SAFETY_MARGIN/2)) {
+
+ /*
+ * Correct fix. smb_read_error may have already been
+ * set. Only set it here if not already set. Global
+ * variables still suck :-). JRA.
+ */
+
+ if (smb_read_error == 0)
+ smb_read_error = READ_ERROR;
+ return false;
+ }
+ }
+ return true;
+}
+
+static ssize_t read_packet_remainder(int fd,
+ char *buffer,
+ unsigned int timeout,
+ ssize_t len)
+{
+ ssize_t ret;
+
+ if(len <= 0) {
+ return len;
+ }
+
+ if (timeout > 0) {
+ ret = read_socket_with_timeout(fd,
+ buffer,
+ len,
+ len,
+ timeout);
+ } else {
+ ret = read_data(fd, buffer, len);
+ }
+
+ if (ret != len) {
+ if (smb_read_error == 0) {
+ smb_read_error = READ_ERROR;
+ }
+ return -1;
+ }
+
+ return len;
+}
+
+/****************************************************************************
+ Attempt a zerocopy writeX read. We know here that len > smb_size-4
+****************************************************************************/
+
+/*
+ * Unfortunately, earlier versions of smbclient/libsmbclient
+ * don't send this "standard" writeX header. I've fixed this
+ * for 3.2 but we'll use the old method with earlier versions.
+ * Windows and CIFSFS at least use this standard size. Not
+ * sure about MacOSX.
+ */
+
+#define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
+ (2*14) + /* word count (including bcc) */ \
+ 1 /* pad byte */)
+
+ssize_t receive_smb_raw_talloc_partial_read(TALLOC_CTX *mem_ctx,
+ const char lenbuf[4],
+ int fd,
+ char **buffer,
+ unsigned int timeout,
+ size_t *p_unread)
+{
+ /* Size of a WRITEX call (+4 byte len). */
+ char writeX_header[4 + STANDARD_WRITE_AND_X_HEADER_SIZE];
+ ssize_t len = smb_len_large(lenbuf); /* Could be a UNIX large writeX. */
+ ssize_t toread;
+ ssize_t ret;
+
+ memcpy(writeX_header, lenbuf, sizeof(lenbuf));
+
+ if (timeout > 0) {
+ ret = read_socket_with_timeout(fd,
+ writeX_header + 4,
+ STANDARD_WRITE_AND_X_HEADER_SIZE,
+ STANDARD_WRITE_AND_X_HEADER_SIZE,
+ timeout);
+ } else {
+ ret = read_data(fd,
+ writeX_header+4,
+ STANDARD_WRITE_AND_X_HEADER_SIZE);
+ }
+
+ if (ret != STANDARD_WRITE_AND_X_HEADER_SIZE) {
+ if (smb_read_error == 0) {
+ smb_read_error = READ_ERROR;
+ }
+ return -1;
+ }
+
+ /*
+ * Ok - now try and see if this is a possible
+ * valid writeX call.
+ */
+
+ if (is_valid_writeX_buffer(writeX_header)) {
+ /*
+ * If the data offset is beyond what
+ * we've read, drain the extra bytes.
+ */
+ uint16_t doff = SVAL(writeX_header,smb_vwv11);
+ ssize_t newlen;
+
+ if (doff > STANDARD_WRITE_AND_X_HEADER_SIZE) {
+ size_t drain = doff - STANDARD_WRITE_AND_X_HEADER_SIZE;
+ if (drain_socket(smbd_server_fd(), drain) != drain) {
+ smb_panic("receive_smb_raw_talloc_partial_read:"
+ " failed to drain pending bytes");
+ }
+ } else {
+ doff = STANDARD_WRITE_AND_X_HEADER_SIZE;
+ }
+
+ /* Spoof down the length and null out the bcc. */
+ set_message_bcc(writeX_header, 0);
+ newlen = smb_len(writeX_header);
+
+ /* Copy the header we've written. */
+
+ *buffer = TALLOC_MEMDUP(mem_ctx,
+ writeX_header,
+ sizeof(writeX_header));
+
+ if (*buffer == NULL) {
+ DEBUG(0, ("Could not allocate inbuf of length %d\n",
+ (int)sizeof(writeX_header)));
+ if (smb_read_error == 0)
+ smb_read_error = READ_ERROR;
+ return -1;
+ }
+
+ /* Work out the remaining bytes. */
+ *p_unread = len - STANDARD_WRITE_AND_X_HEADER_SIZE;
+
+ return newlen + 4;
+ }
+
+ if (!valid_packet_size(len)) {
+ return -1;
+ }
+
+ /*
+ * Not a valid writeX call. Just do the standard
+ * talloc and return.
+ */
+
+ *buffer = TALLOC_ARRAY(mem_ctx, char, len+4);
+
+ if (*buffer == NULL) {
+ DEBUG(0, ("Could not allocate inbuf of length %d\n",
+ (int)len+4));
+ if (smb_read_error == 0)
+ smb_read_error = READ_ERROR;
+ return -1;
+ }
+
+ /* Copy in what we already read. */
+ memcpy(*buffer,
+ writeX_header,
+ 4 + STANDARD_WRITE_AND_X_HEADER_SIZE);
+ toread = len - STANDARD_WRITE_AND_X_HEADER_SIZE;
+
+ if(toread > 0) {
+ ret = read_packet_remainder(fd,
+ (*buffer) + 4 + STANDARD_WRITE_AND_X_HEADER_SIZE,
+ timeout,
+ toread);
+ if (ret != toread) {
+ return -1;
+ }
+ }
+
+ return len + 4;
+}
+
+static ssize_t receive_smb_raw_talloc(TALLOC_CTX *mem_ctx,
+ int fd,
+ char **buffer,
+ unsigned int timeout,
+ size_t *p_unread)
+{
+ char lenbuf[4];
+ ssize_t len,ret;
+ int min_recv_size = lp_min_receive_file_size();
+
+ smb_read_error = 0;
+ *p_unread = 0;
+
+ len = read_smb_length_return_keepalive(fd, lenbuf, timeout);
+ if (len < 0) {
+ DEBUG(10,("receive_smb_raw: length < 0!\n"));
+
+ /*
+ * Correct fix. smb_read_error may have already been
+ * set. Only set it here if not already set. Global
+ * variables still suck :-). JRA.
+ */
+
+ if (smb_read_error == 0)
+ smb_read_error = READ_ERROR;
+ return -1;
+ }
+
+ if (CVAL(lenbuf,0) != SMBkeepalive &&
+ min_recv_size &&
+ len > min_recv_size &&
+ !srv_is_signing_active()) {
+
+ return receive_smb_raw_talloc_partial_read(mem_ctx,
+ lenbuf,
+ fd,
+ buffer,
+ timeout,
+ p_unread);
+ }
+
+ if (!valid_packet_size(len)) {
+ return -1;
+ }
+
+ /*
+ * The +4 here can't wrap, we've checked the length above already.
+ */
+
+ *buffer = TALLOC_ARRAY(mem_ctx, char, len+4);
+
+ if (*buffer == NULL) {
+ DEBUG(0, ("Could not allocate inbuf of length %d\n",
+ (int)len+4));
+ if (smb_read_error == 0)
+ smb_read_error = READ_ERROR;
+ return -1;
+ }
+
+ memcpy(*buffer, lenbuf, sizeof(lenbuf));
+
+ ret = read_packet_remainder(fd, (*buffer)+4, timeout, len);
+ if (ret != len) {
+ return -1;
+ }
+
+ return len + 4;
+}
+
+ssize_t receive_smb_talloc(TALLOC_CTX *mem_ctx, int fd, char **buffer,
+ unsigned int timeout, size_t *p_unread)
+{
+ ssize_t len;
+
+ len = receive_smb_raw_talloc(mem_ctx, fd, buffer, timeout, p_unread);
+
+ if (len < 0) {
+ return -1;
+ }
+
+ /* Check the incoming SMB signature. */
+ if (!srv_check_sign_mac(*buffer, true)) {
+ DEBUG(0, ("receive_smb: SMB Signature verification failed on "
+ "incoming packet!\n"));
+ if (smb_read_error == 0) {
+ smb_read_error = READ_BAD_SIG;
+ }
+ return -1;
+ }
+
+ return len;
+}
+
/*
* Initialize a struct smb_request from an inbuf
*/
diff --git a/source3/smbd/server.c b/source3/smbd/server.c
index bac2d48ad6..fa8e163081 100644
--- a/source3/smbd/server.c
+++ b/source3/smbd/server.c
@@ -39,8 +39,6 @@ extern SIG_ATOMIC_T got_sig_term;
extern SIG_ATOMIC_T reload_after_sighup;
static SIG_ATOMIC_T got_sig_cld;
-extern int smb_read_error;
-
#ifdef WITH_DFS
extern int dcelogin_atmost_once;
#endif /* WITH_DFS */
@@ -64,292 +62,6 @@ static void smbd_set_server_fd(int fd)
client_setfd(fd);
}
-/* Socket functions for smbd packet processing. */
-
-static bool valid_packet_size(len)
-{
- /*
- * A WRITEX with CAP_LARGE_WRITEX can be 64k worth of data plus 65 bytes
- * of header. Don't print the error if this fits.... JRA.
- */
-
- if (len > (BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE)) {
- DEBUG(0,("Invalid packet length! (%lu bytes).\n",
- (unsigned long)len));
- if (len > BUFFER_SIZE + (SAFETY_MARGIN/2)) {
-
- /*
- * Correct fix. smb_read_error may have already been
- * set. Only set it here if not already set. Global
- * variables still suck :-). JRA.
- */
-
- if (smb_read_error == 0)
- smb_read_error = READ_ERROR;
- return false;
- }
- }
- return true;
-}
-
-static ssize_t read_packet_remainder(int fd,
- char *buffer,
- unsigned int timeout,
- ssize_t len)
-{
- ssize_t ret;
-
- if(len <= 0) {
- return len;
- }
-
- if (timeout > 0) {
- ret = read_socket_with_timeout(fd,
- buffer,
- len,
- len,
- timeout);
- } else {
- ret = read_data(fd, buffer, len);
- }
-
- if (ret != len) {
- if (smb_read_error == 0) {
- smb_read_error = READ_ERROR;
- }
- return -1;
- }
-
- return len;
-}
-
-/****************************************************************************
- Attempt a zerocopy writeX read. We know here that len > smb_size-4
-****************************************************************************/
-
-/*
- * Unfortunately, earlier versions of smbclient/libsmbclient
- * don't send this "standard" writeX header. I've fixed this
- * for 3.2 but we'll use the old method with earlier versions.
- * Windows and CIFSFS at least use this standard size. Not
- * sure about MacOSX.
- */
-
-#define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
- (2*14) + /* word count (including bcc) */ \
- 1 /* pad byte */)
-
-ssize_t receive_smb_raw_talloc_partial_read(TALLOC_CTX *mem_ctx,
- const char lenbuf[4],
- int fd,
- char **buffer,
- unsigned int timeout,
- size_t *p_unread)
-{
- /* Size of a WRITEX call (+4 byte len). */
- char writeX_header[4 + STANDARD_WRITE_AND_X_HEADER_SIZE];
- ssize_t len = smb_len_large(lenbuf); /* Could be a UNIX large writeX. */
- ssize_t toread;
- ssize_t ret;
-
- memcpy(writeX_header, lenbuf, sizeof(lenbuf));
-
- if (timeout > 0) {
- ret = read_socket_with_timeout(fd,
- writeX_header + 4,
- STANDARD_WRITE_AND_X_HEADER_SIZE,
- STANDARD_WRITE_AND_X_HEADER_SIZE,
- timeout);
- } else {
- ret = read_data(fd,
- writeX_header+4,
- STANDARD_WRITE_AND_X_HEADER_SIZE);
- }
-
- if (ret != STANDARD_WRITE_AND_X_HEADER_SIZE) {
- if (smb_read_error == 0) {
- smb_read_error = READ_ERROR;
- }
- return -1;
- }
-
- /*
- * Ok - now try and see if this is a possible
- * valid writeX call.
- */
-
- if (is_valid_writeX_buffer(writeX_header)) {
- /*
- * If the data offset is beyond what
- * we've read, drain the extra bytes.
- */
- uint16_t doff = SVAL(writeX_header,smb_vwv11);
- ssize_t newlen;
-
- if (doff > STANDARD_WRITE_AND_X_HEADER_SIZE) {
- size_t drain = doff - STANDARD_WRITE_AND_X_HEADER_SIZE;
- if (drain_socket(smbd_server_fd(), drain) != drain) {
- smb_panic("receive_smb_raw_talloc_partial_read:"
- " failed to drain pending bytes");
- }
- } else {
- doff = STANDARD_WRITE_AND_X_HEADER_SIZE;
- }
-
- /* Spoof down the length and null out the bcc. */
- set_message_bcc(writeX_header, 0);
- newlen = smb_len(writeX_header);
-
- /* Copy the header we've written. */
-
- *buffer = TALLOC_MEMDUP(mem_ctx,
- writeX_header,
- sizeof(writeX_header));
-
- if (*buffer == NULL) {
- DEBUG(0, ("Could not allocate inbuf of length %d\n",
- (int)sizeof(writeX_header)));
- if (smb_read_error == 0)
- smb_read_error = READ_ERROR;
- return -1;
- }
-
- /* Work out the remaining bytes. */
- *p_unread = len - STANDARD_WRITE_AND_X_HEADER_SIZE;
-
- return newlen + 4;
- }
-
- if (!valid_packet_size(len)) {
- return -1;
- }
-
- /*
- * Not a valid writeX call. Just do the standard
- * talloc and return.
- */
-
- *buffer = TALLOC_ARRAY(mem_ctx, char, len+4);
-
- if (*buffer == NULL) {
- DEBUG(0, ("Could not allocate inbuf of length %d\n",
- (int)len+4));
- if (smb_read_error == 0)
- smb_read_error = READ_ERROR;
- return -1;
- }
-
- /* Copy in what we already read. */
- memcpy(*buffer,
- writeX_header,
- 4 + STANDARD_WRITE_AND_X_HEADER_SIZE);
- toread = len - STANDARD_WRITE_AND_X_HEADER_SIZE;
-
- if(toread > 0) {
- ret = read_packet_remainder(fd,
- (*buffer) + 4 + STANDARD_WRITE_AND_X_HEADER_SIZE,
- timeout,
- toread);
- if (ret != toread) {
- return -1;
- }
- }
-
- return len + 4;
-}
-
-static ssize_t receive_smb_raw_talloc(TALLOC_CTX *mem_ctx,
- int fd,
- char **buffer,
- unsigned int timeout,
- size_t *p_unread)
-{
- char lenbuf[4];
- ssize_t len,ret;
- int min_recv_size = lp_min_receive_file_size();
-
- smb_read_error = 0;
- *p_unread = 0;
-
- len = read_smb_length_return_keepalive(fd, lenbuf, timeout);
- if (len < 0) {
- DEBUG(10,("receive_smb_raw: length < 0!\n"));
-
- /*
- * Correct fix. smb_read_error may have already been
- * set. Only set it here if not already set. Global
- * variables still suck :-). JRA.
- */
-
- if (smb_read_error == 0)
- smb_read_error = READ_ERROR;
- return -1;
- }
-
- if (CVAL(lenbuf,0) != SMBkeepalive &&
- min_recv_size &&
- len > min_recv_size &&
- !srv_is_signing_active()) {
-
- return receive_smb_raw_talloc_partial_read(mem_ctx,
- lenbuf,
- fd,
- buffer,
- timeout,
- p_unread);
- }
-
- if (!valid_packet_size(len)) {
- return -1;
- }
-
- /*
- * The +4 here can't wrap, we've checked the length above already.
- */
-
- *buffer = TALLOC_ARRAY(mem_ctx, char, len+4);
-
- if (*buffer == NULL) {
- DEBUG(0, ("Could not allocate inbuf of length %d\n",
- (int)len+4));
- if (smb_read_error == 0)
- smb_read_error = READ_ERROR;
- return -1;
- }
-
- memcpy(*buffer, lenbuf, sizeof(lenbuf));
-
- ret = read_packet_remainder(fd, (*buffer)+4, timeout, len);
- if (ret != len) {
- return -1;
- }
-
- return len + 4;
-}
-
-ssize_t receive_smb_talloc(TALLOC_CTX *mem_ctx, int fd, char **buffer,
- unsigned int timeout, size_t *p_unread)
-{
- ssize_t len;
-
- len = receive_smb_raw_talloc(mem_ctx, fd, buffer, timeout, p_unread);
-
- if (len < 0) {
- return -1;
- }
-
- /* Check the incoming SMB signature. */
- if (!srv_check_sign_mac(*buffer, true)) {
- DEBUG(0, ("receive_smb: SMB Signature verification failed on "
- "incoming packet!\n"));
- if (smb_read_error == 0) {
- smb_read_error = READ_BAD_SIG;
- }
- return -1;
- }
-
- return len;
-}
struct event_context *smbd_event_context(void)
{