diff --git a/documentation/history.doc b/documentation/history.doc index 1b98e77..18bf91d 100644 --- a/documentation/history.doc +++ b/documentation/history.doc @@ -1315,3 +1315,32 @@ smbfs 1.122 (5.5.2018) NetBIOS frame size came out as 65583 bytes (which the NetBIOS frame handles fine), and the size parameter being a 16 bit integer, the truncated size (47 bytes) wreaked havoc all over the place. + + +smbfs 1.123 (6.5.2018) + +- smb_proc_readdir_long() could return an error code which would be + mistaken as the number of directory entries available. The error + code should have been negative. Fixed. + +- Action_ExamineObject() failed to compare the correct file name + length against the maximum permitted file name length. It retained + the full path name length, which could lead to the operation being + aborted. The same problem also existed in Action_ExamineFH(). + +- The buffer size check in the UTF-8 conversion code used by + Action_ExamineObject() should have verified that the name in + ISO 8859-1 form fits into the name buffer. Fixed. + +- Time stamps used for cache validation are now unsigned integers + rather than signed integers. + + +smbfs 1.124 (6.5.2018) + +- recv() returning 0 is now consistently treated as it should + be: end of stream. + +- SMB_COM_READ now receives the inbound data straight into the + file read buffer instead of into the packet buffer, from which + it would then be copied into the file read buffer. diff --git a/source_code/include/smb/smb_fs.h b/source_code/include/smb/smb_fs.h index bc510fc..cadb6e2 100644 --- a/source_code/include/smb/smb_fs.h +++ b/source_code/include/smb/smb_fs.h @@ -69,13 +69,11 @@ int smb_proc_dskattr (struct smb_server *server, struct smb_dskattr *attr); int smb_proc_connect(struct smb_server *server); /* sock.c */ -int smb_receive (struct smb_server *server, int sock_fd); -int smb_receive_with_payload (struct smb_server *server, int sock_fd, void * payload, int payload_size, int * payload_size_received); int smb_catch_keepalive(struct smb_server *server); int smb_dont_catch_keepalive(struct smb_server *server); void smb_release(struct smb_server *server); int smb_connect(struct smb_server *server); -int smb_request(struct smb_server *server,const void * payload,int payload_size); +int smb_request(struct smb_server *server,void * input_payload,const void * output_payload,int payload_size); int smb_trans2_request(struct smb_server *server, int *data_len, int *param_len, char **data, char **param); int smb_request_read_raw(struct smb_server *server, unsigned char *target, int max_len); int smb_request_write_raw(struct smb_server *server, unsigned const char *source, int length); diff --git a/source_code/main.c b/source_code/main.c index a04a1b8..321e3ab 100644 --- a/source_code/main.c +++ b/source_code/main.c @@ -26,8 +26,8 @@ * copy "amiga:Public/Documents/Amiga Files/Shared/dir/Windows-Export/LP2NRFP.h" ram: * smbfs.debug user=guest volume=sicherung //192.168.1.76/sicherung-smb * smbfs maxtransmit=16600 debuglevel=2 dumpsmb dumpsmblevel=2 domain=workgroup user=olsen password=... volume=olsen //felix/olsen - * smbfs debuglevel=2 dumpsmb dumpsmblevel=2 volume=ubuntu-test //192.168.1.33/test - * smbfs debuglevel=2 dumpsmb dumpsmblevel=2 user=olsen password=... volume=olsen //192.168.1.118/olsen + * Samba 4.6.7: smbfs debuglevel=2 dumpsmb dumpsmblevel=2 volume=ubuntu-test //192.168.1.33/test + * Samba 3.0.25: smbfs debuglevel=2 dumpsmb dumpsmblevel=1 user=olsen password=... volume=olsen //192.168.1.118/olsen */ #include "smbfs.h" @@ -4296,6 +4296,8 @@ Action_ExamineObject( SHOWMSG("ZERO root lock"); + ASSERT( len < sizeof(fib->fib_FileName) ); + memcpy(&fib->fib_FileName[1],&volume_name[1],len); fib->fib_FileName[0] = len; @@ -4339,6 +4341,8 @@ Action_ExamineObject( SHOWMSG("root lock"); + ASSERT( len < sizeof(fib->fib_FileName) ); + memcpy(&fib->fib_FileName[1],&volume_name[1],len); fib->fib_FileName[0] = len; @@ -4351,32 +4355,25 @@ Action_ExamineObject( else { const UBYTE * name; - LONG name_len; - LONG i; + int name_len; + int i; name = ln->ln_FullName; name_len = strlen(name); + /* We just want the base name, not the path + * leading up to it. + */ for(i = name_len-1 ; i >= 0 ; i--) { if(name[i] == SMB_PATH_SEPARATOR) { name = &name[i+1]; - - /* We just lost a character and need to account for it. */ - name_len--; - + name_len -= i+1; break; } } - /* Just checking: will the name fit? */ - if(name_len >= sizeof(fib->fib_FileName)) - { - error = ERROR_INVALID_COMPONENT_NAME; - goto out; - } - /* Translate the name of the file/directory from UTF-8 * into AmigaOS ISO 8859-1 (ISO Latin 1) encoding? */ @@ -4385,13 +4382,13 @@ Action_ExamineObject( UBYTE decoded_name[MAX_FILENAME_LEN]; int decoded_name_len; - /* Try to decode the file file, translating it into ISO 8859-1 format. */ + /* Try to decode the file name, translating it into ISO 8859-1 format. */ decoded_name_len = decode_utf8_as_iso8859_1_string(name,name_len,NULL,0); /* Decoding error occured, or the decoded name would be longer than * buffer would allow? */ - if(decoded_name_len < 0 || decoded_name_len >= MAX_FILENAME_LEN) + if(decoded_name_len < 0 || decoded_name_len >= sizeof(fib->fib_FileName)) { error = ERROR_INVALID_COMPONENT_NAME; goto out; @@ -4408,6 +4405,13 @@ Action_ExamineObject( } else { + /* Will the name fit? */ + if(name_len >= sizeof(fib->fib_FileName)) + { + error = ERROR_INVALID_COMPONENT_NAME; + goto out; + } + /* Store the file/directory name in the form expected * by dos.library. */ @@ -5844,17 +5848,11 @@ Action_ExamineFH( if(name[i] == SMB_PATH_SEPARATOR) { name = &name[i+1]; + name_len -= i+1; break; } } - /* Just checking: will the name fit? */ - if(name_len >= sizeof(fib->fib_FileName)) - { - error = ERROR_INVALID_COMPONENT_NAME; - goto out; - } - memset(fib,0,sizeof(*fib)); if(TranslateUTF8) @@ -5863,7 +5861,7 @@ Action_ExamineFH( int decoded_name_len; decoded_name_len = decode_utf8_as_iso8859_1_string(name,name_len,NULL,0); - if(decoded_name_len < 0 || decoded_name_len >= MAX_FILENAME_LEN) + if(decoded_name_len < 0 || decoded_name_len >= sizeof(fib->fib_FileName)) { error = ERROR_INVALID_COMPONENT_NAME; goto out; @@ -5876,6 +5874,13 @@ Action_ExamineFH( } else { + /* Will the name fit? */ + if(name_len >= sizeof(fib->fib_FileName)) + { + error = ERROR_INVALID_COMPONENT_NAME; + goto out; + } + ConvertCString(fib->fib_FileName,sizeof(fib->fib_FileName),name,name_len); if(TranslateNames) diff --git a/source_code/proc.c b/source_code/proc.c index dc56b73..5e9734c 100644 --- a/source_code/proc.c +++ b/source_code/proc.c @@ -702,7 +702,8 @@ smb_request_ok_with_payload ( int command, int wct, int bcc, - const void * payload, + void * input_payload, + const void * output_payload, int payload_size) { int result; @@ -712,7 +713,7 @@ smb_request_ok_with_payload ( s->err = 0; /* Send the message and wait for the response to arrive. */ - result = smb_request (s, payload, payload_size); + result = smb_request (s, input_payload, output_payload, payload_size); /* smb_request() failed? */ if (result < 0) @@ -751,7 +752,7 @@ smb_request_ok_with_payload ( static int smb_request_ok (struct smb_server *s, int command, int wct, int bcc) { - return(smb_request_ok_with_payload (s, command, wct, bcc, NULL, 0)); + return(smb_request_ok_with_payload (s, command, wct, bcc, NULL, NULL, 0)); } /* smb_retry: This function should be called when smb_request_ok has @@ -977,7 +978,6 @@ smb_proc_close (struct smb_server *server, word fileid, dword mtime) int smb_proc_read (struct smb_server *server, struct smb_dirent *finfo, off_t offset, long count, char *data) { - word returned_count, data_len; char *buf = server->transmit_buffer; int result; int error; @@ -991,31 +991,69 @@ smb_proc_read (struct smb_server *server, struct smb_dirent *finfo, off_t offset DSET (buf, smb_vwv2, offset); WSET (buf, smb_vwv4, 0); - if ((error = smb_request_ok (server, SMBread, 5, -1)) < 0) + #if 1 { - result = error; - goto out; + int buffer_format; + + LOG(("smb_proc_read: requesting %ld bytes\n", count)); + + if ((error = smb_request_ok_with_payload (server, SMBread, 5, -1, data, NULL, count)) < 0) + { + LOG(("smb_proc_read: error=%ld\n", error)); + + result = error; + goto out; + } + + buffer_format = BVAL(buf, NETBIOS_HEADER_SIZE+45); + LOG(("smb_proc_read: buffer_format=%ld, should be %ld\n", buffer_format, 1)); + + /* The buffer format must be 1. */ + if(buffer_format == 1) + { + result = WVAL (buf, NETBIOS_HEADER_SIZE+46); /* count of bytes to read */ + + ASSERT( result <= count ); + + LOG(("smb_proc_read: read %ld bytes (should be < %ld)\n", result, count)); + } + else + { + LOG(("smb_proc_read: returning EOF\n")); + result = 0; + } } - - returned_count = WVAL (buf, smb_vwv0); - - /* ZZZ olsen 2018-05-01: this should not be necessary; we should be - * able to break this down into two subsequent - * recv() calls. - */ - smb_decode_data (SMB_BUF (server->transmit_buffer), data, &data_len); - - if (returned_count != data_len) + #else { - LOG (("Warning, returned_count != data_len\n")); - LOG (("ret_c=%ld, data_len=%ld\n", returned_count, data_len)); - } - else - { - LOG (("ret_c=%ld, data_len=%ld\n", returned_count, data_len)); - } + word returned_count, data_len; - result = data_len; + if ((error = smb_request_ok_with_payload (server, SMBread, 5, -1, data, NULL, count)) < 0) + { + result = error; + goto out; + } + + returned_count = WVAL (buf, smb_vwv0); + + /* ZZZ olsen 2018-05-01: this should not be necessary; we should be + * able to break this down into two subsequent + * recv() calls. + */ + smb_decode_data (SMB_BUF (server->transmit_buffer), data, &data_len); + + if (returned_count != data_len) + { + LOG (("Warning, returned_count != data_len\n")); + LOG (("ret_c=%ld, data_len=%ld\n", returned_count, data_len)); + } + else + { + LOG (("ret_c=%ld, data_len=%ld\n", returned_count, data_len)); + } + + result = data_len; + } + #endif out: @@ -1065,7 +1103,7 @@ smb_proc_write (struct smb_server *server, struct smb_dirent *finfo, off_t offse (*p++) = 1; /* Buffer format - this field must be 1 */ WSET (p, 0, count); /* Data length - this field must match what the count field in the SMB header says */ - if ((res = smb_request_ok_with_payload (server, SMBwrite, 1, 0, data, count)) >= 0) + if ((res = smb_request_ok_with_payload (server, SMBwrite, 1, 0, NULL, data, count)) >= 0) res = WVAL (buf, smb_vwv0); return res; @@ -1158,7 +1196,7 @@ smb_proc_write_raw (struct smb_server *server, struct smb_dirent *finfo, off_t o LOG(("requesting SMBwritebraw\n")); - result = smb_request_ok_with_payload (server, SMBwritebraw, 1, 0, data, len); + result = smb_request_ok_with_payload (server, SMBwritebraw, 1, 0, NULL, data, len); if (result < 0) goto out; @@ -2122,7 +2160,7 @@ smb_proc_readdir_long (struct smb_server *server, char *path, int fpos, int cach smb_printerr (server->rcls, server->err); - error = smb_errno (server->rcls, server->err); + error = -smb_errno (server->rcls, server->err); SHOWVALUE(error); break; } @@ -2631,7 +2669,7 @@ smb_proc_reconnect (struct smb_server *server) packet[0] = 0x81; /* SESSION REQUEST */ - if ((result = smb_request (server, NULL, 0)) < 0) + if ((result = smb_request (server, NULL, NULL, 0)) < 0) { LOG (("smb_proc_connect: Failed to send SESSION REQUEST.\n")); goto fail; diff --git a/source_code/smb_abstraction.c b/source_code/smb_abstraction.c index 4504cbe..0696123 100644 --- a/source_code/smb_abstraction.c +++ b/source_code/smb_abstraction.c @@ -20,8 +20,8 @@ /*****************************************************************************/ -#define ATTR_CACHE_TIME 5 /* cache attributes for this time */ -#define DIR_CACHE_TIME 5 /* cache directories for this time */ +#define ATTR_CACHE_TIME 5 /* cache attributes for this time (seconds) */ +#define DIR_CACHE_TIME 5 /* cache directories for this time (seconds) */ #define DIRCACHE_SIZE 170 #define DOS_PATHSEP '\\' @@ -32,7 +32,7 @@ typedef struct dircache int base; int len; int eof; /* cache end is eof */ - long created_at; /* for invalidation */ + ULONG created_at; /* for invalidation */ struct smba_file * cache_for; /* owner of this cache */ int cache_size; struct smb_dirent cache[1]; @@ -53,7 +53,7 @@ struct smba_file struct MinNode node; struct smba_server * server; struct smb_dirent dirent; - long attr_time; /* time when dirent was read */ + ULONG attr_time; /* time when dirent was read */ dircache_t * dircache; /* content cache for directories */ unsigned attr_dirty:1; /* attribute cache is dirty */ unsigned is_valid:1; /* server was down, entry removed, ... */ @@ -79,7 +79,7 @@ struct smba_file /*****************************************************************************/ -static INLINE int make_open(smba_file_t *f, int need_fid); +static int make_open(smba_file_t *f, int need_fid); static int write_attr(smba_file_t *f); static void invalidate_dircache(struct smba_server *server, char *path); static void close_path(smba_server_t *s, char *path); @@ -256,7 +256,7 @@ smba_disconnect (smba_server_t * server) /*****************************************************************************/ -static INLINE int +static int make_open (smba_file_t * f, int need_fid) { smba_server_t *s; @@ -264,9 +264,11 @@ make_open (smba_file_t * f, int need_fid) if (!f->is_valid || (need_fid && !f->dirent.opened)) { + ULONG now = GetCurrentTime(); + s = f->server; - if (!f->is_valid || f->attr_time == -1 || GetCurrentTime() - f->attr_time > ATTR_CACHE_TIME) + if (!f->is_valid || f->attr_time == 0 || (now > f->attr_time && now - f->attr_time > ATTR_CACHE_TIME)) { errnum = smb_proc_getattr_core (&s->server, f->dirent.complete_path, f->dirent.len, &f->dirent); if (errnum < 0) @@ -385,7 +387,7 @@ write_attr (smba_file_t * f) if (errnum < 0) { - f->attr_time = -1; + f->attr_time = 0; goto out; } @@ -765,7 +767,7 @@ smba_write (smba_file_t * f, char *data, long len, long offset) out: if (result < 0) - f->attr_time = -1; + f->attr_time = 0; else if (result > 0) f->dirent.mtime = GetCurrentTime(); @@ -862,9 +864,9 @@ smba_lockrec (smba_file_t *f, long offset, long len, long mode, int unlocked, lo int smba_getattr (smba_file_t * f, smba_stat_t * data) { - long now = GetCurrentTime(); int errnum; int result; + ULONG now; errnum = make_open (f, 0); if (errnum < 0) @@ -873,7 +875,9 @@ smba_getattr (smba_file_t * f, smba_stat_t * data) goto out; } - if (f->attr_time == -1 || (now - f->attr_time) > ATTR_CACHE_TIME) + now = GetCurrentTime(); + + if (f->attr_time == 0 || (now > f->attr_time && now - f->attr_time > ATTR_CACHE_TIME)) { LOG (("file %s\n", f->dirent.complete_path)); @@ -982,11 +986,11 @@ int smba_readdir (smba_file_t * f, long offs, void *d, smba_callback_t callback) { int cache_index, o, eof, count = 0; - long now = GetCurrentTime(); int num_entries; smba_stat_t data; int result; int errnum; + ULONG now; errnum = make_open (f, 0); if (errnum < 0) @@ -995,6 +999,8 @@ smba_readdir (smba_file_t * f, long offs, void *d, smba_callback_t callback) goto out; } + now = GetCurrentTime(); + if (f->dircache == NULL) /* get a cache */ { dircache_t * dircache = f->server->dircache; @@ -1011,7 +1017,7 @@ smba_readdir (smba_file_t * f, long offs, void *d, smba_callback_t callback) } else { - if ((now - f->dircache->created_at) >= DIR_CACHE_TIME) + if (now > f->dircache->created_at && now - f->dircache->created_at >= DIR_CACHE_TIME) { f->dircache->eof = f->dircache->len = f->dircache->base = 0; @@ -1034,6 +1040,7 @@ smba_readdir (smba_file_t * f, long offs, void *d, smba_callback_t callback) f->dircache->base = cache_index; num_entries = smb_proc_readdir (&f->server->server, f->dirent.complete_path, cache_index, f->dircache->cache_size, f->dircache->cache); + /* We stop on error, or if the directory is empty. */ if (num_entries <= 0) { @@ -1043,12 +1050,11 @@ smba_readdir (smba_file_t * f, long offs, void *d, smba_callback_t callback) /* Avoid some hits if restart/retry occured. Should fix the real root * of this problem really, but I am not bored enough atm. -Piru - * ZZZ this needs further investigation. */ if (f->dircache == NULL) { LOG (("lost dircache due to an error, bailing out!\n")); - result = -ENOSPC; + result = -ENOMEM; goto out; } diff --git a/source_code/smbfs_rev.h b/source_code/smbfs_rev.h index 0e99fcf..f647e94 100644 --- a/source_code/smbfs_rev.h +++ b/source_code/smbfs_rev.h @@ -1,6 +1,6 @@ #define VERSION 1 -#define REVISION 122 -#define DATE "5.5.2018" -#define VERS "smbfs 1.122" -#define VSTRING "smbfs 1.122 (5.5.2018)\r\n" -#define VERSTAG "\0$VER: smbfs 1.122 (5.5.2018)" +#define REVISION 124 +#define DATE "6.5.2018" +#define VERS "smbfs 1.124" +#define VSTRING "smbfs 1.124 (6.5.2018)\r\n" +#define VERSTAG "\0$VER: smbfs 1.124 (6.5.2018)" diff --git a/source_code/smbfs_rev.rev b/source_code/smbfs_rev.rev index 9f54fe3..fc902f4 100644 --- a/source_code/smbfs_rev.rev +++ b/source_code/smbfs_rev.rev @@ -1 +1 @@ -122 +124 diff --git a/source_code/sock.c b/source_code/sock.c index e3b6686..6254653 100644 --- a/source_code/sock.c +++ b/source_code/sock.c @@ -57,10 +57,17 @@ /* smb_receive_raw: The NetBIOS header is only stored if want_header != 0. */ static int -smb_receive_raw (const struct smb_server *server, int sock_fd, unsigned char *target, int max_raw_length, int want_header) +smb_receive_raw ( + const struct smb_server * server, + int sock_fd, + unsigned char * target, + int max_raw_length, + char * input_payload, + int input_payload_size, + int want_header) { int len, result; - int already_read; + int num_bytes_received; unsigned char netbios_session_buf[256]; int netbios_session_payload_size; @@ -68,6 +75,14 @@ smb_receive_raw (const struct smb_server *server, int sock_fd, unsigned char *ta /* Read the NetBIOS session header (rfc-1002, section 4.3.1) */ result = recv (sock_fd, netbios_session_buf, NETBIOS_HEADER_SIZE, 0); + if(result == 0) + { + LOG (("smb_receive_raw: EOF\n")); + + /* End of file */ + goto out; + } + if (result < 0) { LOG (("smb_receive_raw: recv error = %ld\n", errno)); @@ -144,7 +159,7 @@ smb_receive_raw (const struct smb_server *server, int sock_fd, unsigned char *ta goto out; } - /* The length in the RFC NB header is the raw data length (17 bits) */ + /* The length in the NetBIOS header is the raw data length (17 bits) */ len = netbios_session_payload_size; if (len > max_raw_length) { @@ -170,35 +185,190 @@ smb_receive_raw (const struct smb_server *server, int sock_fd, unsigned char *ta target += NETBIOS_HEADER_SIZE; } - for(already_read = 0 ; already_read < len ; already_read += result) + /* This is an optimization for the SMB_COM_READ command, which + * tries to avoid copying the received data twice. To this end + * we receive the SMB_COM_READ response up to the point at which + * the message header ends and the data returned by the server + * begins. Then we read the data, storing it directly in the + * receive buffer rather than in the packet buffer, from which + * it would have to be retrieved later. + */ + if(input_payload != NULL) { - result = recv (sock_fd, (void *) (target + already_read), len - already_read, 0); - if (result < 0) + int buffer_format; + + LOG(("input_payload=0x%08lx, payload_size=%ld\n", input_payload, input_payload_size)); + + /* We need to read the following data: + * + * 0: 32 bytes of SMB message header + * 32: 1 byte of word count + * 33: 2 bytes of 'count of bytes returned' (1 word) + * 35: 8 bytes of reserved data (4 words) + * 43: 2 bytes of 'byte count' (1 word) + * 45: 1 byte of 'buffer format' + * 46: 2 bytes of 'count of bytes to read' (1 word). + * + * This adds up to 48 bytes. + */ + + LOG(("reading the first %ld bytes\n", 48)); + + for(num_bytes_received = 0 ; num_bytes_received < 48 && num_bytes_received < len ; num_bytes_received += result) { - LOG (("smb_receive_raw: recvfrom error = %ld\n", errno)); + result = recv (sock_fd, (void *)&target[num_bytes_received], 48 - num_bytes_received, 0); + if(result == 0) + { + /* End of file */ + LOG (("smb_receive_raw: EOF\n")); + break; + } - result = (-errno); + if (result < 0) + { + LOG (("smb_receive_raw: recvfrom error = %ld\n", errno)); + result = (-errno); + + goto out; + } + } + + ASSERT( num_bytes_received == 48 ); + + /* End of file reached? */ + if(num_bytes_received < 48) + { + result = 0; goto out; } + + /* So we read the header. Now we need to figure out if the + * data is in the expected format, and how many bytes are + * waiting to be read. + */ + + /* The buffer format must be 1. */ + buffer_format = BVAL(target, 45); + + LOG(("buffer format = %ld, should be %ld\n", buffer_format, 1)); + + if(buffer_format == 1) + { + int count_of_bytes_returned; + int count_of_bytes_to_read; + int num_data_bytes_received; + + count_of_bytes_returned = WVAL(target, 33); + count_of_bytes_to_read = WVAL(target, 46); + + /* That should never be more data than the read buffer may hold. */ + ASSERT( count_of_bytes_to_read <= input_payload_size ); + ASSERT( count_of_bytes_to_read <= count_of_bytes_returned ); + ASSERT( count_of_bytes_returned <= input_payload_size ); + + LOG(("count of bytes to read = %ld, should be <= %ld\n", count_of_bytes_to_read, input_payload_size)); + + for(num_data_bytes_received = 0 ; + num_data_bytes_received < count_of_bytes_to_read && num_bytes_received < len ; + num_data_bytes_received += result, num_bytes_received += result) + { + result = recv (sock_fd, (void *)&input_payload[num_data_bytes_received], count_of_bytes_to_read - num_data_bytes_received, 0); + if(result == 0) + { + /* End of file */ + LOG (("smb_receive_raw: EOF\n")); + break; + } + + if (result < 0) + { + LOG (("smb_receive_raw: recvfrom error = %ld\n", errno)); + + result = (-errno); + + goto out; + } + } + + ASSERT( count_of_bytes_to_read == count_of_bytes_returned ); + + if(count_of_bytes_to_read < count_of_bytes_returned) + { + LOG(("fewer data available than should be delivered; setting the remainder (%ld bytes) to 0.\n", count_of_bytes_returned - count_of_bytes_to_read)); + + memset(&input_payload[count_of_bytes_to_read],0,count_of_bytes_returned - count_of_bytes_to_read); + } + } + + /* This should never happen, but then we better make sure to + * read the entire message. + */ + if(num_bytes_received < len) + { + LOG(("reading the remaining %ld bytes; this should never happen\n", len - num_bytes_received )); + + for( ; num_bytes_received < len ; num_bytes_received += result) + { + result = recv (sock_fd, (void *)&target[num_bytes_received], len - num_bytes_received, 0); + if(result == 0) + { + LOG (("smb_receive_raw: EOF\n")); + + /* End of file */ + break; + } + + if (result < 0) + { + LOG (("smb_receive_raw: recvfrom error = %ld\n", errno)); + + result = (-errno); + + goto out; + } + } + } + } + else + { + for(num_bytes_received = 0 ; num_bytes_received < len ; num_bytes_received += result) + { + result = recv (sock_fd, (void *)&target[num_bytes_received], len - num_bytes_received, 0); + if(result == 0) + { + /* End of file */ + LOG (("smb_receive_raw: EOF\n")); + break; + } + + if (result < 0) + { + LOG (("smb_receive_raw: recvfrom error = %ld\n", errno)); + + result = (-errno); + + goto out; + } + } } #if defined(DUMP_SMB) { /* If want_header==0 then this is the data returned by SMB_COM_READ_RAW. */ - dump_smb(__FILE__,__LINE__,!want_header,target,already_read,smb_packet_to_consumer,server->max_recv); + dump_smb(__FILE__,__LINE__,!want_header,target,num_bytes_received,smb_packet_to_consumer,server->max_recv); } #endif /* defined(DUMP_SMB) */ - result = len; + result = num_bytes_received; out: return result; } -int -smb_receive (struct smb_server *server, int sock_fd) +static int +smb_receive (struct smb_server *server, int sock_fd, void * input_payload, int payload_size) { byte * packet = server->transmit_buffer; int result; @@ -206,15 +376,16 @@ smb_receive (struct smb_server *server, int sock_fd) ASSERT( server->max_recv <= server->transmit_buffer_size ); result = smb_receive_raw (server, sock_fd, packet, - server->max_recv - NETBIOS_HEADER_SIZE, /* max_xmit in server includes NB header */ - 1); /* We want the header */ + server->max_recv, + input_payload, payload_size, + TRUE); /* We want the NetBIOS frame header */ if (result < 0) { LOG (("smb_receive: receive error: %ld\n", result)); goto out; } - server->rcls = *((unsigned char *) (packet + 9)); + server->rcls = BVAL (packet, 9); server->err = WVAL (packet, 11); if (server->rcls != 0) @@ -263,7 +434,7 @@ smb_receive_trans2 ( (*data_len_ptr) = (*param_len_ptr) = 0; (*param_ptr) = (*data_ptr) = NULL; - result = smb_receive (server, sock_fd); + result = smb_receive (server, sock_fd, NULL, 0); if (result < 0) goto fail; @@ -374,7 +545,7 @@ smb_receive_trans2 ( if (total_data <= data_len && total_param <= param_len) break; - result = smb_receive (server, sock_fd); + result = smb_receive (server, sock_fd, NULL, 0); if (result < 0) goto fail; @@ -447,7 +618,7 @@ smb_connect (struct smb_server *server) * case of error. */ int -smb_request (struct smb_server *server, const void * payload, int payload_size) +smb_request (struct smb_server *server, void * input_payload, const void * output_payload, int payload_size) { int len, result; int sock_fd = server->mount_data.fd; @@ -477,7 +648,7 @@ smb_request (struct smb_server *server, const void * payload, int payload_size) /* If there is a separate payload, only send the header * here and take care of the payload later. */ - if(payload != NULL && payload_size > 0) + if(output_payload != NULL && payload_size > 0) { ASSERT( payload_size < smb_len(buffer) ); ASSERT( len > payload_size ); @@ -485,7 +656,7 @@ smb_request (struct smb_server *server, const void * payload, int payload_size) len -= payload_size; } - LOG (("smb_request: len = %ld, cmd = 0x%lx, payload=0x%08lx, payload_size=%ld\n", len, buffer[8], payload, payload_size)); + LOG (("smb_request: len = %ld, cmd = 0x%lx, input_payload=0x%08lx, output_payload=0x%08lx, payload_size=%ld\n", len, buffer[8], input_payload, output_payload, payload_size)); #if defined(DUMP_SMB) dump_netbios_header(__FILE__,__LINE__,buffer,&buffer[NETBIOS_HEADER_SIZE],len); @@ -501,9 +672,9 @@ smb_request (struct smb_server *server, const void * payload, int payload_size) goto out; } - if(payload != NULL && payload_size > 0) + if(output_payload != NULL && payload_size > 0) { - result = send (sock_fd, (void *)payload, payload_size, 0); + result = send (sock_fd, (void *)output_payload, payload_size, 0); if (result < 0) { LOG(("smb_request: payload send() for %ld bytes failed (errno=%ld)\n", payload_size, errno)); @@ -513,7 +684,7 @@ smb_request (struct smb_server *server, const void * payload, int payload_size) } } - result = smb_receive (server, sock_fd); + result = smb_receive (server, sock_fd, input_payload, payload_size); out: @@ -622,7 +793,7 @@ smb_request_read_raw (struct smb_server *server, unsigned char *target, int max_ } /* Wait for the raw data to be sent by the server. */ - result = smb_receive_raw (server, sock_fd, target, max_len, 0); + result = smb_receive_raw (server, sock_fd, target, max_len, NULL, 0, FALSE); out: @@ -690,7 +861,7 @@ smb_request_write_raw (struct smb_server *server, unsigned const char *source, i /* Wait for the server to respond. */ if(!server->write_behind) { - result = smb_receive (server, sock_fd); + result = smb_receive (server, sock_fd, NULL, 0); if(result < 0) goto out; }