*/
#include "includes.h"
+#include "ntioctl.h"
#include "system/filesys.h"
#include "version.h"
#include "smbd/smbd.h"
#include "smbprofile.h"
#include "rpc_server/srv_pipe_hnd.h"
#include "printing.h"
+#include "lib/util_ea.h"
#define DIR_ENTRY_SAFETY_MARGIN 4096
files_struct *fsp,
const SMB_STRUCT_STAT *psbuf);
+/****************************************************************************
+ Check if an open file handle or pathname is a symlink.
+****************************************************************************/
+
+static NTSTATUS refuse_symlink(connection_struct *conn,
+ const files_struct *fsp,
+ const char *name)
+{
+ SMB_STRUCT_STAT sbuf;
+ const SMB_STRUCT_STAT *pst = NULL;
+
+ if (fsp) {
+ pst = &fsp->fsp_name->st;
+ } else {
+ int ret = vfs_stat_smb_basename(conn,
+ name,
+ &sbuf);
+ if (ret == -1) {
+ return map_nt_error_from_unix(errno);
+ }
+ pst = &sbuf;
+ }
+ if (S_ISLNK(pst->st_ex_mode)) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ return NT_STATUS_OK;
+}
+
/********************************************************************
The canonical "check access" based on object handle or path function.
********************************************************************/
char **names, **tmp;
size_t num_names;
ssize_t sizeret = -1;
+ NTSTATUS status;
+
+ if (pnames) {
+ *pnames = NULL;
+ }
+ *pnum_names = 0;
if (!lp_ea_support(SNUM(conn))) {
- if (pnames) {
- *pnames = NULL;
- }
- *pnum_names = 0;
+ return NT_STATUS_OK;
+ }
+
+ status = refuse_symlink(conn, fsp, fname);
+ if (!NT_STATUS_IS_OK(status)) {
+ /*
+ * Just return no EA's on a symlink.
+ */
return NT_STATUS_OK;
}
if (sizeret == 0) {
TALLOC_FREE(names);
- if (pnames) {
- *pnames = NULL;
- }
- *pnum_names = 0;
return NT_STATUS_OK;
}
NTSTATUS status;
*pea_total_len = 0;
+ *ea_list = NULL;
status = get_ea_names_from_file(talloc_tos(), conn, fsp, fname,
&names, &num_names);
|| samba_private_attr_name(names[i]))
continue;
+ /*
+ * Filter out any underlying POSIX EA names
+ * that a Windows client can't handle.
+ */
+ if (!lp_posix_pathnames() &&
+ is_invalid_windows_ea_name(names[i])) {
+ continue;
+ }
+
listp = talloc(mem_ctx, struct ea_list);
if (listp == NULL) {
return NT_STATUS_NO_MEMORY;
}
- status = get_ea_value(mem_ctx, conn, fsp,
+ status = get_ea_value(listp, conn, fsp,
fname, names[i],
&listp->ea);
if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(listp);
return status;
}
+ if (listp->ea.value.length == 0) {
+ /*
+ * We can never return a zero length EA.
+ * Windows reports the EA's as corrupted.
+ */
+ TALLOC_FREE(listp);
+ continue;
+ }
+
push_ascii_fstring(dos_ea_name, listp->ea.name);
*pea_total_len +=
{
uint8_t *p = (uint8_t *)pdata;
uint8_t *last_start = NULL;
+ bool do_store_data = (pdata != NULL);
*ret_data_size = 0;
size_t dos_namelen;
fstring dos_ea_name;
size_t this_size;
+ size_t pad = 0;
- if (last_start) {
+ if (last_start != NULL && do_store_data) {
SIVAL(last_start, 0, PTR_DIFF(p, last_start));
}
last_start = p;
this_size = 0x08 + dos_namelen + 1 + ea_list->ea.value.length;
if (ea_list->next) {
- size_t pad = 4 - (this_size % 4);
+ pad = (4 - (this_size % 4)) % 4;
this_size += pad;
}
- if (this_size > total_data_size) {
- return NT_STATUS_INFO_LENGTH_MISMATCH;
+ if (do_store_data) {
+ if (this_size > total_data_size) {
+ return NT_STATUS_INFO_LENGTH_MISMATCH;
+ }
+
+ /* We know we have room. */
+ SIVAL(p, 0x00, 0); /* next offset */
+ SCVAL(p, 0x04, ea_list->ea.flags);
+ SCVAL(p, 0x05, dos_namelen);
+ SSVAL(p, 0x06, ea_list->ea.value.length);
+ strlcpy((char *)(p+0x08), dos_ea_name, dos_namelen+1);
+ memcpy(p + 0x08 + dos_namelen + 1, ea_list->ea.value.data, ea_list->ea.value.length);
+ if (pad) {
+ memset(p + 0x08 + dos_namelen + 1 + ea_list->ea.value.length,
+ '\0',
+ pad);
+ }
+ total_data_size -= this_size;
}
- /* We know we have room. */
- SIVAL(p, 0x00, 0); /* next offset */
- SCVAL(p, 0x04, ea_list->ea.flags);
- SCVAL(p, 0x05, dos_namelen);
- SSVAL(p, 0x06, ea_list->ea.value.length);
- strlcpy((char *)(p+0x08), dos_ea_name, dos_namelen+1);
- memcpy(p + 0x08 + dos_namelen + 1, ea_list->ea.value.data, ea_list->ea.value.length);
-
- total_data_size -= this_size;
p += this_size;
}
{
size_t total_ea_len = 0;
TALLOC_CTX *mem_ctx;
- struct ea_list *ea_list;
+ struct ea_list *ea_list = NULL;
if (!lp_ea_support(SNUM(conn))) {
return 0;
fsp = NULL;
}
(void)get_ea_list_from_file_path(mem_ctx, conn, fsp, smb_fname->base_name, &total_ea_len, &ea_list);
+ if(conn->sconn->using_smb2) {
+ NTSTATUS status;
+ unsigned int ret_data_size;
+ /*
+ * We're going to be using fill_ea_chained_buffer() to
+ * marshall EA's - this size is significantly larger
+ * than the SMB1 buffer. Re-calculate the size without
+ * marshalling.
+ */
+ status = fill_ea_chained_buffer(mem_ctx,
+ NULL,
+ 0,
+ &ret_data_size,
+ conn,
+ ea_list);
+ if (!NT_STATUS_IS_OK(status)) {
+ ret_data_size = 0;
+ }
+ total_ea_len = ret_data_size;
+ }
TALLOC_FREE(mem_ctx);
return total_ea_len;
}
return NT_STATUS_EAS_NOT_SUPPORTED;
}
+ status = refuse_symlink(conn, fsp, smb_fname->base_name);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
status = check_access(conn, fsp, smb_fname, FILE_WRITE_EA);
if (!NT_STATUS_IS_OK(status)) {
return status;
return NT_STATUS_INVALID_PARAMETER;
}
+ /*
+ * Filter out invalid Windows EA names - before
+ * we set *any* of them.
+ */
+
+ if (ea_list_has_invalid_name(ea_list)) {
+ return STATUS_INVALID_EA_NAME;
+ }
+
fname = smb_fname->base_name;
for (;ea_list; ea_list = ea_list->next) {
return ea_list_head;
}
-/****************************************************************************
- Read one EA list entry from the buffer.
-****************************************************************************/
-
-struct ea_list *read_ea_list_entry(TALLOC_CTX *ctx, const char *pdata, size_t data_size, size_t *pbytes_used)
-{
- struct ea_list *eal = talloc_zero(ctx, struct ea_list);
- uint16 val_len;
- unsigned int namelen;
- size_t converted_size;
-
- if (!eal) {
- return NULL;
- }
-
- if (data_size < 6) {
- return NULL;
- }
-
- eal->ea.flags = CVAL(pdata,0);
- namelen = CVAL(pdata,1);
- val_len = SVAL(pdata,2);
-
- if (4 + namelen + 1 + val_len > data_size) {
- return NULL;
- }
-
- /* Ensure the name is null terminated. */
- if (pdata[namelen + 4] != '\0') {
- return NULL;
- }
- if (!pull_ascii_talloc(ctx, &eal->ea.name, pdata + 4, &converted_size)) {
- DEBUG(0,("read_ea_list_entry: pull_ascii_talloc failed: %s",
- strerror(errno)));
- }
- if (!eal->ea.name) {
- return NULL;
- }
-
- eal->ea.value = data_blob_talloc(eal, NULL, (size_t)val_len + 1);
- if (!eal->ea.value.data) {
- return NULL;
- }
-
- memcpy(eal->ea.value.data, pdata + 4 + namelen + 1, val_len);
-
- /* Ensure we're null terminated just in case we print the value. */
- eal->ea.value.data[val_len] = '\0';
- /* But don't count the null. */
- eal->ea.value.length--;
-
- if (pbytes_used) {
- *pbytes_used = 4 + namelen + 1 + val_len;
- }
-
- DEBUG(10,("read_ea_list_entry: read ea name %s\n", eal->ea.name));
- dump_data(10, eal->ea.value.data, eal->ea.value.length);
-
- return eal;
-}
-
/****************************************************************************
Read a list of EA names and data from an incoming data buffer. Create an ea_list with them.
****************************************************************************/
void send_trans2_replies(connection_struct *conn,
struct smb_request *req,
+ NTSTATUS status,
const char *params,
int paramsize,
const char *pdata,
if(params_to_send == 0 && data_to_send == 0) {
reply_outbuf(req, 10, 0);
+ if (NT_STATUS_V(status)) {
+ uint8_t eclass;
+ uint32_t ecode;
+ ntstatus_to_dos(status, &eclass, &ecode);
+ error_packet_set((char *)req->outbuf,
+ eclass, ecode, status,
+ __LINE__,__FILE__);
+ }
show_msg((char *)req->outbuf);
if (!srv_send_smb(sconn,
(char *)req->outbuf,
ERRDOS,ERRbufferoverflow,
STATUS_BUFFER_OVERFLOW,
__LINE__,__FILE__);
+ } else if (NT_STATUS_V(status)) {
+ uint8_t eclass;
+ uint32_t ecode;
+ ntstatus_to_dos(status, &eclass, &ecode);
+ error_packet_set((char *)req->outbuf,
+ eclass, ecode, status,
+ __LINE__,__FILE__);
}
/* Send the packet */
reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
goto out;
}
+
+ if (ea_list_has_invalid_name(ea_list)) {
+ int param_len = 30;
+ *pparams = (char *)SMB_REALLOC(*pparams, param_len);
+ if(*pparams == NULL ) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ goto out;
+ }
+ params = *pparams;
+ memset(params, '\0', param_len);
+ send_trans2_replies(conn, req, STATUS_INVALID_EA_NAME,
+ params, param_len, NULL, 0, max_data_bytes);
+ goto out;
+ }
}
status = SMB_VFS_CREATE_FILE(
}
/* Send the required number of replies */
- send_trans2_replies(conn, req, params, 30, *ppdata, 0, max_data_bytes);
+ send_trans2_replies(conn, req, NT_STATUS_OK, params, 30, *ppdata, 0, max_data_bytes);
out:
TALLOC_FREE(smb_fname);
}
ret |= ((perms & UNIX_SET_UID ) ? S_ISUID : 0);
#endif
- switch (ptype) {
- case PERM_NEW_FILE:
- case PERM_EXISTING_FILE:
- /* Apply mode mask */
+ if (ptype == PERM_NEW_FILE) {
+ /*
+ * "create mask"/"force create mode" are
+ * only applied to new files, not existing ones.
+ */
ret &= lp_create_mask(SNUM(conn));
/* Add in force bits */
ret |= lp_force_create_mode(SNUM(conn));
- break;
- case PERM_NEW_DIR:
- case PERM_EXISTING_DIR:
+ } else if (ptype == PERM_NEW_DIR) {
+ /*
+ * "directory mask"/"force directory mode" are
+ * only applied to new directories, not existing ones.
+ */
ret &= lp_dir_mask(SNUM(conn));
/* Add in force bits */
ret |= lp_force_dir_mode(SNUM(conn));
- break;
}
*ret_perms = ret;
SOFF_T(p,0,allocation_size); p += 8;
SIVAL(p,0,mode); p += 4;
q = p; p += 4; /* q is placeholder for name length. */
- {
+ if (mode & FILE_ATTRIBUTE_REPARSE_POINT) {
+ SIVAL(p, 0, IO_REPARSE_TAG_DFS);
+ } else {
unsigned int ea_size = estimate_ea_size(conn, NULL,
smb_fname);
SIVAL(p,0,ea_size); /* Extended attributes */
- p += 4;
}
+ p += 4;
/* Clear the short name buffer. This is
* IMPORTANT as not doing so will trigger
* a Win2k client bug. JRA.
SOFF_T(p,0,allocation_size); p += 8;
SIVAL(p,0,mode); p += 4;
q = p; p += 4; /* q is placeholder for name length. */
- {
+ if (mode & FILE_ATTRIBUTE_REPARSE_POINT) {
+ SIVAL(p, 0, IO_REPARSE_TAG_DFS);
+ } else {
unsigned int ea_size = estimate_ea_size(conn, NULL,
smb_fname);
SIVAL(p,0,ea_size); /* Extended attributes */
- p +=4;
}
+ p += 4;
SIVAL(p,0,0); p += 4; /* Unknown - reserved ? */
SBVAL(p,0,file_index); p += 8;
len = srvstr_push(base_data, flags2, p,
SOFF_T(p,0,allocation_size); p += 8;
SIVAL(p,0,mode); p += 4;
q = p; p += 4; /* q is placeholder for name length */
- {
+ if (mode & FILE_ATTRIBUTE_REPARSE_POINT) {
+ SIVAL(p, 0, IO_REPARSE_TAG_DFS);
+ } else {
unsigned int ea_size = estimate_ea_size(conn, NULL,
smb_fname);
SIVAL(p,0,ea_size); /* Extended attributes */
- p +=4;
}
+ p += 4;
/* Clear the short name buffer. This is
* IMPORTANT as not doing so will trigger
* a Win2k client bug. JRA.
struct smbd_server_connection *sconn = req->sconn;
uint32_t ucf_flags = (UCF_SAVE_LCOMP | UCF_ALWAYS_ALLOW_WCARD_LCOMP);
bool backup_priv = false;
+ bool as_root = false;
if (total_params < 13) {
reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
if (backup_priv) {
become_root();
+ as_root = true;
ntstatus = filename_convert_with_privilege(ctx,
conn,
req,
SSVAL(params,6,0); /* Never an EA error */
SSVAL(params,8,last_entry_off);
- send_trans2_replies(conn, req, params, 10, pdata, PTR_DIFF(p,pdata),
+ send_trans2_replies(conn, req, NT_STATUS_OK, params, 10, pdata, PTR_DIFF(p,pdata),
max_data_bytes);
if ((! *directory) && dptr_path(sconn, dptr_num)) {
}
out:
- if (backup_priv) {
+ if (as_root) {
unbecome_root();
}
struct dptr_struct *dirptr;
struct smbd_server_connection *sconn = req->sconn;
bool backup_priv = false;
+ bool as_root = false;
if (total_params < 13) {
reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
if (backup_priv) {
become_root();
+ as_root = true;
}
/*
dptr_close(sconn, &dptr_num); /* This frees up the saved mask */
}
- if (backup_priv) {
+ if (as_root) {
unbecome_root();
}
SSVAL(params,4,0); /* Never an EA error */
SSVAL(params,6,last_entry_off);
- send_trans2_replies(conn, req, params, 8, pdata, PTR_DIFF(p,pdata),
+ send_trans2_replies(conn, req, NT_STATUS_OK, params, 8, pdata, PTR_DIFF(p,pdata),
max_data_bytes);
return;
uint16_t info_level,
uint16_t flags2,
unsigned int max_data_bytes,
+ size_t *fixed_portion,
struct smb_filename *fname,
char **ppdata,
int *ret_data_len)
uint32 additional_flags = 0;
struct smb_filename smb_fname;
SMB_STRUCT_STAT st;
+ NTSTATUS status = NT_STATUS_OK;
if (fname == NULL || fname->base_name == NULL) {
filename = ".";
memset((char *)pdata,'\0',max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
end_data = pdata + max_data_bytes + DIR_ENTRY_SAFETY_MARGIN - 1;
+ *fixed_portion = 0;
+
switch (info_level) {
case SMB_INFO_ALLOCATION:
{
STR_UNICODE);
SIVAL(pdata,8,len);
data_len = 12 + len;
+ if (max_data_bytes >= 16 && data_len > max_data_bytes) {
+ /* the client only requested a portion of the
+ file system name */
+ data_len = max_data_bytes;
+ status = STATUS_BUFFER_OVERFLOW;
+ }
+ *fixed_portion = 16;
break;
case SMB_QUERY_FS_LABEL_INFO:
DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_VOLUME_INFO namelen = %d, vol=%s serv=%s\n",
(int)strlen(vname),vname,
lp_servicename(talloc_tos(), snum)));
+ if (max_data_bytes >= 24 && data_len > max_data_bytes) {
+ /* the client only requested a portion of the
+ volume label */
+ data_len = max_data_bytes;
+ status = STATUS_BUFFER_OVERFLOW;
+ }
+ *fixed_portion = 24;
break;
case SMB_QUERY_FS_SIZE_INFO:
SBIG_UINT(pdata,8,dfree);
SIVAL(pdata,16,sectors_per_unit);
SIVAL(pdata,20,bytes_per_sector);
+ *fixed_portion = 24;
break;
}
SBIG_UINT(pdata,16,dfree); /* Actual available allocation units. */
SIVAL(pdata,24,sectors_per_unit); /* Sectors per allocation unit. */
SIVAL(pdata,28,bytes_per_sector); /* Bytes per sector. */
+ *fixed_portion = 32;
break;
}
data_len = 8;
SIVAL(pdata,0,FILE_DEVICE_DISK); /* dev type */
SIVAL(pdata,4,characteristics);
+ *fixed_portion = 8;
break;
}
case SMB_SIGNING_OFF:
encrypt_caps = 0;
break;
+ case SMB_SIGNING_DESIRED:
case SMB_SIGNING_IF_REQUIRED:
case SMB_SIGNING_DEFAULT:
encrypt_caps = CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP;
}
*ret_data_len = data_len;
- return NT_STATUS_OK;
+ return status;
}
/****************************************************************************
char *params = *pparams;
uint16_t info_level;
int data_len = 0;
+ size_t fixed_portion;
NTSTATUS status;
if (total_params < 2) {
info_level,
req->flags2,
max_data_bytes,
+ &fixed_portion,
NULL,
ppdata, &data_len);
if (!NT_STATUS_IS_OK(status)) {
return;
}
- send_trans2_replies(conn, req, params, 0, *ppdata, data_len,
+ send_trans2_replies(conn, req, NT_STATUS_OK, params, 0, *ppdata, data_len,
max_data_bytes);
DEBUG( 4, ( "%s info_level = %d\n",
}
send_trans2_replies(conn, req,
+ NT_STATUS_OK,
*pparams,
param_len,
*ppdata,
unsigned int i;
unsigned int ofs = 0;
+ if (max_data_bytes < 32) {
+ return NT_STATUS_INFO_LENGTH_MISMATCH;
+ }
+
for (i = 0; i < num_streams; i++) {
unsigned int next_offset;
size_t namelen;
return;
}
- send_trans2_replies(conn, req, params, param_size, *ppdata, data_size,
+ send_trans2_replies(conn, req, NT_STATUS_OK, params, param_size, *ppdata, data_size,
max_data_bytes);
return;
char *lock_data,
uint16_t flags2,
unsigned int max_data_bytes,
+ size_t *fixed_portion,
char **ppdata,
unsigned int *pdata_size)
{
BasicFileInformationTest. -tpot */
file_index = get_FileIndex(conn, psbuf);
+ *fixed_portion = 0;
+
switch (info_level) {
case SMB_INFO_STANDARD:
DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_STANDARD\n"));
DEBUG(5,("write: %s ", ctime(&mtime)));
DEBUG(5,("change: %s ", ctime(&c_time)));
DEBUG(5,("mode: %x\n", mode));
+ *fixed_portion = data_size;
break;
case SMB_FILE_STANDARD_INFORMATION:
SCVAL(pdata,20,delete_pending?1:0);
SCVAL(pdata,21,(mode&FILE_ATTRIBUTE_DIRECTORY)?1:0);
SSVAL(pdata,22,0); /* Padding. */
+ *fixed_portion = 24;
break;
case SMB_FILE_EA_INFORMATION:
estimate_ea_size(conn, fsp, smb_fname);
DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_EA_INFORMATION\n"));
data_size = 4;
+ *fixed_portion = 4;
SIVAL(pdata,0,ea_size);
break;
}
STR_UNICODE);
data_size = 4 + len;
SIVAL(pdata,0,len);
+ *fixed_portion = 8;
break;
}
SIVAL(pdata,0,len);
pdata += 4 + len;
data_size = PTR_DIFF(pdata,(*ppdata));
+ *fixed_portion = 10;
break;
}
SIVAL(pdata,0,len);
pdata += 4 + len;
data_size = PTR_DIFF(pdata,(*ppdata));
+ *fixed_portion = 104;
break;
}
case SMB_FILE_INTERNAL_INFORMATION:
DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_INTERNAL_INFORMATION\n"));
SBVAL(pdata, 0, file_index);
data_size = 8;
+ *fixed_portion = 8;
break;
case SMB_FILE_ACCESS_INFORMATION:
DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ACCESS_INFORMATION\n"));
SIVAL(pdata, 0, access_mask);
data_size = 4;
+ *fixed_portion = 4;
break;
case SMB_FILE_NAME_INFORMATION:
DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_DISPOSITION_INFORMATION\n"));
data_size = 1;
SCVAL(pdata,0,delete_pending);
+ *fixed_portion = 1;
break;
case SMB_FILE_POSITION_INFORMATION:
DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_POSITION_INFORMATION\n"));
data_size = 8;
SOFF_T(pdata,0,pos);
+ *fixed_portion = 8;
break;
case SMB_FILE_MODE_INFORMATION:
DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_MODE_INFORMATION\n"));
SIVAL(pdata,0,mode);
data_size = 4;
+ *fixed_portion = 4;
break;
case SMB_FILE_ALIGNMENT_INFORMATION:
DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALIGNMENT_INFORMATION\n"));
SIVAL(pdata,0,0); /* No alignment needed. */
data_size = 4;
+ *fixed_portion = 4;
break;
/*
TALLOC_FREE(streams);
+ *fixed_portion = 32;
+
break;
}
case SMB_QUERY_COMPRESSION_INFO:
SIVAL(pdata,8,0); /* ??? */
SIVAL(pdata,12,0); /* ??? */
data_size = 16;
+ *fixed_portion = 16;
break;
case SMB_FILE_NETWORK_OPEN_INFORMATION:
SIVAL(pdata,48,mode);
SIVAL(pdata,52,0); /* ??? */
data_size = 56;
+ *fixed_portion = 56;
break;
case SMB_FILE_ATTRIBUTE_TAG_INFORMATION:
SIVAL(pdata,0,mode);
SIVAL(pdata,4,0);
data_size = 8;
+ *fixed_portion = 8;
break;
/*
uint16 num_file_acls = 0;
uint16 num_def_acls = 0;
+ status = refuse_symlink(conn,
+ fsp,
+ smb_fname->base_name);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
if (fsp && fsp->fh->fd != -1) {
file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp,
talloc_tos());
struct ea_list *ea_list = NULL;
int lock_data_count = 0;
char *lock_data = NULL;
+ size_t fixed_portion;
NTSTATUS status = NT_STATUS_OK;
if (!params) {
return;
}
- status = copy_smb_filename(talloc_tos(), fsp->fsp_name,
- &smb_fname);
- if (!NT_STATUS_IS_OK(status)) {
- reply_nterror(req, status);
+ smb_fname = cp_smb_filename(talloc_tos(), fsp->fsp_name);
+ if (smb_fname == NULL) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
return;
}
/* If this is a stream, check if there is a delete_pending. */
if ((conn->fs_capabilities & FILE_NAMED_STREAMS)
&& is_ntfs_stream_smb_fname(smb_fname)) {
- struct smb_filename *smb_fname_base = NULL;
+ struct smb_filename *smb_fname_base;
/* Create an smb_filename with stream_name == NULL. */
- status =
- create_synthetic_smb_fname(talloc_tos(),
- smb_fname->base_name,
- NULL, NULL,
- &smb_fname_base);
- if (!NT_STATUS_IS_OK(status)) {
- reply_nterror(req, status);
+ smb_fname_base = synthetic_smb_fname(
+ talloc_tos(), smb_fname->base_name,
+ NULL, NULL);
+ if (smb_fname_base == NULL) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
return;
}
ea_list,
lock_data_count, lock_data,
req->flags2, max_data_bytes,
+ &fixed_portion,
ppdata, &data_size);
if (!NT_STATUS_IS_OK(status)) {
reply_nterror(req, status);
return;
}
+ if (fixed_portion > max_data_bytes) {
+ reply_nterror(req, NT_STATUS_INFO_LENGTH_MISMATCH);
+ return;
+ }
- send_trans2_replies(conn, req, params, param_size, *ppdata, data_size,
+ send_trans2_replies(conn, req, NT_STATUS_OK, params, param_size, *ppdata, data_size,
max_data_bytes);
return;
const struct smb_filename *smb_fname,
uint32 dosmode)
{
- struct smb_filename *smb_fname_base = NULL;
+ struct smb_filename *smb_fname_base;
NTSTATUS status;
if (!VALID_STAT(smb_fname->st)) {
}
/* Always operate on the base_name, even if a stream was passed in. */
- status = create_synthetic_smb_fname(talloc_tos(), smb_fname->base_name,
- NULL, &smb_fname->st,
- &smb_fname_base);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
+ smb_fname_base = synthetic_smb_fname(
+ talloc_tos(), smb_fname->base_name, NULL, &smb_fname->st);
+ if (smb_fname_base == NULL) {
+ return NT_STATUS_NO_MEMORY;
}
if (dosmode) {
return NT_STATUS_OK;
}
- status = copy_smb_filename(talloc_tos(), smb_fname, &smb_fname_tmp);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
+ smb_fname_tmp = cp_smb_filename(talloc_tos(), smb_fname);
+ if (smb_fname_tmp == NULL) {
+ return NT_STATUS_NO_MEMORY;
}
smb_fname_tmp->st = *psbuf;
}
/* Create an smb_fname to call rename_internals_fsp() with. */
- status = create_synthetic_smb_fname(talloc_tos(),
- fsp->base_fsp->fsp_name->base_name, newname, NULL,
- &smb_fname_dst);
- if (!NT_STATUS_IS_OK(status)) {
+ smb_fname_dst = synthetic_smb_fname(
+ talloc_tos(), fsp->base_fsp->fsp_name->base_name,
+ newname, NULL);
+ if (smb_fname_dst == NULL) {
+ status = NT_STATUS_NO_MEMORY;
goto out;
}
}
/* Create an smb_fname to call rename_internals_fsp() with. */
- status = create_synthetic_smb_fname(talloc_tos(),
- fsp->base_fsp->fsp_name->base_name, newname, NULL,
- &smb_fname_dst);
- if (!NT_STATUS_IS_OK(status)) {
+ smb_fname_dst = synthetic_smb_fname(
+ talloc_tos(), fsp->base_fsp->fsp_name->base_name,
+ newname, NULL);
+ if (smb_fname_dst == NULL) {
+ status = NT_STATUS_NO_MEMORY;
goto out;
}
goto out;
}
/* Create an smb_fname to call rename_internals_fsp() */
- status = create_synthetic_smb_fname(ctx,
- base_name, NULL,
- NULL,
- &smb_fname_dst);
- if (!NT_STATUS_IS_OK(status)) {
+ smb_fname_dst = synthetic_smb_fname(
+ ctx, base_name, NULL, NULL);
+ if (smb_fname_dst == NULL) {
+ status = NT_STATUS_NO_MEMORY;
goto out;
}
}
uint16 num_def_acls;
bool valid_file_acls = True;
bool valid_def_acls = True;
+ NTSTATUS status;
if (total_data < SMB_POSIX_ACL_HEADER_SIZE) {
return NT_STATUS_INVALID_PARAMETER;
return NT_STATUS_INVALID_PARAMETER;
}
+ status = refuse_symlink(conn, fsp, smb_fname->base_name);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
DEBUG(10,("smb_set_posix_acl: file %s num_file_acls = %u, num_def_acls = %u\n",
smb_fname ? smb_fname_str_dbg(smb_fname) : fsp_str_dbg(fsp),
(unsigned int)num_file_acls,
return status;
}
- status = copy_smb_filename(talloc_tos(), smb_fname,
- &smb_fname_tmp);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
+ smb_fname_tmp = cp_smb_filename(talloc_tos(), smb_fname);
+ if (smb_fname_tmp == NULL) {
+ return NT_STATUS_NO_MEMORY;
}
if (SMB_VFS_STAT(conn, smb_fname_tmp) != 0) {
*/
if (raw_unixmode != SMB_MODE_NO_CHANGE) {
+ int ret;
+
DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
"setting mode 0%o for file %s\n",
(unsigned int)unixmode,
smb_fname_str_dbg(smb_fname)));
- if (SMB_VFS_CHMOD(conn, smb_fname->base_name, unixmode) != 0) {
+ if (fsp && fsp->fh->fd != -1) {
+ ret = SMB_VFS_FCHMOD(fsp, unixmode);
+ } else {
+ ret = SMB_VFS_CHMOD(conn, smb_fname->base_name, unixmode);
+ }
+ if (ret != 0) {
return map_nt_error_from_unix(errno);
}
}
(unsigned int)set_owner,
smb_fname_str_dbg(smb_fname)));
- if (S_ISLNK(sbuf.st_ex_mode)) {
+ if (fsp && fsp->fh->fd != -1) {
+ ret = SMB_VFS_FCHOWN(fsp, set_owner, (gid_t)-1);
+ } else {
+ /*
+ * UNIX extensions calls must always operate
+ * on symlinks.
+ */
ret = SMB_VFS_LCHOWN(conn, smb_fname->base_name,
set_owner, (gid_t)-1);
- } else {
- ret = SMB_VFS_CHOWN(conn, smb_fname->base_name,
- set_owner, (gid_t)-1);
}
if (ret != 0) {
if ((set_grp != (uid_t)SMB_GID_NO_CHANGE) &&
(sbuf.st_ex_gid != set_grp)) {
+ int ret;
+
DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
"changing group %u for file %s\n",
(unsigned int)set_owner,
smb_fname_str_dbg(smb_fname)));
- if (SMB_VFS_CHOWN(conn, smb_fname->base_name, (uid_t)-1,
- set_grp) != 0) {
+ if (fsp && fsp->fh->fd != -1) {
+ ret = SMB_VFS_FCHOWN(fsp, set_owner, (gid_t)-1);
+ } else {
+ /*
+ * UNIX extensions calls must always operate
+ * on symlinks.
+ */
+ ret = SMB_VFS_LCHOWN(conn, smb_fname->base_name, (uid_t)-1,
+ set_grp);
+ }
+ if (ret != 0) {
status = map_nt_error_from_unix(errno);
if (delete_on_fail) {
SMB_VFS_UNLINK(conn, smb_fname);
/* File exists open. File not exist create. */
create_disp = FILE_OPEN_IF;
break;
+ case SMB_O_EXCL:
+ /* O_EXCL on its own without O_CREAT is undefined.
+ We deliberately ignore it as some versions of
+ Linux CIFSFS can send a bare O_EXCL on the
+ wire which other filesystems in the kernel
+ ignore. See bug 9519 for details. */
+
+ /* Fallthrough. */
+
case 0:
/* File exists open. File not exist fail. */
create_disp = FILE_OPEN;
break;
- case SMB_O_EXCL:
- /* O_EXCL on its own without O_CREAT is undefined. */
default:
DEBUG(5,("smb_posix_open: invalid create mode 0x%x\n",
(unsigned int)wire_open_mode ));
}
info_level = SVAL(params,2);
- status = copy_smb_filename(talloc_tos(), fsp->fsp_name,
- &smb_fname);
- if (!NT_STATUS_IS_OK(status)) {
- reply_nterror(req, status);
+ smb_fname = cp_smb_filename(talloc_tos(), fsp->fsp_name);
+ if (smb_fname == NULL) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
return;
}
fsp_str_dbg(fsp)));
SSVAL(params,0,0);
- send_trans2_replies(conn, req, params, 2,
+ send_trans2_replies(conn, req, NT_STATUS_OK, params, 2,
*ppdata, 0,
max_data_bytes);
return;
return;
}
- reply_nterror(req, status);
+ /*
+ * Invalid EA name needs to return 2 param bytes,
+ * not a zero-length error packet.
+ */
+ if (NT_STATUS_EQUAL(status, STATUS_INVALID_EA_NAME)) {
+ send_trans2_replies(conn, req, status, params, 2, NULL, 0,
+ max_data_bytes);
+ } else {
+ reply_nterror(req, status);
+ }
return;
}
- send_trans2_replies(conn, req, params, 2, *ppdata, data_return_size,
+ send_trans2_replies(conn, req, NT_STATUS_OK, params, 2, *ppdata, data_return_size,
max_data_bytes);
return;
SSVAL(params,0,0);
- send_trans2_replies(conn, req, params, 2, *ppdata, 0, max_data_bytes);
+ send_trans2_replies(conn, req, NT_STATUS_OK, params, 2, *ppdata, 0, max_data_bytes);
out:
TALLOC_FREE(smb_dname);
if(fnf_handle == 0)
fnf_handle = 257;
- send_trans2_replies(conn, req, params, 6, *ppdata, 0, max_data_bytes);
+ send_trans2_replies(conn, req, NT_STATUS_OK, params, 6, *ppdata, 0, max_data_bytes);
return;
}
SSVAL(params,0,0); /* No changes */
SSVAL(params,2,0); /* No EA errors */
- send_trans2_replies(conn, req, params, 4, *ppdata, 0, max_data_bytes);
+ send_trans2_replies(conn, req, NT_STATUS_OK, params, 4, *ppdata, 0, max_data_bytes);
return;
}
SSVAL((discard_const_p(uint8_t, req->inbuf)), smb_flg2,
SVAL(req->inbuf,smb_flg2) | FLAGS2_DFS_PATHNAMES);
- send_trans2_replies(conn, req,0,0,*ppdata,reply_size, max_data_bytes);
+ send_trans2_replies(conn, req, NT_STATUS_OK, 0,0,*ppdata,reply_size, max_data_bytes);
return;
}
srvstr_push(pdata, req->flags2, pdata+18,
lp_servicename(talloc_tos(), SNUM(conn)), 13,
STR_ASCII|STR_TERMINATE); /* Service name */
- send_trans2_replies(conn, req, *pparams, 0, *ppdata, 32,
+ send_trans2_replies(conn, req, NT_STATUS_OK, *pparams, 0, *ppdata, 32,
max_data_bytes);
return;
}