From 31c8fb0d77fc1d8480e7a60fac494d521e67a74f Mon Sep 17 00:00:00 2001 From: obarthel Date: Sun, 3 Jun 2018 11:36:04 +0200 Subject: [PATCH] Updated to version 1.146 Please keep in mind that this is still a development version and might surprise you (not necessarily in a good way). Do not let me discourage you to build and test this version, although there will be some risks involved such as data corruption or loss of data. --- documentation/history.doc | 51 +++ source_code/include/smb/smb_fs.h | 4 + source_code/include/smb/smb_fs_sb.h | 9 + source_code/include/smb/smbno.h | 80 ++-- source_code/main.c | 557 ++++++++++++++++++++++++---- source_code/proc.c | 347 ++++++++++++++--- source_code/smb_abstraction.c | 269 +++++++++----- source_code/smb_abstraction.h | 4 +- source_code/smbfs_rev.h | 10 +- source_code/smbfs_rev.rev | 2 +- source_code/sock.c | 135 +++++++ 11 files changed, 1204 insertions(+), 264 deletions(-) diff --git a/documentation/history.doc b/documentation/history.doc index 538bbc4..f73819f 100644 --- a/documentation/history.doc +++ b/documentation/history.doc @@ -1865,3 +1865,54 @@ smbfs 1.144 (1.6.2018) proper directory information, such as the Samba 3.0.37 version which is part of the FRITZ!Box firmware. Note that once Unicode support is enabled, the UTF8, CP437, CP850 and TRANSLATE options will be ignored. + + +smbfs 1.145 (2.6.2018) + +- I broke renaming by mixing up the length of the new name with the + old name length. Fixed. + +- Renaming now also works on hidden files and system files, just like + deletion works on system files and hidden files, too. Keep in mind + that a file or directory which is not write-enabled cannot be + renamed (that's what the documentation says, anyway). + +- Plugged the SMB_COM_READ_RAW/SMB_COM_WRITE_RAW code back into the + file system. Added support for 64 bit file position information. + + +smbfs 1.146 (3.6.2018) + +- Added extra sanity checks for file handles and file locks, which + should prevent files from getting closed twice, or locks from + getting freed twice. We also detect files and locks which smbfs + does not know and reject these before it's too late. + +- Dropped more unused code, e.g. in the cache invalidation function. + +- Instead of using local string buffers, we now allocate memory for + the buffers instead. This avoids truncating path/service names + if these would have become too long for the original local string + buffer to hold. + +- Added the options PREFERWRITERAW, PREFERREADRAW and WRITEBEHIND. + The first two will make smbfs use SMB_COM_WRITE_RAW over + SMB_COM_WRITE_ANDX and SMB_COM_READ_RAW over SMB_COM_READ_ANDX, + respectively. WRITEBEHIND activates somewhat asynchronous + SMB_COM_WRITE_RAW operations, but don't get your hopes up just + yet, as the effects are (so far) rather minor. + + Careful about the PREFERWRITERAW/PREFERREADRAW switches: if the + server does not support these operations, smbfs will fall back + onto the original SMB_COM_WRITE and SMB_COM_READ commands which + cannot be used safely with files larger than 4 Gigabytes. + +- Changed the command template: the debug options are now at the + end of the list. + +- The use of the DEBUGFILE option would pretty reliably trigger + an Enforcer hit, followed by a system crash. Note to self: + don't leave dangling BPTRs behind. + +- If no modification time is provided for a directory entry, + the creation time will be substituted for it. diff --git a/source_code/include/smb/smb_fs.h b/source_code/include/smb/smb_fs.h index 353a8b3..db272fb 100644 --- a/source_code/include/smb/smb_fs.h +++ b/source_code/include/smb/smb_fs.h @@ -79,6 +79,8 @@ int smb_proc_setattr_core(struct smb_server *server, const char *path, int len, int smb_proc_setattrE(struct smb_server *server, word fid, struct smb_dirent *new_entry, int * error_ptr); int smb_proc_dskattr (struct smb_server *server, struct smb_dskattr *attr, int * error_ptr); int smb_proc_connect(struct smb_server *server, int * error_ptr); +int smb_proc_read_raw (struct smb_server *server, struct smb_dirent *finfo, const QUAD * const offset_quad, long count, char *data, int * error_ptr); +int smb_proc_write_raw (struct smb_server *server, struct smb_dirent *finfo, const QUAD * const offset_quad, long count, const char *data, int * error_ptr); /* sock.c */ int smb_discard_netbios_frames(struct smb_server *server, int sock_fd, int * error_ptr); @@ -87,5 +89,7 @@ void smb_release(struct smb_server *server); int smb_connect(struct smb_server *server, int * error_ptr); int smb_request(struct smb_server *server, int command, void * input_payload,const void * output_payload,int payload_size, int * error_ptr); int smb_trans2_request(struct smb_server *server, int command, int *data_len, int *param_len, char **data, char **param, int * error_ptr); +int smb_request_read_raw (struct smb_server *server, unsigned char *target, int max_len, int * error_ptr); +int smb_request_write_raw (struct smb_server *server, unsigned const char *source, int length, int * error_ptr); #endif /* _SMB_FS_H_SMB_H */ diff --git a/source_code/include/smb/smb_fs_sb.h b/source_code/include/smb/smb_fs_sb.h index 3c79d46..f5a603c 100644 --- a/source_code/include/smb/smb_fs_sb.h +++ b/source_code/include/smb/smb_fs_sb.h @@ -59,6 +59,15 @@ struct smb_server /* olsen (2012-12-10): raw SMB over TCP instead of NBT transport? */ int raw_smb; + /* olsen (2016-06-03): Prefer SMB_COM_WRITE_RAW to SMB_COM_WRITE_ANDX? */ + int prefer_write_raw; + + /* olsen (2016-04-20): Use write-behind with SMB_COM_WRITE_RAW? */ + int write_behind; + + /* olsen (2016-06-03): Prefer SMB_COM_READ_RAW to SMB_COM_READ_ANDX? */ + int prefer_read_raw; + /* olsen (2018-05-09): Timeout for send/receive operations in seconds. */ int timeout; diff --git a/source_code/include/smb/smbno.h b/source_code/include/smb/smbno.h index cc2d9d4..51201be 100644 --- a/source_code/include/smb/smbno.h +++ b/source_code/include/smb/smbno.h @@ -5,14 +5,6 @@ #ifndef _SMBNO_H_ #define _SMBNO_H_ -/* these define the attribute byte as seen by DOS */ -#define aRONLY (1L<<0) -#define aHIDDEN (1L<<1) -#define aSYSTEM (1L<<2) -#define aVOLID (1L<<3) -#define aDIR (1L<<4) -#define aARCH (1L<<5) - /* error classes */ #define SUCCESS 0 /* The request was successful. */ #define ERRDOS 0x01 /* Error is from the core DOS operating system set. */ @@ -62,37 +54,37 @@ /* Error codes for the ERRSRV class */ -#define ERRerror 1 /* Non specific error code */ -#define ERRbadpw 2 /* Bad password */ -#define ERRbadtype 3 /* reserved */ -#define ERRaccess 4 /* No permissions to do the requested operation */ -#define ERRinvnid 5 /* tid invalid */ -#define ERRinvnetname 6 /* Invalid servername */ -#define ERRinvdevice 7 /* Invalid device */ -#define ERRqfull 49 /* Print queue full */ -#define ERRqtoobig 50 /* Queued item too big */ -#define ERRqeof 51 -#define ERRinvpfid 52 /* Invalid print file in smb_fid */ -#define ERRsmbcmd 64 /* Unrecognised command */ -#define ERRsrverror 65 /* smb server internal error */ -#define ERRbadBID 66 -#define ERRfilespecs 67 /* fid and pathname invalid combination */ -#define ERRbadlink 68 /* reserved */ -#define ERRbadpermits 69 /* Access specified for a file is not valid */ -#define ERRbadpid 70 /* reserved */ -#define ERRsetattrmode 71 /* attribute mode invalid */ -#define ERRpaused 81 /* Message server paused */ -#define ERRmsgoff 82 /* Not receiving messages */ -#define ERRnoroom 83 /* No room for message */ -#define ERRrmuns 87 /* too many remote usernames */ -#define ERRtimeout 88 /* operation timed out */ -#define ERRnoresource 89 /* No resources currently available for request. */ -#define ERRtoomanyuids 90 /* too many userids */ -#define ERRbaduid 91 /* bad userid */ -#define ERRuseMPX 250 /* temporarily unable to use raw mode, use MPX mode */ -#define ERRuseSTD 251 /* temporarily unable to use raw mode, use std.mode */ -#define ERRcontMPX 252 /* resume MPX mode */ -#define ERRbadPW 254 +#define ERRerror 1 /* Non specific error code */ +#define ERRbadpw 2 /* Bad password */ +#define ERRbadtype 3 /* reserved */ +#define ERRaccess 4 /* No permissions to do the requested operation */ +#define ERRinvnid 5 /* tid invalid */ +#define ERRinvnetname 6 /* Invalid servername */ +#define ERRinvdevice 7 /* Invalid device */ +#define ERRqfull 49 /* Print queue full */ +#define ERRqtoobig 50 /* Queued item too big */ +#define ERRqeof 51 +#define ERRinvpfid 52 /* Invalid print file in smb_fid */ +#define ERRsmbcmd 64 /* Unrecognised command */ +#define ERRsrverror 65 /* smb server internal error */ +#define ERRbadBID 66 +#define ERRfilespecs 67 /* fid and pathname invalid combination */ +#define ERRbadlink 68 /* reserved */ +#define ERRbadpermits 69 /* Access specified for a file is not valid */ +#define ERRbadpid 70 /* reserved */ +#define ERRsetattrmode 71 /* attribute mode invalid */ +#define ERRpaused 81 /* Message server paused */ +#define ERRmsgoff 82 /* Not receiving messages */ +#define ERRnoroom 83 /* No room for message */ +#define ERRrmuns 87 /* too many remote usernames */ +#define ERRtimeout 88 /* operation timed out */ +#define ERRnoresource 89 /* No resources currently available for request. */ +#define ERRtoomanyuids 90 /* too many userids */ +#define ERRbaduid 91 /* bad userid */ +#define ERRuseMPX 250 /* temporarily unable to use raw mode, use MPX mode */ +#define ERRuseSTD 251 /* temporarily unable to use raw mode, use std.mode */ +#define ERRcontMPX 252 /* resume MPX mode */ +#define ERRbadPW 254 #define ERRnotifyEnumDir 1024 #define ERRaccountExpired 2239 #define ERRbadClient 2240 @@ -420,13 +412,13 @@ #define SMB_OPEN_WRITE_THROUGH_ENABLED 0x4000 /* SMB header flags (which go into the "flags" field). */ -#define SMB_FLG_SERVER_TO_REDIR 0x80 +#define SMB_FLG_SERVER_TO_REDIR 0x80 #define SMB_FLG_REQUEST_BATCH_OPLOCK 0x40 -#define SMB_FLG_REQUEST_OPLOCK 0x20 -#define SMB_FLG_CANONICAL_PATHNAMES 0x10 -#define SMB_FLG_CASELESS_PATHNAMES 0x08 +#define SMB_FLG_REQUEST_OPLOCK 0x20 +#define SMB_FLG_CANONICAL_PATHNAMES 0x10 +#define SMB_FLG_CASELESS_PATHNAMES 0x08 #define SMB_FLG_CLIENT_BUF_AVAIL 0x02 -#define SMB_FLG_SUPPORT_LOCKREAD 0x0 +#define SMB_FLG_SUPPORT_LOCKREAD 0x01 /* More SMB header flags (which go into the "flags2" field). */ #define SMB_FLG2_UNICODE_STRINGS 0x8000 diff --git a/source_code/main.c b/source_code/main.c index 7b9ce1b..3cd654d 100644 --- a/source_code/main.c +++ b/source_code/main.c @@ -26,10 +26,10 @@ * 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 - * Fritz!Box: smbfs debuglevel=2 user=nas password=nas volume=fritz.nas //fritzbox-3272/fritz.nas - * Samba 4.6.7: smbfs debuglevel=2 volume=ubuntu-test //ubuntu-17-olaf/test - * Samba 4.7.6: smbfs debuglevel=2 volume=ubuntu-test //ubuntu-18-olaf/test - * Samba 3.0.25: smbfs debuglevel=2 user=olsen password=... volume=olsen //192.168.1.118/olsen + * Fritz!Box: smbfs debuglevel=2 debugfile=ram:fritz.nas.log unicode user=nas password=nas volume=fritz.nas //fritzbox-3272/fritz.nas + * Samba 4.6.7: smbfs debuglevel=2 debugfile=ram:ubuntu-17.log volume=ubuntu-test //ubuntu-17-olaf/test + * Samba 4.7.6: smbfs debuglevel=2 debugfile=ram:ubuntu-18.log volume=ubuntu-test //ubuntu-18-olaf/test + * Samba 3.0.25: smbfs debuglevel=2 debugfile=ram:samba-3.0.25.log user=olsen password=... volume=olsen //192.168.1.118/olsen */ #include "smbfs.h" @@ -53,7 +53,7 @@ /****************************************************************************/ #include "smbfs_rev.h" -STRPTR Version = VERSTAG; +TEXT Version[] = VERSTAG; /****************************************************************************/ @@ -77,6 +77,8 @@ struct FileNode { struct MinNode fn_MinNode; + ULONG fn_Magic; + struct FileHandle * fn_Handle; QUAD fn_OffsetQuad; @@ -90,6 +92,8 @@ struct LockNode { struct MinNode ln_MinNode; + ULONG ln_Magic; + struct FileLock ln_FileLock; smba_file_t * ln_File; @@ -145,7 +149,7 @@ STATIC ULONG stack_usage_exit(const struct StackSwapStruct * stk); STATIC LONG CVSPrintf(const TEXT * format_string, APTR args); STATIC VOID VSPrintf(STRPTR buffer, const TEXT * formatString, APTR args); STATIC VOID Cleanup(VOID); -STATIC BOOL Setup(const TEXT * program_name, const TEXT * service, const TEXT * workgroup, const TEXT * username, STRPTR opt_password, BOOL opt_changecase, const TEXT * opt_clientname, const TEXT * opt_servername, int opt_cachesize, int opt_max_transmit, int opt_timeout, LONG *opt_time_zone_offset, LONG *opt_dst_offset, BOOL opt_raw_smb, BOOL opt_unicode, const TEXT * device_name, const TEXT * volume_name, const TEXT * translation_file); +STATIC BOOL Setup(const TEXT * program_name, const TEXT * service, const TEXT * workgroup, const TEXT * username, STRPTR opt_password, BOOL opt_changecase, const TEXT * opt_clientname, const TEXT * opt_servername, int opt_cachesize, int opt_max_transmit, int opt_timeout, LONG *opt_time_zone_offset, LONG *opt_dst_offset, BOOL opt_raw_smb, BOOL opt_unicode, BOOL opt_prefer_write_raw, BOOL opt_write_behind, BOOL opt_prefer_read_raw, const TEXT * device_name, const TEXT * volume_name, const TEXT * translation_file); STATIC VOID HandleFileSystem(const TEXT * device_name, const TEXT * volume_name, const TEXT * service_name); /****************************************************************************/ @@ -547,20 +551,23 @@ main(VOID) NUMBER CacheSize; NUMBER MaxTransmit; NUMBER Timeout; - NUMBER DebugLevel; - KEY DebugFile; NUMBER TimeZoneOffset; NUMBER DSTOffset; SWITCH NetBIOSTransport; - SWITCH DumpSMB; - NUMBER DumpSMBLevel; - KEY DumpSMBFile; + SWITCH PreferWriteRaw; + SWITCH WriteBehind; + SWITCH PreferReadRaw; SWITCH Unicode; SWITCH UTF8; SWITCH CP437; SWITCH CP850; KEY TranslationFile; KEY Service; + NUMBER DebugLevel; + KEY DebugFile; + SWITCH DumpSMB; + NUMBER DumpSMBLevel; + KEY DumpSMBFile; } args; STRPTR cmd_template = @@ -578,20 +585,23 @@ main(VOID) "CACHE=CACHESIZE/N/K," "MAXTRANSMIT/N/K," "TIMEOUT/N/K," - "DEBUGLEVEL=DEBUG/N/K," - "DEBUGFILE/K," "TZ=TIMEZONEOFFSET/N/K," "DST=DSTOFFSET/N/K," "NETBIOS/S," - "DUMPSMB/S," - "DUMPSMBLEVEL/N/K," - "DUMPSMBFILE/K," + "PREFERWRITERAW/S," + "WRITEBEHIND/S," + "PREFERREADRAW/S," "UNICODE/S," "UTF8/S," "CP437/S," "CP850/S," "TRANSLATE=TRANSLATIONFILE/K," - "SERVICE/A"; + "SERVICE/A," + "DEBUGLEVEL=DEBUG/N/K," + "DEBUGFILE/K," + "DUMPSMB/S," + "DUMPSMBLEVEL/N/K," + "DUMPSMBFILE/K"; BPTR debug_file = (BPTR)NULL; BOOL close_debug_file = FALSE; @@ -810,6 +820,15 @@ main(VOID) if(FindToolType(Icon->do_ToolTypes,"NETBIOS") != NULL) args.NetBIOSTransport = TRUE; + if(FindToolType(Icon->do_ToolTypes,"PREFERWRITERAW") != NULL) + args.PreferWriteRaw = TRUE; + + if(FindToolType(Icon->do_ToolTypes,"WRITEBEHIND") != NULL) + args.WriteBehind = TRUE; + + if(FindToolType(Icon->do_ToolTypes,"PREFERREADRAW") != NULL) + args.PreferReadRaw = TRUE; + str = FindToolType(Icon->do_ToolTypes,"TRANSLATE"); if(str == NULL) str = FindToolType(Icon->do_ToolTypes,"TRANSLATIONFILE"); @@ -1093,6 +1112,9 @@ main(VOID) args.DSTOffset, !args.NetBIOSTransport, /* Use raw SMB transport instead of NetBIOS transport? */ args.Unicode, + args.PreferWriteRaw, + args.WriteBehind, + args.PreferReadRaw, args.DeviceName, args.VolumeName, args.TranslationFile)) @@ -1127,10 +1149,16 @@ main(VOID) } #endif /* DUMP_SMB */ + Cleanup(); + if(close_debug_file && debug_file != (BPTR)NULL) + { Close(debug_file); - Cleanup(); + SETDEBUGFILE((BPTR)NULL); + + SETDEBUGLEVEL(0); + } return(result); } @@ -2272,7 +2300,10 @@ MapErrnoToIoErr(int error) { -1, -1 } }; + #if DEBUG int original_error = error; + #endif /* DEBUG */ + LONG result = ERROR_ACTION_NOT_KNOWN; int i; @@ -2397,16 +2428,25 @@ TranslateCName(TEXT * name,const TEXT * map) STATIC BOOL ReallyRemoveDosEntry(struct DosList * entry) { + struct DosPacket * dp; struct Message * mn; struct MsgPort * port; struct DosList * dl; BOOL result = FALSE; int kind,i; + ENTER(); + if(entry->dol_Type == DLT_DEVICE) + { + D(("removing '%b' (device)", entry->dol_Name)); kind = LDF_DEVICES; + } else + { + D(("removing '%b' (volume)", entry->dol_Name)); kind = LDF_VOLUMES; + } port = entry->dol_Task; @@ -2418,6 +2458,8 @@ ReallyRemoveDosEntry(struct DosList * entry) if(dl != NULL) { + D(("doslist is locked; removing '%b' for good", entry->dol_Name)); + RemDosEntry(entry); UnLockDosList(LDF_WRITE|kind); @@ -2428,11 +2470,21 @@ ReallyRemoveDosEntry(struct DosList * entry) } while((mn = GetMsg(port)) != NULL) - ReplyPkt((struct DosPacket *)mn->mn_Node.ln_Name,DOSFALSE,ERROR_ACTION_NOT_KNOWN); + { + SHOWMSG("returning pending packet"); + + dp = (struct DosPacket *)mn->mn_Node.ln_Name; + + ReplyPkt(dp,(dp->dp_Action == ACTION_READ_LINK) ? -1 : DOSFALSE,ERROR_ACTION_NOT_KNOWN); + } Delay(TICKS_PER_SECOND / 10); } + if(NOT result) + SHOWMSG("that didn't work"); + + RETURN(result); return(result); } @@ -2479,8 +2531,17 @@ Cleanup(VOID) { if(DeviceNodeAdded) { + SHOWMSG("removing the device node"); + if(ReallyRemoveDosEntry(DeviceNode)) + { + SHOWMSG("freeing the device node"); FreeDosEntry(DeviceNode); + } + else + { + SHOWMSG("that didn't work."); + } } else { @@ -2494,10 +2555,19 @@ Cleanup(VOID) { if(VolumeNodeAdded) { + SHOWMSG("removing the volume node"); + if(ReallyRemoveDosEntry(VolumeNode)) + { + SHOWMSG("freeing the volume node"); FreeDosEntry(VolumeNode); - send_disk_change = TRUE; + send_disk_change = TRUE; + } + else + { + SHOWMSG("that didn't work."); + } } else { @@ -2509,18 +2579,32 @@ Cleanup(VOID) if(FileSystemPort != NULL) { + struct DosPacket * dp; struct Message * mn; + SHOWMSG("returning all pending packets"); + /* Return all queued packets; there should be none, though. */ while((mn = GetMsg(FileSystemPort)) != NULL) - ReplyPkt((struct DosPacket *)mn->mn_Node.ln_Name,DOSFALSE,ERROR_ACTION_NOT_KNOWN); + { + dp = (struct DosPacket *)mn->mn_Node.ln_Name; + + ReplyPkt(dp,(dp->dp_Action == ACTION_READ_LINK) ? -1 : DOSFALSE,ERROR_ACTION_NOT_KNOWN); + } + + SHOWMSG("done"); DeleteMsgPort(FileSystemPort); FileSystemPort = NULL; } if(WBStartup == NULL && send_disk_change) + { + SHOWMSG("sending a disk removed event"); SendDiskChange(IECLASS_DISKREMOVED); + } + + SHOWMSG("closing libraries and devices..."); #if defined(__amigaos4__) { @@ -2619,6 +2703,9 @@ Setup( LONG * opt_dst_offset, BOOL opt_raw_smb, BOOL opt_unicode, + BOOL opt_prefer_write_raw, + BOOL opt_write_behind, + BOOL opt_prefer_read_raw, const TEXT * device_name, const TEXT * volume_name, const TEXT * translation_file) @@ -2795,6 +2882,9 @@ Setup( opt_timeout, opt_raw_smb, opt_unicode, + opt_prefer_write_raw, + opt_write_behind, + opt_prefer_read_raw, &error, &smb_error_class, &smb_error, @@ -3562,6 +3652,14 @@ Action_Parent( { struct LockNode * parent_ln = (struct LockNode *)parent->fl_Key; + if(parent_ln == NULL || parent_ln->ln_Magic != ID_SMB_DISK) + { + SHOWMSG("lock doesn't look right"); + + error = ERROR_INVALID_LOCK; + goto out; + } + parent_name = parent_ln->ln_FullName; parent_ln->ln_LastUser = user; @@ -3594,6 +3692,7 @@ Action_Parent( memset(ln,0,sizeof(*ln)); ln->ln_FileLock.fl_Key = (LONG)ln; + ln->ln_Magic = ID_SMB_DISK; ln->ln_FileLock.fl_Access = SHARED_LOCK; ln->ln_FileLock.fl_Task = FileSystemPort; ln->ln_FileLock.fl_Volume = MKBADDR(VolumeNode); @@ -3642,7 +3741,6 @@ Action_DeleteObject( STRPTR full_parent_name = NULL; TEXT name[MAX_FILENAME_LEN+1]; struct LockNode * ln; - int ignored_error; smba_stat_t st; int error; @@ -3660,6 +3758,14 @@ Action_DeleteObject( { ln = (struct LockNode *)parent->fl_Key; + if(ln == NULL || ln->ln_Magic != ID_SMB_DISK) + { + SHOWMSG("lock doesn't look right"); + + error = ERROR_INVALID_LOCK; + goto out; + } + parent_name = ln->ln_FullName; ln->ln_LastUser = user; @@ -3759,7 +3865,7 @@ Action_DeleteObject( goto out; } - smba_close(file,&ignored_error); + smba_close(ServerData,file); file = NULL; if(st.is_dir) @@ -3830,7 +3936,7 @@ Action_DeleteObject( out: if(file != NULL) - smba_close(file,&ignored_error); + smba_close(ServerData,file); FreeMemory(full_name); FreeMemory(full_parent_name); @@ -3859,7 +3965,6 @@ Action_CreateDir( smba_file_t * dir = NULL; const TEXT * base_name; TEXT name[MAX_FILENAME_LEN+1]; - int ignored_error; int error; int i; @@ -3877,6 +3982,14 @@ Action_CreateDir( { struct LockNode * parent_ln = (struct LockNode *)parent->fl_Key; + if(parent_ln == NULL || parent_ln->ln_Magic != ID_SMB_DISK) + { + SHOWMSG("lock doesn't look right"); + + error = ERROR_INVALID_LOCK; + goto out; + } + parent_ln->ln_LastUser = user; parent_name = parent_ln->ln_FullName; @@ -3975,6 +4088,7 @@ Action_CreateDir( memset(ln,0,sizeof(*ln)); ln->ln_FileLock.fl_Key = (LONG)ln; + ln->ln_Magic = ID_SMB_DISK; ln->ln_FileLock.fl_Access = EXCLUSIVE_LOCK; ln->ln_FileLock.fl_Task = FileSystemPort; ln->ln_FileLock.fl_Volume = MKBADDR(VolumeNode); @@ -3995,7 +4109,7 @@ Action_CreateDir( goto out; } - smba_close(dir,&ignored_error); + smba_close(ServerData,dir); dir = NULL; D(("full_name = '%s'",escape_name(full_name))); @@ -4016,7 +4130,7 @@ Action_CreateDir( out: if(dir != NULL) - smba_close(dir,&ignored_error); + smba_close(ServerData,dir); FreeMemory(dir_name); FreeMemory(full_name); @@ -4053,6 +4167,14 @@ Action_LocateObject( { struct LockNode * parent_ln = (struct LockNode *)parent->fl_Key; + if(parent_ln == NULL || parent_ln->ln_Magic != ID_SMB_DISK) + { + SHOWMSG("lock doesn't look right"); + + error = ERROR_INVALID_LOCK; + goto out; + } + parent_ln->ln_LastUser = user; parent_name = parent_ln->ln_FullName; @@ -4121,6 +4243,7 @@ Action_LocateObject( memset(ln,0,sizeof(*ln)); ln->ln_FileLock.fl_Key = (LONG)ln; + ln->ln_Magic = ID_SMB_DISK; ln->ln_FileLock.fl_Access = (mode != EXCLUSIVE_LOCK) ? SHARED_LOCK : EXCLUSIVE_LOCK; ln->ln_FileLock.fl_Task = FileSystemPort; ln->ln_FileLock.fl_Volume = MKBADDR(VolumeNode); @@ -4197,6 +4320,14 @@ Action_CopyDir( { struct LockNode * source = (struct LockNode *)lock->fl_Key; + if(source == NULL || source->ln_Magic != ID_SMB_DISK) + { + SHOWMSG("lock doesn't look right"); + + error = ERROR_INVALID_LOCK; + goto out; + } + source->ln_LastUser = user; source_name = source->ln_FullName; @@ -4220,6 +4351,7 @@ Action_CopyDir( memcpy(full_name,source_name,source_name_len+1); ln->ln_FileLock.fl_Key = (LONG)ln; + ln->ln_Magic = ID_SMB_DISK; ln->ln_FileLock.fl_Access = source_mode; ln->ln_FileLock.fl_Task = FileSystemPort; ln->ln_FileLock.fl_Volume = MKBADDR(VolumeNode); @@ -4260,8 +4392,9 @@ Action_FreeLock( LONG * error_ptr) { LONG result = DOSTRUE; + const struct LockNode * key; + struct LockNode * found; struct LockNode * ln; - int ignored_error; int error = OK; ENTER(); @@ -4271,13 +4404,45 @@ Action_FreeLock( if(lock == NULL) goto out; - ln = (struct LockNode *)lock->fl_Key; + /* Make sure that no lock is released twice, and that we + * know which locks are ours. + */ + found = NULL; + key = (struct LockNode *)lock->fl_Key; - Remove((struct Node *)ln); + if(key == NULL || key->ln_Magic != ID_SMB_DISK) + { + SHOWMSG("lock doesn't look right"); - smba_close(ln->ln_File,&ignored_error); - FreeMemory(ln->ln_FullName); - FreeMemory(ln); + error = ERROR_INVALID_LOCK; + goto out; + } + + for(ln = (struct LockNode *)LockList.mlh_Head ; + ln->ln_MinNode.mln_Succ != NULL ; + ln = (struct LockNode *)ln->ln_MinNode.mln_Succ) + { + if(ln == key) + { + found = ln; + break; + } + } + + if(found == NULL) + { + error = ERROR_INVALID_LOCK; + goto out; + } + + Remove((struct Node *)found); + + smba_close(ServerData,found->ln_File); + + found->ln_Magic = 0; + + FreeMemory(found->ln_FullName); + FreeMemory(found); out: @@ -4310,6 +4475,14 @@ Action_SameLock( { struct LockNode * ln = (struct LockNode *)lock1->fl_Key; + if(ln == NULL || ln->ln_Magic != ID_SMB_DISK) + { + SHOWMSG("lock doesn't look right"); + + error = ERROR_INVALID_LOCK; + goto out; + } + ln->ln_LastUser = user; name1 = ln->ln_FullName; @@ -4323,6 +4496,14 @@ Action_SameLock( { struct LockNode * ln = (struct LockNode *)lock2->fl_Key; + if(ln == NULL || ln->ln_Magic != ID_SMB_DISK) + { + SHOWMSG("lock doesn't look right"); + + error = ERROR_INVALID_LOCK; + goto out; + } + ln->ln_LastUser = user; name2 = ln->ln_FullName; @@ -4338,6 +4519,8 @@ Action_SameLock( if(Stricmp(name1,name2) == SAME) result = DOSTRUE; + out: + (*error_ptr) = error; RETURN(result); @@ -4376,6 +4559,14 @@ Action_SetProtect( { struct LockNode * ln = (struct LockNode *)parent->fl_Key; + if(ln == NULL || ln->ln_Magic != ID_SMB_DISK) + { + SHOWMSG("lock doesn't look right"); + + error = ERROR_INVALID_LOCK; + goto out; + } + ln->ln_LastUser = user; parent_name = ln->ln_FullName; @@ -4468,11 +4659,7 @@ Action_SetProtect( out: if(file != NULL) - { - int ignored_error; - - smba_close(file, &ignored_error); - } + smba_close(ServerData,file); FreeMemory(full_name); @@ -4518,6 +4705,14 @@ Action_RenameObject( { ln = (struct LockNode *)source_lock->fl_Key; + if(ln == NULL || ln->ln_Magic != ID_SMB_DISK) + { + SHOWMSG("lock doesn't look right"); + + error = ERROR_INVALID_LOCK; + goto out; + } + ln->ln_LastUser = user; parent_name = ln->ln_FullName; @@ -4572,6 +4767,14 @@ Action_RenameObject( { ln = (struct LockNode *)destination_lock->fl_Key; + if(ln == NULL || ln->ln_Magic != ID_SMB_DISK) + { + SHOWMSG("lock doesn't look right"); + + error = ERROR_INVALID_LOCK; + goto out; + } + ln->ln_LastUser = user; parent_name = ln->ln_FullName; @@ -4758,7 +4961,9 @@ Action_Info( struct InfoData * id, LONG * error_ptr) { - LONG result; + struct LockNode * ln; + LONG result = DOSFALSE; + LONG error = OK; ENTER(); @@ -4771,21 +4976,28 @@ Action_Info( { SHOWMSG("volume node does not match"); - result = DOSFALSE; - - (*error_ptr) = ERROR_NO_DISK; + error = ERROR_NO_DISK; + goto out; } - else + + ln = (struct LockNode *)lock->fl_Key; + + if(ln == NULL || ln->ln_Magic != ID_SMB_DISK) { - struct LockNode * ln; + SHOWMSG("lock doesn't look right"); - ln = (struct LockNode *)lock->fl_Key; - - ln->ln_LastUser = user; - - result = Action_DiskInfo(id,error_ptr); + error = ERROR_INVALID_LOCK; + goto out; } + ln->ln_LastUser = user; + + result = Action_DiskInfo(id,error_ptr); + + out: + + (*error_ptr) = error; + RETURN(result); return(result); } @@ -4834,6 +5046,14 @@ Action_ExamineObject( LONG seconds; smba_stat_t st; + if(ln == NULL || ln->ln_Magic != ID_SMB_DISK) + { + SHOWMSG("lock doesn't look right"); + + error = ERROR_INVALID_LOCK; + goto out; + } + ln->ln_LastUser = user; if(smba_getattr(ln->ln_File,&st,&error) < 0) @@ -5257,6 +5477,14 @@ Action_ExamineNext( ln = (struct LockNode *)lock->fl_Key; + if(ln == NULL || ln->ln_Magic != ID_SMB_DISK) + { + SHOWMSG("lock doesn't look right"); + + error = ERROR_INVALID_LOCK; + goto out; + } + ln->ln_LastUser = user; /* Check if we should restart scanning the directory @@ -5740,6 +5968,14 @@ Action_ExamineAll( ln = (struct LockNode *)lock->fl_Key; + if(ln == NULL || ln->ln_Magic != ID_SMB_DISK) + { + SHOWMSG("lock doesn't look right"); + + error = ERROR_INVALID_LOCK; + goto out; + } + ln->ln_LastUser = last_user; /* Check if we should restart scanning the directory @@ -5862,14 +6098,17 @@ Action_Find( switch(action) { case ACTION_FINDINPUT: + D(("ACTION_FINDINPUT [Open(\"%b\",MODE_OLDFILE)]",MKBADDR(bcpl_name))); break; case ACTION_FINDOUTPUT: + D(("ACTION_FINDOUTPUT [Open(\"%b\",MODE_NEWFILE)]",MKBADDR(bcpl_name))); break; case ACTION_FINDUPDATE: + D(("ACTION_FINDUPDATE [Open(\"%b\",MODE_READWRITE)]",MKBADDR(bcpl_name))); break; } @@ -5880,6 +6119,14 @@ Action_Find( { struct LockNode * ln = (struct LockNode *)parent->fl_Key; + if(ln == NULL || ln->ln_Magic != ID_SMB_DISK) + { + SHOWMSG("lock doesn't look right"); + + error = ERROR_INVALID_LOCK; + goto out; + } + ln->ln_LastUser = user; parent_name = ln->ln_FullName; @@ -5946,6 +6193,7 @@ Action_Find( memset(fn,0,sizeof(*fn)); fn->fn_Handle = fh; + fn->fn_Magic = ID_SMB_DISK; fn->fn_FullName = full_name; fn->fn_Mode = (action == ACTION_FINDOUTPUT) ? EXCLUSIVE_LOCK : SHARED_LOCK; @@ -5991,7 +6239,7 @@ Action_Find( } if(file != NULL) - smba_close(file,&ignored_error); + smba_close(ServerData,file); } else { @@ -6003,7 +6251,6 @@ Action_Find( /* Create a new file? */ if(create_new_file) { - int ignored_error; smba_file_t * dir; int full_name_len; STRPTR base_name; @@ -6063,7 +6310,8 @@ Action_Find( SHOWMSG("didn't work."); SHOWVALUE(error); - smba_close(dir,&ignored_error); + smba_close(ServerData,dir); + error = MapErrnoToIoErr(error); SHOWVALUE(error); @@ -6073,7 +6321,7 @@ Action_Find( SHOWMSG("good."); - smba_close(dir,&ignored_error); + smba_close(ServerData,dir); } /* Now for the remainder... */ @@ -6117,6 +6365,14 @@ Action_Read( ENTER(); + if(fn == NULL || fn->fn_Magic != ID_SMB_DISK) + { + SHOWMSG("file doesn't look right"); + + error = ERROR_INVALID_LOCK; + goto out; + } + SHOWVALUE(length); if(length > 0) @@ -6155,6 +6411,14 @@ Action_Write( ENTER(); + if(fn == NULL || fn->fn_Magic != ID_SMB_DISK) + { + SHOWMSG("file doesn't look right"); + + error = ERROR_INVALID_LOCK; + goto out; + } + if(WriteProtected) { error = ERROR_DISK_WRITE_PROTECTED; @@ -6189,21 +6453,59 @@ Action_Write( STATIC LONG Action_End( - struct FileNode * fn, + struct FileNode * which_fn, LONG * error_ptr) { - int ignored_error; + LONG result = DOSFALSE; + struct FileNode * fn; + struct FileNode * found; + int error = OK; - Remove((struct Node *)fn); + if(which_fn == NULL || which_fn->fn_Magic != ID_SMB_DISK) + { + SHOWMSG("file doesn't look right"); - smba_close(fn->fn_File,&ignored_error); + error = ERROR_INVALID_LOCK; + goto out; + } - FreeMemory(fn->fn_FullName); - FreeMemory(fn); + found = NULL; - (*error_ptr) = OK; + for(fn = (struct FileNode *)FileList.mlh_Head ; + fn->fn_MinNode.mln_Succ != NULL ; + fn = (struct FileNode *)fn->fn_MinNode.mln_Succ) + { + if(fn == which_fn) + { + found = fn; + break; + } + } - return(DOSTRUE); + if(found == NULL) + { + SHOWMSG("file not known"); + + error = ERROR_INVALID_LOCK; + goto out; + } + + Remove((struct Node *)found); + + smba_close(ServerData,found->fn_File); + + found->fn_Magic = 0; + + FreeMemory(found->fn_FullName); + FreeMemory(found); + + result = DOSTRUE; + + out: + + (*error_ptr) = error; + + return(result); } /****************************************************************************/ @@ -6215,7 +6517,7 @@ Action_Seek( LONG mode, LONG * error_ptr) { - QUAD previous_position_quad = fn->fn_OffsetQuad; + QUAD previous_position_quad; QUAD reference_position_quad; QUAD new_position_quad; LONG result = -1; @@ -6224,6 +6526,16 @@ Action_Seek( ENTER(); + if(fn == NULL || fn->fn_Magic != ID_SMB_DISK) + { + SHOWMSG("file doesn't look right"); + + error = ERROR_INVALID_LOCK; + goto out; + } + + previous_position_quad = fn->fn_OffsetQuad; + switch(mode) { case OFFSET_BEGINNING: @@ -6307,7 +6619,7 @@ Action_SetFileSize( LONG mode, LONG * error_ptr) { - QUAD previous_position_quad = fn->fn_OffsetQuad; + QUAD previous_position_quad; QUAD reference_position_quad; QUAD new_position_quad; LONG result = -1; @@ -6316,6 +6628,16 @@ Action_SetFileSize( ENTER(); + if(fn == NULL || fn->fn_Magic != ID_SMB_DISK) + { + SHOWMSG("file doesn't look right"); + + error = ERROR_INVALID_LOCK; + goto out; + } + + previous_position_quad = fn->fn_OffsetQuad; + switch(mode) { case OFFSET_BEGINNING: @@ -6433,6 +6755,14 @@ Action_SetDate( { struct LockNode * ln = (struct LockNode *)parent->fl_Key; + if(ln == NULL || ln->ln_Magic != ID_SMB_DISK) + { + SHOWMSG("lock doesn't look right"); + + error = ERROR_INVALID_LOCK; + goto out; + } + ln->ln_LastUser = user; parent_name = ln->ln_FullName; @@ -6516,11 +6846,7 @@ Action_SetDate( out: if(file != NULL) - { - int ignored_error; - - smba_close(file,&ignored_error); - } + smba_close(ServerData,file); FreeMemory(full_name); @@ -6552,6 +6878,14 @@ Action_ExamineFH( ENTER(); + if(fn == NULL || fn->fn_Magic != ID_SMB_DISK) + { + SHOWMSG("file doesn't look right"); + + error = ERROR_INVALID_LOCK; + goto out; + } + if(smba_getattr(fn->fn_File,&st,&error) < 0) { error = MapErrnoToIoErr(error); @@ -6690,12 +7024,20 @@ Action_ParentFH( BPTR result = ZERO; struct LockNode * ln = NULL; int error; - STRPTR full_name; + STRPTR full_name = NULL; int full_name_len; int i; ENTER(); + if(fn == NULL || fn->fn_Magic != ID_SMB_DISK) + { + SHOWMSG("file doesn't look right"); + + error = ERROR_INVALID_LOCK; + goto out; + } + full_name_len = strlen(fn->fn_FullName); if(full_name_len < 2) /* Must be large enough to hold SMB_ROOT_DIR_NAME. */ full_name_len = 2; @@ -6733,6 +7075,7 @@ Action_ParentFH( memset(ln,0,sizeof(*ln)); ln->ln_FileLock.fl_Key = (LONG)ln; + ln->ln_Magic = ID_SMB_DISK; ln->ln_FileLock.fl_Access = SHARED_LOCK; ln->ln_FileLock.fl_Task = FileSystemPort; ln->ln_FileLock.fl_Volume = MKBADDR(VolumeNode); @@ -6780,6 +7123,14 @@ Action_CopyDirFH( ENTER(); + if(fn == NULL || fn->fn_Magic != ID_SMB_DISK) + { + SHOWMSG("file doesn't look right"); + + error = ERROR_INVALID_LOCK; + goto out; + } + if(fn->fn_Mode != SHARED_LOCK) { error = ERROR_OBJECT_IN_USE; @@ -6807,6 +7158,7 @@ Action_CopyDirFH( memset(ln,0,sizeof(*ln)); ln->ln_FileLock.fl_Key = (LONG)ln; + ln->ln_Magic = ID_SMB_DISK; ln->ln_FileLock.fl_Access = SHARED_LOCK; ln->ln_FileLock.fl_Task = FileSystemPort; ln->ln_FileLock.fl_Volume = MKBADDR(VolumeNode); @@ -6856,6 +7208,16 @@ Action_FHFromLock( SHOWVALUE(fl); + ln = (struct LockNode *)fl->fl_Key; + + if(ln == NULL || ln->ln_Magic != ID_SMB_DISK) + { + SHOWMSG("lock doesn't look right"); + + error = ERROR_INVALID_LOCK; + goto out; + } + fn = AllocateMemory(sizeof(*fn)); if(fn == NULL) { @@ -6865,14 +7227,14 @@ Action_FHFromLock( memset(fn,0,sizeof(*fn)); - ln = (struct LockNode *)fl->fl_Key; - fn->fn_Handle = fh; + fn->fn_Magic = ID_SMB_DISK; fn->fn_FullName = ln->ln_FullName; fn->fn_File = ln->ln_File; fn->fn_Mode = fl->fl_Access; Remove((struct Node *)ln); + ln->ln_Magic = 0; FreeMemory(ln); fh->fh_Arg1 = (LONG)fn; @@ -6991,7 +7353,17 @@ Action_ChangeMode( if(type == CHANGE_LOCK) { fl = object; + ln = (struct LockNode *)fl->fl_Key; + + if(ln == NULL || ln->ln_Magic != ID_SMB_DISK) + { + SHOWMSG("lock doesn't look right"); + + error = ERROR_INVALID_LOCK; + goto out; + } + name = ln->ln_FullName; old_mode = fl->fl_Access; @@ -7002,6 +7374,15 @@ Action_ChangeMode( struct FileHandle * fh = object; fn = (struct FileNode *)fh->fh_Arg1; + + if(fn == NULL || fn->fn_Magic != ID_SMB_DISK) + { + SHOWMSG("file doesn't look right"); + + error = ERROR_INVALID_LOCK; + goto out; + } + name = fn->fn_FullName; old_mode = fn->fn_Mode; } @@ -7187,6 +7568,14 @@ Action_SetComment( { struct LockNode * ln = (struct LockNode *)parent->fl_Key; + if(ln == NULL || ln->ln_Magic != ID_SMB_DISK) + { + SHOWMSG("lock doesn't look right"); + + error = ERROR_INVALID_LOCK; + goto out; + } + ln->ln_LastUser = user; parent_name = ln->ln_FullName; @@ -7261,11 +7650,7 @@ Action_SetComment( out: if(file != NULL) - { - int ignored_error; - - smba_close(file, &ignored_error); - } + smba_close(ServerData,file); FreeMemory(full_name); @@ -7290,6 +7675,16 @@ Action_LockRecord ( int error; LONG umode; + ENTER(); + + if(fn == NULL || fn->fn_Magic != ID_SMB_DISK) + { + SHOWMSG("file doesn't look right"); + + error = ERROR_INVALID_LOCK; + goto out; + } + /* Sanity checks... */ if (mode < REC_EXCLUSIVE || mode > REC_SHARED_IMMED) { @@ -7348,6 +7743,16 @@ Action_FreeRecord ( LONG result = DOSFALSE; int error; + ENTER(); + + if(fn == NULL || fn->fn_Magic != ID_SMB_DISK) + { + SHOWMSG("file doesn't look right"); + + error = ERROR_INVALID_LOCK; + goto out; + } + /* Sanity checks... */ if(offset < 0 || length <= 0 || offset + length < offset) { diff --git a/source_code/proc.c b/source_code/proc.c index 3d4bd8d..1b333dd 100644 --- a/source_code/proc.c +++ b/source_code/proc.c @@ -42,6 +42,7 @@ * SMBnegprot SMB_COM_NEGOTIATE 0x72 Core Protocol - negotiate protocol * SMBopen SMB_COM_OPEN 0x02 Core Protocol deprecated open file (-> SMB_COM_NT_CREATE_ANDX) * SMBread SMB_COM_READ 0x0A Core Protocol deprecated read from file (-> SMB_COM_READ_ANDX) + * SMBreadbraw SMB_COM_READ_RAW 0x1a Core Protocol deprecated read a block of data with no smb header (-> SMB_COM_READ_ANDX) * SMBreadX SMB_COM_READ_ANDX 0x2E LAN Manager 1.0 - read and X * SMBrmdir SMB_COM_DELETE_DIRECTORY 0x01 Core Protocol - delete directory * SMBsearch SMB_COM_SEARCH 0x81 Core Protocol deprecated search directory (-> SMB_COM_TRANSACTION2+TRANS2_FIND_FIRST2) @@ -53,6 +54,7 @@ * SMBtrans2 SMB_COM_TRANSACTION2 0x32 LAN Manager 1.2 - TRANS2 protocol set * SMBunlink SMB_COM_DELETE 0x06 Core Protocol - delete file * SMBwrite SMB_COM_WRITE 0x0B Core Protocol deprecated write to file (-> SMB_COM_WRITE_ANDX) + * SMBwritebraw SMB_COM_WRITE_RAW 0x1d LAN Manager 1.0 deprecated write a block of data with no smb header (-> SMB_COM_WRITE_ANDX) * SMBwriteX SMB_COM_WRITE_ANDX 0x2F LAN Manager 1.0 - write and X */ @@ -296,7 +298,7 @@ copy_latin1_to_utf16le(byte * to,int to_size, const byte * from,int len) } (*to++) = '\0'; - (*to++) = '\0'; + (*to) = '\0'; num_bytes_written += 2; } @@ -359,7 +361,7 @@ copy_utf16le_to_latin1(byte * to,int to_size,const byte * from,int len) static size_t strnlen(const char * s,size_t max_size) { const char * start = s; - size_t result = 0; + size_t result; if(max_size > 0) { @@ -471,7 +473,9 @@ static byte * smb_encode_dialect (byte * p, const byte * name, int len) { (*p++) = 2; - strcpy (p, name); + + memcpy(p, name, len); + p[len] = '\0'; return p + len + 1; } @@ -480,6 +484,7 @@ static byte * smb_encode_ascii (byte * p, const byte * name, int len) { (*p++) = 4; + memcpy (p, name, len); p[len] = '\0'; @@ -1303,11 +1308,17 @@ smb_proc_open (struct smb_server *server, const char *pathname, int len, int wri params = smb_decode_word(params, &entry->fileid); params += sizeof(dword); /* CreateDisposition */ + + entry->ctime = local2utc (convert_long_date_to_time_t(params)); params += 2 * sizeof(dword); /* CreateTime */ + + entry->atime = local2utc (convert_long_date_to_time_t(params)); params += 2 * sizeof(dword); /* LastAccessTime */ + + entry->wtime = local2utc (convert_long_date_to_time_t(params)); params += 2 * sizeof(dword); /* LastWriteTime */ - entry->ctime = entry->atime = entry->mtime = entry->wtime = local2utc (convert_long_date_to_time_t(params)); + entry->mtime = local2utc (convert_long_date_to_time_t(params)); params += 2 * sizeof(dword); /* LastChangeTime */ params = smb_decode_dword(params, &ext_file_attributes); @@ -1381,6 +1392,10 @@ smb_proc_open (struct smb_server *server, const char *pathname, int len, int wri entry->fileid = WVAL (buf, smb_vwv0); entry->attr = WVAL (buf, smb_vwv1); + + /* This is actually the mtime value, but we use it + * in all other places as well. + */ entry->ctime = entry->atime = entry->mtime = entry->wtime = local2utc (DVAL (buf, smb_vwv2)); entry->size_low = DVAL (buf, smb_vwv4); @@ -1474,6 +1489,39 @@ smb_proc_read (struct smb_server *server, struct smb_dirent *finfo, off_t offset return result; } +/* count must be <= 65535. No error number is returned. A result of 0 + indicates an error, which has to be investigated by a normal read + call. */ +int +smb_proc_read_raw (struct smb_server *server, struct smb_dirent *finfo, const QUAD * const offset_quad, long count, char *data, int * error_ptr) +{ + char *buf = server->transmit_buffer; + int result; + + ASSERT( count <= 65535 ); + + retry: + + smb_setup_header (server, SMBreadbraw, 10, 0); + + WSET (buf, smb_vwv0, finfo->fileid); + DSET (buf, smb_vwv1, offset_quad->Low); + WSET (buf, smb_vwv3, count); /* maxcnt */ + WSET (buf, smb_vwv4, 0); /* mincnt */ + DSET (buf, smb_vwv5, 0); /* timeout */ + WSET (buf, smb_vwv7, 0); /* reserved */ + DSET (buf, smb_vwv8, offset_quad->High); + + result = smb_request_read_raw (server, data, count, error_ptr); + if (result < 0) + { + if (smb_retry (server)) + goto retry; + } + + return result; +} + int smb_proc_write (struct smb_server *server, struct smb_dirent *finfo, off_t offset, long count, const char *data, int * error_ptr) { @@ -1513,6 +1561,179 @@ smb_proc_write (struct smb_server *server, struct smb_dirent *finfo, off_t offse return result; } +int +smb_proc_write_raw (struct smb_server *server, struct smb_dirent *finfo, const QUAD * const offset_quad, long count, const char *data, int * error_ptr) +{ + char *buf = server->transmit_buffer; + int num_bytes_written = 0; + int result; + long max_len; + 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 + * a single SMB_COM_WRITE_RAW packet... + * + * 'max_buffer_size' is the maximum size of a complete SMB message + * including the message header, the parameter and data blocks. + * + * The message header accounts for + * 4(protocol)+1(command)+4(status)+1(flags)+2(flags2)+2(pidhigh)+ + * 8(securityfeatures)+2(reserved)+2(tid)+2(pidlow)+2(uid)+2(mid) + * = 32 bytes + * + * The parameters of a SMB_COM_WRITE_RAW command account for + * 1(wordcount)+2(fid)+2(countofbytes)+2(reserved1)+4(offset)+ + * 4(timeout)+2(writemode)+4(reserved2)+2(datalength)+2(dataoffset)+ + * 4(offset high) + * = 29 bytes + * + * The data part of a SMB_COM_WRITE_RAW command account for + * 2(bytecount)+0(pad) = 2 bytes, not including + * the actual payload + * + * This leaves 'max_buffer_size' - 63 for the payload. + */ + max_len = server->max_buffer_size; + if(max_len > 65535) + max_len = 65535; + + max_len -= 63; + + LOG(("maximum length for payload = %ld bytes\n", max_len)); + + /* Number of bytes to write is smaller than the maximum + * number of bytes which may be sent in a single SMB + * message, including parameter and data fields? + */ + if (count <= max_len) + { + LOG(("count (%ld) <= max_len (%ld) -- send no data with the message.\n",count,max_len)); + + len = 0; /* Send a zero length SMB_COM_WRITE_RAW message, followed by the raw data. */ + } + else + { + len = count - max_len; /* Send some of the data as part of the SMB_COM_WRITE_RAW message, followed by the remaining raw data. */ + + LOG(("count (%ld) > max_len (%ld) -- send %ld bytes with the message.\n",count,max_len,len)); + } + + retry: + + p = smb_setup_header (server, SMBwritebraw, 14, len); + + WSET (buf, smb_vwv0, finfo->fileid); + WSET (buf, smb_vwv1, count); + WSET (buf, smb_vwv2, 0); /* reserved */ + DSET (buf, smb_vwv3, offset_quad->Low); + DSET (buf, smb_vwv5, 0); /* timeout */ + + if(server->write_behind) + WSET (buf, smb_vwv7, 0); /* do not send a final result response. */ + else + WSET (buf, smb_vwv7, 1); /* send final result response */ + + DSET (buf, smb_vwv8, 0); /* reserved */ + + if (server->protocol > PROTOCOL_COREPLUS) + { + WSET (buf, smb_vwv10, len); + WSET (buf, smb_vwv11, p - smb_base(buf)); + WSET (buf, smb_vwv12, offset_quad->High); + } + else + { + WSET (buf, smb_vwv10, 0); + } + + LOG(("requesting SMBwritebraw\n")); + + result = smb_request_ok_with_payload (server, SMBwritebraw, 1, 0, NULL, data, len, error_ptr); + if (result < 0) + { + if (smb_retry (server)) + goto retry; + else + goto out; + } + + num_bytes_written += len; + + data += len; + count -= len; + + LOG (("bytes sent so far = %ld\n", num_bytes_written)); + + if(count > 0) + { + LOG(("sending %ld bytes of data (raw)\n",count)); + + ASSERT( count <= 65535 ); + + result = smb_request_write_raw (server, data, count, error_ptr); + if (result < 0) + { + /* Roll back the counters */ + num_bytes_written -= len; + + data -= len; + count += len; + + if (smb_retry (server)) + goto retry; + else + goto out; + } + + if(server->write_behind) + { + /* We just assume success; the next file operation to follow + * will set an error status if something went wrong. + */ + result = num_bytes_written + count; + } + else + { + int error; + + /* We have to do the checks of smb_request_ok here as well */ + if ((error = smb_valid_packet (server->transmit_buffer)) != 0) + { + LOG (("not a valid packet!\n")); + + (*error_ptr) = error; + result = -1; + + goto out; + } + else if (server->rcls != 0) + { + LOG (("server error %ld/%ld\n", server->rcls, server->err)); + + smb_printerr (server->rcls, server->err); + + (*error_ptr) = error_check_smb_error; + result = -1; + + goto out; + } + + result = num_bytes_written + count; + } + + LOG (("bytes sent so far = %ld\n", result)); + } + + out: + + return result; +} + int smb_proc_writex (struct smb_server *server, struct smb_dirent *finfo, const QUAD * const offset_quad, long count, const char *data, int * error_ptr) { @@ -1735,7 +1956,7 @@ smb_proc_create (struct smb_server *server, const char *path, int len, struct sm } int -smb_proc_mv (struct smb_server *server, const char *opath, const int olen, const char *npath, const int nlen, int * error_ptr) +smb_proc_mv (struct smb_server *server, const char *old_path, const int old_path_len, const char *new_path, const int new_path_len, int * error_ptr) { char *p; char *buf = server->transmit_buffer; @@ -1743,9 +1964,9 @@ smb_proc_mv (struct smb_server *server, const char *opath, const int olen, const int result; if(server->unicode_enabled) - size = 2 + 1 + 2 * (olen+1) + 1 + 2 * (nlen+1); + size = 2 + 1 + 2 * (old_path_len+1) + 1 + 2 * (new_path_len+1); else - size = 2 + 1 + (olen+1) + 1 + (nlen+1); + size = 2 + 1 + (old_path_len+1) + 1 + (new_path_len+1); ASSERT( smb_payload_size(server, 1, size) >= 0 ); @@ -1753,20 +1974,20 @@ smb_proc_mv (struct smb_server *server, const char *opath, const int olen, const p = smb_setup_header (server, SMBmv, 1, size); - WSET (buf, smb_vwv0, 0); + WSET (buf, smb_vwv0, SMB_FILE_ATTRIBUTE_SYSTEM | SMB_FILE_ATTRIBUTE_HIDDEN); if(server->unicode_enabled) { (*p++) = 4; /* A null-terminated string follows. */ - p += copy_latin1_to_utf16le(p,2 * (olen+1),opath,olen); + p += copy_latin1_to_utf16le(p,2 * (old_path_len+1),old_path,old_path_len); (*p++) = 4; /* A null-terminated string follows. */ - (void) copy_latin1_to_utf16le(p,2 * (nlen+1),npath,nlen); + (void) copy_latin1_to_utf16le(p,2 * (new_path_len+1),new_path,new_path_len); } else { - p = smb_encode_ascii (p, opath, olen); - smb_encode_ascii (p, npath, olen); + p = smb_encode_ascii (p, old_path, old_path_len); + (void) smb_encode_ascii (p, new_path, new_path_len); } result = smb_request_ok (server, SMBmv, 0, 0, error_ptr); @@ -2058,10 +2279,10 @@ smb_proc_readdir_short (struct smb_server *server, const char *path, int fpos, i word count; char status[SMB_STATUS_SIZE]; int entries_asked = (server->max_recv - 100) / SMB_DIRINFO_SIZE; - int dirlen = strlen (path); + int path_len = strlen (path); char * mask; - mask = malloc(dirlen + 4 + 1); + mask = malloc(path_len + 4 + 1); if (mask == NULL) { (*error_ptr) = ENOMEM; @@ -2070,8 +2291,8 @@ smb_proc_readdir_short (struct smb_server *server, const char *path, int fpos, i goto out; } - strcpy (mask, path); - strcat (mask, "\\*.*"); + memcpy(mask, path, path_len); + memcpy(&mask[path_len], "\\*.*", 5); /* Length includes terminating NUL. */ LOG (("SMB call readdir %ld @ %ld\n", cache_size, fpos)); LOG ((" mask = '%s'\n", escape_name(mask))); @@ -3500,9 +3721,7 @@ smb_proc_reconnect (struct smb_server *server, int * error_ptr) int password_len; unsigned char nt_password[24]; int nt_password_len; - unsigned char full_share[SMB_MAXNAMELEN+1]; - int full_share_len; - int full_share_size; + char * share_name = NULL; byte *packet; dword max_buffer_size; int packet_size; @@ -3511,7 +3730,7 @@ smb_proc_reconnect (struct smb_server *server, int * error_ptr) if (result < 0) { LOG (("could not smb_connect\n")); - goto fail; + goto out; } /* Unless we know better, we don't go for Unicode just yet. */ @@ -3569,7 +3788,7 @@ smb_proc_reconnect (struct smb_server *server, int * error_ptr) (*error_ptr) = ENOMEM; result = -1; - goto fail; + goto out; } packet = server->transmit_buffer; @@ -3591,7 +3810,7 @@ smb_proc_reconnect (struct smb_server *server, int * error_ptr) if (result < 0) { LOG (("Failed to send SESSION REQUEST.\n")); - goto fail; + goto out; } if (packet[0] != 0x82) @@ -3607,7 +3826,7 @@ smb_proc_reconnect (struct smb_server *server, int * error_ptr) (*error_ptr) = error_session_request_failed; result = -1; - goto fail; + goto out; } LOG (("Passed SESSION REQUEST.\n")); @@ -3616,7 +3835,7 @@ smb_proc_reconnect (struct smb_server *server, int * error_ptr) /* Now we are ready to send a SMB Negotiate Protocol packet. */ plength = 0; for (i = 0; i < num_prots ; i++) - plength += strlen (prots[i].name) + 2; + plength += 1 + strlen (prots[i].name) + 1; ASSERT( smb_payload_size(server, 0, plength) >= 0 ); @@ -3633,11 +3852,9 @@ smb_proc_reconnect (struct smb_server *server, int * error_ptr) if (result < 0) { LOG (("Failure requesting SMBnegprot\n")); - goto fail; + goto out; } - LOG (("Verified!\n")); - p = SMB_VWV (packet); p = smb_decode_word (p, &dialect_index); @@ -3652,7 +3869,7 @@ smb_proc_reconnect (struct smb_server *server, int * error_ptr) (*error_ptr) = error_unsupported_dialect; result = -1; - goto fail; + goto out; } server->protocol = prots[dialect_index].prot; @@ -3695,7 +3912,7 @@ smb_proc_reconnect (struct smb_server *server, int * error_ptr) /* Skip "system time" (1 qword) and "server time zone" (1 word). */ p += 2 * sizeof(dword) + sizeof(word); - server->crypt_key_length = (*p++); + server->crypt_key_length = (*p); memcpy(server->crypt_key,SMB_BUF(packet),server->crypt_key_length); } @@ -3785,6 +4002,7 @@ smb_proc_reconnect (struct smb_server *server, int * error_ptr) if((server->security_mode & NEGOTIATE_USER_SECURITY) == 0) { SHOWMSG("share level security; zapping passwords"); + strcpy(password,""); password_len = 0; @@ -3891,7 +4109,7 @@ smb_proc_reconnect (struct smb_server *server, int * error_ptr) if (result < 0) { LOG (("SMBsessetupX failed\n")); - goto fail; + goto out; } smb_decode_word (packet + 32, &server->server_uid); @@ -3915,38 +4133,57 @@ smb_proc_reconnect (struct smb_server *server, int * error_ptr) if(nt_password_len > 0) { + int server_name_len; + int service_len; + int share_name_len; + int share_name_size; int padding_needed; - strlcpy(full_share,"//",sizeof(full_share)); - strlcat(full_share,server->mount_data.server_name,sizeof(full_share)); - strlcat(full_share,"/",sizeof(full_share)); - strlcat(full_share,server->mount_data.service,sizeof(full_share)); + server_name_len = strlen(server->mount_data.server_name); + service_len = strlen(server->mount_data.service); - full_share_len = strlen(full_share); + share_name_len = 2 + server_name_len + 1 + service_len; - for(i = 0 ; i < full_share_len ; i++) + share_name = malloc(share_name_len+1); + if(share_name == NULL) { - if(full_share[i] == '/') - full_share[i] = '\\'; + LOG (("No memory! Bailing out.\n")); + + (*error_ptr) = ENOMEM; + + result = -1; + goto out; } - StringToUpper(full_share); + memcpy(share_name,"//",2); + memcpy(&share_name[2],server->mount_data.server_name,server_name_len); + share_name[2 + server_name_len] = '/'; + memcpy(&share_name[2 + server_name_len + 1],server->mount_data.service,service_len+1); /* Length includes terminating NUL byte. */ - D(("full_share = '%s'", escape_name(full_share))); + /* Flip the slashes, so they become backslashes. */ + for(i = 0 ; i < share_name_len ; i++) + { + if(share_name[i] == '/') + share_name[i] = '\\'; + } + + StringToUpper(share_name); + + D(("share_name = '%s'", escape_name(share_name))); if(server->unicode_enabled) - full_share_size = 2 * (full_share_len + 1); + share_name_size = 2 * (share_name_len + 1); else - full_share_size = full_share_len + 1; + share_name_size = share_name_len + 1; if(server->unicode_enabled && (password_len % 2) == 0) padding_needed = 1; else padding_needed = 0; - ASSERT( smb_payload_size(server, 4, password_len + padding_needed + full_share_size + strlen(dev)+1) >= 0 ); + ASSERT( smb_payload_size(server, 4, password_len + padding_needed + share_name_size + strlen(dev)+1) >= 0 ); - smb_setup_header (server, SMBtconX, 4, password_len + padding_needed + full_share_size + strlen(dev)+1); + smb_setup_header (server, SMBtconX, 4, password_len + padding_needed + share_name_size + strlen(dev)+1); WSET (packet, smb_vwv0, 0xFF); WSET (packet, smb_vwv3, password_len); @@ -3960,11 +4197,11 @@ smb_proc_reconnect (struct smb_server *server, int * error_ptr) (*p++) = 0; if(server->unicode_enabled) - copy_latin1_to_utf16le(p,full_share_size,full_share,full_share_len); + copy_latin1_to_utf16le(p,share_name_size,share_name,share_name_len); else - memcpy(p,full_share,full_share_size); + memcpy(p,share_name,share_name_size); - p += full_share_size; + p += share_name_size; strcpy(p,dev); @@ -3974,7 +4211,7 @@ smb_proc_reconnect (struct smb_server *server, int * error_ptr) SHOWVALUE(SMB_WCT(packet)); LOG (("SMBtconX not verified.\n")); - goto fail; + goto out; } SHOWVALUE(SMB_WCT(packet)); @@ -3999,7 +4236,7 @@ smb_proc_reconnect (struct smb_server *server, int * error_ptr) if (result < 0) { LOG (("SMBtcon not verified.\n")); - goto fail; + goto out; } LOG (("OK! Managed to set up SMBtcon!\n")); @@ -4050,7 +4287,7 @@ smb_proc_reconnect (struct smb_server *server, int * error_ptr) (*error_ptr) = ENOMEM; result = -1; - goto fail; + goto out; } } @@ -4067,11 +4304,15 @@ smb_proc_reconnect (struct smb_server *server, int * error_ptr) LOG (("Normal exit\n")); - return 0; + result = 0; - fail: + out: - server->state = CONN_INVALID; + if(share_name != NULL) + free(share_name); + + if(result < 0) + server->state = CONN_INVALID; return result; } diff --git a/source_code/smb_abstraction.c b/source_code/smb_abstraction.c index 3031b38..9a794fc 100644 --- a/source_code/smb_abstraction.c +++ b/source_code/smb_abstraction.c @@ -49,6 +49,9 @@ smba_connect ( int timeout, int opt_raw_smb, int opt_unicode, + int opt_prefer_write_raw, + int opt_write_behind, + int opt_prefer_read_raw, int * error_ptr, int * smb_error_class_ptr, int * smb_error_ptr, @@ -75,16 +78,25 @@ smba_connect ( memset (&data, 0, sizeof (data)); memset (hostname, 0, sizeof (hostname)); - /* Olaf (2012-12-10): force raw SMB over TCP rather than NetBIOS. */ + /* Use raw SMB over TCP rather than NetBIOS. */ if(opt_raw_smb) res->server.raw_smb = TRUE; - /* olsen (2018-05-09): Timeout for send/receive operations in seconds. */ + /* Timeout for send/receive operations in seconds. */ res->server.timeout = timeout; - /* olsen (2018-06-01): Enable Unicode support if the server supports it. */ + /* Enable Unicode support if the server supports it, too. */ res->server.use_unicode = opt_unicode; + /* Prefer SMB_COM_WRITE_RAW over SMB_COM_WRITE_ANDX? */ + res->server.prefer_write_raw = opt_prefer_write_raw; + + /* Enable asynchronous SMB_COM_WRITE_RAW operations? */ + res->server.write_behind = opt_write_behind; + + /* Prefer SMB_COM_READ_RAW over SMB_COM_READ_ANDX? */ + res->server.prefer_read_raw = opt_prefer_read_raw; + if(smba_setup_dircache (res,cache_size,error_ptr) < 0) { ReportError("Directory cache initialization failed (%ld, %s).",(*error_ptr),posix_strerror(*error_ptr)); @@ -97,6 +109,7 @@ smba_connect ( gethostname (hostname, MAXHOSTNAMELEN); + /* Only retain the host name, drop any domain names following it. */ if ((s = strchr (hostname, '.')) != NULL) (*s) = '\0'; @@ -405,38 +418,59 @@ write_attr (smba_file_t * f, int * error_ptr) /*****************************************************************************/ void -smba_close (smba_file_t * f, int * error_ptr) +smba_close (smba_server_t * s, smba_file_t * f) { - if(f != NULL) + smba_file_t * found; + smba_file_t * file; + + found = NULL; + + for(file = (smba_file_t *)s->open_files.mlh_Head ; + file->node.mln_Succ != NULL ; + file = (smba_file_t *)file->node.mln_Succ) { - if(f->node.mln_Succ != NULL || f->node.mln_Pred != NULL) - Remove((struct Node *)f); - - if(f->attr_dirty) - write_attr(f, error_ptr); - - if (f->dirent.opened) + if(file == f) { - LOG (("closing file '%s' (fileid=0x%04lx)\n", escape_name(f->dirent.complete_path), f->dirent.fileid)); + found = f; + break; + } + } + + if(found != NULL) + { + int ignored_error; + + Remove((struct Node *)found); + + if(found->attr_dirty) + write_attr(found, &ignored_error); + + if (found->dirent.opened) + { + LOG (("closing file '%s' (fileid=0x%04lx)\n", escape_name(found->dirent.complete_path), found->dirent.fileid)); /* Don't change the modification time unless the contents * of the file were changed. */ - smb_proc_close (&f->server->server, f->dirent.fileid, f->modified ? f->dirent.mtime : 0, error_ptr); + smb_proc_close (&found->server->server, found->dirent.fileid, found->modified ? found->dirent.mtime : 0, &ignored_error); } - if (f->dircache != NULL) + if (found->dircache != NULL) { - f->dircache->cache_for = NULL; - f->dircache->len = 0; - f->dircache = NULL; + found->dircache->cache_for = NULL; + found->dircache->len = 0; + found->dircache = NULL; } - f->server->num_open_files--; + found->server->num_open_files--; - LOG(("file closed, number of open files = %ld\n",f->server->num_open_files)); + LOG(("file closed, number of open files = %ld\n",found->server->num_open_files)); - free (f); + free (found); + } + else + { + LOG(("file seems to be invalid\n")); } } @@ -455,7 +489,8 @@ smba_read (smba_file_t * f, char *data, long len, const QUAD * const offset, int D(("read %ld bytes from offset %ld",len,offset)); - if (f->server->server.protocol >= PROTOCOL_LANMAN1) + /* SMB_COM_READ_ANDX supported? */ + if (f->server->server.protocol >= PROTOCOL_LANMAN1 && !f->server->server.prefer_read_raw) { QUAD position_quad = (*offset); int max_readx_size; @@ -517,6 +552,48 @@ smba_read (smba_file_t * f, char *data, long len, const QUAD * const offset, int } while (len > 0); } + /* SMB_COM_READ_RAW and SMB_COM_WRITE_RAW supported? */ + else if ((f->server->server.capabilities & CAP_RAW_MODE) != 0) + { + int max_raw_size = f->server->server.max_raw_size; + QUAD position_quad = (*offset); + int n; + + do + { + /* SMB_COM_READ_RAW can only read up to 65535 bytes. */ + 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, &position_quad, n, data, error_ptr); + if(result <= 0) + { + D(("!!! wanted to read %ld bytes, got %ld",n,result)); + break; + } + + num_bytes_read += result; + len -= result; + add_64_plus_32_to_64(&position_quad,result,&position_quad); + data += result; + + if(result < n) + { + D(("read returned fewer characters than expected (%ld < %ld)",result,n)); + break; + } + } + while(len > 0); + } else { int max_size_smb_com_read; @@ -611,7 +688,7 @@ smba_write (smba_file_t * f, const char *data, long len, const QUAD * const offs max_buffer_size = f->server->server.max_buffer_size; /* SMB_COM_WRITE_ANDX supported? */ - if (f->server->server.protocol >= PROTOCOL_LANMAN1) + if (f->server->server.protocol >= PROTOCOL_LANMAN1 && !f->server->server.prefer_write_raw) { QUAD position_quad = (*offset); int max_writex_size; @@ -672,6 +749,62 @@ smba_write (smba_file_t * f, const char *data, long len, const QUAD * const offs } while(len > 0); } + else if ((f->server->server.capabilities & CAP_RAW_MODE) != 0) + { + int max_raw_size = f->server->server.max_raw_size; + int max_size_smb_com_write_raw; + QUAD position_quad = (*offset); + int n; + + /* Try to send the maximum number of bytes with the two SMBwritebraw packets. + * This is how it breaks down: + * + * The message header accounts for + * 4(protocol)+1(command)+4(status)+1(flags)+2(flags2)+2(pidhigh)+ + * 8(securityfeatures)+2(reserved)+2(tid)+2(pidlow)+2(uid)+2(mid) + * = 32 bytes + * + * The parameters of a SMB_COM_WRITE_RAW command account for + * 1(wordcount)+2(fid)+2(countofbytes)+2(reserved1)+4(offset)+ + * 4(timeout)+2(writemode)+4(reserved2)+2(datalength)+ + * 2(dataoffset) = 25 bytes + * + * 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_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; + + /* 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; + + LOG (("len = %ld, max_size_smb_com_write_raw = %ld\n", len, max_size_smb_com_write_raw)); + + do + { + n = min(len, max_size_smb_com_write_raw); + + ASSERT( n > 0 ); + + if(n > max_raw_size) + n = max_raw_size; + + ASSERT( n <= 65535 ); + + result = smb_proc_write_raw (&f->server->server, &f->dirent, &position_quad, n, data, error_ptr); + if(result < 0) + goto out; + + data += result; + add_64_plus_32_to_64(&position_quad,result,&position_quad); + len -= result; + num_bytes_written += result; + } + while(len > 0); + } else { int max_size_smb_com_write, count; @@ -1053,56 +1186,23 @@ smba_readdir (smba_file_t * f, long offs, void *d, smba_callback_t callback, int /*****************************************************************************/ static void -invalidate_dircache (struct smba_server * server, const char * path) +invalidate_dircache (struct smba_server * server) { dircache_t * dircache = server->dircache; - char other_path[SMB_MAXNAMELEN + 1]; ENTER(); - if(path != NULL) - { - int len,i; - - strlcpy(other_path,path,sizeof(other_path)); - - len = strlen(other_path); - for(i = len-1 ; i >= 0 ; i--) - { - if(i == 0) - { - other_path[0] = DOS_PATHSEP; - other_path[1] = '\0'; - } - else if (other_path[i] == DOS_PATHSEP) - { - other_path[i] = '\0'; - break; - } - } - } - else - { - other_path[0] = '\0'; - } - - D(("other_path = '%s'", escape_name(other_path))); - if(dircache->cache_for != NULL) D(("dircache->cache_for->dirent.complete_path = '%s'", escape_name(dircache->cache_for->dirent.complete_path))); else SHOWMSG("-- directory cache is empty --"); - if(path == NULL || (dircache->cache_for != NULL && CompareNames(other_path,dircache->cache_for->dirent.complete_path) == SAME)) - { - SHOWMSG("clearing directory cache"); + dircache->eof = dircache->len = dircache->base = 0; - dircache->eof = dircache->len = dircache->base = 0; - if(dircache->cache_for != NULL) - { - dircache->cache_for->dircache = NULL; - dircache->cache_for = NULL; - } + if(dircache->cache_for != NULL) + { + dircache->cache_for->dircache = NULL; + dircache->cache_for = NULL; } LEAVE(); @@ -1161,8 +1261,6 @@ smba_create (smba_file_t * dir, const char *name, int * error_ptr) goto out; } - /* invalidate_dircache (dir->server, path); */ - out: if(path != NULL) @@ -1177,13 +1275,18 @@ int smba_mkdir (smba_file_t * dir, const char *name, int * error_ptr) { char *path = NULL; + int path_len; + int name_len; int result; result = make_open (dir, open_dont_need_fid, open_writable, open_dont_truncate, error_ptr); if (result < 0) goto out; - path = malloc (strlen (name) + dir->dirent.len + 2); + name_len = strlen (name); + path_len = dir->dirent.len + 1 + name_len; + + path = malloc (path_len + 1); if(path == NULL) { (*error_ptr) = ENOMEM; @@ -1194,14 +1297,13 @@ smba_mkdir (smba_file_t * dir, const char *name, int * error_ptr) memcpy (path, dir->dirent.complete_path, dir->dirent.len); path[dir->dirent.len] = DOS_PATHSEP; - strcpy (&path[dir->dirent.len + 1], name); + memcpy (&path[dir->dirent.len + 1], name, name_len); + path[path_len] = '\0'; - result = smb_proc_mkdir (&dir->server->server, path, strlen (path), error_ptr); + result = smb_proc_mkdir (&dir->server->server, path, path_len, error_ptr); if(result < 0) goto out; - /* invalidate_dircache (dir->server, path); */ - out: if(path != NULL) @@ -1259,8 +1361,6 @@ smba_remove (smba_server_t * s, const char *path, int * error_ptr) if(result < 0) goto out; - /* invalidate_dircache (s, path); */ - out: return result; @@ -1281,8 +1381,6 @@ smba_rmdir (smba_server_t * s, const char *path, int * error_ptr) if(result < 0) goto out; - /* invalidate_dircache (s, path); */ - out: return result; @@ -1303,8 +1401,6 @@ smba_rename (smba_server_t * s, const char *from, const char *to, int * error_pt if(result < 0) goto out; - /* invalidate_dircache (s, from); */ - out: return(result); @@ -1340,7 +1436,7 @@ smb_invalidate_all_inodes (struct smb_server *server) ENTER(); - invalidate_dircache (server->abstraction, NULL); + invalidate_dircache (server->abstraction); for (f = (smba_file_t *)server->abstraction->open_files.mlh_Head; f->node.mln_Succ != NULL; @@ -1512,6 +1608,9 @@ smba_start( int opt_timeout, int opt_raw_smb, int opt_unicode, + int opt_prefer_write_raw, + int opt_write_behind, + int opt_prefer_read_raw, int * error_ptr, int * smb_error_class_ptr, int * smb_error_ptr, @@ -1574,12 +1673,13 @@ smba_start( } /* Brian Willette: Now we will set the server name to the DNS - hostname, hopefully this will be the same as the NetBIOS name for - the server. - We do this because the user supplied no hostname, and we - need one for NetBIOS, this is the best guess choice we have - NOTE: If the names are different between DNS and NetBIOS on - the windows side, the user MUST use the -s option. */ + * hostname, hopefully this will be the same as the NetBIOS name for + * the server. + * We do this because the user supplied no hostname, and we + * need one for NetBIOS, this is the best guess choice we have + * NOTE: If the names are different between DNS and NetBIOS on + * the windows side, the user MUST use the -s option. + */ for (i = 0; h->h_name[i] != '.' && h->h_name[i] != '\0' && i < 255; i++) hostName[i] = h->h_name[i]; @@ -1683,6 +1783,9 @@ smba_start( opt_timeout, opt_raw_smb, opt_unicode, + opt_prefer_write_raw, + opt_write_behind, + opt_prefer_read_raw, error_ptr, smb_error_class_ptr, smb_error_ptr, @@ -1800,7 +1903,7 @@ smba_change_dircache_size(struct smba_server * server,int cache_size) } } - invalidate_dircache(server, NULL); + invalidate_dircache(server); free_dircache(old_dircache); diff --git a/source_code/smb_abstraction.h b/source_code/smb_abstraction.h index 8ef423f..d2d6080 100644 --- a/source_code/smb_abstraction.h +++ b/source_code/smb_abstraction.h @@ -119,7 +119,7 @@ typedef int (*smba_callback_t) (void *d, int fpos, int nextpos, char *name, int /****************************************************************************/ int smba_open(smba_server_t *s, char *name, int writable, int truncate, smba_file_t **file, int * error_ptr); -void smba_close(smba_file_t *f, int * error_ptr); +void smba_close(smba_server_t * s, smba_file_t *f); int smba_read(smba_file_t *f, char *data, long len, const QUAD * const offset, int * error_ptr); int smba_write(smba_file_t *f, const char *data, long len, const QUAD * const offset, int * error_ptr); int smba_lockrec (smba_file_t *f, long offset, long len, long mode, int unlocked, long timeout, int * error_ptr); @@ -133,7 +133,7 @@ int smba_rmdir(smba_server_t *s, const char *path, int * error_ptr); int smba_rename(smba_server_t *s, const char *from, const char *to, int * error_ptr); int smba_statfs(smba_server_t *s, long *bsize, long *blocks, long *bfree, int * error_ptr); void smb_invalidate_all_inodes(struct smb_server *server); -int smba_start(const char *service, const char *opt_workgroup, const char *opt_username, const char *opt_password, const char *opt_clientname, const char *opt_servername, int opt_cachesize, int opt_max_transmit, int opt_timeout, int opt_raw_smb, int opt_unicode, int * error_ptr, int * smb_error_class_ptr, int * smb_error_ptr, smba_server_t **result); +int smba_start(const char *service, const char *opt_workgroup, const char *opt_username, const char *opt_password, const char *opt_clientname, const char *opt_servername, int opt_cachesize, int opt_max_transmit, int opt_timeout, int opt_raw_smb, int opt_unicode, int opt_prefer_write_raw, int opt_write_behind, int opt_prefer_read_raw, int * error_ptr, int * smb_error_class_ptr, int * smb_error_ptr, smba_server_t **result); void smba_disconnect(smba_server_t *server); int smba_get_dircache_size(struct smba_server * server); int smba_change_dircache_size(struct smba_server * server,int cache_size); diff --git a/source_code/smbfs_rev.h b/source_code/smbfs_rev.h index 663cf69..2fce6a6 100644 --- a/source_code/smbfs_rev.h +++ b/source_code/smbfs_rev.h @@ -1,6 +1,6 @@ #define VERSION 1 -#define REVISION 144 -#define DATE "1.6.2018" -#define VERS "smbfs 1.144" -#define VSTRING "smbfs 1.144 (1.6.2018)\r\n" -#define VERSTAG "\0$VER: smbfs 1.144 (1.6.2018)" +#define REVISION 146 +#define DATE "3.6.2018" +#define VERS "smbfs 1.146" +#define VSTRING "smbfs 1.146 (3.6.2018)\r\n" +#define VERSTAG "\0$VER: smbfs 1.146 (3.6.2018)" diff --git a/source_code/smbfs_rev.rev b/source_code/smbfs_rev.rev index a29644e..878d5a0 100644 --- a/source_code/smbfs_rev.rev +++ b/source_code/smbfs_rev.rev @@ -1 +1 @@ -144 +146 diff --git a/source_code/sock.c b/source_code/sock.c index 7f155d4..6b1343c 100644 --- a/source_code/sock.c +++ b/source_code/sock.c @@ -1284,3 +1284,138 @@ smb_trans2_request (struct smb_server *server, int command, int *data_len, int * return result; } + +int +smb_request_read_raw (struct smb_server *server, unsigned char *target, int max_len, int * error_ptr) +{ + unsigned char *buffer = server->transmit_buffer; + int sock_fd = server->mount_data.fd; + int len, result; + + ASSERT( error_ptr != NULL ); + + if (server->state != CONN_VALID) + { + LOG (("Connection state is invalid\n")); + + (*error_ptr) = error_server_connection_invalid; + + result = -1; + goto out; + } + + /* Length includes the NetBIOS session header (4 bytes), which + * is prepended to the packet to be sent. + */ + len = NETBIOS_HEADER_SIZE + smb_len (buffer); + + LOG (("len = %ld cmd = 0x%02lx\n", len, buffer[8])); + LOG (("target=%lx, max_len=%ld\n", (unsigned int) target, max_len)); + LOG (("buffer=%lx, sock=%lx\n", (unsigned int) buffer, (unsigned int) sock_fd)); + + #if defined(DUMP_SMB) + dump_netbios_header(__FILE__,__LINE__,buffer,NULL,0); + 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. */ + result = send (sock_fd, (void *) buffer, len, 0); + if (result < 0) + { + LOG(("send() for %ld bytes failed (errno=%ld)\n", len, errno)); + + (*error_ptr) = errno; + + goto out; + } + + /* Wait for the raw data to be sent by the server. */ + result = smb_receive_raw (server, SMBreadbraw, sock_fd, target, max_len, NULL, 0, FALSE, error_ptr); + + out: + + if (result < 0) + smb_check_server_connection(server,(*error_ptr)); + + LOG (("result = %ld\n", result)); + + return result; +} + +/* smb_request_write_raw assumes that the request SMBwriteBraw has been + * completed successfully, so that we can send the raw data now. + */ +int +smb_request_write_raw (struct smb_server *server, unsigned const char *source, int length, int * error_ptr) +{ + byte nb_header[NETBIOS_HEADER_SIZE]; + int sock_fd = server->mount_data.fd; + int result; + + if (server->state != CONN_VALID) + { + LOG (("Connection state is invalid\n")); + + (*error_ptr) = error_server_connection_invalid; + + result = -1; + goto out; + } + + ASSERT( length <= 65535 ); + + /* Send the NetBIOS header. */ + smb_encode_smb_length (nb_header, length); + + #if defined(DUMP_SMB) + dump_netbios_header(__FILE__,__LINE__,nb_header,NULL,0); + #endif /* defined(DUMP_SMB) */ + + result = send (sock_fd, nb_header, NETBIOS_HEADER_SIZE, 0); + if(result < 0) + { + LOG(("send() for %ld bytes failed (errno=%ld)\n", NETBIOS_HEADER_SIZE, errno)); + + (*error_ptr) = errno; + + goto out; + } + + #if defined(DUMP_SMB) + dump_smb(__FILE__,__LINE__,0,source,length,smb_packet_from_consumer,server->max_recv); + #endif /* defined(DUMP_SMB) */ + + /* Now send the data to be written. */ + result = send (sock_fd, (void *)source, length, 0); + if(result < 0) + { + LOG(("send() for %ld bytes failed (errno=%ld)\n", length, errno)); + + (*error_ptr) = errno; + + goto out; + } + + /* Wait for the server to respond. */ + if(!server->write_behind) + { + result = smb_receive (server, SMBwritebraw, sock_fd, NULL, 0, error_ptr); + if(result < 0) + goto out; + } + else + { + LOG(("not waiting for server to respond\n")); + } + + result = length; + + out: + + if (result < 0) + smb_check_server_connection(server,(*error_ptr)); + + LOG (("result = %ld\n", result)); + + return result; +}