diff --git a/documentation/history.doc b/documentation/history.doc index 5a6fdcf..51c53a3 100644 --- a/documentation/history.doc +++ b/documentation/history.doc @@ -1192,3 +1192,73 @@ smbfs 1.117 (11.4.2018) - Looks like the SMB_COM_WRITE_RAW implementation is really as simple as the documentation suggested. Just two packets need to be sent to to the server. + + +smbfs 1.118 (29.4.2018) + +- Added const qualifier to pointers to immutable data, to identify + further trouble spots. + +- Replaced some instances of memcpy() with memmove(). For all others + a debug version of memcpy() is being used which should log an error + if the source/destination should overlap. + +- When started as a shell command, error messages now go to + stderr, if possible. + +- Action_ExamineObject() could remove the leading '\' path separator + from the internal representation of the object's path name, but + fail to remember that it had truncated the name. This would result + in Examine() returning a file/directory name with a trailing NUL + character. + + The file system cannot access an object by that name, which means + that it would report an error for an object which clearly exists. + Fixing this bug might just resolve a number of inexplicable file + access errors. + + +smbfs 1.119 (1.5.2018) + +- Replaced the constant 4 with what it actually stands for, + this being the size of the NetBIOS frame header (NETBIOS_HEADER_SIZE). + +- The debug output no longer includes any plain text passwords. + Note that weakly-encrypted password data may still show up, + though. + +- The size of the packet buffer used for transmission and + reception of NetBIOS frames is now stored properly and does + not include the extra 512 byte safety margin added to the + end. + +- How much data the SMB_COM_READ/SMB_COM_WRITE and SMB_COM_WRITE_RAW + may receive and transmit is now decoded much more accurately, with + the respective limitations (local transmit buffer size, server's + reported size limits) taken into account. + +- Renamed the various "maximum whatever size" variables used by the + SMB_COM_READ/SMB_COM_READ_RAW and SMB_COM_WRITE/SMB_COM_WRITE_RAW + commands to make it slightly clearer which respective command the + limitations apply to. + + +smbfs 1.120 (1.5.2018) + +- Both SMB_COM_WRITE and SMB_COM_WRITE_RAW commands would copy the + data to be transmitted into the transmit buffer and then send + the transmit buffer contents. + + It is not actually necessary to make this redundant copy because + the contents of the NetBIOS frame header and the SMB commands do + not depend upon knowledge of what's in the data to be sent. So + we just send the header with send() and the data with another + send() call. This might improve write performance somewhat. + + Note that the payload of the write operations will no longer + show up as part of the SMB dump, as it is transmitted later. + + Similar code exists for SMB_COM_READ, but smbfs will always try + to use SMB_COM_READ_RAW first, which does not return its data + in a separate NetBIOS frame whose contents first have to be + picked apart. No change should be necessary here. diff --git a/source_code/dump_smb.c b/source_code/dump_smb.c index 22c9b81..f50180e 100644 --- a/source_code/dump_smb.c +++ b/source_code/dump_smb.c @@ -161,13 +161,13 @@ fill_header(const unsigned char * packet,int length,struct smb_header * header) header->raw_packet_size = length; header->raw_packet = (char *)packet; - memcpy(header->signature,next_data_bytes(packet,4,&offset),4); + memmove(header->signature,next_data_bytes(packet,4,&offset),4); header->command = next_data_byte(packet,&offset); header->status = next_data_dword(packet,&offset); header->flags = next_data_byte(packet,&offset); header->flags2 = next_data_word(packet,&offset); header->extra.pid_high = next_data_word(packet,&offset); - memcpy(header->extra.signature,next_data_words(packet,4,&offset),sizeof(unsigned short) * 4); + memmove(header->extra.signature,next_data_words(packet,4,&offset),sizeof(unsigned short) * 4); skip_data_words(packet,1,&offset); header->tid = next_data_word(packet,&offset); header->pid = next_data_word(packet,&offset); @@ -420,7 +420,7 @@ add_lb_flag(struct line_buffer *lb,const char * str) { if(lb->length + len < sizeof(lb->line)-1) { - memcpy(&lb->line[lb->length],str,len); + memmove(&lb->line[lb->length],str,len); lb->length += len; lb->line[lb->length] = '\0'; @@ -430,10 +430,10 @@ add_lb_flag(struct line_buffer *lb,const char * str) { if(lb->length + 2 + len < sizeof(lb->line)-1) { - memcpy(&lb->line[lb->length],", ",2); + memmove(&lb->line[lb->length],", ",2); lb->length += 2; - memcpy(&lb->line[lb->length],str,len); + memmove(&lb->line[lb->length],str,len); lb->length += len; lb->line[lb->length] = '\0'; diff --git a/source_code/include/smb/smb_fs.h b/source_code/include/smb/smb_fs.h index 698b9ea..688044f 100644 --- a/source_code/include/smb/smb_fs.h +++ b/source_code/include/smb/smb_fs.h @@ -68,11 +68,12 @@ 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); int smb_release(struct smb_server *server); int smb_connect(struct smb_server *server); -int smb_request(struct smb_server *server); +int smb_request(struct smb_server *server,const void * 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 9f4ea94..4622b5a 100644 --- a/source_code/main.c +++ b/source_code/main.c @@ -146,7 +146,7 @@ VOID ASM AsmFreePooled(REG(a0,APTR poolHeader),REG(a1,APTR memory),REG(d0,ULONG /* Forward declarations for local routines. */ LONG _start(STRPTR args, LONG args_length, struct ExecBase * exec_base); -LONG VARARGS68K LocalPrintf(STRPTR format, ...); +LONG VARARGS68K LocalFPrintf(BPTR output, const UBYTE * format, ...); STRPTR amitcp_strerror(int error); STRPTR host_strerror(int error); LONG CompareNames(STRPTR a, STRPTR b); @@ -159,7 +159,7 @@ ULONG GetCurrentTime(VOID); VOID GMTime(time_t seconds, struct tm *tm); time_t MakeTime(const struct tm *const tm); VOID VARARGS68K SPrintf(STRPTR buffer, STRPTR formatString, ...); -int BroadcastNameQuery(char *name, char *scope, UBYTE *address); +int BroadcastNameQuery(const char *name, const char *scope, UBYTE *address); /****************************************************************************/ @@ -171,9 +171,9 @@ STATIC ULONG stack_usage_exit(const struct StackSwapStruct * stk); /****************************************************************************/ INLINE STATIC BOOL ReallyRemoveDosEntry(struct DosList *entry); -INLINE STATIC LONG BuildFullName(STRPTR parent_name, STRPTR name, STRPTR *result_ptr, LONG *result_size_ptr); -INLINE STATIC VOID TranslateCName(UBYTE *name, UBYTE *map); -INLINE STATIC VOID ConvertCString(APTR bstring, LONG max_len, STRPTR cstring, LONG len); +INLINE STATIC LONG BuildFullName(const UBYTE * parent_name, STRPTR name, STRPTR *result_ptr, LONG *result_size_ptr); +INLINE STATIC VOID TranslateCName(UBYTE *name, const UBYTE *map); +INLINE STATIC VOID ConvertCString(void * bstring, LONG max_len, const UBYTE * cstring, LONG len); STATIC VOID DisplayErrorList(VOID); STATIC VOID AddError(STRPTR fmt, APTR args); STATIC LONG CVSPrintf(STRPTR format_string, APTR args); @@ -185,41 +185,41 @@ STATIC LONG CheckAccessModeCollision(STRPTR name, LONG mode); STATIC LONG NameAlreadyInUse(STRPTR name); STATIC BOOL IsReservedName(STRPTR name); STATIC LONG MapErrnoToIoErr(int error); -STATIC VOID TranslateBName(UBYTE *name, UBYTE *map); +STATIC VOID TranslateBName(UBYTE *name, const UBYTE *map); STATIC VOID Cleanup(VOID); STATIC BOOL Setup(STRPTR program_name, STRPTR service, STRPTR workgroup, STRPTR username, STRPTR opt_password, BOOL opt_changecase, STRPTR opt_clientname, STRPTR opt_servername, int opt_cachesize, int opt_max_transmit, LONG *opt_time_zone_offset, LONG *opt_dst_offset, BOOL opt_raw_smb, BOOL opt_write_behind, BOOL opt_prefer_write_raw, STRPTR device_name, STRPTR volume_name, STRPTR translation_file); -STATIC VOID ConvertBString(LONG max_len, STRPTR cstring, APTR bstring); +STATIC VOID ConvertBString(LONG max_len, STRPTR cstring, const void * bstring); STATIC BPTR Action_Parent(struct FileLock *parent, LONG *error_ptr); -STATIC LONG Action_DeleteObject(struct FileLock *parent, APTR bcpl_name, LONG *error_ptr); -STATIC BPTR Action_CreateDir(struct FileLock *parent, APTR bcpl_name, LONG *error_ptr); -STATIC BPTR Action_LocateObject(struct FileLock *parent, APTR bcpl_name, LONG mode, LONG *error_ptr); +STATIC LONG Action_DeleteObject(struct FileLock *parent, const void * bcpl_name, LONG *error_ptr); +STATIC BPTR Action_CreateDir(struct FileLock *parent, const void * bcpl_name, LONG *error_ptr); +STATIC BPTR Action_LocateObject(struct FileLock *parent, const void * bcpl_name, LONG mode, LONG *error_ptr); STATIC BPTR Action_CopyDir(struct FileLock *lock, LONG *error_ptr); STATIC LONG Action_FreeLock(struct FileLock *lock, LONG *error_ptr); STATIC LONG Action_SameLock(struct FileLock *lock1, struct FileLock *lock2, LONG *error_ptr); -STATIC LONG Action_SetProtect(struct FileLock *parent, APTR bcpl_name, LONG mask, LONG *error_ptr); -STATIC LONG Action_RenameObject(struct FileLock *source_lock, APTR source_bcpl_name, struct FileLock *destination_lock, APTR destination_bcpl_name, LONG *error_ptr); +STATIC LONG Action_SetProtect(struct FileLock *parent, const void * bcpl_name, LONG mask, LONG *error_ptr); +STATIC LONG Action_RenameObject(struct FileLock *source_lock, const void * source_bcpl_name, struct FileLock *destination_lock, const void * destination_bcpl_name, LONG *error_ptr); STATIC LONG Action_DiskInfo(struct InfoData *id, LONG *error_ptr); STATIC LONG Action_Info(struct FileLock *lock, struct InfoData *id, LONG *error_ptr); STATIC LONG Action_ExamineObject(struct FileLock *lock, struct FileInfoBlock *fib, LONG *error_ptr); -STATIC BOOL NameIsAcceptable(STRPTR name, LONG max_len); +STATIC BOOL NameIsAcceptable(const UBYTE * name, LONG max_len); STATIC LONG Action_ExamineNext(struct FileLock *lock, struct FileInfoBlock *fib, LONG *error_ptr); STATIC LONG Action_ExamineAll(struct FileLock *lock, struct ExAllData *ed, ULONG size, ULONG type, struct ExAllControl *eac, LONG *error_ptr); -STATIC LONG Action_Find(LONG action, struct FileHandle *fh, struct FileLock *parent, APTR bcpl_name, LONG *error_ptr); +STATIC LONG Action_Find(LONG action, struct FileHandle *fh, struct FileLock *parent, const void * bcpl_name, LONG *error_ptr); STATIC LONG Action_Read(struct FileNode *fn, APTR mem, LONG length, LONG *error_ptr); STATIC LONG Action_Write(struct FileNode *fn, APTR mem, LONG length, LONG *error_ptr); STATIC LONG Action_End(struct FileNode *fn, LONG *error_ptr); STATIC LONG Action_Seek(struct FileNode *fn, LONG position, LONG mode, LONG *error_ptr); STATIC LONG Action_SetFileSize(struct FileNode *fn, LONG position, LONG mode, LONG *error_ptr); -STATIC LONG Action_SetDate(struct FileLock *parent, APTR bcpl_name, struct DateStamp *ds, LONG *error_ptr); +STATIC LONG Action_SetDate(struct FileLock *parent, const void * bcpl_name, const struct DateStamp *ds, LONG *error_ptr); STATIC LONG Action_ExamineFH(struct FileNode *fn, struct FileInfoBlock *fib, LONG *error_ptr); STATIC BPTR Action_ParentFH(struct FileNode *fn, LONG *error_ptr); STATIC BPTR Action_CopyDirFH(struct FileNode *fn, LONG *error_ptr); STATIC LONG Action_FHFromLock(struct FileHandle *fh, struct FileLock *fl, LONG *error_ptr); -STATIC LONG Action_RenameDisk(APTR bcpl_name, LONG *error_ptr); +STATIC LONG Action_RenameDisk(const void * bcpl_name, LONG *error_ptr); STATIC LONG Action_ChangeMode(LONG type, APTR object, LONG new_mode, LONG *error_ptr); STATIC LONG Action_WriteProtect(LONG flag, ULONG key, LONG *error_ptr); STATIC LONG Action_MoreCache(LONG buffer_delta, LONG *error_ptr); -STATIC LONG Action_SetComment(struct FileLock *parent, APTR bcpl_name, APTR bcpl_comment, LONG *error_ptr); +STATIC LONG Action_SetComment(struct FileLock *parent, const void * bcpl_name, const void * bcpl_comment, LONG *error_ptr); STATIC LONG Action_LockRecord(struct FileNode *fn, LONG offset, LONG length, LONG mode, ULONG timeout, LONG *error_ptr); STATIC LONG Action_FreeRecord(struct FileNode *fn, LONG offset, LONG length, LONG *error_ptr); STATIC VOID HandleFileSystem(STRPTR device_name, STRPTR volume_name, STRPTR service_name); @@ -298,7 +298,7 @@ STATIC APTR MemoryPool; STATIC struct RDArgs * Parameters; STATIC struct DiskObject * Icon; -STATIC struct WBStartup * WBStartup; +STATIC struct WBStartup * WBStartup; STATIC struct MinList ErrorList; @@ -1064,9 +1064,20 @@ main(VOID) SETPROGRAMNAME(FilePart(program_name)); if(args.DebugLevel != NULL) + { + #if !defined(DEBUG) + { + if(WBStartup == NULL) + ReportError("This version of smbfs cannot create debug output."); + } + #endif /* !DEBUG */ + SETDEBUGLEVEL(*args.DebugLevel); + } else + { SETDEBUGLEVEL(0); + } /* Enable SMB packet decoding, but only if not started from Workbench. */ #if defined(DUMP_SMB) @@ -1079,6 +1090,11 @@ main(VOID) if(args.DumpSMB && WBStartup == NULL) control_smb_dump(TRUE, dump_smb_level, (const char *)args.DumpSMBFile); } + #else + { + if(WBStartup == NULL && (args.DumpSMBLevel != NULL || args.DumpSMB)) + ReportError("This version of smbfs cannot create SMB debug output."); + } #endif /* DUMP_SMB */ D(("%s (%s)",VERS,DATE)); @@ -1137,21 +1153,24 @@ main(VOID) /****************************************************************************/ LONG VARARGS68K -LocalPrintf(STRPTR format, ...) +LocalFPrintf(BPTR output, const UBYTE * format, ...) { va_list args; LONG result; + if(output == ZERO) + output = Output(); + #if defined(__amigaos4__) { va_startlinear(args,format); - result = VPrintf(format,va_getlinearva(args,APTR)); + result = VFPrintf(output, format, va_getlinearva(args,APTR)); va_end(args); } #else { va_start(args,format); - result = VPrintf(format,args); + result = VFPrintf(output, format, args); va_end(args); } #endif /* __amigaos4__ */ @@ -1404,27 +1423,34 @@ ReportError(STRPTR fmt,...) } else { + struct Process * this_process = (struct Process *)FindTask(NULL); UBYTE program_name[MAX_FILENAME_LEN]; + BPTR output; GetProgramName(program_name,sizeof(program_name)); - LocalPrintf("%s: ",FilePart(program_name)); + if(this_process->pr_CES != ZERO) + output = this_process->pr_CES; + else + output = Output(); + + LocalFPrintf(output, "%s: ",FilePart(program_name)); #if defined(__amigaos4__) { va_startlinear(args,fmt); - VPrintf(fmt,va_getlinearva(args,APTR)); + VFPrintf(output, fmt, va_getlinearva(args,APTR)); va_end(args); } #else { va_start(args,fmt); - VPrintf(fmt,args); + VFPrintf(output,fmt,args); va_end(args); } #endif /* __amigaos4__ */ - LocalPrintf("\n"); + LocalFPrintf(output, "\n"); } } } @@ -1738,7 +1764,7 @@ L2_Encode(UBYTE * dst, const UBYTE * name, const UBYTE pad, const UBYTE sfx, con } int -BroadcastNameQuery(char *name, char *scope, UBYTE *address) +BroadcastNameQuery(const char *name, const char *scope, UBYTE *address) { static const UBYTE header[12] = { @@ -2215,7 +2241,7 @@ MapErrnoToIoErr(int error) * via a mapping table. */ INLINE STATIC VOID -TranslateBName(UBYTE * name,UBYTE * map) +TranslateBName(UBYTE * name,const UBYTE * map) { LONG len; UBYTE c; @@ -2232,7 +2258,7 @@ TranslateBName(UBYTE * name,UBYTE * map) /* Translate a NUL terminated file name via a mapping table. */ INLINE STATIC VOID -TranslateCName(UBYTE * name,UBYTE * map) +TranslateCName(UBYTE * name,const UBYTE * map) { UBYTE c; @@ -2458,7 +2484,7 @@ Setup( STRPTR program_name, STRPTR service, STRPTR workgroup, - STRPTR username, + STRPTR username, STRPTR opt_password, BOOL opt_changecase, STRPTR opt_clientname, @@ -2797,7 +2823,7 @@ Setup( */ if(volume_name != NULL && VolumeNode != NULL) { - AddDosEntry(VolumeNode); + AddDosEntry(VolumeNode); VolumeNodeAdded = TRUE; } @@ -2823,9 +2849,9 @@ Setup( /* Convert a BCPL string into a standard NUL terminated 'C' string. */ INLINE STATIC VOID -ConvertBString(LONG max_len,STRPTR cstring,APTR bstring) +ConvertBString(LONG max_len,STRPTR cstring,const void * bstring) { - STRPTR from = bstring; + const UBYTE * from = bstring; LONG len = from[0]; if(len > max_len-1) @@ -2839,9 +2865,9 @@ ConvertBString(LONG max_len,STRPTR cstring,APTR bstring) /* Convert a NUL terminated 'C' string into a BCPL string. */ INLINE STATIC VOID -ConvertCString(APTR bstring,LONG max_len,STRPTR cstring,LONG len) +ConvertCString(void * bstring,LONG max_len,const UBYTE * cstring,LONG len) { - STRPTR to = bstring; + UBYTE * to = bstring; if(len > max_len-1) len = max_len-1; @@ -2859,10 +2885,10 @@ ConvertCString(APTR bstring,LONG max_len,STRPTR cstring,LONG len) */ STATIC LONG BuildFullName( - STRPTR parent_name, - STRPTR name, - STRPTR * result_ptr, - LONG * result_size_ptr) + const UBYTE * parent_name, + STRPTR name, + STRPTR * result_ptr, + LONG * result_size_ptr) { LONG error = OK; STRPTR buffer; @@ -3166,7 +3192,7 @@ FindNextLockNode(STRPTR name,struct LockNode * last_ln) STATIC LONG Action_DeleteObject( struct FileLock * parent, - APTR bcpl_name, + const void * bcpl_name, LONG * error_ptr) { LONG result = DOSFALSE; @@ -3216,7 +3242,7 @@ Action_DeleteObject( /* Figure out how long the UTF-8 version will become. */ encoded_name_len = encode_iso8859_1_as_utf8_string(name,name_len,NULL,0); - + /* Encoding error occured, or the resulting name is longer than the buffer will hold? */ if(encoded_name_len < 0 || encoded_name_len >= sizeof(name)) { @@ -3281,8 +3307,7 @@ Action_DeleteObject( } } - /* NOTE: Mark all locks to this object as restart, not just first - one - Piru */ + /* NOTE: Mark all locks to this object as restart, not just first one - Piru */ ln = NULL; while ((ln = FindNextLockNode(full_parent_name, ln)) != NULL) ln->ln_RestartExamine = TRUE; @@ -3372,7 +3397,7 @@ Action_DeleteObject( STATIC BPTR Action_CreateDir( struct FileLock * parent, - APTR bcpl_name, + const void * bcpl_name, LONG * error_ptr) { BPTR result = ZERO; @@ -3381,6 +3406,7 @@ Action_CreateDir( struct LockNode * ln = NULL; STRPTR parent_name; STRPTR dir_name = NULL; + size_t dir_name_size; smba_file_t * dir = NULL; STRPTR base_name; UBYTE name[MAX_FILENAME_LEN]; @@ -3443,7 +3469,11 @@ Action_CreateDir( goto out; } - dir_name = AllocateMemory(strlen(full_name)+3); + SHOWSTRING(full_name); + + dir_name_size = strlen(full_name)+3; + + dir_name = AllocateMemory(dir_name_size); if(dir_name == NULL) { error = ERROR_NO_FREE_STORE; @@ -3451,11 +3481,16 @@ Action_CreateDir( } strcpy(dir_name,full_name); + base_name = NULL; + for(i = strlen(dir_name)-1 ; i >= 0 ; i--) { if(dir_name[i] == SMB_PATH_SEPARATOR) { + /* Is this a case of '\name'? If so, see to it that + * dir_name becomes '\' and base_name becomes 'foo'. + */ if(i == 0) { memmove(&dir_name[1],&dir_name[0],strlen(dir_name)+1); @@ -3469,6 +3504,8 @@ Action_CreateDir( } } + D(("full path name = '%s', directory name = '%s'\n", dir_name, base_name)); + ln = AllocateMemory(sizeof(*ln)); if(ln == NULL) { @@ -3484,7 +3521,7 @@ Action_CreateDir( ln->ln_FileLock.fl_Volume = MKBADDR(VolumeNode); ln->ln_FullName = full_name; - error = smba_open(ServerData,dir_name,strlen(full_name)+3,&dir); + error = smba_open(ServerData,dir_name,dir_name_size,&dir); if(error < 0) { error = MapErrnoToIoErr(error); @@ -3538,7 +3575,7 @@ Action_CreateDir( STATIC BPTR Action_LocateObject( struct FileLock * parent, - APTR bcpl_name, + const void * bcpl_name, LONG mode, LONG * error_ptr) { @@ -3836,7 +3873,7 @@ Action_SameLock( STATIC LONG Action_SetProtect( struct FileLock * parent, - APTR bcpl_name, + const void * bcpl_name, LONG mask, LONG * error_ptr) { @@ -3970,9 +4007,9 @@ Action_SetProtect( STATIC LONG Action_RenameObject( struct FileLock * source_lock, - APTR source_bcpl_name, + const void * source_bcpl_name, struct FileLock * destination_lock, - APTR destination_bcpl_name, + const void * destination_bcpl_name, LONG * error_ptr) { struct LockNode * ln; @@ -4253,12 +4290,12 @@ Action_ExamineObject( if(lock == NULL) { - STRPTR volume_name = BADDR(VolumeNode->dol_Name); + const UBYTE * volume_name = BADDR(VolumeNode->dol_Name); LONG len = volume_name[0]; SHOWMSG("ZERO root lock"); - memcpy(fib->fib_FileName+1,volume_name+1,len); + memcpy(&fib->fib_FileName[1],&volume_name[1],len); fib->fib_FileName[0] = len; fib->fib_DirEntryType = ST_ROOT; @@ -4296,12 +4333,12 @@ Action_ExamineObject( if(strcmp(ln->ln_FullName,SMB_ROOT_DIR_NAME) == SAME) { - STRPTR volume_name = BADDR(VolumeNode->dol_Name); + const UBYTE * volume_name = BADDR(VolumeNode->dol_Name); LONG len = volume_name[0]; SHOWMSG("root lock"); - memcpy(fib->fib_FileName+1,volume_name+1,len); + memcpy(&fib->fib_FileName[1],&volume_name[1],len); fib->fib_FileName[0] = len; fib->fib_DirEntryType = ST_ROOT; @@ -4312,7 +4349,7 @@ Action_ExamineObject( } else { - STRPTR name; + const UBYTE * name; LONG name_len; LONG i; @@ -4324,6 +4361,10 @@ Action_ExamineObject( if(name[i] == SMB_PATH_SEPARATOR) { name = &name[i+1]; + + /* We just lost a character and need to account for it. */ + name_len--; + break; } } @@ -4345,7 +4386,7 @@ Action_ExamineObject( /* Try to decode the file file, 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? */ @@ -4422,7 +4463,7 @@ Action_ExamineObject( /****************************************************************************/ STATIC BOOL -NameIsAcceptable(STRPTR name,LONG max_len) +NameIsAcceptable(const UBYTE * name,LONG max_len) { BOOL result = FALSE; UBYTE c; @@ -4455,7 +4496,7 @@ dir_scan_callback_func_exnext( struct FileInfoBlock * fib, int unused_fpos, int nextpos, - char * name, + const UBYTE * name, int eof, smba_stat_t * st) { @@ -4473,7 +4514,7 @@ dir_scan_callback_func_exnext( /* Skip file and drawer names that we wouldn't be * able to handle in the first place. */ - if(!NameIsAcceptable((STRPTR)name,sizeof(fib->fib_FileName)) || (st->is_hidden && OmitHidden)) + if(!NameIsAcceptable(name,sizeof(fib->fib_FileName)) || (st->is_hidden && OmitHidden)) goto out; name_len = strlen(name); @@ -4636,7 +4677,7 @@ struct ExAllContext struct ExAllData * ec_Next; ULONG ec_BytesLeft; ULONG ec_MinSize; - struct ExAllControl * ec_Control; + struct ExAllControl * ec_Control; ULONG ec_Type; LONG ec_Error; BOOL ec_FirstAttempt; @@ -4647,7 +4688,7 @@ dir_scan_callback_func_exall( struct ExAllContext * ec, int unused_fpos, int nextpos, - char * name, + const UBYTE * name, int eof, smba_stat_t * st) { @@ -4684,7 +4725,7 @@ dir_scan_callback_func_exall( /* Use the decoded replacement name. */ name = decoded_name; - } + } } /* Skip file and drawer names that we wouldn't be @@ -4766,7 +4807,7 @@ dir_scan_callback_func_exall( seconds = 0; ed->ed_Days = (seconds / (24 * 60 * 60)); - ed->ed_Mins = (seconds % (24 * 60 * 60)) / 60; + ed->ed_Mins = (seconds % (24 * 60 * 60)) / 60; ed->ed_Ticks = (seconds % 60) * TICKS_PER_SECOND; } @@ -5049,7 +5090,7 @@ Action_Find( LONG action, struct FileHandle * fh, struct FileLock * parent, - APTR bcpl_name, + const void * bcpl_name, LONG * error_ptr) { LONG result = DOSFALSE; @@ -5415,22 +5456,22 @@ Action_Seek( switch(mode) { case OFFSET_BEGINNING: - + mode = 0; break; - + case OFFSET_CURRENT: - + mode = 1; break; - + case OFFSET_END: - + mode = 2; break; - + default: - + error = ERROR_ACTION_NOT_KNOWN; goto out; } @@ -5647,10 +5688,10 @@ Action_SetFileSize( STATIC LONG Action_SetDate( - struct FileLock * parent, - APTR bcpl_name, - struct DateStamp * ds, - LONG * error_ptr) + struct FileLock * parent, + const void * bcpl_name, + const struct DateStamp * ds, + LONG * error_ptr) { LONG result = DOSFALSE; STRPTR full_name = NULL; @@ -6088,14 +6129,14 @@ Action_FHFromLock( STATIC LONG Action_RenameDisk( - APTR bcpl_name, - LONG * error_ptr) + const void * bcpl_name, + LONG * error_ptr) { LONG result = DOSFALSE; LONG error = OK; STRPTR old_name; STRPTR new_name; - UBYTE * name; + const UBYTE * name; LONG len; ENTER(); @@ -6354,8 +6395,8 @@ Action_MoreCache( STATIC LONG Action_SetComment( struct FileLock * parent, - APTR bcpl_name, - APTR bcpl_comment, + const void * bcpl_name, + const void * bcpl_comment, LONG * error_ptr) { LONG result = DOSFALSE; @@ -6611,7 +6652,7 @@ HandleFileSystem(STRPTR device_name,STRPTR volume_name,STRPTR service_name) break; } - LocalPrintf("Connected '%s' to '%s:'; \"Break %ld\" or [Ctrl-C] to stop... ", + LocalFPrintf(ZERO, "Connected '%s' to '%s:'; \"Break %ld\" or [Ctrl-C] to stop... ", service_name,name,which); Flush(Output()); @@ -6632,7 +6673,7 @@ HandleFileSystem(STRPTR device_name,STRPTR volume_name,STRPTR service_name) old_priority = this_process->pr_Task.tc_Node.ln_Pri; if(old_priority < 10) SetTaskPri((struct Task *)this_process, 10); - + Permit(); do @@ -6988,14 +7029,14 @@ HandleFileSystem(STRPTR device_name,STRPTR volume_name,STRPTR service_name) * has already been changed. */ Forbid(); - + if(old_priority < 10 && this_process->pr_Task.tc_Node.ln_Pri == 10) SetTaskPri((struct Task *)this_process, old_priority); - + Permit(); if(sign_off) - LocalPrintf("stopped.\n"); + LocalFPrintf(ZERO, "stopped.\n"); LEAVE(); } @@ -7083,7 +7124,7 @@ strlcat(char *dst, const char *src, size_t siz) (*d) = '\0'; - result = dlen + (s - src); /* count does not include NUL */ + result = dlen + (s - src); /* count does not include NUL */ } return(result); diff --git a/source_code/proc.c b/source_code/proc.c index e6a1ba8..5d91812 100644 --- a/source_code/proc.c +++ b/source_code/proc.c @@ -72,8 +72,8 @@ static INLINE word smb_bcc(const byte *packet); static INLINE int smb_verify(const byte *packet, int command, int wct, int bcc); static byte *smb_encode_dialect(byte *p, const byte *name, int len); static byte *smb_encode_ascii(byte *p, const byte *name, int len); -static void smb_encode_vblock(byte *p, const byte *data, word len, int unused_fs); -static byte *smb_decode_data(const byte *p, byte *data, word *data_len, int fs); +static void smb_encode_vblock(byte *p, const byte *data, word len); +static byte *smb_decode_data(const byte *p, byte *data, word *data_len); static byte *smb_name_mangle(byte *p, const byte *name); static int date_dos2unix(unsigned short time_value, unsigned short date); static void date_unix2dos(int unix_date, unsigned short *time_value, unsigned short *date); @@ -305,7 +305,7 @@ smb_encode_ascii (byte * p, const byte * name, int len) } static void -smb_encode_vblock (byte * p, const byte * data, word len, int unused_fs) +smb_encode_vblock (byte * p, const byte * data, word len) { (*p++) = 5; p = smb_encode_word (p, len); @@ -313,7 +313,7 @@ smb_encode_vblock (byte * p, const byte * data, word len, int unused_fs) } static byte * -smb_decode_data (const byte * p, byte * data, word * data_len, int unused_fs) +smb_decode_data (const byte * p, byte * data, word * data_len) { word len; @@ -478,9 +478,11 @@ smb_valid_packet (const byte * packet) static INLINE int smb_verify (const byte * packet, int command, int wct, int bcc) { - return (SMB_CMD (packet) == command && + return ( + SMB_CMD (packet) == command && SMB_WCT (packet) >= wct && - (bcc == -1 || SMB_BCC (packet) >= bcc)) ? 0 : -EIO; + (bcc == -1 || SMB_BCC (packet) >= bcc) + ) ? 0 : -EIO; } static int @@ -655,7 +657,13 @@ smb_dump_packet (const byte * packet) returns 0, you can be quite sure that everything went well. When the answer is <=0, the returned number is a valid unix errno. */ static int -smb_request_ok (struct smb_server *s, int command, int wct, int bcc) +smb_request_ok_with_payload ( + struct smb_server *s, + int command, + int wct, + int bcc, + const void * payload, + int payload_size) { int result; int error; @@ -663,7 +671,7 @@ smb_request_ok (struct smb_server *s, int command, int wct, int bcc) s->rcls = 0; s->err = 0; - result = smb_request (s); + result = smb_request (s, payload, payload_size); if (result < 0) { LOG (("smb_request failed\n")); @@ -730,6 +738,15 @@ smb_request_ok (struct smb_server *s, int command, int wct, int bcc) return(result); } +/* Same thing as smb_request_ok(), but without this payload + * business... + */ +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)); +} + /* smb_retry: This function should be called when smb_request_ok has indicated an error. If the error was indicated because the connection was killed, we try to reconnect. If smb_retry returns 0, @@ -953,6 +970,8 @@ smb_proc_read (struct smb_server *server, struct smb_dirent *finfo, off_t offset int result; int error; + ASSERT( count <= 65535 ); + smb_setup_header_exclusive (server, SMBread, 5, 0); WSET (buf, smb_vwv0, finfo->fileid); @@ -968,7 +987,11 @@ smb_proc_read (struct smb_server *server, struct smb_dirent *finfo, off_t offset returned_count = WVAL (buf, smb_vwv0); - smb_decode_data (SMB_BUF (server->packet), data, &data_len, fs); + /* 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->packet), data, &data_len); if (returned_count != data_len) { @@ -996,6 +1019,8 @@ smb_proc_read_raw (struct smb_server *server, struct smb_dirent *finfo, off_t of char *buf = server->packet; int result; + ASSERT( count <= 65535 ); + smb_setup_header_exclusive (server, SMBreadbraw, 8, 0); WSET (buf, smb_vwv0, finfo->fileid); @@ -1017,6 +1042,8 @@ smb_proc_write (struct smb_server *server, struct smb_dirent *finfo, off_t offse char *buf = server->packet; byte *p; + ASSERT( count < 65535 ); + p = smb_setup_header_exclusive (server, SMBwrite, 5, count + 3); WSET (buf, smb_vwv0, finfo->fileid); WSET (buf, smb_vwv1, count); @@ -1025,15 +1052,13 @@ smb_proc_write (struct smb_server *server, struct smb_dirent *finfo, off_t offse (*p++) = 1; WSET (p, 0, count); - memcpy (p + 2, data, count); - if ((res = smb_request_ok (server, SMBwrite, 1, 0)) >= 0) + if ((res = smb_request_ok_with_payload (server, SMBwrite, 1, 0, data, count)) >= 0) res = WVAL (buf, smb_vwv0); return res; } -/* count must be <= 65535 */ int smb_proc_write_raw (struct smb_server *server, struct smb_dirent *finfo, off_t offset, long count, const char *data) { @@ -1044,6 +1069,8 @@ smb_proc_write_raw (struct smb_server *server, struct smb_dirent *finfo, off_t o long len; byte *p; + ASSERT( count <= 65535 ); + LOG (("number of bytes to send = %ld\n", count)); /* Calculate maximum number of bytes that could be transferred with @@ -1068,10 +1095,11 @@ smb_proc_write_raw (struct smb_server *server, struct smb_dirent *finfo, off_t o * * This leaves 'max_buffer_size' - 59 for the payload. */ - if(server->max_raw_size < server->max_buffer_size) - max_len = server->max_raw_size - 59 - NETBIOS_HEADER_SIZE; - else - max_len = server->max_buffer_size - 59 - NETBIOS_HEADER_SIZE; + max_len = server->max_buffer_size; + if(max_len > 65535) + max_len = 65535; + + max_len -= 59 - NETBIOS_HEADER_SIZE; LOG(("maximum length for payload = %ld bytes\n", max_len)); @@ -1116,12 +1144,9 @@ smb_proc_write_raw (struct smb_server *server, struct smb_dirent *finfo, off_t o WSET (buf, smb_vwv10, 0); } - if (len > 0) - memcpy (p, data, len); - LOG(("requesting SMBwritebraw\n")); - result = smb_request_ok (server, SMBwritebraw, 1, 0); + result = smb_request_ok_with_payload (server, SMBwritebraw, 1, 0, data, len); LOG (("first request returned %ld\n", result)); @@ -1139,6 +1164,8 @@ smb_proc_write_raw (struct smb_server *server, struct smb_dirent *finfo, off_t o { LOG(("sending %ld bytes of data (raw)\n",count)); + ASSERT( count <= 65535 ); + result = smb_request_write_raw (server, data, count); LOG(("raw request returned %ld\n", result)); @@ -1192,7 +1219,7 @@ smb_proc_lseek (struct smb_server *server, struct smb_dirent *finfo, off_t offse retry: - smb_setup_header (server, SMBlseek, 4,0); + smb_setup_header (server, SMBlseek, 4, 0); WSET (buf, smb_vwv0, finfo->fileid); WSET (buf, smb_vwv1, mode); @@ -1253,7 +1280,7 @@ smb_proc_lockingX (struct smb_server *server, struct smb_dirent *finfo, struct s if (smb_retry (server)) goto retry; } - + return result; } @@ -1510,7 +1537,7 @@ smb_proc_readdir_short (struct smb_server *server, char *path, int fpos, int cac WSET (buf, smb_vwv0, entries_asked); WSET (buf, smb_vwv1, aDIR); p = smb_encode_ascii (p, "", 0); - (void) smb_encode_vblock (p, status, SMB_STATUS_SIZE, 0); + (void) smb_encode_vblock (p, status, SMB_STATUS_SIZE); } if ((error = smb_request_ok (server, SMBsearch, 1, -1)) < 0) @@ -1709,13 +1736,14 @@ smb_decode_long_dirent (char *p, struct smb_dirent *finfo, int level) if (finfo != NULL) { strlcpy (finfo->complete_path, p + 27, finfo->complete_path_size); - finfo->len = strlen (finfo->complete_path); - finfo->size = DVAL (p, 16); - finfo->attr = BVAL (p, 24); - finfo->ctime = date_dos2unix (WVAL (p, 6), WVAL (p, 4)); - finfo->atime = date_dos2unix (WVAL (p, 10), WVAL (p, 8)); - finfo->mtime = date_dos2unix (WVAL (p, 14), WVAL (p, 12)); - finfo->wtime = finfo->mtime; + + finfo->len = strlen (finfo->complete_path); + finfo->size = DVAL (p, 16); + finfo->attr = BVAL (p, 24); + finfo->ctime = date_dos2unix (WVAL (p, 6), WVAL (p, 4)); + finfo->atime = date_dos2unix (WVAL (p, 10), WVAL (p, 8)); + finfo->mtime = date_dos2unix (WVAL (p, 14), WVAL (p, 12)); + finfo->wtime = finfo->mtime; #if DEBUG { @@ -1756,13 +1784,14 @@ smb_decode_long_dirent (char *p, struct smb_dirent *finfo, int level) if (finfo != NULL) { strlcpy (finfo->complete_path, p + 31, finfo->complete_path_size); - finfo->len = strlen (finfo->complete_path); - finfo->size = DVAL (p, 16); - finfo->attr = BVAL (p, 24); - finfo->ctime = date_dos2unix (WVAL (p, 6), WVAL (p, 4)); - finfo->atime = date_dos2unix (WVAL (p, 10), WVAL (p, 8)); - finfo->mtime = date_dos2unix (WVAL (p, 14), WVAL (p, 12)); - finfo->wtime = finfo->mtime; + + finfo->len = strlen (finfo->complete_path); + finfo->size = DVAL (p, 16); + finfo->attr = BVAL (p, 24); + finfo->ctime = date_dos2unix (WVAL (p, 6), WVAL (p, 4)); + finfo->atime = date_dos2unix (WVAL (p, 10), WVAL (p, 8)); + finfo->mtime = date_dos2unix (WVAL (p, 14), WVAL (p, 12)); + finfo->wtime = finfo->mtime; #if DEBUG { @@ -1992,7 +2021,7 @@ smb_proc_readdir_long (struct smb_server *server, char *path, int fpos, int cach p = SMB_BUF (outbuf); (*p++) = 0; /* put in a null smb_name */ - + /* ZZZ the following may be unnecessary, because they * likely represent random data used for alignment * padding purposes. @@ -2297,12 +2326,12 @@ smb_proc_getattrE (struct smb_server *server, struct smb_dirent *entry) if ((result = smb_request_ok (server, SMBgetattrE, 11, 0)) < 0) goto out; - entry->ctime = date_dos2unix (WVAL (buf, smb_vwv1), WVAL (buf, smb_vwv0)); - entry->atime = date_dos2unix (WVAL (buf, smb_vwv3), WVAL (buf, smb_vwv2)); - entry->mtime = date_dos2unix (WVAL (buf, smb_vwv5), WVAL (buf, smb_vwv4)); - entry->wtime = entry->mtime; - entry->size = DVAL (buf, smb_vwv6); - entry->attr = WVAL (buf, smb_vwv10); + entry->ctime = date_dos2unix (WVAL (buf, smb_vwv1), WVAL (buf, smb_vwv0)); + entry->atime = date_dos2unix (WVAL (buf, smb_vwv3), WVAL (buf, smb_vwv2)); + entry->mtime = date_dos2unix (WVAL (buf, smb_vwv5), WVAL (buf, smb_vwv4)); + entry->wtime = entry->mtime; + entry->size = DVAL (buf, smb_vwv6); + entry->attr = WVAL (buf, smb_vwv10); #if DEBUG { @@ -2425,8 +2454,8 @@ smb_proc_dskattr (struct smb_server *server, struct smb_dskattr *attr) ****************************************************************************/ struct smb_prots { - enum smb_protocol prot; - const char *name; + enum smb_protocol prot; + const char * name; }; /* smb_proc_reconnect: We expect the server to be locked, so that you @@ -2512,12 +2541,12 @@ smb_proc_reconnect (struct smb_server *server) if (server->packet != NULL) free (server->packet); - server->packet_size = packet_size + packet_fudge_size; + server->packet_size = packet_size; /* Add a bit of fudge to account for the NetBIOS session * header and whatever else might show up... */ - server->packet = malloc (packet_size + packet_fudge_size); + server->packet = malloc (server->packet_size + packet_fudge_size); if (server->packet == NULL) { LOG (("smb_proc_connect: No memory! Bailing out.\n")); @@ -2531,7 +2560,7 @@ smb_proc_reconnect (struct smb_server *server) if(!server->raw_smb) { /* Start with an RFC1002 session request packet. */ - p = packet + 4; + p = packet + NETBIOS_HEADER_SIZE; p = smb_name_mangle (p, server->mount_data.server_name); p = smb_name_mangle (p, server->mount_data.client_name); @@ -2540,7 +2569,7 @@ smb_proc_reconnect (struct smb_server *server) packet[0] = 0x81; /* SESSION REQUEST */ - if ((result = smb_request (server)) < 0) + if ((result = smb_request (server, NULL, 0)) < 0) { LOG (("smb_proc_connect: Failed to send SESSION REQUEST.\n")); goto fail; @@ -2608,7 +2637,9 @@ smb_proc_reconnect (struct smb_server *server) int user_len = strlen (server->mount_data.username)+1; dword server_sesskey; - LOG (("smb_proc_connect: password = %s\n",server->mount_data.password)); + /* + LOG (("smb_proc_connect: password = %s\n",server->mount_data.password*)); + */ LOG (("smb_proc_connect: usernam = %s\n",server->mount_data.username)); LOG (("smb_proc_connect: blkmode = %ld\n",WVAL (packet, smb_vwv5))); @@ -2619,7 +2650,7 @@ smb_proc_reconnect (struct smb_server *server) /* Skip "max mpx count" (1 word) and "max number vcs" (1 word). */ p += 2 * sizeof(word); - + p = smb_decode_dword(p, &max_buffer_size); SHOWVALUE (max_buffer_size); p = smb_decode_dword(p, &server->max_raw_size); @@ -2903,18 +2934,20 @@ smb_proc_reconnect (struct smb_server *server) if(packet_size < (int)max_buffer_size) { SHOWVALUE(packet_size); - + /* We need to allocate a larger packet buffer. */ packet_size = max_buffer_size; - + D(("packet size updated to %ld bytes\n", packet_size)); - + free (server->packet); /* Add a bit of fudge to account for the NetBIOS session * header and whatever else might show up... */ - server->packet = malloc (packet_size + packet_fudge_size); + server->packet_size = packet_size; + + server->packet = malloc (server->packet_size + packet_fudge_size); if (server->packet == NULL) { LOG (("smb_proc_connect: No memory! Bailing out.\n")); @@ -2932,10 +2965,6 @@ smb_proc_reconnect (struct smb_server *server) D(("maximum buffer size limited to %ld bytes\n", max_buffer_size)); } - /* Add a bit of fudge to account for the NetBIOS session - * header and whatever else might show up... - */ - server->packet_size = packet_size + packet_fudge_size; server->max_buffer_size = max_buffer_size; LOG (("smb_proc_connect: Normal exit\n")); diff --git a/source_code/quad_math.c b/source_code/quad_math.c index dcec18e..8c172eb 100644 --- a/source_code/quad_math.c +++ b/source_code/quad_math.c @@ -29,7 +29,7 @@ /* Divide a 64 bit integer by a 32 bit integer, filling in a 64 bit quotient and returning a 32 bit remainder. */ ULONG -divide_64_by_32(QUAD * dividend,ULONG divisor,QUAD * quotient) +divide_64_by_32(const QUAD * const dividend,ULONG divisor,QUAD * quotient) { QUAD dividend_cdef = (*dividend); ULONG dividend_ab = 0; diff --git a/source_code/quad_math.h b/source_code/quad_math.h index 86b94e8..7cc7c83 100644 --- a/source_code/quad_math.h +++ b/source_code/quad_math.h @@ -39,7 +39,7 @@ typedef struct /****************************************************************************/ -ULONG divide_64_by_32(QUAD * dividend,ULONG divisor,QUAD * quotient); +ULONG divide_64_by_32(const QUAD * const dividend,ULONG divisor,QUAD * quotient); ULONG subtract_64_from_64_to_64(const QUAD * const minuend,const QUAD * const subtrahend,QUAD * difference); /****************************************************************************/ diff --git a/source_code/smb_abstraction.c b/source_code/smb_abstraction.c index a07883c..b5d7a8b 100644 --- a/source_code/smb_abstraction.c +++ b/source_code/smb_abstraction.c @@ -29,34 +29,34 @@ typedef struct dircache { - int base; - int len; - int eof; /* cache end is eof */ - long created_at; /* for invalidation */ - struct smba_file *cache_for; /* owner of this cache */ - int cache_size; - struct smb_dirent cache[1]; + int base; + int len; + int eof; /* cache end is eof */ + long created_at; /* for invalidation */ + struct smba_file * cache_for; /* owner of this cache */ + int cache_size; + struct smb_dirent cache[1]; } dircache_t; /* opaque structures for server and files: */ struct smba_server { - struct smb_server server; - struct MinList open_files; - dircache_t * dircache; - unsigned supports_E:1; - unsigned supports_E_known:1; + struct smb_server server; + struct MinList open_files; + dircache_t * dircache; + unsigned supports_E:1; + unsigned supports_E_known:1; }; struct smba_file { - struct MinNode node; - struct smba_server *server; - struct smb_dirent dirent; - long 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, ... */ + struct MinNode node; + struct smba_server * server; + struct smb_dirent dirent; + long 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, ... */ }; /*****************************************************************************/ @@ -68,6 +68,11 @@ struct smba_file */ #define NETBIOS_HEADER_SIZE 4 +/* The NetBIOS frame payload cannot be larger than 131071 bytes, + * which is (2^71)-1. + */ +#define MAX_NETBIOS_FRAME_SIZE 131071 + /*****************************************************************************/ #include "smb_abstraction.h" @@ -280,14 +285,14 @@ make_open (smba_file_t * f, int need_fid) { if (!s->supports_E_known) { - s->supports_E_known = 1; - s->supports_E = 0; + s->supports_E_known = 1; + s->supports_E = 0; } /* ignore errors here */ } else { - s->supports_E_known = 1; - s->supports_E = 1; + s->supports_E_known = 1; + s->supports_E = 1; } } } @@ -297,14 +302,14 @@ make_open (smba_file_t * f, int need_fid) /* don't open directory, initialize directory cache */ if (f->dircache != NULL) { - f->dircache->cache_for = NULL; - f->dircache->len = 0; - f->dircache = NULL; + f->dircache->cache_for = NULL; + f->dircache->len = 0; + f->dircache = NULL; } } - f->attr_time = GetCurrentTime(); - f->is_valid = 1; + f->attr_time = GetCurrentTime(); + f->is_valid = 1; } errnum = 0; @@ -425,8 +430,9 @@ smba_close (smba_file_t * f) int smba_read (smba_file_t * f, char *data, long len, long offset) { + int max_receive = f->server->server.max_recv; int num_bytes_read = 0; - int maxsize, count, result = 0; + int count, result = 0; int errnum; errnum = make_open (f, 1); @@ -441,16 +447,23 @@ smba_read (smba_file_t * f, char *data, long len, long offset) /* SMB_COM_READ_RAW and SMB_COM_WRITE_RAW supported? */ if (f->server->server.capabilities & CAP_RAW_MODE) { - dword max_raw_size = f->server->server.max_raw_size; + int max_raw_size = f->server->server.max_raw_size; int n; do { - n = min(len,(long)max_raw_size); - /* SMB_COM_READ_RAW can only read up to 65535 bytes. */ - if(n > 65535) - n = 65535; + n = min(len, 65535); + + /* The maximum number of bytes to be read in raw + * mode may be limited, too. + */ + if(n > max_raw_size) + n = max_raw_size; + + /* Limit how much data we are prepared to receive? */ + if(n > max_receive) + n = max_receive; result = smb_proc_read_raw (&f->server->server, &f->dirent, offset, n, data); if(result <= 0) @@ -478,6 +491,8 @@ smba_read (smba_file_t * f, char *data, long len, long offset) */ if (result <= 0 && num_bytes_read == 0) { + int max_size_smb_com_read; + /* Calculate maximum number of bytes that could be transferred with * a single SMBread packet... * @@ -499,15 +514,30 @@ smba_read (smba_file_t * f, char *data, long len, long offset) * * This leaves 'max_buffer_size' - 48 for the payload. */ - /*maxsize = f->server->server.max_buffer_size - SMB_HEADER_LEN - 5 * 2 - 5;*/ - maxsize = f->server->server.max_buffer_size - 48 - NETBIOS_HEADER_SIZE; + /*max_size_smb_com_read = f->server->server.max_buffer_size - SMB_HEADER_LEN - 5 * 2 - 5;*/ + max_size_smb_com_read = f->server->server.max_buffer_size - 48 - NETBIOS_HEADER_SIZE; + + /* ZZZ SMB_COM_READ uses the packet buffer to receive + * the data, which is why there is another limit to how + * much data can be received. + */ + if(max_size_smb_com_read > f->server->server.packet_size - 48 - NETBIOS_HEADER_SIZE) + max_size_smb_com_read = f->server->server.packet_size - 48 - NETBIOS_HEADER_SIZE; do { - count = min(len,maxsize); + /* SMB_COM_READ can read only up to 65535 bytes anyway. */ + count = min(len, 65535); if(count == 0) break; + if(count > max_size_smb_com_read) + count = max_size_smb_com_read; + + /* Limit how much data we are prepared to receive? */ + if(count > max_receive) + count = max_receive; + result = smb_proc_read (&f->server->server, &f->dirent, offset, count, data, 0); if (result < 0) goto out; @@ -543,7 +573,7 @@ int smba_write (smba_file_t * f, char *data, long len, long offset) { dword max_buffer_size; - int maxsize, count, result; + int max_size_smb_com_write, count, result; int num_bytes_written = 0; int errnum; @@ -579,15 +609,22 @@ smba_write (smba_file_t * f, char *data, long len, long offset) * * This leaves 'max_buffer_size' - 48 for the payload. */ - /*maxsize = f->server->server.max_buffer_size - (SMB_HEADER_LEN + 5 * sizeof (word) + 5) - 4;*/ - maxsize = max_buffer_size - 48 - NETBIOS_HEADER_SIZE; + /*max_size_smb_com_write = f->server->server.max_buffer_size - (SMB_HEADER_LEN + 5 * sizeof (word) + 5) - 4;*/ + max_size_smb_com_write = max_buffer_size - 48 - NETBIOS_HEADER_SIZE; - LOG (("len = %ld, maxsize = %ld\n", len, maxsize)); + /* SMB_COM_WRITE cannot transmit more than 65535 bytes. */ + if(max_size_smb_com_write > 65535) + max_size_smb_com_write = 65535; - if (len <= maxsize) + LOG (("len = %ld, max_size_smb_com_write = %ld\n", len, max_size_smb_com_write)); + + /* Can we transmit this data with a single SMBwrite command? */ + if (len <= max_size_smb_com_write) { LOG (("use single write\n")); + ASSERT( len <= 65535 ); + /* Use a single SMBwrite packet whenever possible instead of a SMBwritebraw * because that requires two packets to be sent. */ @@ -605,9 +642,9 @@ smba_write (smba_file_t * f, char *data, long len, long offset) if (f->server->server.capabilities & CAP_RAW_MODE) { - dword max_raw_size = f->server->server.max_raw_size; + int max_raw_size = f->server->server.max_raw_size; int prefer_write_raw = f->server->server.prefer_write_raw; - int max_xmit; + int max_size_smb_com_write_raw; int n; /* Try to send the maximum number of bytes with the two SMBwritebraw packets. @@ -623,51 +660,45 @@ smba_write (smba_file_t * f, char *data, long len, long offset) * 4(timeout)+2(writemode)+4(reserved2)+2(datalength)+ * 2(dataoffset) = 25 bytes * - * The data poart of a SMB_COM_WRITE_RAW command accounts for + * The data part of a SMB_COM_WRITE_RAW command accounts for * 2(bytecount) = 2 bytes * * This leaves 'max_buffer_size' - 59 for the payload. */ - /*max_xmit = 2 * f->server->server.max_buffer_size - (SMB_HEADER_LEN + 12 * sizeof (word) + 4) - 8;*/ - max_xmit = max_buffer_size - 59 - NETBIOS_HEADER_SIZE + min(max_buffer_size, max_raw_size); + /*max_size_smb_com_write_raw = 2 * f->server->server.max_buffer_size - (SMB_HEADER_LEN + 12 * sizeof (word) + 4) - 8;*/ + max_size_smb_com_write_raw = max(max_buffer_size, max_raw_size) - 59 - NETBIOS_HEADER_SIZE; - LOG (("len = %ld, max_xmit = %ld\n", len, max_xmit)); + /* SMB_COM_WRITE_RAW cannot transmit more than 65535 bytes. */ + if(max_size_smb_com_write_raw > 65535) + max_size_smb_com_write_raw = 65535; - /* If the number of bytes that should be transferred exceed the number of - * bytes that could be transferred by a single call to smb_proc_write_raw(), - * the data is transfered as before: Only by the second packet. This - * prevents the CPU from copying the data into the transferbuffer. - */ - if (prefer_write_raw || max_xmit < len) - { - max_xmit = max_buffer_size - NETBIOS_HEADER_SIZE; - - LOG (("max_xmit changed to %ld\n", max_xmit)); - } + LOG (("len = %ld, max_size_smb_com_write_raw = %ld\n", len, max_size_smb_com_write_raw)); do { - n = min(len,max_xmit); + n = min(len, max_size_smb_com_write_raw); - if (!prefer_write_raw && n <= maxsize) + ASSERT( n > 0 ); + + /* Should we try and send this data with a single SMB_COM_WRITE? */ + if (!prefer_write_raw && n <= max_size_smb_com_write) { - LOG (("n (%ld) <= maxsize (%ld)\n", n, maxsize)); + LOG (("n (%ld) <= max_size_smb_com_write (%ld)\n", n, max_size_smb_com_write)); + + ASSERT( n <= 65535 ); /* Use a single SMBwrite packet whenever possible instead of a * SMBwritebraw because that requires two packets to be sent. */ result = smb_proc_write (&f->server->server, &f->dirent, offset, n, data); } + /* Use SMB_COM_WRITE_RAW instead. */ else { - if(n > (int)max_raw_size) + if(n > max_raw_size) n = max_raw_size; - /* Maximum SMB_COM_RAW_WRITE length is 65535 bytes. */ - if(n > 65535) - n = 65535; - - LOG (("n (%ld) > maxsize (%ld)\n", n, maxsize)); + ASSERT( n <= 65535 ); result = smb_proc_write_raw (&f->server->server, &f->dirent, offset, n, data); } @@ -695,14 +726,16 @@ smba_write (smba_file_t * f, char *data, long len, long offset) */ if (result <= 0 && num_bytes_written == 0) { - LOG (("resume with single writes len = %ld, maxsize = %ld\n", len, maxsize)); + LOG (("resume with single writes len = %ld, max_size_smb_com_write = %ld\n", len, max_size_smb_com_write)); do { - count = min(len,maxsize); + count = min(len, max_size_smb_com_write); if(count == 0) break; + ASSERT( count <= 65535 ); + result = smb_proc_write (&f->server->server, &f->dirent, offset, count, data); if (result < 0) goto out; @@ -732,7 +765,7 @@ smba_write (smba_file_t * f, char *data, long len, long offset) f->attr_time = -1; else if (result > 0) f->dirent.mtime = GetCurrentTime(); - + /* Even if one write access failed, we may have succeeded * at writing some data. Hence we update the cached file * size here. @@ -1028,15 +1061,15 @@ smba_readdir (smba_file_t * f, long offs, void *d, smba_callback_t callback) LOG (("delivering '%s', cache_index=%ld, eof=%ld\n", f->dircache->cache[o].complete_path, cache_index, eof)); - data.is_dir = (f->dircache->cache[o].attr & aDIR) != 0; - data.is_wp = (f->dircache->cache[o].attr & aRONLY) != 0; - data.is_hidden = (f->dircache->cache[o].attr & aHIDDEN) != 0; - data.is_system = (f->dircache->cache[o].attr & aSYSTEM) != 0; - data.is_archive = (f->dircache->cache[o].attr & aARCH) != 0; - data.size = f->dircache->cache[o].size; - data.atime = f->dircache->cache[o].atime; - data.ctime = f->dircache->cache[o].ctime; - data.mtime = f->dircache->cache[o].mtime; + data.is_dir = (f->dircache->cache[o].attr & aDIR) != 0; + data.is_wp = (f->dircache->cache[o].attr & aRONLY) != 0; + data.is_hidden = (f->dircache->cache[o].attr & aHIDDEN) != 0; + data.is_system = (f->dircache->cache[o].attr & aSYSTEM) != 0; + data.is_archive = (f->dircache->cache[o].attr & aARCH) != 0; + data.size = f->dircache->cache[o].size; + data.atime = f->dircache->cache[o].atime; + data.ctime = f->dircache->cache[o].ctime; + data.mtime = f->dircache->cache[o].mtime; if ((*callback) (d, cache_index, cache_index + 1, f->dircache->cache[o].complete_path, eof, &data)) break; @@ -1736,7 +1769,7 @@ smba_change_dircache_size(struct smba_server * server,int cache_size) } invalidate_dircache(server, NULL); - + free_dircache(old_dircache); server->dircache = new_cache; diff --git a/source_code/smbfs.h b/source_code/smbfs.h index 544deb8..2fb91f6 100644 --- a/source_code/smbfs.h +++ b/source_code/smbfs.h @@ -126,7 +126,7 @@ extern int h_errno; /****************************************************************************/ -extern int BroadcastNameQuery(char *name, char *scope, UBYTE *address); +extern int BroadcastNameQuery(const char *name, const char *scope, UBYTE *address); extern LONG CompareNames(STRPTR a,STRPTR b); extern LONG GetTimeZoneDelta(VOID); extern STRPTR amitcp_strerror(int error); @@ -159,7 +159,18 @@ extern APTR AllocateMemory(ULONG size); /****************************************************************************/ #undef memcpy + +#if defined (DEBUG) + #define memcpy(to,from,size) \ + do \ + { \ + ASSERT(((const char *)(to)) >= ((const char *)(from))+(size) || ((const char *)(from)) >= ((const char*)(to))+(size)); \ + CopyMem((APTR)(from),(APTR)(to),(ULONG)(size)); \ + } \ + while(0) +#else #define memcpy(to,from,size) ((void)CopyMem((APTR)(from),(APTR)(to),(ULONG)(size))) +#endif /* DEBUG */ /****************************************************************************/ diff --git a/source_code/smbfs_rev.h b/source_code/smbfs_rev.h index 9b0d3fe..41a69cf 100644 --- a/source_code/smbfs_rev.h +++ b/source_code/smbfs_rev.h @@ -1,6 +1,6 @@ #define VERSION 1 -#define REVISION 117 -#define DATE "11.4.2018" -#define VERS "smbfs 1.117" -#define VSTRING "smbfs 1.117 (11.4.2018)\r\n" -#define VERSTAG "\0$VER: smbfs 1.117 (11.4.2018)" +#define REVISION 120 +#define DATE "1.5.2018" +#define VERS "smbfs 1.120" +#define VSTRING "smbfs 1.120 (1.5.2018)\r\n" +#define VERSTAG "\0$VER: smbfs 1.120 (1.5.2018)" diff --git a/source_code/smbfs_rev.rev b/source_code/smbfs_rev.rev index 5bc6609..52bd8e4 100644 --- a/source_code/smbfs_rev.rev +++ b/source_code/smbfs_rev.rev @@ -1 +1 @@ -117 +120 diff --git a/source_code/sock.c b/source_code/sock.c index 43ef2f1..ea3224f 100644 --- a/source_code/sock.c +++ b/source_code/sock.c @@ -18,6 +18,15 @@ /*****************************************************************************/ +/* Some message size calculations include the size of the NetBIOS session + * header, which may not be necessary. The "message size" in question is not + * the same as the underlying transport layer, which in this case is + * NetBIOS over TCP. + */ +#define NETBIOS_HEADER_SIZE 4 + +/*****************************************************************************/ + #include "smb_abstraction.h" #include "dump_smb.h" @@ -60,7 +69,7 @@ smb_receive_raw (const struct smb_server *server, int sock_fd, unsigned char *ta re_recv: /* Read the NetBIOS session header (rfc-1002, section 4.3.1) */ - result = recvfrom (sock_fd, netbios_session_buf, 4, 0, NULL, NULL); + result = recvfrom (sock_fd, netbios_session_buf, NETBIOS_HEADER_SIZE, 0, NULL, NULL); if (result < 0) { LOG (("smb_receive_raw: recv error = %ld\n", errno)); @@ -68,24 +77,24 @@ smb_receive_raw (const struct smb_server *server, int sock_fd, unsigned char *ta goto out; } - if (result < 4) + if (result < NETBIOS_HEADER_SIZE) { - LOG (("smb_receive_raw: got less than 4 bytes\n")); + LOG (("smb_receive_raw: got less than %ld bytes\n", NETBIOS_HEADER_SIZE)); result = -EIO; goto out; } - netbios_session_payload_size = (int)smb_len (netbios_session_buf); + netbios_session_payload_size = (int)smb_len(netbios_session_buf); SHOWVALUE(netbios_session_payload_size); #if defined(DUMP_SMB) { if(netbios_session_buf[0] != 0x00 && netbios_session_payload_size > 0) { - if(netbios_session_payload_size > 256 - 4) - netbios_session_payload_size = 256 - 4; + if(netbios_session_payload_size > 256 - NETBIOS_HEADER_SIZE) + netbios_session_payload_size = 256 - NETBIOS_HEADER_SIZE; - result = recvfrom (sock_fd, &netbios_session_buf[4], netbios_session_payload_size - 4, 0, NULL, NULL); + result = recvfrom (sock_fd, &netbios_session_buf[NETBIOS_HEADER_SIZE], netbios_session_payload_size - NETBIOS_HEADER_SIZE, 0, NULL, NULL); if (result < 0) { LOG (("smb_receive_raw: recv error = %ld\n", errno)); @@ -93,13 +102,13 @@ smb_receive_raw (const struct smb_server *server, int sock_fd, unsigned char *ta goto out; } - if(result < netbios_session_payload_size - 4) + if(result < netbios_session_payload_size - NETBIOS_HEADER_SIZE) { result = -EIO; goto out; } - dump_netbios_header(__FILE__,__LINE__,netbios_session_buf,&netbios_session_buf[4],netbios_session_payload_size); + dump_netbios_header(__FILE__,__LINE__,netbios_session_buf,&netbios_session_buf[NETBIOS_HEADER_SIZE],netbios_session_payload_size); } else { @@ -146,15 +155,15 @@ smb_receive_raw (const struct smb_server *server, int sock_fd, unsigned char *ta if (want_header) { /* Check for buffer overflow. */ - if(len + 4 > max_raw_length) + if(len + NETBIOS_HEADER_SIZE > max_raw_length) { LOG (("smb_receive_raw: Received length (%ld) > max_xmit (%ld)!\n", len, max_raw_length)); result = -EIO; goto out; } - memcpy (target, netbios_session_buf, 4); - target += 4; + memcpy (target, netbios_session_buf, NETBIOS_HEADER_SIZE); + target += NETBIOS_HEADER_SIZE; } for(already_read = 0 ; already_read < len ; already_read += result) @@ -192,8 +201,10 @@ smb_receive (struct smb_server *server, int sock_fd) byte * packet = server->packet; int result; + ASSERT( server->max_recv <= server->packet_size ); + result = smb_receive_raw (server, sock_fd, packet, - server->max_recv - 4, /* max_xmit in server includes NB header */ + server->max_recv - NETBIOS_HEADER_SIZE, /* max_xmit in server includes NB header */ 1); /* We want the header */ if (result < 0) { @@ -412,7 +423,7 @@ smb_connect (struct smb_server *server) * case of error. */ int -smb_request (struct smb_server *server) +smb_request (struct smb_server *server, const void * payload, int payload_size) { int len, result; int sock_fd = server->mount_data.fd; @@ -434,13 +445,24 @@ smb_request (struct smb_server *server) /* Length includes the NetBIOS session header (4 bytes), which * is prepended to the packet to be sent. */ - len = smb_len (buffer) + 4; + len = smb_len (buffer) + NETBIOS_HEADER_SIZE; - LOG (("smb_request: len = %ld cmd = 0x%lx\n", len, buffer[8])); + /* If there is a separate payload, only send the header + * here and take of the payload later. + */ + if(payload != NULL && payload_size > 0) + { + ASSERT( payload_size < smb_len(buffer) ); + ASSERT( len > payload_size ); + + len -= payload_size; + } + + LOG (("smb_request: len = %ld, cmd = 0x%lx, payload=%lx, payload_size=%ld\n", len, buffer[8], payload, payload_size)); #if defined(DUMP_SMB) - dump_netbios_header(__FILE__,__LINE__,buffer,&buffer[4],len); - dump_smb(__FILE__,__LINE__,0,buffer+4,len-4,smb_packet_from_consumer,server->max_recv); + dump_netbios_header(__FILE__,__LINE__,buffer,&buffer[NETBIOS_HEADER_SIZE],len); + dump_smb(__FILE__,__LINE__,0,buffer+NETBIOS_HEADER_SIZE,len-NETBIOS_HEADER_SIZE,smb_packet_from_consumer,server->max_recv); #endif /* defined(DUMP_SMB) */ result = send (sock_fd, (void *) buffer, len, 0); @@ -449,12 +471,23 @@ smb_request (struct smb_server *server) LOG (("smb_request: send error = %ld\n", errno)); result = (-errno); + goto out; } - else + + if(payload != NULL && payload_size > 0) { - result = smb_receive (server, sock_fd); + result = send (sock_fd, (void *)payload, payload_size, 0); + if (result < 0) + { + LOG (("smb_request: payload send error = %ld\n", errno)); + + result = (-errno); + goto out; + } } + result = smb_receive (server, sock_fd); + out: if (result < 0) @@ -486,13 +519,13 @@ smb_trans2_request (struct smb_server *server, int *data_len, int *param_len, ch /* Length includes the NetBIOS session header (4 bytes), which * is prepended to the packet to be sent. */ - len = smb_len (buffer) + 4; + len = smb_len (buffer) + NETBIOS_HEADER_SIZE; LOG (("smb_request: len = %ld cmd = 0x%02lx\n", len, buffer[8])); #if defined(DUMP_SMB) dump_netbios_header(__FILE__,__LINE__,buffer,NULL,0); - dump_smb(__FILE__,__LINE__,0,buffer+4,len-4,smb_packet_from_consumer,server->max_recv); + dump_smb(__FILE__,__LINE__,0,buffer+NETBIOS_HEADER_SIZE,len-NETBIOS_HEADER_SIZE,smb_packet_from_consumer,server->max_recv); #endif /* defined(DUMP_SMB) */ result = send (sock_fd, (void *) buffer, len, 0); @@ -537,7 +570,7 @@ smb_request_read_raw (struct smb_server *server, unsigned char *target, int max_ /* Length includes the NetBIOS session header (4 bytes), which * is prepended to the packet to be sent. */ - len = smb_len (buffer) + 4; + len = smb_len (buffer) + NETBIOS_HEADER_SIZE; LOG (("smb_request_read_raw: len = %ld cmd = 0x%02lx\n", len, buffer[8])); LOG (("smb_request_read_raw: target=%lx, max_len=%ld\n", (unsigned int) target, max_len)); @@ -545,7 +578,7 @@ smb_request_read_raw (struct smb_server *server, unsigned char *target, int max_ #if defined(DUMP_SMB) dump_netbios_header(__FILE__,__LINE__,buffer,NULL,0); - dump_smb(__FILE__,__LINE__,0,buffer+4,len-4,smb_packet_from_consumer,server->max_recv); + dump_smb(__FILE__,__LINE__,0,buffer+NETBIOS_HEADER_SIZE,len-NETBIOS_HEADER_SIZE,smb_packet_from_consumer,server->max_recv); #endif /* defined(DUMP_SMB) */ /* Request that data should be read in raw mode. */ @@ -585,7 +618,7 @@ int smb_request_write_raw (struct smb_server *server, unsigned const char *source, int length) { int result; - byte nb_header[4]; + byte nb_header[NETBIOS_HEADER_SIZE]; int sock_fd = server->mount_data.fd; int num_bytes_written = 0; @@ -595,6 +628,9 @@ smb_request_write_raw (struct smb_server *server, unsigned const char *source, i goto out; } + if(length > 65535) + length = 65535; + /* Send the NetBIOS header. */ smb_encode_smb_length (nb_header, length); @@ -602,8 +638,8 @@ smb_request_write_raw (struct smb_server *server, unsigned const char *source, i dump_netbios_header(__FILE__,__LINE__,nb_header,NULL,0); #endif /* defined(DUMP_SMB) */ - result = send (sock_fd, nb_header, 4, 0); - if (result == 4) + result = send (sock_fd, nb_header, NETBIOS_HEADER_SIZE, 0); + if (result == NETBIOS_HEADER_SIZE) { #if defined(DUMP_SMB) dump_smb(__FILE__,__LINE__,0,source,length,smb_packet_from_consumer,server->max_recv); @@ -618,7 +654,7 @@ smb_request_write_raw (struct smb_server *server, unsigned const char *source, i /* Wait for the server to respond. */ if(!server->write_behind) { - LOG(("waiting for server to respond... ")); + LOG(("waiting for server to respond...\n")); result = smb_receive (server, sock_fd); LOG(("response = %ld\n", result)); } @@ -629,6 +665,7 @@ smb_request_write_raw (struct smb_server *server, unsigned const char *source, i } else { + LOG(("send() for %ld bytes failed\n", length)); result = (-errno); } }