#include "includes.h"
-extern int Protocol;
+extern int max_send;
+extern enum protocol_types Protocol;
extern int smb_read_error;
-extern int global_oplock_break;
-extern BOOL case_sensitive;
-extern BOOL case_preserve;
-extern BOOL short_case_preserve;
extern struct current_user current_user;
static const char *known_nt_pipes[] = {
"\\lsass",
"\\lsarpc",
"\\winreg",
+ "\\initshutdown",
"\\spoolss",
"\\netdfs",
"\\rpcecho",
+ "\\svcctl",
+ "\\eventlog",
+ "\\unixinfo",
NULL
};
-/* Map generic permissions to file object specific permissions */
-
-struct generic_mapping file_generic_mapping = {
- FILE_GENERIC_READ,
- FILE_GENERIC_WRITE,
- FILE_GENERIC_EXECUTE,
- FILE_GENERIC_ALL
-};
-
static char *nttrans_realloc(char **ptr, size_t size)
{
- char *tptr = NULL;
- if (ptr==NULL)
+ if (ptr==NULL) {
smb_panic("nttrans_realloc() called with NULL ptr\n");
+ }
- tptr = Realloc_zero(*ptr, size);
- if(tptr == NULL) {
- *ptr = NULL;
+ *ptr = (char *)SMB_REALLOC(*ptr, size);
+ if(*ptr == NULL) {
return NULL;
}
-
- *ptr = tptr;
-
- return tptr;
+ memset(*ptr,'\0',size);
+ return *ptr;
}
-
/****************************************************************************
Send the required number of replies back.
We assume all fields other than the data fields are
HACK ! Always assumes smb_setup field is zero.
****************************************************************************/
-static int send_nt_replies(char *inbuf, char *outbuf, int bufsize, NTSTATUS nt_error, char *params,
- int paramsize, char *pdata, int datasize)
+int send_nt_replies(char *outbuf, int bufsize, NTSTATUS nt_error,
+ char *params, int paramsize, char *pdata, int datasize)
{
- extern int max_send;
int data_to_send = datasize;
int params_to_send = paramsize;
int useable_space;
set_message(outbuf,18,0,True);
- if (NT_STATUS_V(nt_error))
+ if (NT_STATUS_V(nt_error)) {
ERROR_NT(nt_error);
+ }
/*
* If there genuinely are no parameters or data to send just send
*/
if(params_to_send == 0 && data_to_send == 0) {
- if (!send_smb(smbd_server_fd(),outbuf))
- exit_server("send_nt_replies: send_smb failed.");
+ show_msg(outbuf);
+ if (!send_smb(smbd_server_fd(),outbuf)) {
+ exit_server_cleanly("send_nt_replies: send_smb failed.");
+ }
return 0;
}
* can cause NT redirector problems.
*/
- if (((params_to_send % 4) != 0) && (data_to_send != 0))
+ if (((params_to_send % 4) != 0) && (data_to_send != 0)) {
data_alignment_offset = 4 - (params_to_send % 4);
+ }
/*
* Space is bufsize minus Netbios over TCP header minus SMB header.
* Copy the param bytes into the packet.
*/
- if(params_sent_thistime)
+ if(params_sent_thistime) {
memcpy((smb_buf(outbuf)+alignment_offset),pp,params_sent_thistime);
+ }
/*
* Copy in the data bytes
*/
- if(data_sent_thistime)
+ if(data_sent_thistime) {
memcpy(smb_buf(outbuf)+alignment_offset+params_sent_thistime+
data_alignment_offset,pd,data_sent_thistime);
+ }
DEBUG(9,("nt_rep: params_sent_thistime = %d, data_sent_thistime = %d, useable_space = %d\n",
params_sent_thistime, data_sent_thistime, useable_space));
params_to_send, data_to_send, paramsize, datasize));
/* Send the packet */
- if (!send_smb(smbd_server_fd(),outbuf))
- exit_server("send_nt_replies: send_smb failed.");
+ show_msg(outbuf);
+ if (!send_smb(smbd_server_fd(),outbuf)) {
+ exit_server_cleanly("send_nt_replies: send_smb failed.");
+ }
pp += params_sent_thistime;
pd += data_sent_thistime;
return 0;
}
+/****************************************************************************
+ Is it an NTFS stream name ?
+****************************************************************************/
+
+BOOL is_ntfs_stream_name(const char *fname)
+{
+ if (lp_posix_pathnames()) {
+ return False;
+ }
+ return (strchr_m(fname, ':') != NULL) ? True : False;
+}
+
/****************************************************************************
Save case statics.
****************************************************************************/
Save case semantics.
****************************************************************************/
-static void set_posix_case_semantics(uint32 file_attributes)
+static void set_posix_case_semantics(connection_struct *conn, uint32 file_attributes)
{
- if(!(file_attributes & FILE_FLAG_POSIX_SEMANTICS))
+ if(!(file_attributes & FILE_FLAG_POSIX_SEMANTICS)) {
return;
+ }
- saved_case_sensitive = case_sensitive;
- saved_case_preserve = case_preserve;
- saved_short_case_preserve = short_case_preserve;
+ saved_case_sensitive = conn->case_sensitive;
+ saved_case_preserve = conn->case_preserve;
+ saved_short_case_preserve = conn->short_case_preserve;
/* Set to POSIX. */
- case_sensitive = True;
- case_preserve = True;
- short_case_preserve = True;
+ conn->case_sensitive = True;
+ conn->case_preserve = True;
+ conn->short_case_preserve = True;
}
/****************************************************************************
Restore case semantics.
****************************************************************************/
-static void restore_case_semantics(uint32 file_attributes)
+static void restore_case_semantics(connection_struct *conn, uint32 file_attributes)
{
- if(!(file_attributes & FILE_FLAG_POSIX_SEMANTICS))
+ if(!(file_attributes & FILE_FLAG_POSIX_SEMANTICS)) {
return;
-
- case_sensitive = saved_case_sensitive;
- case_preserve = saved_case_preserve;
- short_case_preserve = saved_short_case_preserve;
-}
-
-/****************************************************************************
- Utility function to map create disposition.
-****************************************************************************/
-
-static int map_create_disposition( uint32 create_disposition)
-{
- int ret;
-
- switch( create_disposition ) {
- case FILE_CREATE:
- /* create if not exist, fail if exist */
- ret = (FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_FAIL);
- break;
- case FILE_SUPERSEDE:
- case FILE_OVERWRITE_IF:
- /* create if not exist, trunc if exist */
- ret = (FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_TRUNCATE);
- break;
- case FILE_OPEN:
- /* fail if not exist, open if exists */
- ret = (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN);
- break;
- case FILE_OPEN_IF:
- /* create if not exist, open if exists */
- ret = (FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_OPEN);
- break;
- case FILE_OVERWRITE:
- /* fail if not exist, truncate if exists */
- ret = (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_TRUNCATE);
- break;
- default:
- DEBUG(0,("map_create_disposition: Incorrect value for create_disposition = %d\n",
- create_disposition ));
- return -1;
}
- DEBUG(10,("map_create_disposition: Mapped create_disposition 0x%lx to 0x%x\n",
- (unsigned long)create_disposition, ret ));
-
- return ret;
-}
-
-/****************************************************************************
- Utility function to map share modes.
-****************************************************************************/
-
-static int map_share_mode( char *fname, uint32 create_options,
- uint32 *desired_access, uint32 share_access, uint32 file_attributes)
-{
- int smb_open_mode = -1;
- uint32 original_desired_access = *desired_access;
-
- /*
- * Convert GENERIC bits to specific bits.
- */
-
- se_map_generic(desired_access, &file_generic_mapping);
-
- switch( *desired_access & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA) ) {
- case FILE_READ_DATA:
- smb_open_mode = DOS_OPEN_RDONLY;
- break;
- case FILE_WRITE_DATA:
- case FILE_APPEND_DATA:
- case FILE_WRITE_DATA|FILE_APPEND_DATA:
- smb_open_mode = DOS_OPEN_WRONLY;
- break;
- case FILE_READ_DATA|FILE_WRITE_DATA:
- case FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA:
- case FILE_READ_DATA|FILE_APPEND_DATA:
- smb_open_mode = DOS_OPEN_RDWR;
- break;
- }
-
- /*
- * NB. For DELETE_ACCESS we should really check the
- * directory permissions, as that is what controls
- * delete, and for WRITE_DAC_ACCESS we should really
- * check the ownership, as that is what controls the
- * chmod. Note that this is *NOT* a security hole (this
- * note is for you, Andrew) as we are not *allowing*
- * the access at this point, the actual unlink or
- * chown or chmod call would do this. We are just helping
- * clients out by telling them if they have a hope
- * of any of this succeeding. POSIX acls may still
- * deny the real call. JRA.
- */
-
- if (smb_open_mode == -1) {
-
- if(*desired_access & (DELETE_ACCESS|WRITE_DAC_ACCESS|WRITE_OWNER_ACCESS|SYNCHRONIZE_ACCESS|
- FILE_EXECUTE|FILE_READ_ATTRIBUTES|
- FILE_READ_EA|FILE_WRITE_EA|SYSTEM_SECURITY_ACCESS|
- FILE_WRITE_ATTRIBUTES|READ_CONTROL_ACCESS)) {
- smb_open_mode = DOS_OPEN_RDONLY;
- } else if(*desired_access == 0) {
-
- /*
- * JRA - NT seems to sometimes send desired_access as zero. play it safe
- * and map to a stat open.
- */
-
- smb_open_mode = DOS_OPEN_RDONLY;
-
- } else {
- DEBUG(0,("map_share_mode: Incorrect value 0x%lx for desired_access to file %s\n",
- (unsigned long)*desired_access, fname));
- return -1;
- }
- }
-
- /*
- * Set the special bit that means allow share delete.
- * This is held outside the normal share mode bits at 1<<15.
- * JRA.
- */
-
- if(share_access & FILE_SHARE_DELETE) {
- smb_open_mode |= ALLOW_SHARE_DELETE;
- DEBUG(10,("map_share_mode: FILE_SHARE_DELETE requested. open_mode = 0x%x\n", smb_open_mode));
- }
-
- if(*desired_access & DELETE_ACCESS) {
- DEBUG(10,("map_share_mode: DELETE_ACCESS requested. open_mode = 0x%x\n", smb_open_mode));
- }
-
- /*
- * We need to store the intent to open for Delete. This
- * is what determines if a delete on close flag can be set.
- * This is the wrong way (and place) to store this, but for 2.2 this
- * is the only practical way. JRA.
- */
-
- if (create_options & FILE_DELETE_ON_CLOSE) {
- /*
- * W2K3 bug compatibility mode... To set delete on close
- * the redirector must have *specifically* set DELETE_ACCESS
- * in the desired_access field. Just asking for GENERIC_ALL won't do. JRA.
- */
-
- if (!(original_desired_access & DELETE_ACCESS)) {
- DEBUG(5,("map_share_mode: FILE_DELETE_ON_CLOSE requested without \
-DELETE_ACCESS for file %s. (desired_access = 0x%lx)\n",
- fname, (unsigned long)*desired_access));
- return -1;
- }
- /* Implicit delete access is *NOT* requested... */
- smb_open_mode |= DELETE_ON_CLOSE_FLAG;
- DEBUG(10,("map_share_mode: FILE_DELETE_ON_CLOSE requested. open_mode = 0x%x\n", smb_open_mode));
- }
-
- /* Add in the requested share mode. */
- switch( share_access & (FILE_SHARE_READ|FILE_SHARE_WRITE)) {
- case FILE_SHARE_READ:
- smb_open_mode |= SET_DENY_MODE(DENY_WRITE);
- break;
- case FILE_SHARE_WRITE:
- smb_open_mode |= SET_DENY_MODE(DENY_READ);
- break;
- case (FILE_SHARE_READ|FILE_SHARE_WRITE):
- smb_open_mode |= SET_DENY_MODE(DENY_NONE);
- break;
- case FILE_SHARE_NONE:
- smb_open_mode |= SET_DENY_MODE(DENY_ALL);
- break;
- }
-
- /*
- * Handle an O_SYNC request.
- */
-
- if(file_attributes & FILE_FLAG_WRITE_THROUGH)
- smb_open_mode |= FILE_SYNC_OPENMODE;
-
- DEBUG(10,("map_share_mode: Mapped desired access 0x%lx, share access 0x%lx, file attributes 0x%lx \
-to open_mode 0x%x\n", (unsigned long)*desired_access, (unsigned long)share_access,
- (unsigned long)file_attributes, smb_open_mode ));
-
- return smb_open_mode;
+ conn->case_sensitive = saved_case_sensitive;
+ conn->case_preserve = saved_case_preserve;
+ conn->short_case_preserve = saved_short_case_preserve;
}
/****************************************************************************
char *inbuf, char *outbuf, int *ppnum)
{
smb_np_struct *p = NULL;
-
uint16 vuid = SVAL(inbuf, smb_uid);
int i;
-
+
DEBUG(4,("nt_open_pipe: Opening pipe %s.\n", fname));
/* See if it is one we want to handle. */
- if (lp_disable_spoolss() && strequal(fname, "\\spoolss"))
+ if (lp_disable_spoolss() && strequal(fname, "\\spoolss")) {
return(ERROR_BOTH(NT_STATUS_OBJECT_NAME_NOT_FOUND,ERRDOS,ERRbadpipe));
+ }
- for( i = 0; known_nt_pipes[i]; i++ )
- if( strequal(fname,known_nt_pipes[i]))
+ for( i = 0; known_nt_pipes[i]; i++ ) {
+ if( strequal(fname,known_nt_pipes[i])) {
break;
+ }
+ }
- if ( known_nt_pipes[i] == NULL )
+ if ( known_nt_pipes[i] == NULL ) {
return(ERROR_BOTH(NT_STATUS_OBJECT_NAME_NOT_FOUND,ERRDOS,ERRbadpipe));
+ }
/* Strip \\ off the name. */
fname++;
DEBUG(3,("nt_open_pipe: Known pipe %s opening.\n", fname));
p = open_rpc_pipe_p(fname, conn, vuid);
- if (!p)
+ if (!p) {
return(ERROR_DOS(ERRSRV,ERRnofids));
+ }
+ /* TODO: Add pipe to db */
+
+ if ( !store_pipe_opendb( p ) ) {
+ DEBUG(3,("nt_open_pipe: failed to store %s pipe open.\n", fname));
+ }
+
*ppnum = p->pnum;
-
return 0;
}
int ret;
int pnum = -1;
char *p = NULL;
- NTSTATUS status;
- srvstr_get_path(inbuf, fname, smb_buf(inbuf), sizeof(fname), STR_TERMINATE,&status);
- if (!NT_STATUS_IS_OK(status))
- return ERROR_NT(status);
+ srvstr_pull_buf(inbuf, fname, smb_buf(inbuf), sizeof(fname), STR_TERMINATE);
- if ((ret = nt_open_pipe(fname, conn, inbuf, outbuf, &pnum)) != 0)
+ if ((ret = nt_open_pipe(fname, conn, inbuf, outbuf, &pnum)) != 0) {
return ret;
+ }
/*
* Deal with pipe return.
return chain_reply(inbuf,outbuf,length,bufsize);
}
+/****************************************************************************
+ Reply to an NT create and X call for a quota file.
+****************************************************************************/
+
+int reply_ntcreate_and_X_quota(connection_struct *conn,
+ char *inbuf,
+ char *outbuf,
+ int length,
+ int bufsize,
+ enum FAKE_FILE_TYPE fake_file_type,
+ const char *fname)
+{
+ int result;
+ char *p;
+ uint32 desired_access = IVAL(inbuf,smb_ntcreate_DesiredAccess);
+ files_struct *fsp;
+ NTSTATUS status;
+
+ status = open_fake_file(conn, fake_file_type, fname, desired_access,
+ &fsp);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return ERROR_NT(status);
+ }
+
+ set_message(outbuf,34,0,True);
+
+ p = outbuf + smb_vwv2;
+
+ /* SCVAL(p,0,NO_OPLOCK_RETURN); */
+ p++;
+ SSVAL(p,0,fsp->fnum);
+
+ DEBUG(5,("reply_ntcreate_and_X_quota: fnum = %d, open name = %s\n", fsp->fnum, fsp->fsp_name));
+
+ result = chain_reply(inbuf,outbuf,length,bufsize);
+ return result;
+}
+
/****************************************************************************
Reply to an NT create and X call.
****************************************************************************/
{
int result;
pstring fname;
- enum FAKE_FILE_TYPE fake_file_type = FAKE_FILE_TYPE_NONE;
uint32 flags = IVAL(inbuf,smb_ntcreate_Flags);
- uint32 desired_access = IVAL(inbuf,smb_ntcreate_DesiredAccess);
+ uint32 access_mask = IVAL(inbuf,smb_ntcreate_DesiredAccess);
uint32 file_attributes = IVAL(inbuf,smb_ntcreate_FileAttributes);
uint32 share_access = IVAL(inbuf,smb_ntcreate_ShareAccess);
uint32 create_disposition = IVAL(inbuf,smb_ntcreate_CreateDisposition);
uint32 create_options = IVAL(inbuf,smb_ntcreate_CreateOptions);
uint16 root_dir_fid = (uint16)IVAL(inbuf,smb_ntcreate_RootDirectoryFid);
- SMB_BIG_UINT allocation_size = 0;
- int smb_ofun;
- int smb_open_mode;
- int smb_attr = (file_attributes & SAMBA_ATTRIBUTES_MASK);
/* Breakout the oplock request bits so we can set the
reply bits separately. */
int oplock_request = 0;
- mode_t unixmode;
- int fmode=0,rmode=0;
+ uint32 fattr=0;
SMB_OFF_T file_len = 0;
SMB_STRUCT_STAT sbuf;
- int smb_action = 0;
+ int info = 0;
BOOL bad_path = False;
files_struct *fsp=NULL;
char *p = NULL;
- time_t c_time;
+ struct timespec c_timespec;
+ struct timespec a_timespec;
+ struct timespec m_timespec;
BOOL extended_oplock_granted = False;
NTSTATUS status;
START_PROFILE(SMBntcreateX);
- DEBUG(10,("reply_ntcreateX: flags = 0x%x, desired_access = 0x%x \
-file_attributes = 0x%x, share_access = 0x%x, create_disposition = 0x%x \
-create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attributes,
- share_access, create_disposition,
- create_options, root_dir_fid ));
+ DEBUG(10,("reply_ntcreate_and_X: flags = 0x%x, access_mask = 0x%x "
+ "file_attributes = 0x%x, share_access = 0x%x, "
+ "create_disposition = 0x%x create_options = 0x%x "
+ "root_dir_fid = 0x%x\n",
+ (unsigned int)flags,
+ (unsigned int)access_mask,
+ (unsigned int)file_attributes,
+ (unsigned int)share_access,
+ (unsigned int)create_disposition,
+ (unsigned int)create_options,
+ (unsigned int)root_dir_fid ));
/* If it's an IPC, use the pipe handler. */
return ERROR_NT(NT_STATUS_NOT_SUPPORTED);
}
- /*
- * We need to construct the open_and_X ofun value from the
- * NT values, as that's what our code is structured to accept.
- */
-
- if((smb_ofun = map_create_disposition( create_disposition )) == -1) {
- END_PROFILE(SMBntcreateX);
- return(ERROR_DOS(ERRDOS,ERRnoaccess));
- }
-
/*
* Get the file name.
*/
/*
* This filename is relative to a directory fid.
*/
+ pstring rel_fname;
files_struct *dir_fsp = file_fsp(inbuf,smb_ntcreate_RootDirectoryFid);
size_t dir_name_len;
if(!dir_fsp->is_directory) {
- srvstr_get_path(inbuf, fname, smb_buf(inbuf), sizeof(fname), STR_TERMINATE,&status);
+ srvstr_get_path(inbuf, fname, smb_buf(inbuf), sizeof(fname), 0, STR_TERMINATE, &status);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBntcreateX);
return ERROR_NT(status);
* Check to see if this is a mac fork of some kind.
*/
- if( strchr_m(fname, ':')) {
+ if( is_ntfs_stream_name(fname)) {
END_PROFILE(SMBntcreateX);
return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
}
*/
if(fname[dir_name_len-1] != '\\' && fname[dir_name_len-1] != '/') {
- pstrcat(fname, "\\");
+ pstrcat(fname, "/");
dir_name_len++;
}
- srvstr_get_path(inbuf, &fname[dir_name_len], smb_buf(inbuf), sizeof(fname)-dir_name_len, STR_TERMINATE,&status);
+ srvstr_get_path(inbuf, rel_fname, smb_buf(inbuf), sizeof(rel_fname), 0, STR_TERMINATE, &status);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBntcreateX);
return ERROR_NT(status);
}
+ pstrcat(fname, rel_fname);
} else {
- srvstr_get_path(inbuf, fname, smb_buf(inbuf), sizeof(fname), STR_TERMINATE,&status);
+ srvstr_get_path(inbuf, fname, smb_buf(inbuf), sizeof(fname), 0, STR_TERMINATE, &status);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBntcreateX);
return ERROR_NT(status);
* Check to see if this is a mac fork of some kind.
*/
- if( strchr_m(fname, ':')) {
-
-#ifdef HAVE_SYS_QUOTAS
- if ((fake_file_type=is_fake_file(fname))!=FAKE_FILE_TYPE_NONE) {
+ if( is_ntfs_stream_name(fname)) {
+ enum FAKE_FILE_TYPE fake_file_type = is_fake_file(fname);
+ if (fake_file_type!=FAKE_FILE_TYPE_NONE) {
/*
- * here we go! support for changing the disk quotas --metze
+ * Here we go! support for changing the disk quotas --metze
*
- * we need to fake up to open this MAGIC QUOTA file
- * and return a valid FID
+ * We need to fake up to open this MAGIC QUOTA file
+ * and return a valid FID.
*
* w2k close this file directly after openening
* xp also tries a QUERY_FILE_INFO on the file and then close it
*/
+ result = reply_ntcreate_and_X_quota(conn, inbuf, outbuf, length, bufsize,
+ fake_file_type, fname);
+ END_PROFILE(SMBntcreateX);
+ return result;
} else {
-#endif
END_PROFILE(SMBntcreateX);
return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
-#ifdef HAVE_SYS_QUOTAS
}
-#endif
}
}
*/
RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
- if((smb_open_mode = map_share_mode(fname, create_options, &desired_access,
- share_access,
- file_attributes)) == -1) {
- END_PROFILE(SMBntcreateX);
- return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
- }
-
oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
if (oplock_request) {
oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
* Check if POSIX semantics are wanted.
*/
- set_posix_case_semantics(file_attributes);
+ set_posix_case_semantics(conn, file_attributes);
unix_convert(fname,conn,0,&bad_path,&sbuf);
-
- unixmode = unix_mode(conn,smb_attr | aARCH, fname);
-
+
+ if (bad_path) {
+ restore_case_semantics(conn, file_attributes);
+ END_PROFILE(SMBntcreateX);
+ return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+ }
+ /* All file access must go through check_name() */
+ if (!check_name(fname,conn)) {
+ restore_case_semantics(conn, file_attributes);
+ END_PROFILE(SMBntcreateX);
+ return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
+ }
+
+#if 0
+ /* This is the correct thing to do (check every time) but can_delete is
+ expensive (it may have to read the parent directory permissions). So
+ for now we're not doing it unless we have a strong hint the client
+ is really going to delete this file. */
+ if (desired_access & DELETE_ACCESS) {
+#else
+ /* Setting FILE_SHARE_DELETE is the hint. */
+ if (lp_acl_check_permissions(SNUM(conn)) && (share_access & FILE_SHARE_DELETE)
+ && (access_mask & DELETE_ACCESS)) {
+#endif
+ status = can_delete(conn, fname, file_attributes, bad_path, True);
+ /* We're only going to fail here if it's access denied, as that's the
+ only error we care about for "can we delete this ?" questions. */
+ if (!NT_STATUS_IS_OK(status) && (NT_STATUS_EQUAL(status,NT_STATUS_ACCESS_DENIED) ||
+ NT_STATUS_EQUAL(status,NT_STATUS_CANNOT_DELETE))) {
+ restore_case_semantics(conn, file_attributes);
+ END_PROFILE(SMBntcreateX);
+ return ERROR_NT(NT_STATUS_ACCESS_DENIED);
+ }
+ }
+
/*
* If it's a request for a directory open, deal with it separately.
*/
return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
}
- fsp = open_directory(conn, fname, &sbuf, desired_access, smb_open_mode, smb_ofun, unixmode, &smb_action);
-
- restore_case_semantics(file_attributes);
+ status = open_directory(conn, fname, &sbuf,
+ access_mask,
+ share_access,
+ create_disposition,
+ create_options,
+ &info, &fsp);
+
+ restore_case_semantics(conn, file_attributes);
- if(!fsp) {
+ if(!NT_STATUS_IS_OK(status)) {
+ if (!use_nt_status() && NT_STATUS_EQUAL(
+ status, NT_STATUS_OBJECT_NAME_COLLISION)) {
+ status = NT_STATUS_DOS(ERRDOS, ERRfilexists);
+ }
END_PROFILE(SMBntcreateX);
- return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess);
+ return ERROR_NT(status);
}
} else {
/*
* before issuing an oplock break request to
* our client. JRA. */
- if (fake_file_type==FAKE_FILE_TYPE_NONE) {
- fsp = open_file_shared1(conn,fname,&sbuf,
- desired_access,
- smb_open_mode,
- smb_ofun,unixmode, oplock_request,
- &rmode,&smb_action);
- } else {
- /* to open a fake_file --metze */
- fsp = open_fake_file_shared1(fake_file_type,conn,fname,&sbuf,
- desired_access,
- smb_open_mode,
- smb_ofun,unixmode, oplock_request,
- &rmode,&smb_action);
- }
-
- if (!fsp) {
+ status = open_file_ntcreate(conn,fname,&sbuf,
+ access_mask,
+ share_access,
+ create_disposition,
+ create_options,
+ file_attributes,
+ oplock_request,
+ &info, &fsp);
+ if (!NT_STATUS_IS_OK(status)) {
/* We cheat here. There are two cases we
* care about. One is a directory rename,
* where the NT client will attempt to
* we handle in the open_file_stat case. JRA.
*/
- if(errno == EISDIR) {
+ if (NT_STATUS_EQUAL(status,
+ NT_STATUS_FILE_IS_A_DIRECTORY)) {
/*
* Fail the open if it was explicitly a non-directory file.
*/
if (create_options & FILE_NON_DIRECTORY_FILE) {
- restore_case_semantics(file_attributes);
- SSVAL(outbuf, smb_flg2,
- SVAL(outbuf,smb_flg2) | FLAGS2_32_BIT_ERROR_CODES);
+ restore_case_semantics(conn, file_attributes);
END_PROFILE(SMBntcreateX);
- return ERROR_NT(NT_STATUS_FILE_IS_A_DIRECTORY);
+ return ERROR_FORCE_NT(NT_STATUS_FILE_IS_A_DIRECTORY);
}
oplock_request = 0;
- fsp = open_directory(conn, fname, &sbuf, desired_access, smb_open_mode, smb_ofun, unixmode, &smb_action);
-
- if(!fsp) {
- restore_case_semantics(file_attributes);
+ status = open_directory(conn, fname, &sbuf,
+ access_mask,
+ share_access,
+ create_disposition,
+ create_options,
+ &info, &fsp);
+
+ if(!NT_STATUS_IS_OK(status)) {
+ restore_case_semantics(conn, file_attributes);
+ if (!use_nt_status() && NT_STATUS_EQUAL(
+ status, NT_STATUS_OBJECT_NAME_COLLISION)) {
+ status = NT_STATUS_DOS(ERRDOS, ERRfilexists);
+ }
END_PROFILE(SMBntcreateX);
- return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess);
+ return ERROR_NT(status);
}
} else {
- restore_case_semantics(file_attributes);
+ restore_case_semantics(conn, file_attributes);
END_PROFILE(SMBntcreateX);
- return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess);
+ if (open_was_deferred(SVAL(inbuf,smb_mid))) {
+ /* We have re-scheduled this call. */
+ return -1;
+ }
+ return ERROR_NT(status);
}
}
}
- restore_case_semantics(file_attributes);
+ restore_case_semantics(conn, file_attributes);
file_len = sbuf.st_size;
- fmode = dos_mode(conn,fname,&sbuf);
- if(fmode == 0)
- fmode = FILE_ATTRIBUTE_NORMAL;
- if (!fsp->is_directory && (fmode & aDIR)) {
- close_file(fsp,False);
+ fattr = dos_mode(conn,fname,&sbuf);
+ if(fattr == 0) {
+ fattr = FILE_ATTRIBUTE_NORMAL;
+ }
+ if (!fsp->is_directory && (fattr & aDIR)) {
+ close_file(fsp,ERROR_CLOSE);
END_PROFILE(SMBntcreateX);
return ERROR_DOS(ERRDOS,ERRnoaccess);
}
/* Save the requested allocation size. */
- allocation_size = (SMB_BIG_UINT)IVAL(inbuf,smb_ntcreate_AllocationSize);
+ if ((info == FILE_WAS_CREATED) || (info == FILE_WAS_OVERWRITTEN)) {
+ SMB_BIG_UINT allocation_size = (SMB_BIG_UINT)IVAL(inbuf,smb_ntcreate_AllocationSize);
#ifdef LARGE_SMB_OFF_T
- allocation_size |= (((SMB_BIG_UINT)IVAL(inbuf,smb_ntcreate_AllocationSize + 4)) << 32);
+ allocation_size |= (((SMB_BIG_UINT)IVAL(inbuf,smb_ntcreate_AllocationSize + 4)) << 32);
#endif
- if (allocation_size && (allocation_size > (SMB_BIG_UINT)file_len)) {
- fsp->initial_allocation_size = SMB_ROUNDUP(allocation_size,SMB_ROUNDUP_ALLOCATION_SIZE);
- if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
- close_file(fsp,False);
- END_PROFILE(SMBntcreateX);
- return ERROR_NT(NT_STATUS_DISK_FULL);
+ if (allocation_size && (allocation_size > (SMB_BIG_UINT)file_len)) {
+ fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
+ if (fsp->is_directory) {
+ close_file(fsp,ERROR_CLOSE);
+ END_PROFILE(SMBntcreateX);
+ /* Can't set allocation size on a directory. */
+ return ERROR_NT(NT_STATUS_ACCESS_DENIED);
+ }
+ if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
+ close_file(fsp,ERROR_CLOSE);
+ END_PROFILE(SMBntcreateX);
+ return ERROR_NT(NT_STATUS_DISK_FULL);
+ }
+ } else {
+ fsp->initial_allocation_size = smb_roundup(fsp->conn,(SMB_BIG_UINT)file_len);
}
- } else {
- fsp->initial_allocation_size = SMB_ROUNDUP(((SMB_BIG_UINT)file_len),SMB_ROUNDUP_ALLOCATION_SIZE);
}
/*
* correct bit for extended oplock reply.
*/
- if (oplock_request && lp_fake_oplocks(SNUM(conn)))
+ if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
extended_oplock_granted = True;
+ }
- if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
+ if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
extended_oplock_granted = True;
+ }
#if 0
/* W2K sends back 42 words here ! If we do the same it breaks offline sync. Go figure... ? JRA. */
} else {
SCVAL(p,0, EXCLUSIVE_OPLOCK_RETURN);
}
- } else if (LEVEL_II_OPLOCK_TYPE(fsp->oplock_type)) {
+ } else if (fsp->oplock_type == LEVEL_II_OPLOCK) {
SCVAL(p,0, LEVEL_II_OPLOCK_RETURN);
} else {
SCVAL(p,0,NO_OPLOCK_RETURN);
p++;
SSVAL(p,0,fsp->fnum);
p += 2;
- if ((create_disposition == FILE_SUPERSEDE) && (smb_action == FILE_WAS_OVERWRITTEN))
+ if ((create_disposition == FILE_SUPERSEDE) && (info == FILE_WAS_OVERWRITTEN)) {
SIVAL(p,0,FILE_WAS_SUPERSEDED);
- else
- SIVAL(p,0,smb_action);
+ } else {
+ SIVAL(p,0,info);
+ }
p += 4;
/* Create time. */
- c_time = get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn)));
+ c_timespec = get_create_timespec(&sbuf,lp_fake_dir_create_times(SNUM(conn)));
+ a_timespec = get_atimespec(&sbuf);
+ m_timespec = get_mtimespec(&sbuf);
if (lp_dos_filetime_resolution(SNUM(conn))) {
- c_time &= ~1;
- sbuf.st_atime &= ~1;
- sbuf.st_mtime &= ~1;
- sbuf.st_mtime &= ~1;
+ dos_filetime_timespec(&c_timespec);
+ dos_filetime_timespec(&a_timespec);
+ dos_filetime_timespec(&m_timespec);
}
- put_long_date(p,c_time);
+ put_long_date_timespec(p, c_timespec);
p += 8;
- put_long_date(p,sbuf.st_atime); /* access time */
+ put_long_date_timespec(p, a_timespec); /* access time */
p += 8;
- put_long_date(p,sbuf.st_mtime); /* write time */
+ put_long_date_timespec(p, m_timespec); /* write time */
p += 8;
- put_long_date(p,sbuf.st_mtime); /* change time */
+ put_long_date_timespec(p, m_timespec); /* change time */
p += 8;
- SIVAL(p,0,fmode); /* File Attributes. */
+ SIVAL(p,0,fattr); /* File Attributes. */
p += 4;
- SOFF_T(p, 0, get_allocation_size(fsp,&sbuf));
+ SOFF_T(p, 0, get_allocation_size(conn,fsp,&sbuf));
p += 8;
SOFF_T(p,0,file_len);
p += 8;
- if (flags & EXTENDED_RESPONSE_REQUIRED)
+ if (flags & EXTENDED_RESPONSE_REQUIRED) {
SSVAL(p,2,0x7);
+ }
p += 4;
SCVAL(p,0,fsp->is_directory ? 1 : 0);
****************************************************************************/
static int do_nt_transact_create_pipe( connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
- char **ppsetup, uint32 setup_count,
+ uint16 **ppsetup, uint32 setup_count,
char **ppparams, uint32 parameter_count,
char **ppdata, uint32 data_count)
{
return ERROR_DOS(ERRDOS,ERRnoaccess);
}
- srvstr_pull(inbuf, fname, params+53, sizeof(fname), parameter_count-53, STR_TERMINATE);
- status = check_path_syntax(fname);
+ srvstr_get_path(inbuf, fname, params+53, sizeof(fname), parameter_count-53, STR_TERMINATE, &status);
if (!NT_STATUS_IS_OK(status)) {
return ERROR_NT(status);
}
- if ((ret = nt_open_pipe(fname, conn, inbuf, outbuf, &pnum)) != 0)
+ if ((ret = nt_open_pipe(fname, conn, inbuf, outbuf, &pnum)) != 0) {
return ret;
+ }
/* Realloc the size of parameters and data we will return */
params = nttrans_realloc(ppparams, 69);
- if(params == NULL)
+ if(params == NULL) {
return ERROR_DOS(ERRDOS,ERRnomem);
+ }
p = params;
SCVAL(p,0,NO_OPLOCK_RETURN);
DEBUG(5,("do_nt_transact_create_pipe: open name = %s\n", fname));
/* Send the required number of replies */
- send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, params, 69, *ppdata, 0);
+ send_nt_replies(outbuf, bufsize, NT_STATUS_OK, params, 69, *ppdata, 0);
return -1;
}
TALLOC_CTX *mem_ctx;
BOOL ret;
- if (sd_len == 0) {
+ if (sd_len == 0 || !lp_nt_acl_support(SNUM(fsp->conn))) {
return NT_STATUS_OK;
}
return NT_STATUS_NO_MEMORY;
}
- if (psd->off_owner_sid==0)
+ if (psd->owner_sid==0) {
security_info_sent &= ~OWNER_SECURITY_INFORMATION;
- if (psd->off_grp_sid==0)
+ }
+ if (psd->group_sid==0) {
security_info_sent &= ~GROUP_SECURITY_INFORMATION;
- if (psd->off_sacl==0)
+ }
+ if (psd->sacl==0) {
security_info_sent &= ~SACL_SECURITY_INFORMATION;
- if (psd->off_dacl==0)
+ }
+ if (psd->dacl==0) {
security_info_sent &= ~DACL_SECURITY_INFORMATION;
+ }
- ret = SMB_VFS_FSET_NT_ACL( fsp, fsp->fd, security_info_sent, psd);
+ ret = SMB_VFS_FSET_NT_ACL( fsp, fsp->fh->fd, security_info_sent, psd);
if (!ret) {
talloc_destroy(mem_ctx);
return NT_STATUS_OK;
}
+/****************************************************************************
+ Read a list of EA names and data from an incoming data buffer. Create an ea_list with them.
+****************************************************************************/
+
+static struct ea_list *read_nttrans_ea_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size)
+{
+ struct ea_list *ea_list_head = NULL;
+ size_t offset = 0;
+
+ if (data_size < 4) {
+ return NULL;
+ }
+
+ while (offset + 4 <= data_size) {
+ size_t next_offset = IVAL(pdata,offset);
+ struct ea_list *eal = read_ea_list_entry(ctx, pdata + offset + 4, data_size - offset - 4, NULL);
+
+ if (!eal) {
+ return NULL;
+ }
+
+ DLIST_ADD_END(ea_list_head, eal, struct ea_list *);
+ if (next_offset == 0) {
+ break;
+ }
+ offset += next_offset;
+ }
+
+ return ea_list_head;
+}
+
/****************************************************************************
Reply to a NT_TRANSACT_CREATE call (needs to process SD's).
****************************************************************************/
static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
- char **ppsetup, uint32 setup_count,
+ uint16 **ppsetup, uint32 setup_count,
char **ppparams, uint32 parameter_count,
- char **ppdata, uint32 data_count)
+ char **ppdata, uint32 data_count, uint32 max_data_count)
{
pstring fname;
char *params = *ppparams;
char *data = *ppdata;
/* Breakout the oplock request bits so we can set the reply bits separately. */
int oplock_request = 0;
- mode_t unixmode;
- int fmode=0,rmode=0;
+ uint32 fattr=0;
SMB_OFF_T file_len = 0;
SMB_STRUCT_STAT sbuf;
- int smb_action = 0;
+ int info = 0;
BOOL bad_path = False;
files_struct *fsp = NULL;
char *p = NULL;
BOOL extended_oplock_granted = False;
uint32 flags;
- uint32 desired_access;
+ uint32 access_mask;
uint32 file_attributes;
uint32 share_access;
uint32 create_disposition;
uint32 create_options;
uint32 sd_len;
+ uint32 ea_len;
uint16 root_dir_fid;
- SMB_BIG_UINT allocation_size = 0;
- int smb_ofun;
- int smb_open_mode;
- int smb_attr;
- time_t c_time;
- NTSTATUS nt_status;
+ struct timespec c_timespec;
+ struct timespec a_timespec;
+ struct timespec m_timespec;
+ struct ea_list *ea_list = NULL;
+ TALLOC_CTX *ctx = NULL;
+ char *pdata = NULL;
+ NTSTATUS status;
DEBUG(5,("call_nt_transact_create\n"));
*/
if (IS_IPC(conn)) {
- if (lp_nt_pipe_support())
+ if (lp_nt_pipe_support()) {
return do_nt_transact_create_pipe(conn, inbuf, outbuf, length,
bufsize,
ppsetup, setup_count,
ppparams, parameter_count,
ppdata, data_count);
- else
+ } else {
return ERROR_DOS(ERRDOS,ERRnoaccess);
+ }
}
/*
if(parameter_count < 54) {
DEBUG(0,("call_nt_transact_create - insufficient parameters (%u)\n", (unsigned int)parameter_count));
- return ERROR_DOS(ERRDOS,ERRnoaccess);
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
}
flags = IVAL(params,0);
- desired_access = IVAL(params,8);
+ access_mask = IVAL(params,8);
file_attributes = IVAL(params,20);
share_access = IVAL(params,24);
create_disposition = IVAL(params,28);
create_options = IVAL(params,32);
sd_len = IVAL(params,36);
+ ea_len = IVAL(params,40);
root_dir_fid = (uint16)IVAL(params,4);
- smb_attr = (file_attributes & SAMBA_ATTRIBUTES_MASK);
- if (create_options & FILE_OPEN_BY_FILE_ID) {
- return ERROR_NT(NT_STATUS_NOT_SUPPORTED);
+ /* Ensure the data_len is correct for the sd and ea values given. */
+ if ((ea_len + sd_len > data_count) ||
+ (ea_len > data_count) || (sd_len > data_count) ||
+ (ea_len + sd_len < ea_len) || (ea_len + sd_len < sd_len)) {
+ DEBUG(10,("call_nt_transact_create - ea_len = %u, sd_len = %u, data_count = %u\n",
+ (unsigned int)ea_len, (unsigned int)sd_len, (unsigned int)data_count ));
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
}
- /*
- * We need to construct the open_and_X ofun value from the
- * NT values, as that's what our code is structured to accept.
- */
+ if (ea_len) {
+ if (!lp_ea_support(SNUM(conn))) {
+ DEBUG(10,("call_nt_transact_create - ea_len = %u but EA's not supported.\n",
+ (unsigned int)ea_len ));
+ return ERROR_NT(NT_STATUS_EAS_NOT_SUPPORTED);
+ }
+
+ if (ea_len < 10) {
+ DEBUG(10,("call_nt_transact_create - ea_len = %u - too small (should be more than 10)\n",
+ (unsigned int)ea_len ));
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
+ }
- if((smb_ofun = map_create_disposition( create_disposition )) == -1)
- return ERROR_DOS(ERRDOS,ERRbadmem);
+ if (create_options & FILE_OPEN_BY_FILE_ID) {
+ return ERROR_NT(NT_STATUS_NOT_SUPPORTED);
+ }
/*
* Get the file name.
/*
* This filename is relative to a directory fid.
*/
-
files_struct *dir_fsp = file_fsp(params,4);
size_t dir_name_len;
- if(!dir_fsp)
+ if(!dir_fsp) {
return ERROR_DOS(ERRDOS,ERRbadfid);
+ }
if(!dir_fsp->is_directory) {
-
- srvstr_pull(inbuf, fname, params+53, sizeof(fname), parameter_count-53, STR_TERMINATE);
- nt_status = check_path_syntax(fname);
- if (!NT_STATUS_IS_OK(nt_status)) {
- return ERROR_NT(nt_status);
+ srvstr_get_path(inbuf, fname, params+53, sizeof(fname), parameter_count-53, STR_TERMINATE, &status);
+ if (!NT_STATUS_IS_OK(status)) {
+ return ERROR_NT(status);
}
/*
* Check to see if this is a mac fork of some kind.
*/
- if( strchr_m(fname, ':'))
+ if( is_ntfs_stream_name(fname)) {
return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+ }
return ERROR_DOS(ERRDOS,ERRbadfid);
}
*/
if((fname[dir_name_len-1] != '\\') && (fname[dir_name_len-1] != '/')) {
- pstrcat(fname, "\\");
+ pstrcat(fname, "/");
dir_name_len++;
}
- srvstr_pull(inbuf, &fname[dir_name_len], params+53, sizeof(fname)-dir_name_len,
- parameter_count-53, STR_TERMINATE);
- nt_status = check_path_syntax(fname);
- if (!NT_STATUS_IS_OK(nt_status)) {
- return ERROR_NT(nt_status);
+ {
+ pstring tmpname;
+ srvstr_get_path(inbuf, tmpname, params+53, sizeof(tmpname), parameter_count-53, STR_TERMINATE, &status);
+ if (!NT_STATUS_IS_OK(status)) {
+ return ERROR_NT(status);
+ }
+ pstrcat(fname, tmpname);
}
} else {
- srvstr_pull(inbuf, fname, params+53, sizeof(fname), parameter_count-53, STR_TERMINATE);
- nt_status = check_path_syntax(fname);
- if (!NT_STATUS_IS_OK(nt_status)) {
- return ERROR_NT(nt_status);
+ srvstr_get_path(inbuf, fname, params+53, sizeof(fname), parameter_count-53, STR_TERMINATE, &status);
+ if (!NT_STATUS_IS_OK(status)) {
+ return ERROR_NT(status);
}
/*
* Check to see if this is a mac fork of some kind.
*/
- if( strchr_m(fname, ':'))
+ if( is_ntfs_stream_name(fname)) {
return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+ }
}
- /*
- * Now contruct the smb_open_mode value from the desired access
- * and the share access.
- */
-
- if((smb_open_mode = map_share_mode( fname, create_options, &desired_access,
- share_access, file_attributes)) == -1)
- return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
-
oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
* Check if POSIX semantics are wanted.
*/
- set_posix_case_semantics(file_attributes);
+ set_posix_case_semantics(conn, file_attributes);
RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
unix_convert(fname,conn,0,&bad_path,&sbuf);
+ if (bad_path) {
+ restore_case_semantics(conn, file_attributes);
+ return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+ }
+ /* All file access must go through check_name() */
+ if (!check_name(fname,conn)) {
+ restore_case_semantics(conn, file_attributes);
+ return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
+ }
- unixmode = unix_mode(conn,smb_attr | aARCH, fname);
-
+#if 0
+ /* This is the correct thing to do (check every time) but can_delete is
+ expensive (it may have to read the parent directory permissions). So
+ for now we're not doing it unless we have a strong hint the client
+ is really going to delete this file. */
+ if (desired_access & DELETE_ACCESS) {
+#else
+ /* Setting FILE_SHARE_DELETE is the hint. */
+ if (lp_acl_check_permissions(SNUM(conn)) && (share_access & FILE_SHARE_DELETE) && (access_mask & DELETE_ACCESS)) {
+#endif
+ status = can_delete(conn, fname, file_attributes, bad_path, True);
+ /* We're only going to fail here if it's access denied, as that's the
+ only error we care about for "can we delete this ?" questions. */
+ if (!NT_STATUS_IS_OK(status) && (NT_STATUS_EQUAL(status,NT_STATUS_ACCESS_DENIED) ||
+ NT_STATUS_EQUAL(status,NT_STATUS_CANNOT_DELETE))) {
+ restore_case_semantics(conn, file_attributes);
+ return ERROR_NT(status);
+ }
+ }
+
+ if (ea_len) {
+ pdata = data + sd_len;
+
+ /* We have already checked that ea_len <= data_count here. */
+ ea_list = read_nttrans_ea_list(tmp_talloc_ctx(), pdata,
+ ea_len);
+ if (!ea_list ) {
+ restore_case_semantics(conn, file_attributes);
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
+ }
+
/*
* If it's a request for a directory open, deal with it separately.
*/
/* Can't open a temp directory. IFS kit test. */
if (file_attributes & FILE_ATTRIBUTE_TEMPORARY) {
+ restore_case_semantics(conn, file_attributes);
return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
}
* CreateDirectory() call.
*/
- fsp = open_directory(conn, fname, &sbuf, desired_access, smb_open_mode, smb_ofun, unixmode, &smb_action);
-
- if(!fsp) {
- restore_case_semantics(file_attributes);
- return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess);
+ status = open_directory(conn, fname, &sbuf,
+ access_mask,
+ share_access,
+ create_disposition,
+ create_options,
+ &info, &fsp);
+ if(!NT_STATUS_IS_OK(status)) {
+ restore_case_semantics(conn, file_attributes);
+ return ERROR_NT(status);
}
} else {
* Ordinary file case.
*/
- fsp = open_file_shared1(conn,fname,&sbuf,desired_access,
- smb_open_mode,smb_ofun,unixmode,
- oplock_request,&rmode,&smb_action);
-
- if (!fsp) {
+ status = open_file_ntcreate(conn,fname,&sbuf,
+ access_mask,
+ share_access,
+ create_disposition,
+ create_options,
+ file_attributes,
+ oplock_request,
+ &info, &fsp);
- if(errno == EISDIR) {
+ if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status,
+ NT_STATUS_FILE_IS_A_DIRECTORY)) {
/*
* Fail the open if it was explicitly a non-directory file.
*/
if (create_options & FILE_NON_DIRECTORY_FILE) {
- restore_case_semantics(file_attributes);
- SSVAL(outbuf, smb_flg2, SVAL(outbuf,smb_flg2) | FLAGS2_32_BIT_ERROR_CODES);
- return ERROR_NT(NT_STATUS_FILE_IS_A_DIRECTORY);
+ restore_case_semantics(conn, file_attributes);
+ return ERROR_FORCE_NT(NT_STATUS_FILE_IS_A_DIRECTORY);
}
oplock_request = 0;
- fsp = open_directory(conn, fname, &sbuf, desired_access, smb_open_mode, smb_ofun, unixmode, &smb_action);
-
- if(!fsp) {
- restore_case_semantics(file_attributes);
- return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess);
+ status = open_directory(conn, fname, &sbuf,
+ access_mask,
+ share_access,
+ create_disposition,
+ create_options,
+ &info, &fsp);
+ if(!NT_STATUS_IS_OK(status)) {
+ restore_case_semantics(conn, file_attributes);
+ return ERROR_NT(status);
}
} else {
- restore_case_semantics(file_attributes);
- return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess);
+ restore_case_semantics(conn, file_attributes);
+ if (open_was_deferred(SVAL(inbuf,smb_mid))) {
+ /* We have re-scheduled this call. */
+ return -1;
+ }
+ return ERROR_NT(status);
}
}
-
- file_len = sbuf.st_size;
- fmode = dos_mode(conn,fname,&sbuf);
- if(fmode == 0)
- fmode = FILE_ATTRIBUTE_NORMAL;
-
- if (fmode & aDIR) {
- close_file(fsp,False);
- restore_case_semantics(file_attributes);
- return ERROR_DOS(ERRDOS,ERRnoaccess);
- }
-
- /*
- * If the caller set the extended oplock request bit
- * and we granted one (by whatever means) - set the
- * correct bit for extended oplock reply.
- */
-
- if (oplock_request && lp_fake_oplocks(SNUM(conn)))
- extended_oplock_granted = True;
-
- if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
- extended_oplock_granted = True;
}
/*
- * Now try and apply the desired SD.
+ * According to the MS documentation, the only time the security
+ * descriptor is applied to the opened file is iff we *created* the
+ * file; an existing file stays the same.
+ *
+ * Also, it seems (from observation) that you can open the file with
+ * any access mask but you can still write the sd. We need to override
+ * the granted access before we call set_sd
+ * Patch for bug #2242 from Tom Lackemann <cessnatomny@yahoo.com>.
*/
- if (sd_len && !NT_STATUS_IS_OK(nt_status = set_sd( fsp, data, sd_len, ALL_SECURITY_INFORMATION))) {
- close_file(fsp,False);
- restore_case_semantics(file_attributes);
- return ERROR_NT(nt_status);
- }
+ if (lp_nt_acl_support(SNUM(conn)) && sd_len && info == FILE_WAS_CREATED) {
+ uint32 saved_access_mask = fsp->access_mask;
+
+ /* We have already checked that sd_len <= data_count here. */
+
+ fsp->access_mask = FILE_GENERIC_ALL;
+
+ status = set_sd( fsp, data, sd_len, ALL_SECURITY_INFORMATION);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_destroy(ctx);
+ close_file(fsp,ERROR_CLOSE);
+ restore_case_semantics(conn, file_attributes);
+ return ERROR_NT(status);
+ }
+ fsp->access_mask = saved_access_mask;
+ }
- restore_case_semantics(file_attributes);
+ if (ea_len && (info == FILE_WAS_CREATED)) {
+ status = set_ea(conn, fsp, fname, ea_list);
+ if (!NT_STATUS_IS_OK(status)) {
+ close_file(fsp,ERROR_CLOSE);
+ restore_case_semantics(conn, file_attributes);
+ return ERROR_NT(status);
+ }
+ }
+
+ restore_case_semantics(conn, file_attributes);
+ file_len = sbuf.st_size;
+ fattr = dos_mode(conn,fname,&sbuf);
+ if(fattr == 0) {
+ fattr = FILE_ATTRIBUTE_NORMAL;
+ }
+ if (!fsp->is_directory && (fattr & aDIR)) {
+ close_file(fsp,ERROR_CLOSE);
+ return ERROR_DOS(ERRDOS,ERRnoaccess);
+ }
+
/* Save the requested allocation size. */
- allocation_size = (SMB_BIG_UINT)IVAL(params,12);
+ if ((info == FILE_WAS_CREATED) || (info == FILE_WAS_OVERWRITTEN)) {
+ SMB_BIG_UINT allocation_size = (SMB_BIG_UINT)IVAL(params,12);
#ifdef LARGE_SMB_OFF_T
- allocation_size |= (((SMB_BIG_UINT)IVAL(params,16)) << 32);
+ allocation_size |= (((SMB_BIG_UINT)IVAL(params,16)) << 32);
#endif
- if (allocation_size && (allocation_size > file_len)) {
- fsp->initial_allocation_size = SMB_ROUNDUP(allocation_size,SMB_ROUNDUP_ALLOCATION_SIZE);
- if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
- close_file(fsp,False);
- return ERROR_NT(NT_STATUS_DISK_FULL);
+ if (allocation_size && (allocation_size > file_len)) {
+ fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
+ if (fsp->is_directory) {
+ close_file(fsp,ERROR_CLOSE);
+ /* Can't set allocation size on a directory. */
+ return ERROR_NT(NT_STATUS_ACCESS_DENIED);
+ }
+ if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
+ close_file(fsp,ERROR_CLOSE);
+ return ERROR_NT(NT_STATUS_DISK_FULL);
+ }
+ } else {
+ fsp->initial_allocation_size = smb_roundup(fsp->conn, (SMB_BIG_UINT)file_len);
}
- } else {
- fsp->initial_allocation_size = SMB_ROUNDUP(((SMB_BIG_UINT)file_len),SMB_ROUNDUP_ALLOCATION_SIZE);
+ }
+
+ /*
+ * If the caller set the extended oplock request bit
+ * and we granted one (by whatever means) - set the
+ * correct bit for extended oplock reply.
+ */
+
+ if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
+ extended_oplock_granted = True;
+ }
+
+ if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
+ extended_oplock_granted = True;
}
/* Realloc the size of parameters and data we will return */
params = nttrans_realloc(ppparams, 69);
- if(params == NULL)
+ if(params == NULL) {
return ERROR_DOS(ERRDOS,ERRnomem);
+ }
p = params;
- if (extended_oplock_granted)
- SCVAL(p,0, BATCH_OPLOCK_RETURN);
- else if (LEVEL_II_OPLOCK_TYPE(fsp->oplock_type))
+ if (extended_oplock_granted) {
+ if (flags & REQUEST_BATCH_OPLOCK) {
+ SCVAL(p,0, BATCH_OPLOCK_RETURN);
+ } else {
+ SCVAL(p,0, EXCLUSIVE_OPLOCK_RETURN);
+ }
+ } else if (fsp->oplock_type == LEVEL_II_OPLOCK) {
SCVAL(p,0, LEVEL_II_OPLOCK_RETURN);
- else
+ } else {
SCVAL(p,0,NO_OPLOCK_RETURN);
+ }
p += 2;
SSVAL(p,0,fsp->fnum);
p += 2;
- if ((create_disposition == FILE_SUPERSEDE) && (smb_action == FILE_WAS_OVERWRITTEN))
+ if ((create_disposition == FILE_SUPERSEDE) && (info == FILE_WAS_OVERWRITTEN)) {
SIVAL(p,0,FILE_WAS_SUPERSEDED);
- else
- SIVAL(p,0,smb_action);
+ } else {
+ SIVAL(p,0,info);
+ }
p += 8;
/* Create time. */
- c_time = get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn)));
+ c_timespec = get_create_timespec(&sbuf,lp_fake_dir_create_times(SNUM(conn)));
+ a_timespec = get_atimespec(&sbuf);
+ m_timespec = get_mtimespec(&sbuf);
if (lp_dos_filetime_resolution(SNUM(conn))) {
- c_time &= ~1;
- sbuf.st_atime &= ~1;
- sbuf.st_mtime &= ~1;
- sbuf.st_mtime &= ~1;
+ dos_filetime_timespec(&c_timespec);
+ dos_filetime_timespec(&a_timespec);
+ dos_filetime_timespec(&m_timespec);
}
- put_long_date(p,c_time);
+ put_long_date_timespec(p, c_timespec); /* create time. */
p += 8;
- put_long_date(p,sbuf.st_atime); /* access time */
+ put_long_date_timespec(p, a_timespec); /* access time */
p += 8;
- put_long_date(p,sbuf.st_mtime); /* write time */
+ put_long_date_timespec(p, m_timespec); /* write time */
p += 8;
- put_long_date(p,sbuf.st_mtime); /* change time */
+ put_long_date_timespec(p, m_timespec); /* change time */
p += 8;
- SIVAL(p,0,fmode); /* File Attributes. */
+ SIVAL(p,0,fattr); /* File Attributes. */
p += 4;
- SOFF_T(p, 0, get_allocation_size(fsp,&sbuf));
+ SOFF_T(p, 0, get_allocation_size(conn,fsp,&sbuf));
p += 8;
SOFF_T(p,0,file_len);
p += 8;
- if (flags & EXTENDED_RESPONSE_REQUIRED)
+ if (flags & EXTENDED_RESPONSE_REQUIRED) {
SSVAL(p,2,0x7);
+ }
p += 4;
SCVAL(p,0,fsp->is_directory ? 1 : 0);
DEBUG(5,("call_nt_transact_create: open name = %s\n", fname));
/* Send the required number of replies */
- send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, params, 69, *ppdata, 0);
+ send_nt_replies(outbuf, bufsize, NT_STATUS_OK, params, 69, *ppdata, 0);
return -1;
}
/****************************************************************************
Reply to a NT CANCEL request.
+ conn POINTER CAN BE NULL HERE !
****************************************************************************/
int reply_ntcancel(connection_struct *conn,
return(-1);
}
+/****************************************************************************
+ Copy a file.
+****************************************************************************/
+
+static NTSTATUS copy_internals(connection_struct *conn, char *oldname, char *newname, uint32 attrs)
+{
+ BOOL bad_path_oldname = False;
+ BOOL bad_path_newname = False;
+ SMB_STRUCT_STAT sbuf1, sbuf2;
+ pstring last_component_oldname;
+ pstring last_component_newname;
+ files_struct *fsp1,*fsp2;
+ uint32 fattr;
+ int info;
+ SMB_OFF_T ret=-1;
+ int close_ret;
+ NTSTATUS status = NT_STATUS_OK;
+
+ ZERO_STRUCT(sbuf1);
+ ZERO_STRUCT(sbuf2);
+
+ /* No wildcards. */
+ if (ms_has_wild(newname) || ms_has_wild(oldname)) {
+ return NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
+ }
+
+ if (!CAN_WRITE(conn))
+ return NT_STATUS_MEDIA_WRITE_PROTECTED;
+
+ unix_convert(oldname,conn,last_component_oldname,&bad_path_oldname,&sbuf1);
+ if (bad_path_oldname) {
+ return NT_STATUS_OBJECT_PATH_NOT_FOUND;
+ }
+
+ /* Quick check for "." and ".." */
+ if (last_component_oldname[0] == '.') {
+ if (!last_component_oldname[1] || (last_component_oldname[1] == '.' && !last_component_oldname[2])) {
+ return NT_STATUS_OBJECT_NAME_INVALID;
+ }
+ }
+
+ /* Source must already exist. */
+ if (!VALID_STAT(sbuf1)) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+ if (!check_name(oldname,conn)) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ /* Ensure attributes match. */
+ fattr = dos_mode(conn,oldname,&sbuf1);
+ if ((fattr & ~attrs) & (aHIDDEN | aSYSTEM)) {
+ return NT_STATUS_NO_SUCH_FILE;
+ }
+
+ unix_convert(newname,conn,last_component_newname,&bad_path_newname,&sbuf2);
+ if (bad_path_newname) {
+ return NT_STATUS_OBJECT_PATH_NOT_FOUND;
+ }
+
+ /* Quick check for "." and ".." */
+ if (last_component_newname[0] == '.') {
+ if (!last_component_newname[1] || (last_component_newname[1] == '.' && !last_component_newname[2])) {
+ return NT_STATUS_OBJECT_NAME_INVALID;
+ }
+ }
+
+ /* Disallow if newname already exists. */
+ if (VALID_STAT(sbuf2)) {
+ return NT_STATUS_OBJECT_NAME_COLLISION;
+ }
+
+ if (!check_name(newname,conn)) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ /* No links from a directory. */
+ if (S_ISDIR(sbuf1.st_mode)) {
+ return NT_STATUS_FILE_IS_A_DIRECTORY;
+ }
+
+ /* Ensure this is within the share. */
+ if (!reduce_name(conn, oldname) != 0) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ DEBUG(10,("copy_internals: doing file copy %s to %s\n", oldname, newname));
+
+ status = open_file_ntcreate(conn,oldname,&sbuf1,
+ FILE_READ_DATA, /* Read-only. */
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
+ FILE_OPEN,
+ 0, /* No create options. */
+ FILE_ATTRIBUTE_NORMAL,
+ NO_OPLOCK,
+ &info, &fsp1);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = open_file_ntcreate(conn,newname,&sbuf2,
+ FILE_WRITE_DATA, /* Read-only. */
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
+ FILE_CREATE,
+ 0, /* No create options. */
+ fattr,
+ NO_OPLOCK,
+ &info, &fsp2);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ close_file(fsp1,ERROR_CLOSE);
+ return status;
+ }
+
+ if (sbuf1.st_size) {
+ ret = vfs_transfer_file(fsp1, fsp2, sbuf1.st_size);
+ }
+
+ /*
+ * As we are opening fsp1 read-only we only expect
+ * an error on close on fsp2 if we are out of space.
+ * Thus we don't look at the error return from the
+ * close of fsp1.
+ */
+ close_file(fsp1,NORMAL_CLOSE);
+
+ /* Ensure the modtime is set correctly on the destination file. */
+ fsp_set_pending_modtime(fsp2, sbuf1.st_mtime);
+
+ close_ret = close_file(fsp2,NORMAL_CLOSE);
+
+ /* Grrr. We have to do this as open_file_ntcreate adds aARCH when it
+ creates the file. This isn't the correct thing to do in the copy
+ case. JRA */
+ file_set_dosmode(conn, newname, fattr, &sbuf2,
+ parent_dirname(newname));
+
+ if (ret < (SMB_OFF_T)sbuf1.st_size) {
+ return NT_STATUS_DISK_FULL;
+ }
+
+ if (close_ret != 0) {
+ status = map_nt_error_from_unix(close_ret);
+ DEBUG(3,("copy_internals: Error %s copy file %s to %s\n",
+ nt_errstr(status), oldname, newname));
+ }
+ return status;
+}
+
/****************************************************************************
Reply to a NT rename request.
****************************************************************************/
char *inbuf,char *outbuf,int length,int bufsize)
{
int outsize = 0;
- pstring name;
+ pstring oldname;
pstring newname;
char *p;
NTSTATUS status;
+ BOOL path1_contains_wcard = False;
+ BOOL path2_contains_wcard = False;
+ uint32 attrs = SVAL(inbuf,smb_vwv0);
+ uint16 rename_type = SVAL(inbuf,smb_vwv1);
START_PROFILE(SMBntrename);
p = smb_buf(inbuf) + 1;
- p += srvstr_get_path(inbuf, name, p, sizeof(name), STR_TERMINATE,&status);
+ p += srvstr_get_path_wcard(inbuf, oldname, p, sizeof(oldname), 0, STR_TERMINATE, &status, &path1_contains_wcard);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBntrename);
return ERROR_NT(status);
}
+
+ if( is_ntfs_stream_name(oldname)) {
+ /* Can't rename a stream. */
+ END_PROFILE(SMBntrename);
+ return ERROR_NT(NT_STATUS_ACCESS_DENIED);
+ }
+
+ if (ms_has_wild(oldname)) {
+ END_PROFILE(SMBntrename);
+ return ERROR_NT(NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
+ }
+
p++;
- p += srvstr_get_path(inbuf, newname, p, sizeof(newname), STR_TERMINATE,&status);
+ p += srvstr_get_path_wcard(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status, &path2_contains_wcard);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBntrename);
return ERROR_NT(status);
}
- RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
+ RESOLVE_DFSPATH(oldname, conn, inbuf, outbuf);
RESOLVE_DFSPATH(newname, conn, inbuf, outbuf);
- DEBUG(3,("reply_ntrename : %s -> %s\n",name,newname));
+ DEBUG(3,("reply_ntrename : %s -> %s\n",oldname,newname));
- status = rename_internals(conn, name, newname, False);
+ switch(rename_type) {
+ case RENAME_FLAG_RENAME:
+ status = rename_internals(conn, oldname, newname, attrs, False, path1_contains_wcard);
+ break;
+ case RENAME_FLAG_HARD_LINK:
+ if (path1_contains_wcard || path2_contains_wcard) {
+ /* No wildcards. */
+ status = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
+ } else {
+ status = hardlink_internals(conn, oldname, newname);
+ }
+ break;
+ case RENAME_FLAG_COPY:
+ if (path1_contains_wcard || path2_contains_wcard) {
+ /* No wildcards. */
+ status = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
+ } else {
+ status = copy_internals(conn, oldname, newname, attrs);
+ }
+ break;
+ case RENAME_FLAG_MOVE_CLUSTER_INFORMATION:
+ status = NT_STATUS_INVALID_PARAMETER;
+ break;
+ default:
+ status = NT_STATUS_ACCESS_DENIED; /* Default error. */
+ break;
+ }
+
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBntrename);
+ if (open_was_deferred(SVAL(inbuf,smb_mid))) {
+ /* We have re-scheduled this call. */
+ return -1;
+ }
return ERROR_NT(status);
}
* Win2k needs a changenotify request response before it will
* update after a rename..
*/
- process_pending_change_notify_queue((time_t)0);
- outsize = set_message(outbuf,0,0,True);
-
- END_PROFILE(SMBntrename);
- return(outsize);
-}
-
-/****************************************************************************
- Reply to an unsolicited SMBNTtranss - just ignore it!
-****************************************************************************/
-
-int reply_nttranss(connection_struct *conn,
- char *inbuf,char *outbuf,int length,int bufsize)
-{
- START_PROFILE(SMBnttranss);
- DEBUG(4,("Ignoring nttranss of length %d\n",length));
- END_PROFILE(SMBnttranss);
- return(-1);
+ process_pending_change_notify_queue((time_t)0);
+ outsize = set_message(outbuf,0,0,False);
+
+ END_PROFILE(SMBntrename);
+ return(outsize);
}
/****************************************************************************
don't allow a directory to be opened.
****************************************************************************/
-static int call_nt_transact_notify_change(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
- char **ppsetup, uint32 setup_count,
- char **ppparams, uint32 parameter_count,
- char **ppdata, uint32 data_count)
+static int call_nt_transact_notify_change(connection_struct *conn, char *inbuf,
+ char *outbuf, int length,
+ int bufsize,
+ uint16 **ppsetup, uint32 setup_count,
+ char **ppparams,
+ uint32 parameter_count,
+ char **ppdata, uint32 data_count,
+ uint32 max_data_count,
+ uint32 max_param_count)
{
- char *setup = *ppsetup;
+ uint16 *setup = *ppsetup;
files_struct *fsp;
uint32 flags;
+ NTSTATUS status;
- if(setup_count < 6)
+ if(setup_count < 6) {
return ERROR_DOS(ERRDOS,ERRbadfunc);
+ }
- fsp = file_fsp(setup,4);
+ fsp = file_fsp((char *)setup,4);
flags = IVAL(setup, 0);
DEBUG(3,("call_nt_transact_notify_change\n"));
- if(!fsp)
+ if(!fsp) {
return ERROR_DOS(ERRDOS,ERRbadfid);
+ }
+
+ DEBUG(3,("call_nt_transact_notify_change: notify change called on "
+ "directory name = %s\n", fsp->fsp_name ));
- if((!fsp->is_directory) || (conn != fsp->conn))
+ if((!fsp->is_directory) || (conn != fsp->conn)) {
return ERROR_DOS(ERRDOS,ERRbadfid);
+ }
+
+ if (fsp->notify == NULL) {
+ if (!(fsp->notify = TALLOC_ZERO_P(
+ NULL, struct notify_change_buf))) {
+ return ERROR_NT(NT_STATUS_NO_MEMORY);
+ }
+ }
+
+ if (fsp->notify->num_changes > 0) {
- if (!change_notify_set(inbuf, fsp, conn, flags))
- return(UNIXERROR(ERRDOS,ERRbadfid));
+ /*
+ * We've got changes pending, respond immediately
+ */
+
+ SMB_ASSERT(fsp->notify->requests == NULL);
+
+ change_notify_reply(inbuf, max_param_count,
+ fsp->notify->num_changes,
+ fsp->notify->changes);
+
+ TALLOC_FREE(fsp->notify->changes);
+ fsp->notify->num_changes = 0;
+
+ /*
+ * change_notify_reply() above has independently sent its
+ * results
+ */
+ return -1;
+ }
+
+ /*
+ * No changes pending, queue the request
+ */
- DEBUG(3,("call_nt_transact_notify_change: notify change called on directory \
-name = %s\n", fsp->fsp_name ));
+ status = change_notify_add_request(inbuf, max_param_count, fsp);
+ if (!NT_STATUS_IS_OK(status)) {
+ return ERROR_NT(status);
+ }
return -1;
}
****************************************************************************/
static int call_nt_transact_rename(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
- char **ppsetup, uint32 setup_count,
+ uint16 **ppsetup, uint32 setup_count,
char **ppparams, uint32 parameter_count,
- char **ppdata, uint32 data_count)
+ char **ppdata, uint32 data_count, uint32 max_data_count)
{
char *params = *ppparams;
pstring new_name;
files_struct *fsp = NULL;
BOOL replace_if_exists = False;
+ BOOL path_contains_wcard = False;
NTSTATUS status;
- if(parameter_count < 4)
+ if(parameter_count < 5) {
return ERROR_DOS(ERRDOS,ERRbadfunc);
+ }
fsp = file_fsp(params, 0);
replace_if_exists = (SVAL(params,2) & RENAME_REPLACE_IF_EXISTS) ? True : False;
CHECK_FSP(fsp, conn);
- srvstr_pull(inbuf, new_name, params+4, sizeof(new_name), -1, STR_TERMINATE);
- status = check_path_syntax(new_name);
+ srvstr_get_path_wcard(inbuf, new_name, params+4, sizeof(new_name), parameter_count - 4, STR_TERMINATE, &status, &path_contains_wcard);
if (!NT_STATUS_IS_OK(status)) {
return ERROR_NT(status);
}
status = rename_internals(conn, fsp->fsp_name,
- new_name, replace_if_exists);
+ new_name, 0, replace_if_exists, path_contains_wcard);
if (!NT_STATUS_IS_OK(status))
return ERROR_NT(status);
/*
* Rename was successful.
*/
- send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, NULL, 0, NULL, 0);
+ send_nt_replies(outbuf, bufsize, NT_STATUS_OK, NULL, 0, NULL, 0);
DEBUG(3,("nt transact rename from = %s, to = %s succeeded.\n",
fsp->fsp_name, new_name));
static size_t get_null_nt_acl(TALLOC_CTX *mem_ctx, SEC_DESC **ppsd)
{
- extern DOM_SID global_sid_World;
size_t sd_size;
*ppsd = make_standard_sec_desc( mem_ctx, &global_sid_World, &global_sid_World, NULL, &sd_size);
****************************************************************************/
static int call_nt_transact_query_security_desc(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
- char **ppsetup, uint32 setup_count,
+ uint16 **ppsetup, uint32 setup_count,
char **ppparams, uint32 parameter_count,
- char **ppdata, uint32 data_count)
+ char **ppdata, uint32 data_count, uint32 max_data_count)
{
- uint32 max_data_count = IVAL(inbuf,smb_nt_MaxDataCount);
char *params = *ppparams;
char *data = *ppdata;
prs_struct pd;
TALLOC_CTX *mem_ctx;
files_struct *fsp = NULL;
- if(parameter_count < 8)
+ if(parameter_count < 8) {
return ERROR_DOS(ERRDOS,ERRbadfunc);
+ }
fsp = file_fsp(params,0);
- if(!fsp)
+ if(!fsp) {
return ERROR_DOS(ERRDOS,ERRbadfid);
+ }
security_info_wanted = IVAL(params,4);
- DEBUG(3,("call_nt_transact_query_security_desc: file = %s\n", fsp->fsp_name ));
+ DEBUG(3,("call_nt_transact_query_security_desc: file = %s, info_wanted = 0x%x\n", fsp->fsp_name,
+ (unsigned int)security_info_wanted ));
params = nttrans_realloc(ppparams, 4);
- if(params == NULL)
+ if(params == NULL) {
return ERROR_DOS(ERRDOS,ERRnomem);
+ }
if ((mem_ctx = talloc_init("call_nt_transact_query_security_desc")) == NULL) {
DEBUG(0,("call_nt_transact_query_security_desc: talloc_init failed.\n"));
* Get the permissions to return.
*/
- if (!lp_nt_acl_support(SNUM(conn)))
+ if (!lp_nt_acl_support(SNUM(conn))) {
sd_size = get_null_nt_acl(mem_ctx, &psd);
- else
- sd_size = SMB_VFS_FGET_NT_ACL(fsp, fsp->fd, security_info_wanted, &psd);
+ } else {
+ sd_size = SMB_VFS_FGET_NT_ACL(fsp, fsp->fh->fd, security_info_wanted, &psd);
+ }
if (sd_size == 0) {
talloc_destroy(mem_ctx);
return(UNIXERROR(ERRDOS,ERRnoaccess));
}
- DEBUG(3,("call_nt_transact_query_security_desc: sd_size = %d.\n",(int)sd_size));
+ DEBUG(3,("call_nt_transact_query_security_desc: sd_size = %lu.\n",(unsigned long)sd_size));
SIVAL(params,0,(uint32)sd_size);
if(max_data_count < sd_size) {
- send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_BUFFER_TOO_SMALL,
- params, 4, *ppdata, 0);
+ send_nt_replies(outbuf, bufsize, NT_STATUS_BUFFER_TOO_SMALL,
+ params, 4, *ppdata, 0);
talloc_destroy(mem_ctx);
return -1;
}
talloc_destroy(mem_ctx);
- send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, params, 4, data, (int)sd_size);
+ send_nt_replies(outbuf, bufsize, NT_STATUS_OK, params, 4, data,
+ (int)sd_size);
return -1;
}
****************************************************************************/
static int call_nt_transact_set_security_desc(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
- char **ppsetup, uint32 setup_count,
+ uint16 **ppsetup, uint32 setup_count,
char **ppparams, uint32 parameter_count,
- char **ppdata, uint32 data_count)
+ char **ppdata, uint32 data_count, uint32 max_data_count)
{
char *params= *ppparams;
char *data = *ppdata;
uint32 security_info_sent = 0;
NTSTATUS nt_status;
- if(parameter_count < 8)
+ if(parameter_count < 8) {
return ERROR_DOS(ERRDOS,ERRbadfunc);
+ }
- if((fsp = file_fsp(params,0)) == NULL)
+ if((fsp = file_fsp(params,0)) == NULL) {
return ERROR_DOS(ERRDOS,ERRbadfid);
+ }
- if(!lp_nt_acl_support(SNUM(conn)))
+ if(!lp_nt_acl_support(SNUM(conn))) {
goto done;
+ }
security_info_sent = IVAL(params,4);
DEBUG(3,("call_nt_transact_set_security_desc: file = %s, sent 0x%x\n", fsp->fsp_name,
(unsigned int)security_info_sent ));
- if (data_count == 0)
+ if (data_count == 0) {
return ERROR_DOS(ERRDOS, ERRnoaccess);
+ }
- if (!NT_STATUS_IS_OK(nt_status = set_sd( fsp, data, data_count, security_info_sent)))
+ if (!NT_STATUS_IS_OK(nt_status = set_sd( fsp, data, data_count, security_info_sent))) {
return ERROR_NT(nt_status);
+ }
done:
- send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, NULL, 0, NULL, 0);
+ send_nt_replies(outbuf, bufsize, NT_STATUS_OK, NULL, 0, NULL, 0);
return -1;
}
****************************************************************************/
static int call_nt_transact_ioctl(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
- char **ppsetup, uint32 setup_count,
+ uint16 **ppsetup, uint32 setup_count,
char **ppparams, uint32 parameter_count,
- char **ppdata, uint32 data_count)
+ char **ppdata, uint32 data_count, uint32 max_data_count)
{
uint32 function;
uint16 fidnum;
DEBUG(10,("call_nt_transact_ioctl: function[0x%08X] FID[0x%04X] isFSctl[0x%02X] compfilter[0x%02X]\n",
function, fidnum, isFSctl, compfilter));
- fsp=file_fsp(*ppsetup, 4);
+ fsp=file_fsp((char *)*ppsetup, 4);
/* this check is done in each implemented function case for now
because I don't want to break anything... --metze
FSP_BELONGS_CONN(fsp,conn);*/
so we can know if we need to pre-allocate or not */
DEBUG(10,("FSCTL_SET_SPARSE: called on FID[0x%04X](but not implemented)\n", fidnum));
- send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, NULL, 0, NULL, 0);
+ send_nt_replies(outbuf, bufsize, NT_STATUS_OK, NULL, 0, NULL,
+ 0);
return -1;
case FSCTL_0x000900C0:
*/
DEBUG(10,("FSCTL_0x000900C0: called on FID[0x%04X](but not implemented)\n",fidnum));
- send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, NULL, 0, NULL, 0);
+ send_nt_replies(outbuf, bufsize, NT_STATUS_OK, NULL, 0, NULL,
+ 0);
return -1;
case FSCTL_GET_REPARSE_POINT:
*/
DEBUG(10,("FSCTL_GET_REPARSE_POINT: called on FID[0x%04X](but not implemented)\n",fidnum));
- send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_NOT_A_REPARSE_POINT, NULL, 0, NULL, 0);
+ send_nt_replies(outbuf, bufsize, NT_STATUS_NOT_A_REPARSE_POINT,
+ NULL, 0, NULL, 0);
return -1;
case FSCTL_SET_REPARSE_POINT:
*/
DEBUG(10,("FSCTL_SET_REPARSE_POINT: called on FID[0x%04X](but not implemented)\n",fidnum));
- send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_NOT_A_REPARSE_POINT, NULL, 0, NULL, 0);
+ send_nt_replies(outbuf, bufsize, NT_STATUS_NOT_A_REPARSE_POINT,
+ NULL, 0, NULL, 0);
return -1;
case FSCTL_GET_SHADOW_COPY_DATA: /* don't know if this name is right...*/
* Allocate the correct amount and return the pointer to let
* it be deallocated when we return.
*/
- uint32 max_data_count = IVAL(inbuf,smb_nt_MaxDataCount);
SHADOW_COPY_DATA *shadow_data = NULL;
TALLOC_CTX *shadow_mem_ctx = NULL;
BOOL labels = False;
return ERROR_NT(NT_STATUS_NO_MEMORY);
}
- shadow_data = (SHADOW_COPY_DATA *)talloc_zero(shadow_mem_ctx,sizeof(SHADOW_COPY_DATA));
+ shadow_data = TALLOC_ZERO_P(shadow_mem_ctx,SHADOW_COPY_DATA);
if (shadow_data == NULL) {
DEBUG(0,("talloc_zero() failed!\n"));
+ talloc_destroy(shadow_mem_ctx);
return ERROR_NT(NT_STATUS_NO_MEMORY);
}
talloc_destroy(shadow_data->mem_ctx);
- send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, NULL, 0, pdata, data_count);
+ send_nt_replies(outbuf, bufsize, NT_STATUS_OK, NULL, 0,
+ pdata, data_count);
return -1;
}
sid_parse(pdata+4,sid_len,&sid);
DEBUGADD(10,("for SID: %s\n",sid_string_static(&sid)));
- if (!NT_STATUS_IS_OK(sid_to_uid(&sid, &uid))) {
+ if (!sid_to_uid(&sid, &uid)) {
DEBUG(0,("sid_to_uid: failed, sid[%s] sid_len[%lu]\n",
sid_string_static(&sid),(unsigned long)sid_len));
uid = (-1);
*/
/* this works for now... */
- send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, NULL, 0, NULL, 0);
+ send_nt_replies(outbuf, bufsize, NT_STATUS_OK, NULL, 0,
+ NULL, 0);
return -1;
}
default:
****************************************************************************/
static int call_nt_transact_get_user_quota(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
- char **ppsetup, uint32 setup_count,
+ uint16 **ppsetup, uint32 setup_count,
char **ppparams, uint32 parameter_count,
- char **ppdata, uint32 data_count)
+ char **ppdata, uint32 data_count, uint32 max_data_count)
{
NTSTATUS nt_status = NT_STATUS_OK;
- uint32 max_data_count = IVAL(inbuf,smb_nt_MaxDataCount);
char *params = *ppparams;
char *pdata = *ppdata;
char *entry;
SMB_NTQUOTA_STRUCT qt;
SMB_NTQUOTA_LIST *tmp_list;
SMB_NTQUOTA_HANDLE *qt_handle = NULL;
- extern struct current_user current_user;
ZERO_STRUCT(qt);
/* access check */
- if (current_user.uid != 0) {
- DEBUG(1,("set_user_quota: access_denied service [%s] user [%s]\n",
+ if (current_user.ut.uid != 0) {
+ DEBUG(1,("get_user_quota: access_denied service [%s] user [%s]\n",
lp_servicename(SNUM(conn)),conn->user));
return ERROR_DOS(ERRDOS,ERRnoaccess);
}
return ERROR_NT(NT_STATUS_INVALID_HANDLE);
}
- /* the NULL pointer cheking for fsp->fake_file_handle->pd
+ /* the NULL pointer checking for fsp->fake_file_handle->pd
* is done by CHECK_NTQUOTA_HANDLE_OK()
*/
qt_handle = (SMB_NTQUOTA_HANDLE *)fsp->fake_file_handle->pd;
/* Realloc the size of parameters and data we will return */
param_len = 4;
params = nttrans_realloc(ppparams, param_len);
- if(params == NULL)
+ if(params == NULL) {
return ERROR_DOS(ERRDOS,ERRnomem);
+ }
data_len = 0;
SIVAL(params,0,data_len);
/* Realloc the size of parameters and data we will return */
param_len = 4;
params = nttrans_realloc(ppparams, param_len);
- if(params == NULL)
+ if(params == NULL) {
return ERROR_DOS(ERRDOS,ERRnomem);
+ }
/* we should not trust the value in max_data_count*/
max_data_count = MIN(max_data_count,2048);
pdata = nttrans_realloc(ppdata, max_data_count);/* should be max data count from client*/
- if(pdata == NULL)
+ if(pdata == NULL) {
return ERROR_DOS(ERRDOS,ERRnomem);
+ }
entry = pdata;
-
/* set params Size of returned Quota Data 4 bytes*/
/* but set it later when we know it */
}
sid_len = IVAL(pdata,4);
+ /* Ensure this is less than 1mb. */
+ if (sid_len > (1024*1024)) {
+ return ERROR_DOS(ERRDOS,ERRnomem);
+ }
if (data_count < 8+sid_len) {
DEBUG(0,("TRANSACT_GET_USER_QUOTA_FOR_SID: requires %d >= %lu bytes data\n",data_count,(unsigned long)(8+sid_len)));
sid_parse(pdata+8,sid_len,&sid);
-
if (vfs_get_ntquota(fsp, SMB_USER_QUOTA_TYPE, &sid, &qt)!=0) {
ZERO_STRUCT(qt);
/*
/* Realloc the size of parameters and data we will return */
param_len = 4;
params = nttrans_realloc(ppparams, param_len);
- if(params == NULL)
+ if(params == NULL) {
return ERROR_DOS(ERRDOS,ERRnomem);
+ }
pdata = nttrans_realloc(ppdata, data_len);
- if(pdata == NULL)
+ if(pdata == NULL) {
return ERROR_DOS(ERRDOS,ERRnomem);
+ }
entry = pdata;
break;
}
- send_nt_replies(inbuf, outbuf, bufsize, nt_status, params, param_len, pdata, data_len);
+ send_nt_replies(outbuf, bufsize, nt_status, params, param_len,
+ pdata, data_len);
return -1;
}
****************************************************************************/
static int call_nt_transact_set_user_quota(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
- char **ppsetup, uint32 setup_count,
+ uint16 **ppsetup, uint32 setup_count,
char **ppparams, uint32 parameter_count,
- char **ppdata, uint32 data_count)
+ char **ppdata, uint32 data_count, uint32 max_data_count)
{
char *params = *ppparams;
char *pdata = *ppdata;
ZERO_STRUCT(qt);
/* access check */
- if (conn->admin_user != True) {
+ if (current_user.ut.uid != 0) {
DEBUG(1,("set_user_quota: access_denied service [%s] user [%s]\n",
lp_servicename(SNUM(conn)),conn->user));
return ERROR_DOS(ERRDOS,ERRnoaccess);
return ERROR_DOS(ERRSRV,ERRerror);
}
- send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, params, param_len, pdata, data_len);
+ send_nt_replies(outbuf, bufsize, NT_STATUS_OK, params, param_len,
+ pdata, data_len);
return -1;
}
#endif /* HAVE_SYS_QUOTAS */
+static int handle_nttrans(connection_struct *conn,
+ struct trans_state *state,
+ char *inbuf, char *outbuf, int size, int bufsize)
+{
+ int outsize;
+
+ if (Protocol >= PROTOCOL_NT1) {
+ SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2) | 0x40); /* IS_LONG_NAME */
+ }
+
+ /* Now we must call the relevant NT_TRANS function */
+ switch(state->call) {
+ case NT_TRANSACT_CREATE:
+ {
+ START_PROFILE_NESTED(NT_transact_create);
+ outsize = call_nt_transact_create(conn, inbuf, outbuf,
+ size, bufsize,
+ &state->setup, state->setup_count,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return);
+ END_PROFILE_NESTED(NT_transact_create);
+ break;
+ }
+
+ case NT_TRANSACT_IOCTL:
+ {
+ START_PROFILE_NESTED(NT_transact_ioctl);
+ outsize = call_nt_transact_ioctl(conn, inbuf, outbuf,
+ size, bufsize,
+ &state->setup, state->setup_count,
+ &state->param, state->total_param,
+ &state->data, state->total_data, state->max_data_return);
+ END_PROFILE_NESTED(NT_transact_ioctl);
+ break;
+ }
+
+ case NT_TRANSACT_SET_SECURITY_DESC:
+ {
+ START_PROFILE_NESTED(NT_transact_set_security_desc);
+ outsize = call_nt_transact_set_security_desc(conn, inbuf, outbuf,
+ size, bufsize,
+ &state->setup, state->setup_count,
+ &state->param, state->total_param,
+ &state->data, state->total_data, state->max_data_return);
+ END_PROFILE_NESTED(NT_transact_set_security_desc);
+ break;
+ }
+
+ case NT_TRANSACT_NOTIFY_CHANGE:
+ {
+ START_PROFILE_NESTED(NT_transact_notify_change);
+ outsize = call_nt_transact_notify_change(
+ conn, inbuf, outbuf, size, bufsize,
+ &state->setup, state->setup_count,
+ &state->param, state->total_param,
+ &state->data, state->total_data,
+ state->max_data_return,
+ state->max_param_return);
+ END_PROFILE_NESTED(NT_transact_notify_change);
+ break;
+ }
+
+ case NT_TRANSACT_RENAME:
+ {
+ START_PROFILE_NESTED(NT_transact_rename);
+ outsize = call_nt_transact_rename(conn, inbuf, outbuf,
+ size, bufsize,
+ &state->setup, state->setup_count,
+ &state->param, state->total_param,
+ &state->data, state->total_data, state->max_data_return);
+ END_PROFILE_NESTED(NT_transact_rename);
+ break;
+ }
+
+ case NT_TRANSACT_QUERY_SECURITY_DESC:
+ {
+ START_PROFILE_NESTED(NT_transact_query_security_desc);
+ outsize = call_nt_transact_query_security_desc(conn, inbuf, outbuf,
+ size, bufsize,
+ &state->setup, state->setup_count,
+ &state->param, state->total_param,
+ &state->data, state->total_data, state->max_data_return);
+ END_PROFILE_NESTED(NT_transact_query_security_desc);
+ break;
+ }
+
+#ifdef HAVE_SYS_QUOTAS
+ case NT_TRANSACT_GET_USER_QUOTA:
+ {
+ START_PROFILE_NESTED(NT_transact_get_user_quota);
+ outsize = call_nt_transact_get_user_quota(conn, inbuf, outbuf,
+ size, bufsize,
+ &state->setup, state->setup_count,
+ &state->param, state->total_param,
+ &state->data, state->total_data, state->max_data_return);
+ END_PROFILE_NESTED(NT_transact_get_user_quota);
+ break;
+ }
+
+ case NT_TRANSACT_SET_USER_QUOTA:
+ {
+ START_PROFILE_NESTED(NT_transact_set_user_quota);
+ outsize = call_nt_transact_set_user_quota(conn, inbuf, outbuf,
+ size, bufsize,
+ &state->setup, state->setup_count,
+ &state->param, state->total_param,
+ &state->data, state->total_data, state->max_data_return);
+ END_PROFILE_NESTED(NT_transact_set_user_quota);
+ break;
+ }
+#endif /* HAVE_SYS_QUOTAS */
+
+ default:
+ /* Error in request */
+ DEBUG(0,("reply_nttrans: Unknown request %d in nttrans call\n",
+ state->call));
+ return ERROR_DOS(ERRSRV,ERRerror);
+ }
+ return outsize;
+}
+
/****************************************************************************
Reply to a SMBNTtrans.
****************************************************************************/
int reply_nttrans(connection_struct *conn,
- char *inbuf,char *outbuf,int length,int bufsize)
+ char *inbuf,char *outbuf,int size,int bufsize)
{
int outsize = 0;
-#if 0 /* Not used. */
- uint16 max_setup_count = CVAL(inbuf, smb_nt_MaxSetupCount);
- uint32 max_parameter_count = IVAL(inbuf, smb_nt_MaxParameterCount);
- uint32 max_data_count = IVAL(inbuf,smb_nt_MaxDataCount);
-#endif /* Not used. */
- uint32 total_parameter_count = IVAL(inbuf, smb_nt_TotalParameterCount);
- uint32 total_data_count = IVAL(inbuf, smb_nt_TotalDataCount);
- uint32 parameter_count = IVAL(inbuf,smb_nt_ParameterCount);
- uint32 parameter_offset = IVAL(inbuf,smb_nt_ParameterOffset);
- uint32 data_count = IVAL(inbuf,smb_nt_DataCount);
- uint32 data_offset = IVAL(inbuf,smb_nt_DataOffset);
- uint16 setup_count = 2*CVAL(inbuf,smb_nt_SetupCount); /* setup count is in *words* */
+ uint32 pscnt = IVAL(inbuf,smb_nt_ParameterCount);
+ uint32 psoff = IVAL(inbuf,smb_nt_ParameterOffset);
+ uint32 dscnt = IVAL(inbuf,smb_nt_DataCount);
+ uint32 dsoff = IVAL(inbuf,smb_nt_DataOffset);
+
uint16 function_code = SVAL( inbuf, smb_nt_Function);
- char *params = NULL, *data = NULL, *setup = NULL;
- uint32 num_params_sofar, num_data_sofar;
- START_PROFILE(SMBnttrans);
+ NTSTATUS result;
+ struct trans_state *state;
- if(global_oplock_break &&
- ((function_code == NT_TRANSACT_CREATE) ||
- (function_code == NT_TRANSACT_RENAME))) {
- /*
- * Queue this open message as we are the process of an oplock break.
- */
+ START_PROFILE(SMBnttrans);
- DEBUG(2,("reply_nttrans: queueing message code 0x%x \
-due to being in oplock break state.\n", (unsigned int)function_code ));
+ if (IS_IPC(conn) && (function_code != NT_TRANSACT_CREATE)) {
+ END_PROFILE(SMBnttrans);
+ return ERROR_DOS(ERRSRV,ERRaccess);
+ }
- push_oplock_pending_smb_message( inbuf, length);
+ result = allow_new_trans(conn->pending_trans, SVAL(inbuf, smb_mid));
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(2, ("Got invalid nttrans request: %s\n", nt_errstr(result)));
END_PROFILE(SMBnttrans);
- return -1;
+ return ERROR_NT(result);
}
- if (IS_IPC(conn) && (function_code != NT_TRANSACT_CREATE)) {
+ if ((state = TALLOC_P(conn->mem_ctx, struct trans_state)) == NULL) {
END_PROFILE(SMBnttrans);
return ERROR_DOS(ERRSRV,ERRaccess);
}
- outsize = set_message(outbuf,0,0,True);
+ state->cmd = SMBnttrans;
+
+ state->mid = SVAL(inbuf,smb_mid);
+ state->vuid = SVAL(inbuf,smb_uid);
+ state->total_data = IVAL(inbuf, smb_nt_TotalDataCount);
+ state->data = NULL;
+ state->total_param = IVAL(inbuf, smb_nt_TotalParameterCount);
+ state->param = NULL;
+ state->max_data_return = IVAL(inbuf,smb_nt_MaxDataCount);
+ state->max_param_return = IVAL(inbuf,smb_nt_MaxParameterCount);
+
+ /* setup count is in *words* */
+ state->setup_count = 2*CVAL(inbuf,smb_nt_SetupCount);
+ state->setup = NULL;
+ state->call = function_code;
/*
- * All nttrans messages we handle have smb_wct == 19 + setup_count.
- * Ensure this is so as a sanity check.
+ * All nttrans messages we handle have smb_wct == 19 +
+ * state->setup_count. Ensure this is so as a sanity check.
*/
- if(CVAL(inbuf, smb_wct) != 19 + (setup_count/2)) {
+ if(CVAL(inbuf, smb_wct) != 19 + (state->setup_count/2)) {
DEBUG(2,("Invalid smb_wct %d in nttrans call (should be %d)\n",
- CVAL(inbuf, smb_wct), 19 + (setup_count/2)));
+ CVAL(inbuf, smb_wct), 19 + (state->setup_count/2)));
goto bad_param;
}
-
- /* Allocate the space for the setup, the maximum needed parameters and data */
-
- if(setup_count > 0)
- setup = (char *)malloc(setup_count);
- if (total_parameter_count > 0)
- params = (char *)malloc(total_parameter_count);
- if (total_data_count > 0)
- data = (char *)malloc(total_data_count);
-
- if ((total_parameter_count && !params) || (total_data_count && !data) ||
- (setup_count && !setup)) {
- SAFE_FREE(setup);
- SAFE_FREE(params);
- SAFE_FREE(data);
- DEBUG(0,("reply_nttrans : Out of memory\n"));
+
+ /* Don't allow more than 128mb for each value. */
+ if ((state->total_data > (1024*1024*128)) ||
+ (state->total_param > (1024*1024*128))) {
END_PROFILE(SMBnttrans);
return ERROR_DOS(ERRDOS,ERRnomem);
}
- /* Copy the param and data bytes sent with this request into the params buffer */
- num_params_sofar = parameter_count;
- num_data_sofar = data_count;
-
- if (parameter_count > total_parameter_count || data_count > total_data_count)
+ if ((dscnt > state->total_data) || (pscnt > state->total_param))
goto bad_param;
- if(setup) {
- DEBUG(10,("reply_nttrans: setup_count = %d\n", setup_count));
- if ((smb_nt_SetupStart + setup_count < smb_nt_SetupStart) ||
- (smb_nt_SetupStart + setup_count < setup_count))
+ if (state->total_data) {
+ /* Can't use talloc here, the core routines do realloc on the
+ * params and data. */
+ if ((state->data = (char *)SMB_MALLOC(state->total_data)) == NULL) {
+ DEBUG(0,("reply_nttrans: data malloc fail for %u "
+ "bytes !\n", (unsigned int)state->total_data));
+ TALLOC_FREE(state);
+ END_PROFILE(SMBnttrans);
+ return(ERROR_DOS(ERRDOS,ERRnomem));
+ }
+ if ((dsoff+dscnt < dsoff) || (dsoff+dscnt < dscnt))
goto bad_param;
- if (smb_nt_SetupStart + setup_count > length)
+ if ((smb_base(inbuf)+dsoff+dscnt > inbuf + size) ||
+ (smb_base(inbuf)+dsoff+dscnt < smb_base(inbuf)))
goto bad_param;
- memcpy( setup, &inbuf[smb_nt_SetupStart], setup_count);
- dump_data(10, setup, setup_count);
+ memcpy(state->data,smb_base(inbuf)+dsoff,dscnt);
}
- if(params) {
- DEBUG(10,("reply_nttrans: parameter_count = %d\n", parameter_count));
- if ((parameter_offset + parameter_count < parameter_offset) ||
- (parameter_offset + parameter_count < parameter_count))
+
+ if (state->total_param) {
+ /* Can't use talloc here, the core routines do realloc on the
+ * params and data. */
+ if ((state->param = (char *)SMB_MALLOC(state->total_param)) == NULL) {
+ DEBUG(0,("reply_nttrans: param malloc fail for %u "
+ "bytes !\n", (unsigned int)state->total_param));
+ SAFE_FREE(state->data);
+ TALLOC_FREE(state);
+ END_PROFILE(SMBnttrans);
+ return(ERROR_DOS(ERRDOS,ERRnomem));
+ }
+ if ((psoff+pscnt < psoff) || (psoff+pscnt < pscnt))
goto bad_param;
- if ((smb_base(inbuf) + parameter_offset + parameter_count > inbuf + length)||
- (smb_base(inbuf) + parameter_offset + parameter_count < smb_base(inbuf)))
+ if ((smb_base(inbuf)+psoff+pscnt > inbuf + size) ||
+ (smb_base(inbuf)+psoff+pscnt < smb_base(inbuf)))
goto bad_param;
- memcpy( params, smb_base(inbuf) + parameter_offset, parameter_count);
- dump_data(10, params, parameter_count);
+ memcpy(state->param,smb_base(inbuf)+psoff,pscnt);
}
- if(data) {
- DEBUG(10,("reply_nttrans: data_count = %d\n",data_count));
- if ((data_offset + data_count < data_offset) || (data_offset + data_count < data_count))
+
+ state->received_data = dscnt;
+ state->received_param = pscnt;
+
+ if(state->setup_count > 0) {
+ DEBUG(10,("reply_nttrans: state->setup_count = %d\n",
+ state->setup_count));
+ state->setup = (uint16 *)TALLOC(state, state->setup_count);
+ if (state->setup == NULL) {
+ DEBUG(0,("reply_nttrans : Out of memory\n"));
+ SAFE_FREE(state->data);
+ SAFE_FREE(state->param);
+ TALLOC_FREE(state);
+ END_PROFILE(SMBnttrans);
+ return ERROR_DOS(ERRDOS,ERRnomem);
+ }
+
+ if ((smb_nt_SetupStart + state->setup_count < smb_nt_SetupStart) ||
+ (smb_nt_SetupStart + state->setup_count < state->setup_count)) {
goto bad_param;
- if ((smb_base(inbuf) + data_offset + data_count > inbuf + length) ||
- (smb_base(inbuf) + data_offset + data_count < smb_base(inbuf)))
+ }
+ if (smb_nt_SetupStart + state->setup_count > size) {
goto bad_param;
+ }
- memcpy( data, smb_base(inbuf) + data_offset, data_count);
- dump_data(10, data, data_count);
+ memcpy( state->setup, &inbuf[smb_nt_SetupStart], state->setup_count);
+ dump_data(10, (char *)state->setup, state->setup_count);
}
- srv_signing_trans_start(SVAL(inbuf,smb_mid));
+ if ((state->received_data == state->total_data) &&
+ (state->received_param == state->total_param)) {
+ outsize = handle_nttrans(conn, state, inbuf, outbuf,
+ size, bufsize);
+ SAFE_FREE(state->param);
+ SAFE_FREE(state->data);
+ TALLOC_FREE(state);
+ END_PROFILE(SMBnttrans);
+ return outsize;
+ }
- if(num_data_sofar < total_data_count || num_params_sofar < total_parameter_count) {
- /* We need to send an interim response then receive the rest
- of the parameter/data bytes */
- outsize = set_message(outbuf,0,0,True);
- srv_signing_trans_stop();
- if (!send_smb(smbd_server_fd(),outbuf))
- exit_server("reply_nttrans: send_smb failed.");
+ DLIST_ADD(conn->pending_trans, state);
- while( num_data_sofar < total_data_count || num_params_sofar < total_parameter_count) {
- BOOL ret;
- uint32 parameter_displacement;
- uint32 data_displacement;
+ /* We need to send an interim response then receive the rest
+ of the parameter/data bytes */
+ outsize = set_message(outbuf,0,0,False);
+ show_msg(outbuf);
+ END_PROFILE(SMBnttrans);
+ return outsize;
- ret = receive_next_smb(inbuf,bufsize,SMB_SECONDARY_WAIT);
+ bad_param:
- /*
- * The sequence number for the trans reply is always
- * based on the last secondary received.
- */
+ DEBUG(0,("reply_nttrans: invalid trans parameters\n"));
+ SAFE_FREE(state->data);
+ SAFE_FREE(state->param);
+ TALLOC_FREE(state);
+ END_PROFILE(SMBnttrans);
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+}
+
+/****************************************************************************
+ Reply to a SMBnttranss
+ ****************************************************************************/
- srv_signing_trans_start(SVAL(inbuf,smb_mid));
+int reply_nttranss(connection_struct *conn, char *inbuf,char *outbuf,
+ int size,int bufsize)
+{
+ int outsize = 0;
+ unsigned int pcnt,poff,dcnt,doff,pdisp,ddisp;
+ struct trans_state *state;
- if((ret && (CVAL(inbuf, smb_com) != SMBnttranss)) || !ret) {
- outsize = set_message(outbuf,0,0,True);
- if(ret) {
- DEBUG(0,("reply_nttrans: Invalid secondary nttrans packet\n"));
- } else {
- DEBUG(0,("reply_nttrans: %s in getting secondary nttrans response.\n",
- (smb_read_error == READ_ERROR) ? "error" : "timeout" ));
- }
- goto bad_param;
- }
-
- /* Revise total_params and total_data in case they have changed downwards */
- if (IVAL(inbuf, smb_nts_TotalParameterCount) < total_parameter_count)
- total_parameter_count = IVAL(inbuf, smb_nts_TotalParameterCount);
- if (IVAL(inbuf, smb_nts_TotalDataCount) < total_data_count)
- total_data_count = IVAL(inbuf, smb_nts_TotalDataCount);
-
- parameter_count = IVAL(inbuf,smb_nts_ParameterCount);
- parameter_offset = IVAL(inbuf, smb_nts_ParameterOffset);
- parameter_displacement = IVAL(inbuf, smb_nts_ParameterDisplacement);
- num_params_sofar += parameter_count;
-
- data_count = IVAL(inbuf, smb_nts_DataCount);
- data_displacement = IVAL(inbuf, smb_nts_DataDisplacement);
- data_offset = IVAL(inbuf, smb_nts_DataOffset);
- num_data_sofar += data_count;
-
- if (num_params_sofar > total_parameter_count || num_data_sofar > total_data_count) {
- DEBUG(0,("reply_nttrans2: data overflow in secondary nttrans packet"));
- goto bad_param;
- }
+ START_PROFILE(SMBnttranss);
- if (parameter_count) {
- if (parameter_displacement + parameter_count >= total_parameter_count)
- goto bad_param;
- if ((parameter_displacement + parameter_count < parameter_displacement) ||
- (parameter_displacement + parameter_count < parameter_count))
- goto bad_param;
- if (parameter_displacement > total_parameter_count)
- goto bad_param;
- if ((smb_base(inbuf) + parameter_offset + parameter_count >= inbuf + bufsize) ||
- (smb_base(inbuf) + parameter_offset + parameter_count < smb_base(inbuf)))
- goto bad_param;
- if (parameter_displacement + params < params)
- goto bad_param;
-
- memcpy( ¶ms[parameter_displacement], smb_base(inbuf) + parameter_offset, parameter_count);
- }
+ show_msg(inbuf);
- if (data_count) {
- if (data_displacement + data_count >= total_data_count)
- goto bad_param;
- if ((data_displacement + data_count < data_displacement) ||
- (data_displacement + data_count < data_count))
- goto bad_param;
- if (data_displacement > total_data_count)
- goto bad_param;
- if ((smb_base(inbuf) + data_offset + data_count >= inbuf + bufsize) ||
- (smb_base(inbuf) + data_offset + data_count < smb_base(inbuf)))
- goto bad_param;
- if (data_displacement + data < data)
- goto bad_param;
-
- memcpy( &data[data_displacement], smb_base(inbuf)+ data_offset, data_count);
- }
+ for (state = conn->pending_trans; state != NULL;
+ state = state->next) {
+ if (state->mid == SVAL(inbuf,smb_mid)) {
+ break;
}
}
- if (Protocol >= PROTOCOL_NT1)
- SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2) | FLAGS2_IS_LONG_NAME);
+ if ((state == NULL) || (state->cmd != SMBnttrans)) {
+ END_PROFILE(SMBnttranss);
+ return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
- /* Now we must call the relevant NT_TRANS function */
- switch(function_code) {
- case NT_TRANSACT_CREATE:
- START_PROFILE_NESTED(NT_transact_create);
- outsize = call_nt_transact_create(conn, inbuf, outbuf,
- length, bufsize,
- &setup, setup_count,
- ¶ms, total_parameter_count,
- &data, total_data_count);
- END_PROFILE_NESTED(NT_transact_create);
- break;
- case NT_TRANSACT_IOCTL:
- START_PROFILE_NESTED(NT_transact_ioctl);
- outsize = call_nt_transact_ioctl(conn, inbuf, outbuf,
- length, bufsize,
- &setup, setup_count,
- ¶ms, total_parameter_count,
- &data, total_data_count);
- END_PROFILE_NESTED(NT_transact_ioctl);
- break;
- case NT_TRANSACT_SET_SECURITY_DESC:
- START_PROFILE_NESTED(NT_transact_set_security_desc);
- outsize = call_nt_transact_set_security_desc(conn, inbuf, outbuf,
- length, bufsize,
- &setup, setup_count,
- ¶ms, total_parameter_count,
- &data, total_data_count);
- END_PROFILE_NESTED(NT_transact_set_security_desc);
- break;
- case NT_TRANSACT_NOTIFY_CHANGE:
- START_PROFILE_NESTED(NT_transact_notify_change);
- outsize = call_nt_transact_notify_change(conn, inbuf, outbuf,
- length, bufsize,
- &setup, setup_count,
- ¶ms, total_parameter_count,
- &data, total_data_count);
- END_PROFILE_NESTED(NT_transact_notify_change);
- break;
- case NT_TRANSACT_RENAME:
- START_PROFILE_NESTED(NT_transact_rename);
- outsize = call_nt_transact_rename(conn, inbuf, outbuf,
- length, bufsize,
- &setup, setup_count,
- ¶ms, total_parameter_count,
- &data, total_data_count);
- END_PROFILE_NESTED(NT_transact_rename);
- break;
+ /* Revise state->total_param and state->total_data in case they have
+ changed downwards */
+ if (IVAL(inbuf, smb_nts_TotalParameterCount) < state->total_param) {
+ state->total_param = IVAL(inbuf, smb_nts_TotalParameterCount);
+ }
+ if (IVAL(inbuf, smb_nts_TotalDataCount) < state->total_data) {
+ state->total_data = IVAL(inbuf, smb_nts_TotalDataCount);
+ }
- case NT_TRANSACT_QUERY_SECURITY_DESC:
- START_PROFILE_NESTED(NT_transact_query_security_desc);
- outsize = call_nt_transact_query_security_desc(conn, inbuf, outbuf,
- length, bufsize,
- &setup, setup_count,
- ¶ms, total_parameter_count,
- &data, total_data_count);
- END_PROFILE_NESTED(NT_transact_query_security_desc);
- break;
-#ifdef HAVE_SYS_QUOTAS
- case NT_TRANSACT_GET_USER_QUOTA:
- START_PROFILE_NESTED(NT_transact_get_user_quota);
- outsize = call_nt_transact_get_user_quota(conn, inbuf, outbuf,
- length, bufsize,
- &setup, setup_count,
- ¶ms, total_parameter_count,
- &data, total_data_count);
- END_PROFILE_NESTED(NT_transact_get_user_quota);
- break;
- case NT_TRANSACT_SET_USER_QUOTA:
- START_PROFILE_NESTED(NT_transact_set_user_quota);
- outsize = call_nt_transact_set_user_quota(conn, inbuf, outbuf,
- length, bufsize,
- &setup, setup_count,
- ¶ms, total_parameter_count,
- &data, total_data_count);
- END_PROFILE_NESTED(NT_transact_set_user_quota);
- break;
-#endif /* HAVE_SYS_QUOTAS */
- default:
- /* Error in request */
- DEBUG(0,("reply_nttrans: Unknown request %d in nttrans call\n", function_code));
- SAFE_FREE(setup);
- SAFE_FREE(params);
- SAFE_FREE(data);
- END_PROFILE(SMBnttrans);
- srv_signing_trans_stop();
- return ERROR_DOS(ERRSRV,ERRerror);
+ pcnt = IVAL(inbuf,smb_nts_ParameterCount);
+ poff = IVAL(inbuf, smb_nts_ParameterOffset);
+ pdisp = IVAL(inbuf, smb_nts_ParameterDisplacement);
+
+ dcnt = IVAL(inbuf, smb_nts_DataCount);
+ ddisp = IVAL(inbuf, smb_nts_DataDisplacement);
+ doff = IVAL(inbuf, smb_nts_DataOffset);
+
+ state->received_param += pcnt;
+ state->received_data += dcnt;
+
+ if ((state->received_data > state->total_data) ||
+ (state->received_param > state->total_param))
+ goto bad_param;
+
+ if (pcnt) {
+ if (pdisp+pcnt > state->total_param)
+ goto bad_param;
+ if ((pdisp+pcnt < pdisp) || (pdisp+pcnt < pcnt))
+ goto bad_param;
+ if (pdisp > state->total_param)
+ goto bad_param;
+ if ((smb_base(inbuf) + poff + pcnt > inbuf + size) ||
+ (smb_base(inbuf) + poff + pcnt < smb_base(inbuf)))
+ goto bad_param;
+ if (state->param + pdisp < state->param)
+ goto bad_param;
+
+ memcpy(state->param+pdisp,smb_base(inbuf)+poff,
+ pcnt);
+ }
+
+ if (dcnt) {
+ if (ddisp+dcnt > state->total_data)
+ goto bad_param;
+ if ((ddisp+dcnt < ddisp) || (ddisp+dcnt < dcnt))
+ goto bad_param;
+ if (ddisp > state->total_data)
+ goto bad_param;
+ if ((smb_base(inbuf) + doff + dcnt > inbuf + size) ||
+ (smb_base(inbuf) + doff + dcnt < smb_base(inbuf)))
+ goto bad_param;
+ if (state->data + ddisp < state->data)
+ goto bad_param;
+
+ memcpy(state->data+ddisp, smb_base(inbuf)+doff,
+ dcnt);
}
- /* As we do not know how many data packets will need to be
- returned here the various call_nt_transact_xxxx calls
- must send their own. Thus a call_nt_transact_xxxx routine only
- returns a value other than -1 when it wants to send
- an error packet.
- */
+ if ((state->received_param < state->total_param) ||
+ (state->received_data < state->total_data)) {
+ END_PROFILE(SMBnttranss);
+ return -1;
+ }
- srv_signing_trans_stop();
+ /* construct_reply_common has done us the favor to pre-fill the
+ * command field with SMBnttranss which is wrong :-)
+ */
+ SCVAL(outbuf,smb_com,SMBnttrans);
- SAFE_FREE(setup);
- SAFE_FREE(params);
- SAFE_FREE(data);
- END_PROFILE(SMBnttrans);
- return outsize; /* If a correct response was needed the call_nt_transact_xxxx
- calls have already sent it. If outsize != -1 then it is
- returning an error packet. */
+ outsize = handle_nttrans(conn, state, inbuf, outbuf,
+ size, bufsize);
- bad_param:
+ DLIST_REMOVE(conn->pending_trans, state);
+ SAFE_FREE(state->data);
+ SAFE_FREE(state->param);
+ TALLOC_FREE(state);
- srv_signing_trans_stop();
- SAFE_FREE(params);
- SAFE_FREE(data);
- SAFE_FREE(setup);
- END_PROFILE(SMBnttrans);
+ if (outsize == 0) {
+ END_PROFILE(SMBnttranss);
+ return(ERROR_DOS(ERRSRV,ERRnosupport));
+ }
+
+ END_PROFILE(SMBnttranss);
+ return(outsize);
+
+ bad_param:
+
+ DEBUG(0,("reply_nttranss: invalid trans parameters\n"));
+ DLIST_REMOVE(conn->pending_trans, state);
+ SAFE_FREE(state->data);
+ SAFE_FREE(state->param);
+ TALLOC_FREE(state);
+ END_PROFILE(SMBnttranss);
return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
}