#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[] = {
"\\spoolss",
"\\netdfs",
"\\rpcecho",
- "\\epmapper",
+ "\\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);
+ tptr = SMB_REALLOC(*ptr, size);
if(tptr == NULL) {
*ptr = NULL;
return NULL;
}
+ memset(tptr,'\0',size);
*ptr = tptr;
return tptr;
}
-
/****************************************************************************
Send the required number of replies back.
We assume all fields other than the data fields are
static int send_nt_replies(char *inbuf, 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))
+ show_msg(outbuf);
+ if (!send_smb(smbd_server_fd(),outbuf)) {
exit_server("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))
+ show_msg(outbuf);
+ if (!send_smb(smbd_server_fd(),outbuf)) {
exit_server("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;
/* 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));
+ }
*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 = open_fake_file(conn, fake_file_type, fname, desired_access);
+
+ if (!fsp) {
+ return ERROR_NT(NT_STATUS_ACCESS_DENIED);
+ }
+
+ set_message(outbuf,34,0,True);
+
+ p = outbuf + smb_vwv2;
+
+ /* SCVAL(p,0,NO_OPLOCK_RETURN); */
+ p++;
+ SSVAL(p,0,fsp->fnum);
+#if 0
+ p += 2;
+ SIVAL(p,0,smb_action);
+ p += 4;
+
+ /* Create time. */
+ put_long_date(p,c_time);
+ p += 8;
+ put_long_date(p,sbuf.st_atime); /* access time */
+ p += 8;
+ put_long_date(p,sbuf.st_mtime); /* write time */
+ p += 8;
+ put_long_date(p,sbuf.st_mtime); /* change time */
+ p += 8;
+ SIVAL(p,0,fattr); /* File Attributes. */
+ p += 4;
+ 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)
+ SSVAL(p,2,0x7);
+ p += 4;
+ SCVAL(p,0,fsp->is_directory ? 1 : 0);
+#endif
+
+ 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;
START_PROFILE(SMBntcreateX);
- DEBUG(10,("reply_ntcreateX: flags = 0x%x, desired_access = 0x%x \
+ DEBUG(10,("reply_ntcreateX: 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", flags, desired_access, file_attributes,
- share_access, create_disposition,
- create_options, root_dir_fid ));
+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,False);
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);
}
-
/*
we need to handle the case when we get a
relative open relative to a file and the
pathname is blank - this is a reopen!
(hint from demyn plantenberg)
*/
-
END_PROFILE(SMBntcreateX);
return(ERROR_DOS(ERRDOS,ERRbadfid));
*/
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,False);
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,False);
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);
+ fsp = open_directory(conn, fname, &sbuf,
+ access_mask,
+ share_access,
+ create_disposition,
+ create_options,
+ &info);
+
+ restore_case_semantics(conn, file_attributes);
if(!fsp) {
END_PROFILE(SMBntcreateX);
* 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);
- }
-
+ fsp = open_file_ntcreate(conn,fname,&sbuf,
+ access_mask,
+ share_access,
+ create_disposition,
+ create_options,
+ file_attributes,
+ oplock_request,
+ &info);
if (!fsp) {
/* We cheat here. There are two cases we
* care about. One is a directory rename,
*/
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);
-
+ fsp = open_directory(conn, fname, &sbuf,
+ access_mask,
+ share_access,
+ create_disposition,
+ create_options,
+ &info);
+
if(!fsp) {
- 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);
}
} else {
- restore_case_semantics(file_attributes);
+ restore_case_semantics(conn, file_attributes);
END_PROFILE(SMBntcreateX);
+ if (open_was_deferred(SVAL(inbuf,smb_mid))) {
+ /* We have re-scheduled this call. */
+ return -1;
+ }
return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess);
}
}
}
- 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)) {
+ fattr = dos_mode(conn,fname,&sbuf);
+ if(fattr == 0) {
+ fattr = FILE_ATTRIBUTE_NORMAL;
+ }
+ if (!fsp->is_directory && (fattr & aDIR)) {
close_file(fsp,False);
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,False);
+ 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,False);
+ 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. */
p += 8;
put_long_date(p,sbuf.st_mtime); /* 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 += 12;
+ p += 8;
+ if (flags & EXTENDED_RESPONSE_REQUIRED) {
+ SSVAL(p,2,0x7);
+ }
+ p += 4;
SCVAL(p,0,fsp->is_directory ? 1 : 0);
-
+
DEBUG(5,("reply_ntcreate_and_X: fnum = %d, open name = %s\n", fsp->fnum, fsp->fsp_name));
result = chain_reply(inbuf,outbuf,length,bufsize);
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, False);
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);
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->off_owner_sid==0) {
security_info_sent &= ~OWNER_SECURITY_INFORMATION;
- if (psd->off_grp_sid==0)
+ }
+ if (psd->off_grp_sid==0) {
security_info_sent &= ~GROUP_SECURITY_INFORMATION;
- if (psd->off_sacl==0)
+ }
+ if (psd->off_sacl==0) {
security_info_sent &= ~SACL_SECURITY_INFORMATION;
- if (psd->off_dacl==0)
+ }
+ if (psd->off_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 *tmp;
+ struct ea_list *eal = read_ea_list_entry(ctx, pdata + offset + 4, data_size - offset - 4, NULL);
+
+ DLIST_ADD_END(ea_list_head, eal, tmp);
+ 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,
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 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, False);
+ 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, False);
+ 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, False);
+ 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);
+ END_PROFILE(SMBntcreateX);
+ return ERROR_NT(status);
+ }
+ }
+
+ if (ea_len) {
+ ctx = talloc_init("NTTRANS_CREATE_EA");
+ if (!ctx) {
+ talloc_destroy(ctx);
+ restore_case_semantics(conn, file_attributes);
+ return ERROR_NT(NT_STATUS_NO_MEMORY);
+ }
+
+ pdata = data + sd_len;
+
+ /* We have already checked that ea_len <= data_count here. */
+ ea_list = read_nttrans_ea_list(ctx, pdata, ea_len);
+ if (!ea_list ) {
+ talloc_destroy(ctx);
+ 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) {
+ talloc_destroy(ctx);
+ 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);
-
+ fsp = open_directory(conn, fname, &sbuf,
+ access_mask,
+ share_access,
+ create_disposition,
+ create_options,
+ &info);
if(!fsp) {
- restore_case_semantics(file_attributes);
+ talloc_destroy(ctx);
+ restore_case_semantics(conn, file_attributes);
return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess);
}
* Ordinary file case.
*/
- fsp = open_file_shared1(conn,fname,&sbuf,desired_access,
- smb_open_mode,smb_ofun,unixmode,
- oplock_request,&rmode,&smb_action);
+ fsp = open_file_ntcreate(conn,fname,&sbuf,
+ access_mask,
+ share_access,
+ create_disposition,
+ create_options,
+ file_attributes,
+ oplock_request,
+ &info);
if (!fsp) {
-
if(errno == EISDIR) {
/*
*/
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);
-
+ fsp = open_directory(conn, fname, &sbuf,
+ access_mask,
+ share_access,
+ create_disposition,
+ create_options,
+ &info);
if(!fsp) {
- restore_case_semantics(file_attributes);
+ talloc_destroy(ctx);
+ restore_case_semantics(conn, file_attributes);
return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess);
}
} else {
- restore_case_semantics(file_attributes);
+ talloc_destroy(ctx);
+ restore_case_semantics(conn, file_attributes);
+ if (open_was_deferred(SVAL(inbuf,smb_mid))) {
+ /* We have re-scheduled this call. */
+ return -1;
+ }
return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess);
}
}
-
- 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,False);
+ 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);
+ talloc_destroy(ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ close_file(fsp,False);
+ 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,False);
+ 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,False);
+ /* 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,False);
+ 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)
+ if (extended_oplock_granted) {
SCVAL(p,0, BATCH_OPLOCK_RETURN);
- else if (LEVEL_II_OPLOCK_TYPE(fsp->oplock_type))
+ } else if (LEVEL_II_OPLOCK_TYPE(fsp->oplock_type)) {
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. */
p += 8;
put_long_date(p,sbuf.st_mtime); /* 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) {
+ 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));
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));
+
+ fsp1 = open_file_ntcreate(conn,oldname,&sbuf1,
+ FILE_READ_DATA, /* Read-only. */
+ 0, /* No sharing. */
+ FILE_OPEN,
+ 0, /* No create options. */
+ FILE_ATTRIBUTE_NORMAL,
+ INTERNAL_OPEN_ONLY,
+ &info);
+
+ if (!fsp1) {
+ status = get_saved_ntstatus();
+ if (NT_STATUS_IS_OK(status)) {
+ status = NT_STATUS_ACCESS_DENIED;
+ }
+ set_saved_ntstatus(NT_STATUS_OK);
+ return status;
+ }
+
+ fsp2 = open_file_ntcreate(conn,newname,&sbuf2,
+ FILE_WRITE_DATA, /* Read-only. */
+ 0, /* No sharing. */
+ FILE_CREATE,
+ 0, /* No create options. */
+ fattr,
+ INTERNAL_OPEN_ONLY,
+ &info);
+
+ if (!fsp2) {
+ status = get_saved_ntstatus();
+ if (NT_STATUS_IS_OK(status)) {
+ status = NT_STATUS_ACCESS_DENIED;
+ }
+ set_saved_ntstatus(NT_STATUS_OK);
+ close_file(fsp1,False);
+ 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,False);
+
+ /* Ensure the modtime is set correctly on the destination file. */
+ fsp_set_pending_modtime(fsp2, sbuf1.st_mtime);
+
+ close_ret = close_file(fsp2,False);
+
+ /* Grrr. We have to do this as open_file_shared1 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, True);
+
+ 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;
+ 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(inbuf, oldname, p, sizeof(oldname), 0, STR_TERMINATE, &status, True);
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(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status, False);
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);
+ break;
+ case RENAME_FLAG_HARD_LINK:
+ status = hardlink_internals(conn, oldname, newname);
+ break;
+ case RENAME_FLAG_COPY:
+ 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);
}
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)
+ char **ppdata, uint32 data_count, uint32 max_data_count)
{
char *setup = *ppsetup;
files_struct *fsp;
uint32 flags;
- if(setup_count < 6)
+ if(setup_count < 6) {
return ERROR_DOS(ERRDOS,ERRbadfunc);
+ }
fsp = file_fsp(setup,4);
flags = IVAL(setup, 0);
DEBUG(3,("call_nt_transact_notify_change\n"));
- if(!fsp)
+ if(!fsp) {
return ERROR_DOS(ERRDOS,ERRbadfid);
+ }
- if((!fsp->is_directory) || (conn != fsp->conn))
+ if((!fsp->is_directory) || (conn != fsp->conn)) {
return ERROR_DOS(ERRDOS,ERRbadfid);
+ }
- if (!change_notify_set(inbuf, fsp, conn, flags))
+ if (!change_notify_set(inbuf, fsp, conn, flags)) {
return(UNIXERROR(ERRDOS,ERRbadfid));
+ }
DEBUG(3,("call_nt_transact_notify_change: notify change called on directory \
name = %s\n", fsp->fsp_name ));
static int call_nt_transact_rename(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)
+ char **ppdata, uint32 data_count, uint32 max_data_count)
{
char *params = *ppparams;
pstring new_name;
BOOL replace_if_exists = False;
NTSTATUS status;
- if(parameter_count < 4)
+ if(parameter_count < 4) {
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(inbuf, new_name, params+4, sizeof(new_name), -1, STR_TERMINATE, &status, True);
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);
if (!NT_STATUS_IS_OK(status))
return ERROR_NT(status);
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,
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);
static int call_nt_transact_set_security_desc(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)
+ 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:
static int call_nt_transact_ioctl(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)
+ char **ppdata, uint32 data_count, uint32 max_data_count)
{
uint32 function;
uint16 fidnum;
* 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);
}
static int call_nt_transact_get_user_quota(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)
+ 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;
/* access check */
if (current_user.uid != 0) {
- DEBUG(1,("set_user_quota: access_denied service [%s] user [%s]\n",
+ DEBUG(1,("get_user_quota: access_denied service [%s] user [%s]\n",
lp_servicename(SNUM(conn)),conn->user));
return ERROR_DOS(ERRDOS,ERRnoaccess);
}
/* 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;
static int call_nt_transact_set_user_quota(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)
+ 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.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);
char *inbuf,char *outbuf,int length,int bufsize)
{
int outsize = 0;
+ uint32 max_data_count = IVAL(inbuf,smb_nt_MaxDataCount);
#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 num_params_sofar, num_data_sofar;
START_PROFILE(SMBnttrans);
- 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.
- */
-
- DEBUG(2,("reply_nttrans: queueing message code 0x%x \
-due to being in oplock break state.\n", (unsigned int)function_code ));
-
- push_oplock_pending_smb_message( inbuf, length);
- END_PROFILE(SMBnttrans);
- return -1;
- }
-
if (IS_IPC(conn) && (function_code != NT_TRANSACT_CREATE)) {
END_PROFILE(SMBnttrans);
return ERROR_DOS(ERRSRV,ERRaccess);
CVAL(inbuf, smb_wct), 19 + (setup_count/2)));
goto bad_param;
}
-
+
+ /* Don't allow more than 128mb for each value. */
+ if ((total_parameter_count > (1024*1024*128)) || (total_data_count > (1024*1024*128))) {
+ END_PROFILE(SMBnttrans);
+ return ERROR_DOS(ERRDOS,ERRnomem);
+ }
+
/* 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(setup_count > 0) {
+ setup = (char *)SMB_MALLOC(setup_count);
+ }
+ if (total_parameter_count > 0) {
+ params = (char *)SMB_MALLOC(total_parameter_count);
+ }
+ if (total_data_count > 0) {
+ data = (char *)SMB_MALLOC(total_data_count);
+ }
if ((total_parameter_count && !params) || (total_data_count && !data) ||
(setup_count && !setup)) {
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))
+ (smb_nt_SetupStart + setup_count < setup_count)) {
goto bad_param;
- if (smb_nt_SetupStart + setup_count > length)
+ }
+ if (smb_nt_SetupStart + setup_count > length) {
goto bad_param;
+ }
memcpy( setup, &inbuf[smb_nt_SetupStart], setup_count);
dump_data(10, setup, setup_count);
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))
+ (parameter_offset + parameter_count < parameter_count)) {
goto bad_param;
+ }
if ((smb_base(inbuf) + parameter_offset + parameter_count > inbuf + length)||
- (smb_base(inbuf) + parameter_offset + parameter_count < smb_base(inbuf)))
+ (smb_base(inbuf) + parameter_offset + parameter_count < smb_base(inbuf))) {
goto bad_param;
+ }
memcpy( params, smb_base(inbuf) + parameter_offset, parameter_count);
dump_data(10, params, parameter_count);
}
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))
+ if ((data_offset + data_count < data_offset) || (data_offset + data_count < data_count)) {
goto bad_param;
+ }
if ((smb_base(inbuf) + data_offset + data_count > inbuf + length) ||
- (smb_base(inbuf) + data_offset + data_count < smb_base(inbuf)))
+ (smb_base(inbuf) + data_offset + data_count < smb_base(inbuf))) {
goto bad_param;
+ }
memcpy( data, smb_base(inbuf) + data_offset, data_count);
dump_data(10, data, data_count);
of the parameter/data bytes */
outsize = set_message(outbuf,0,0,True);
srv_signing_trans_stop();
- if (!send_smb(smbd_server_fd(),outbuf))
+ show_msg(outbuf);
+ if (!send_smb(smbd_server_fd(),outbuf)) {
exit_server("reply_nttrans: send_smb failed.");
+ }
while( num_data_sofar < total_data_count || num_params_sofar < total_parameter_count) {
BOOL ret;
ret = receive_next_smb(inbuf,bufsize,SMB_SECONDARY_WAIT);
+ /* We need to re-calcuate the new length after we've read the secondary packet. */
+ length = smb_len(inbuf) + 4;
+
/*
* The sequence number for the trans reply is always
* based on the last secondary received.
}
/* Revise total_params and total_data in case they have changed downwards */
- if (IVAL(inbuf, smb_nts_TotalParameterCount) < total_parameter_count)
+ 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)
+ }
+ 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);
}
if (parameter_count) {
- if (parameter_displacement + parameter_count >= total_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))
+ (parameter_displacement + parameter_count < parameter_count)) {
goto bad_param;
- if (parameter_displacement > total_parameter_count)
+ }
+ 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)))
+ }
+ if ((smb_base(inbuf) + parameter_offset + parameter_count > inbuf + length) ||
+ (smb_base(inbuf) + parameter_offset + parameter_count < smb_base(inbuf))) {
goto bad_param;
- if (parameter_displacement + params < params)
+ }
+ if (parameter_displacement + params < params) {
goto bad_param;
+ }
memcpy( ¶ms[parameter_displacement], smb_base(inbuf) + parameter_offset, parameter_count);
}
if (data_count) {
- if (data_displacement + data_count >= total_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))
+ (data_displacement + data_count < data_count)) {
goto bad_param;
- if (data_displacement > total_data_count)
+ }
+ 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)))
+ }
+ if ((smb_base(inbuf) + data_offset + data_count > inbuf + length) ||
+ (smb_base(inbuf) + data_offset + data_count < smb_base(inbuf))) {
goto bad_param;
- if (data_displacement + data < data)
+ }
+ if (data_displacement + data < data) {
goto bad_param;
+ }
memcpy( &data[data_displacement], smb_base(inbuf)+ data_offset, data_count);
}
}
}
- if (Protocol >= PROTOCOL_NT1)
+ if (Protocol >= PROTOCOL_NT1) {
SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2) | FLAGS2_IS_LONG_NAME);
+ }
/* Now we must call the relevant NT_TRANS function */
switch(function_code) {
length, bufsize,
&setup, setup_count,
¶ms, total_parameter_count,
- &data, total_data_count);
+ &data, total_data_count, max_data_count);
END_PROFILE_NESTED(NT_transact_create);
break;
case NT_TRANSACT_IOCTL:
length, bufsize,
&setup, setup_count,
¶ms, total_parameter_count,
- &data, total_data_count);
+ &data, total_data_count, max_data_count);
END_PROFILE_NESTED(NT_transact_ioctl);
break;
case NT_TRANSACT_SET_SECURITY_DESC:
length, bufsize,
&setup, setup_count,
¶ms, total_parameter_count,
- &data, total_data_count);
+ &data, total_data_count, max_data_count);
END_PROFILE_NESTED(NT_transact_set_security_desc);
break;
case NT_TRANSACT_NOTIFY_CHANGE:
length, bufsize,
&setup, setup_count,
¶ms, total_parameter_count,
- &data, total_data_count);
+ &data, total_data_count, max_data_count);
END_PROFILE_NESTED(NT_transact_notify_change);
break;
case NT_TRANSACT_RENAME:
length, bufsize,
&setup, setup_count,
¶ms, total_parameter_count,
- &data, total_data_count);
+ &data, total_data_count, max_data_count);
END_PROFILE_NESTED(NT_transact_rename);
break;
length, bufsize,
&setup, setup_count,
¶ms, total_parameter_count,
- &data, total_data_count);
+ &data, total_data_count, max_data_count);
END_PROFILE_NESTED(NT_transact_query_security_desc);
break;
#ifdef HAVE_SYS_QUOTAS
length, bufsize,
&setup, setup_count,
¶ms, total_parameter_count,
- &data, total_data_count);
+ &data, total_data_count, max_data_count);
END_PROFILE_NESTED(NT_transact_get_user_quota);
break;
case NT_TRANSACT_SET_USER_QUOTA:
length, bufsize,
&setup, setup_count,
¶ms, total_parameter_count,
- &data, total_data_count);
+ &data, total_data_count, max_data_count);
END_PROFILE_NESTED(NT_transact_set_user_quota);
break;
#endif /* HAVE_SYS_QUOTAS */