#include "includes.h"
#include "ntioctl.h"
#include "system/filesys.h"
+#include "lib/util/time_basic.h"
#include "version.h"
#include "smbd/smbd.h"
#include "smbd/globals.h"
#include "lib/util_ea.h"
#include "lib/readdir_attr.h"
#include "messages.h"
+#include "smb1_utils.h"
+#include "libcli/smb/smb2_posix.h"
#define DIR_ENTRY_SAFETY_MARGIN 4096
return NT_STATUS_OK;
}
-/********************************************************************
- The canonical "check access" based on object handle or path function.
-********************************************************************/
+#if defined(HAVE_POSIX_ACLS)
+/****************************************************************************
+ Utility function to open a fsp for a POSIX handle operation.
+****************************************************************************/
-NTSTATUS check_access(connection_struct *conn,
- files_struct *fsp,
- const struct smb_filename *smb_fname,
- uint32_t access_mask)
+static NTSTATUS get_posix_fsp(connection_struct *conn,
+ struct smb_request *req,
+ const struct smb_filename *smb_fname,
+ uint32_t access_mask,
+ files_struct **ret_fsp)
{
NTSTATUS status;
+ struct smb_filename *smb_fname_tmp = NULL;
+ uint32_t create_disposition = FILE_OPEN;
+ uint32_t share_access = FILE_SHARE_READ|
+ FILE_SHARE_WRITE|
+ FILE_SHARE_DELETE;
+ struct smb2_create_blobs *posx = NULL;
- if (fsp) {
- status = check_access_fsp(fsp, access_mask);
- } else {
- status = smbd_check_access_rights(conn, smb_fname,
- false, access_mask);
+ /*
+ * Only FILE_FLAG_POSIX_SEMANTICS matters on existing files,
+ * but set reasonable defaults.
+ */
+ uint32_t file_attributes = 0664;
+ uint32_t oplock = NO_OPLOCK;
+ uint32_t create_options = FILE_NON_DIRECTORY_FILE;
+
+ /* File or directory must exist. */
+ if (!VALID_STAT(smb_fname->st)) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+ /* Cannot be a symlink. */
+ if (S_ISLNK(smb_fname->st.st_ex_mode)) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ /* Set options correctly for directory open. */
+ if (S_ISDIR(smb_fname->st.st_ex_mode)) {
+ /*
+ * Only FILE_FLAG_POSIX_SEMANTICS matters on existing
+ * directories, but set reasonable defaults.
+ */
+ file_attributes = 0775;
+ create_options = FILE_DIRECTORY_FILE;
+ }
+
+ /* Createfile uses a non-const smb_fname. */
+ smb_fname_tmp = cp_smb_filename(talloc_tos(),
+ smb_fname);
+ if (smb_fname_tmp == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ status = make_smb2_posix_create_ctx(
+ talloc_tos(), &posx, file_attributes);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
+ nt_errstr(status));
+ goto done;
}
+ status = SMB_VFS_CREATE_FILE(
+ conn, /* conn */
+ req, /* req */
+ 0, /* root_dir_fid */
+ smb_fname_tmp, /* fname */
+ access_mask, /* access_mask */
+ share_access, /* share_access */
+ create_disposition,/* create_disposition*/
+ create_options, /* create_options */
+ file_attributes,/* file_attributes */
+ oplock, /* oplock_request */
+ NULL, /* lease */
+ 0, /* allocation_size */
+ 0, /* private_flags */
+ NULL, /* sd */
+ NULL, /* ea_list */
+ ret_fsp, /* result */
+ NULL, /* pinfo */
+ posx, /* in_context */
+ NULL); /* out_context */
+
+done:
+ TALLOC_FREE(posx);
+ TALLOC_FREE(smb_fname_tmp);
return status;
}
+#endif
+
+/********************************************************************
+ The canonical "check access" based on path.
+********************************************************************/
+
+static NTSTATUS check_access(connection_struct *conn,
+ struct files_struct *dirfsp,
+ const struct smb_filename *smb_fname,
+ uint32_t access_mask)
+{
+ SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
+ return smbd_check_access_rights(conn,
+ dirfsp,
+ smb_fname,
+ false,
+ access_mask);
+}
/********************************************************************
Roundup a value to the nearest allocation roundup size boundary.
return val;
}
-/********************************************************************
- Create a 64 bit FileIndex. If the file is on the same device as
- the root of the share, just return the 64-bit inode. If it isn't,
- mangle as we used to do.
-********************************************************************/
-
-uint64_t get_FileIndex(connection_struct *conn, const SMB_STRUCT_STAT *psbuf)
-{
- uint64_t file_index;
- if (conn->sconn->aapl_zero_file_id) {
- return 0;
- }
- if (conn->base_share_dev == psbuf->st_ex_dev) {
- return (uint64_t)psbuf->st_ex_ino;
- }
- file_index = ((psbuf->st_ex_ino) & UINT32_MAX); /* FileIndexLow */
- file_index |= ((uint64_t)((psbuf->st_ex_dev) & UINT32_MAX)) << 32; /* FileIndexHigh */
- return file_index;
-}
-
-
-/********************************************************************
- Globally (for this connection / multi-channel) disable file-ID
- calculation. This is required to be global because it serves
- Macs in AAPL mode, which is globally set.
-********************************************************************/
-void aapl_force_zero_file_id(struct smbd_server_connection *sconn)
-{
- sconn->aapl_zero_file_id = true;
-}
-
/****************************************************************************
Utility functions for dealing with extended attributes.
****************************************************************************/
SCVAL(p,1,dos_namelen);
SSVAL(p,2,ea_list->ea.value.length);
strlcpy(p+4, dos_ea_name, dos_namelen+1);
- memcpy( p + 4 + dos_namelen + 1, ea_list->ea.value.data, ea_list->ea.value.length);
+ if (ea_list->ea.value.length > 0) {
+ memcpy(p + 4 + dos_namelen + 1,
+ ea_list->ea.value.data,
+ ea_list->ea.value.length);
+ }
total_data_size -= 4 + dos_namelen + 1 + ea_list->ea.value.length;
p += 4 + dos_namelen + 1 + ea_list->ea.value.length;
return status;
}
- status = check_access(conn, fsp, smb_fname, FILE_WRITE_EA);
+ if (fsp != NULL) {
+ status = check_access_fsp(fsp, FILE_WRITE_EA);
+ } else {
+ status = check_access(conn,
+ conn->cwd_fsp,
+ smb_fname,
+ FILE_WRITE_EA);
+ }
if (!NT_STATUS_IS_OK(status)) {
return status;
}
/* We have re-scheduled this call. */
goto out;
}
- reply_openerror(req, status);
- goto out;
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
+ reply_openerror(req, status);
+ goto out;
+ }
+
+ fsp = fcb_or_dos_open(
+ req,
+ smb_fname,
+ access_mask,
+ create_options,
+ private_flags);
+ if (fsp == NULL) {
+ bool ok = defer_smb1_sharing_violation(req);
+ if (ok) {
+ goto out;
+ }
+ reply_openerror(req, status);
+ goto out;
+ }
+
+ smb_action = FILE_WAS_OPENED;
}
size = get_file_size_stat(&smb_fname->st);
Map wire perms onto standard UNIX permissions. Obey share restrictions.
****************************************************************************/
-enum perm_type { PERM_NEW_FILE, PERM_NEW_DIR, PERM_EXISTING_FILE, PERM_EXISTING_DIR};
-
-static NTSTATUS unix_perms_from_wire( connection_struct *conn,
- const SMB_STRUCT_STAT *psbuf,
- uint32_t perms,
- enum perm_type ptype,
- mode_t *ret_perms)
+NTSTATUS unix_perms_from_wire(connection_struct *conn,
+ const SMB_STRUCT_STAT *psbuf,
+ uint32_t perms,
+ enum perm_type ptype,
+ mode_t *ret_perms)
{
mode_t ret = 0;
uint32_t reskey=0;
uint64_t file_size = 0;
uint64_t allocation_size = 0;
- uint64_t file_index = 0;
+ uint64_t file_id = 0;
size_t len = 0;
struct timespec mdate_ts = {0};
struct timespec adate_ts = {0};
}
}
- file_index = get_FileIndex(conn, &smb_fname->st);
+ file_id = SMB_VFS_FS_FILE_ID(conn, &smb_fname->st);
mdate_ts = smb_fname->st.st_ex_mtime;
adate_ts = smb_fname->st.st_ex_atime;
was_8_3 = mangle_is_8_3(fname, True, conn->params);
p += 4;
SIVAL(p,0,reskey); p += 4;
- put_long_date_timespec(conn->ts_res,p,create_date_ts); p += 8;
- put_long_date_timespec(conn->ts_res,p,adate_ts); p += 8;
- put_long_date_timespec(conn->ts_res,p,mdate_ts); p += 8;
- put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8;
+ put_long_date_full_timespec(conn->ts_res,p,&create_date_ts); p += 8;
+ put_long_date_full_timespec(conn->ts_res,p,&adate_ts); p += 8;
+ put_long_date_full_timespec(conn->ts_res,p,&mdate_ts); p += 8;
+ put_long_date_full_timespec(conn->ts_res,p,&cdate_ts); p += 8;
SOFF_T(p,0,file_size); p += 8;
SOFF_T(p,0,allocation_size); p += 8;
SIVAL(p,0,mode); p += 4;
DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_DIRECTORY_INFO\n"));
p += 4;
SIVAL(p,0,reskey); p += 4;
- put_long_date_timespec(conn->ts_res,p,create_date_ts); p += 8;
- put_long_date_timespec(conn->ts_res,p,adate_ts); p += 8;
- put_long_date_timespec(conn->ts_res,p,mdate_ts); p += 8;
- put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8;
+ put_long_date_full_timespec(conn->ts_res,p,&create_date_ts); p += 8;
+ put_long_date_full_timespec(conn->ts_res,p,&adate_ts); p += 8;
+ put_long_date_full_timespec(conn->ts_res,p,&mdate_ts); p += 8;
+ put_long_date_full_timespec(conn->ts_res,p,&cdate_ts); p += 8;
SOFF_T(p,0,file_size); p += 8;
SOFF_T(p,0,allocation_size); p += 8;
SIVAL(p,0,mode); p += 4;
DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_FULL_DIRECTORY_INFO\n"));
p += 4;
SIVAL(p,0,reskey); p += 4;
- put_long_date_timespec(conn->ts_res,p,create_date_ts); p += 8;
- put_long_date_timespec(conn->ts_res,p,adate_ts); p += 8;
- put_long_date_timespec(conn->ts_res,p,mdate_ts); p += 8;
- put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8;
+ put_long_date_full_timespec(conn->ts_res,p,&create_date_ts); p += 8;
+ put_long_date_full_timespec(conn->ts_res,p,&adate_ts); p += 8;
+ put_long_date_full_timespec(conn->ts_res,p,&mdate_ts); p += 8;
+ put_long_date_full_timespec(conn->ts_res,p,&cdate_ts); p += 8;
SOFF_T(p,0,file_size); p += 8;
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;
status = srvstr_push(base_data, flags2, p,
fname, PTR_DIFF(end_data, p),
STR_TERMINATE_ASCII, &len);
DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_ID_FULL_DIRECTORY_INFO\n"));
p += 4;
SIVAL(p,0,reskey); p += 4;
- put_long_date_timespec(conn->ts_res,p,create_date_ts); p += 8;
- put_long_date_timespec(conn->ts_res,p,adate_ts); p += 8;
- put_long_date_timespec(conn->ts_res,p,mdate_ts); p += 8;
- put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8;
+ put_long_date_full_timespec(conn->ts_res,p,&create_date_ts); p += 8;
+ put_long_date_full_timespec(conn->ts_res,p,&adate_ts); p += 8;
+ put_long_date_full_timespec(conn->ts_res,p,&mdate_ts); p += 8;
+ put_long_date_full_timespec(conn->ts_res,p,&cdate_ts); p += 8;
SOFF_T(p,0,file_size); p += 8;
SOFF_T(p,0,allocation_size); p += 8;
SIVAL(p,0,mode); p += 4;
}
p += 4;
SIVAL(p,0,0); p += 4; /* Unknown - reserved ? */
- SBVAL(p,0,file_index); p += 8;
+ SBVAL(p,0,file_id); p += 8;
status = srvstr_push(base_data, flags2, p,
fname, PTR_DIFF(end_data, p),
STR_TERMINATE_ASCII, &len);
was_8_3 = mangle_is_8_3(fname, True, conn->params);
p += 4;
SIVAL(p,0,reskey); p += 4;
- put_long_date_timespec(conn->ts_res,p,create_date_ts); p += 8;
- put_long_date_timespec(conn->ts_res,p,adate_ts); p += 8;
- put_long_date_timespec(conn->ts_res,p,mdate_ts); p += 8;
- put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8;
+ put_long_date_full_timespec(conn->ts_res,p,&create_date_ts); p += 8;
+ put_long_date_full_timespec(conn->ts_res,p,&adate_ts); p += 8;
+ put_long_date_full_timespec(conn->ts_res,p,&mdate_ts); p += 8;
+ put_long_date_full_timespec(conn->ts_res,p,&cdate_ts); p += 8;
SOFF_T(p,0,file_size); p += 8;
SOFF_T(p,0,allocation_size); p += 8;
SIVAL(p,0,mode); p += 4;
}
p += 2;
- SBVAL(p,0,file_index); p += 8;
+ SBVAL(p,0,file_id); p += 8;
status = srvstr_push(base_data, flags2, p,
fname, PTR_DIFF(end_data, p),
STR_TERMINATE_ASCII, &len);
bool mask_contains_wcard = False;
struct ea_list *ea_list = NULL;
NTSTATUS ntstatus = NT_STATUS_OK;
- bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
- struct dptr_struct *dirptr = NULL;
+ bool ask_sharemode = lp_smbd_search_ask_sharemode(SNUM(conn));
struct smbd_server_connection *sconn = req->sconn;
- uint32_t ucf_flags = UCF_SAVE_LCOMP | UCF_ALWAYS_ALLOW_WCARD_LCOMP |
+ uint32_t ucf_flags = UCF_ALWAYS_ALLOW_WCARD_LCOMP |
ucf_flags_from_smb_request(req);
bool backup_priv = false;
bool as_root = false;
+ files_struct *fsp = NULL;
+ const struct loadparm_substitution *lp_sub =
+ loadparm_s3_global_substitution();
+ int ret;
if (total_params < 13) {
reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
goto out;
}
- mask = smb_dname->original_lcomp;
+ mask = get_original_lcomp(talloc_tos(),
+ conn,
+ directory,
+ ucf_flags);
+ if (mask == NULL) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ goto out;
+ }
directory = smb_dname->base_name;
}
params = *pparams;
+ /*
+ * As we've cut off the last component from
+ * smb_fname we need to re-stat smb_dname
+ * so FILE_OPEN disposition knows the directory
+ * exists.
+ */
+ if (req->posix_pathnames) {
+ ret = SMB_VFS_LSTAT(conn, smb_dname);
+ } else {
+ ret = SMB_VFS_STAT(conn, smb_dname);
+ }
+
+ if (ret == -1) {
+ ntstatus = map_nt_error_from_unix(errno);
+ reply_nterror(req, ntstatus);
+ goto out;
+ }
+
+ /*
+ * Open an fsp on this directory for the dptr.
+ */
+ ntstatus = SMB_VFS_CREATE_FILE(
+ conn, /* conn */
+ req, /* req */
+ 0, /* root_dir_fid */
+ smb_dname, /* dname */
+ FILE_LIST_DIRECTORY, /* access_mask */
+ FILE_SHARE_READ|
+ FILE_SHARE_WRITE, /* share_access */
+ FILE_OPEN, /* create_disposition*/
+ FILE_DIRECTORY_FILE, /* create_options */
+ FILE_ATTRIBUTE_DIRECTORY,/* file_attributes */
+ NO_OPLOCK, /* oplock_request */
+ NULL, /* lease */
+ 0, /* allocation_size */
+ 0, /* private_flags */
+ NULL, /* sd */
+ NULL, /* ea_list */
+ &fsp, /* result */
+ NULL, /* pinfo */
+ NULL, /* in_context */
+ NULL);/* out_context */
+
+ if (!NT_STATUS_IS_OK(ntstatus)) {
+ DBG_ERR("failed to open directory %s\n",
+ smb_fname_str_dbg(smb_dname));
+ reply_nterror(req, ntstatus);
+ goto out;
+ }
+
/* Save the wildcard match and attribs we are using on this directory -
needed as lanman2 assumes these are being saved between calls */
ntstatus = dptr_create(conn,
req,
- NULL, /* fsp */
- smb_dname,
+ fsp, /* fsp */
False,
True,
req->smbpid,
mask,
mask_contains_wcard,
dirtype,
- &dirptr);
+ &fsp->dptr);
if (!NT_STATUS_IS_OK(ntstatus)) {
+ /*
+ * Use NULL here for the first parameter (req)
+ * as this is not a client visible handle so
+ * can'tbe part of an SMB1 chain.
+ */
+ close_file(NULL, fsp, NORMAL_CLOSE);
+ fsp = NULL;
reply_nterror(req, ntstatus);
goto out;
}
if (backup_priv) {
/* Remember this in case we have
to do a findnext. */
- dptr_set_priv(dirptr);
+ dptr_set_priv(fsp->dptr);
}
- dptr_num = dptr_dnum(dirptr);
+ dptr_num = dptr_dnum(fsp->dptr);
DEBUG(4,("dptr_num is %d, wcard = %s, attr = %d\n", dptr_num, mask, dirtype));
/* We don't need to check for VOL here as this is returned by
a different TRANS2 call. */
DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
- directory,lp_dont_descend(talloc_tos(), SNUM(conn))));
+ directory,lp_dont_descend(talloc_tos(), lp_sub, SNUM(conn))));
if (in_list(directory,
- lp_dont_descend(talloc_tos(), SNUM(conn)),
+ lp_dont_descend(talloc_tos(), lp_sub, SNUM(conn)),
conn->case_sensitive)) {
dont_descend = True;
}
} else {
ntstatus = get_lanman2_dir_entry(talloc_tos(),
conn,
- dirptr,
+ fsp->dptr,
req->flags2,
mask,dirtype,info_level,
requires_resume_key,dont_descend,
/* Check if we can close the dirptr */
if(close_after_first || (finished && close_if_end)) {
DEBUG(5,("call_trans2findfirst - (2) closing dptr_num %d\n", dptr_num));
- dptr_close(sconn, &dptr_num);
+ dptr_num = -1;
+ close_file(NULL, fsp, NORMAL_CLOSE);
+ fsp = NULL;
}
/*
*/
if(numentries == 0) {
- dptr_close(sconn, &dptr_num);
+ dptr_num = -1;
+ /*
+ * We may have already closed the file in the
+ * close_after_first or finished case above.
+ */
+ if (fsp != NULL) {
+ close_file(NULL, fsp, NORMAL_CLOSE);
+ fsp = NULL;
+ }
if (get_Protocol() < PROTOCOL_NT1) {
reply_force_doserror(req, ERRDOS, ERRnofiles);
goto out;
int space_remaining;
struct ea_list *ea_list = NULL;
NTSTATUS ntstatus = NT_STATUS_OK;
- bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
+ bool ask_sharemode = lp_smbd_search_ask_sharemode(SNUM(conn));
TALLOC_CTX *ctx = talloc_tos();
- struct dptr_struct *dirptr;
struct smbd_server_connection *sconn = req->sconn;
bool backup_priv = false;
bool as_root = false;
+ files_struct *fsp = NULL;
+ const struct loadparm_substitution *lp_sub =
+ loadparm_s3_global_substitution();
if (total_params < 13) {
reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
params = *pparams;
/* Check that the dptr is valid */
- if(!(dirptr = dptr_fetch_lanman2(sconn, dptr_num))) {
+ fsp = dptr_fetch_lanman2_fsp(sconn, dptr_num);
+ if (fsp == NULL) {
reply_nterror(req, STATUS_NO_MORE_FILES);
return;
}
/* Get the attr mask from the dptr */
dirtype = dptr_attr(sconn, dptr_num);
- backup_priv = dptr_get_priv(dirptr);
+ backup_priv = dptr_get_priv(fsp->dptr);
DEBUG(3,("dptr_num is %d, mask = %s, attr = %x, dirptr=(0x%lX,%ld) "
"backup_priv = %d\n",
dptr_num, mask, dirtype,
- (long)dirptr,
- dptr_TellDir(dirptr),
+ (long)fsp->dptr,
+ dptr_TellDir(fsp->dptr),
(int)backup_priv));
/* We don't need to check for VOL here as this is returned by
a different TRANS2 call. */
DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
- directory,lp_dont_descend(ctx, SNUM(conn))));
- if (in_list(directory,lp_dont_descend(ctx, SNUM(conn)),conn->case_sensitive))
+ directory,lp_dont_descend(ctx, lp_sub, SNUM(conn))));
+ if (in_list(directory,lp_dont_descend(ctx, lp_sub, SNUM(conn)),conn->case_sensitive))
dont_descend = True;
p = pdata;
* should already be at the correct place.
*/
- finished = !dptr_SearchDir(dirptr, resume_name, ¤t_pos, &st);
+ finished = !dptr_SearchDir(fsp->dptr, resume_name, ¤t_pos, &st);
} /* end if resume_name && !continue_bit */
for (i=0;(i<(int)maxentries) && !finished && !out_of_space ;i++) {
bool got_exact_match = False;
- /* this is a heuristic to avoid seeking the dirptr except when
+ /* this is a heuristic to avoid seeking the fsp->dptr except when
absolutely necessary. It allows for a filename of about 40 chars */
if (space_remaining < DIRLEN_GUESS && numentries > 0) {
out_of_space = True;
} else {
ntstatus = get_lanman2_dir_entry(ctx,
conn,
- dirptr,
+ fsp->dptr,
req->flags2,
mask,dirtype,info_level,
requires_resume_key,dont_descend,
smb_fn_name(req->cmd),
mask, directory, dirtype, numentries ) );
- /* Check if we can close the dirptr */
+ /* Check if we can close the fsp->dptr */
if(close_after_request || (finished && close_if_end)) {
DEBUG(5,("call_trans2findnext: closing dptr_num = %d\n", dptr_num));
- dptr_close(sconn, &dptr_num); /* This frees up the saved mask */
+ dptr_num = -1;
+ close_file(NULL, fsp, NORMAL_CLOSE);
+ fsp = NULL;
}
if (as_root) {
unsigned char *create_volume_objectid(connection_struct *conn, unsigned char objid[16])
{
- E_md4hash(lp_servicename(talloc_tos(), SNUM(conn)),objid);
+ const struct loadparm_substitution *lp_sub =
+ loadparm_s3_global_substitution();
+
+ E_md4hash(lp_servicename(talloc_tos(), lp_sub, SNUM(conn)),objid);
return objid;
}
char **ppdata,
int *ret_data_len)
{
+ const struct loadparm_substitution *lp_sub =
+ loadparm_s3_global_substitution();
char *pdata, *end_data;
int data_len = 0;
size_t len = 0;
* Add volume serial number - hash of a combination of
* the called hostname and the service name.
*/
- SIVAL(pdata,0,str_checksum(lp_servicename(talloc_tos(), snum)) ^ (str_checksum(get_local_machine_name())<<16) );
+ SIVAL(pdata,0,str_checksum(lp_servicename(talloc_tos(), lp_sub, snum)) ^ (str_checksum(get_local_machine_name())<<16) );
/*
* Win2k3 and previous mess this up by sending a name length
* one byte short. I believe only older clients (OS/2 Win9x) use
* Add volume serial number - hash of a combination of
* the called hostname and the service name.
*/
- SIVAL(pdata,8,str_checksum(lp_servicename(talloc_tos(), snum)) ^
+ SIVAL(pdata,8,str_checksum(lp_servicename(talloc_tos(), lp_sub, snum)) ^
(str_checksum(get_local_machine_name())<<16));
/* Max label len is 32 characters. */
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)));
+ lp_servicename(talloc_tos(), lp_sub, snum)));
if (max_data_bytes >= 24 && data_len > max_data_bytes) {
/* the client only requested a portion of the
volume label */
if (get_current_uid(conn) != 0) {
DEBUG(0,("get_user_quota: access_denied "
"service [%s] user [%s]\n",
- lp_servicename(talloc_tos(), SNUM(conn)),
+ lp_servicename(talloc_tos(), lp_sub, SNUM(conn)),
conn->session_info->unix_info->unix_name));
return NT_STATUS_ACCESS_DENIED;
}
status = vfs_get_ntquota(&fsp, SMB_USER_FS_QUOTA_TYPE,
NULL, "as);
if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0,("vfs_get_ntquota() failed for service [%s]\n",lp_servicename(talloc_tos(), SNUM(conn))));
+ DEBUG(0,("vfs_get_ntquota() failed for service [%s]\n",lp_servicename(talloc_tos(), lp_sub, SNUM(conn))));
return status;
}
data_len = 48;
DEBUG(10,("SMB_FS_QUOTA_INFORMATION: for service [%s]\n",
- lp_servicename(talloc_tos(), SNUM(conn))));
+ lp_servicename(talloc_tos(), lp_sub, SNUM(conn))));
/* Unknown1 24 NULL bytes*/
SBIG_UINT(pdata,0,(uint64_t)0);
return NT_STATUS_INVALID_LEVEL;
#endif /* EOPNOTSUPP */
} else {
- DEBUG(0,("vfs_statvfs() failed for service [%s]\n",lp_servicename(talloc_tos(), SNUM(conn))));
+ DEBUG(0,("vfs_statvfs() failed for service [%s]\n",lp_servicename(talloc_tos(), lp_sub, SNUM(conn))));
return NT_STATUS_DOS(ERRSRV, ERRerror);
}
break;
files_struct *fsp,
const DATA_BLOB *qdata)
{
+ const struct loadparm_substitution *lp_sub =
+ loadparm_s3_global_substitution();
NTSTATUS status;
SMB_NTQUOTA_STRUCT quotas;
/* access check */
if ((get_current_uid(conn) != 0) || !CAN_WRITE(conn)) {
DEBUG(3, ("set_fsquota: access_denied service [%s] user [%s]\n",
- lp_servicename(talloc_tos(), SNUM(conn)),
+ lp_servicename(talloc_tos(), lp_sub, SNUM(conn)),
conn->session_info->unix_info->unix_name));
return NT_STATUS_ACCESS_DENIED;
}
/* now set the quotas */
if (vfs_set_ntquota(fsp, SMB_USER_FS_QUOTA_TYPE, NULL, "as)!=0) {
DEBUG(1, ("vfs_set_ntquota() failed for service [%s]\n",
- lp_servicename(talloc_tos(), SNUM(conn))));
+ lp_servicename(talloc_tos(), lp_sub, SNUM(conn))));
status = map_nt_error_from_unix(errno);
} else {
status = NT_STATUS_OK;
char **ppdata, int total_data,
unsigned int max_data_bytes)
{
+ const struct loadparm_substitution *lp_sub =
+ loadparm_s3_global_substitution();
struct smbXsrv_connection *xconn = req->xconn;
char *pdata = *ppdata;
char *params = *pparams;
uint16_t info_level;
DEBUG(10,("call_trans2setfsinfo: for service [%s]\n",
- lp_servicename(talloc_tos(), SNUM(conn))));
+ lp_servicename(talloc_tos(), lp_sub, SNUM(conn))));
/* */
if (total_params < 4) {
files_struct *fsp,
const SMB_STRUCT_STAT *psbuf)
{
- uint64_t file_index = get_FileIndex(conn, psbuf);
dev_t devno;
DEBUG(10,("store_file_unix_basic: SMB_QUERY_FILE_UNIX_BASIC\n"));
SOFF_T(pdata,0,SMB_VFS_GET_ALLOC_SIZE(conn,fsp,psbuf)); /* Number of bytes used on disk - 64 Bit */
pdata += 8;
- put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER, pdata, psbuf->st_ex_ctime); /* Change Time 64 Bit */
- put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER ,pdata+8, psbuf->st_ex_atime); /* Last access time 64 Bit */
- put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER, pdata+16, psbuf->st_ex_mtime); /* Last modification time 64 Bit */
+ put_long_date_full_timespec(TIMESTAMP_SET_NT_OR_BETTER, pdata, &psbuf->st_ex_ctime); /* Change Time 64 Bit */
+ put_long_date_full_timespec(TIMESTAMP_SET_NT_OR_BETTER ,pdata+8, &psbuf->st_ex_atime); /* Last access time 64 Bit */
+ put_long_date_full_timespec(TIMESTAMP_SET_NT_OR_BETTER, pdata+16, &psbuf->st_ex_mtime); /* Last modification time 64 Bit */
pdata += 24;
SIVAL(pdata,0,psbuf->st_ex_uid); /* user id for the owner */
SIVAL(pdata,4,0);
pdata += 8;
- SINO_T_VAL(pdata,0,(SMB_INO_T)file_index); /* inode number */
+ SINO_T_VAL(pdata, 0, psbuf->st_ex_ino); /* inode number */
pdata += 8;
SIVAL(pdata,0, unix_perms_to_wire(psbuf->st_ex_mode)); /* Standard UNIX file permissions */
pdata = store_file_unix_basic(conn, pdata, fsp, psbuf);
/* Create (birth) time 64 bit */
- put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER,pdata, psbuf->st_ex_btime);
+ put_long_date_full_timespec(TIMESTAMP_SET_NT_OR_BETTER,pdata, &psbuf->st_ex_btime);
pdata += 8;
map_info2_flags_from_sbuf(psbuf, &file_flags, &flags_mask);
return NT_STATUS_OK;
}
+#if defined(HAVE_POSIX_ACLS)
+static NTSTATUS smb_query_posix_acl(connection_struct *conn,
+ struct smb_request *req,
+ files_struct *fsp,
+ struct smb_filename *smb_fname,
+ char *pdata,
+ unsigned int data_size_in,
+ unsigned int *pdata_size_out)
+{
+ SMB_ACL_T file_acl = NULL;
+ SMB_ACL_T def_acl = NULL;
+ uint16_t num_file_acls = 0;
+ uint16_t num_def_acls = 0;
+ unsigned int size_needed = 0;
+ NTSTATUS status;
+ bool ok;
+ bool close_fsp = false;
+
+ /*
+ * Ensure we always operate on a file descriptor, not just
+ * the filename.
+ */
+ if (fsp == NULL) {
+ uint32_t access_mask = SEC_STD_READ_CONTROL|
+ FILE_READ_ATTRIBUTES|
+ FILE_WRITE_ATTRIBUTES;
+
+ status = get_posix_fsp(conn,
+ req,
+ smb_fname,
+ access_mask,
+ &fsp);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ goto out;
+ }
+ close_fsp = true;
+ }
+
+ SMB_ASSERT(fsp != NULL);
+
+ status = refuse_symlink(conn,
+ fsp,
+ fsp->fsp_name);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto out;
+ }
+
+ file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp,
+ talloc_tos());
+
+ if (file_acl == NULL && no_acl_syscall_error(errno)) {
+ DBG_INFO("ACLs not implemented on "
+ "filesystem containing %s\n",
+ fsp_str_dbg(fsp));
+ status = NT_STATUS_NOT_IMPLEMENTED;
+ goto out;
+ }
+
+ if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
+ /*
+ * We can only have default POSIX ACLs on
+ * directories.
+ */
+ if (!fsp->fsp_flags.is_directory) {
+ DBG_INFO("Non-directory open %s\n",
+ fsp_str_dbg(fsp));
+ status = NT_STATUS_INVALID_HANDLE;
+ goto out;
+ }
+ def_acl = SMB_VFS_SYS_ACL_GET_FILE(conn,
+ fsp->fsp_name,
+ SMB_ACL_TYPE_DEFAULT,
+ talloc_tos());
+ def_acl = free_empty_sys_acl(conn, def_acl);
+ }
+
+ num_file_acls = count_acl_entries(conn, file_acl);
+ num_def_acls = count_acl_entries(conn, def_acl);
+
+ /* Wrap checks. */
+ if (num_file_acls + num_def_acls < num_file_acls) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto out;
+ }
+
+ size_needed = num_file_acls + num_def_acls;
+
+ /*
+ * (size_needed * SMB_POSIX_ACL_ENTRY_SIZE) must be less
+ * than UINT_MAX, so check by division.
+ */
+ if (size_needed > (UINT_MAX/SMB_POSIX_ACL_ENTRY_SIZE)) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto out;
+ }
+
+ size_needed = size_needed*SMB_POSIX_ACL_ENTRY_SIZE;
+ if (size_needed + SMB_POSIX_ACL_HEADER_SIZE < size_needed) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto out;
+ }
+ size_needed += SMB_POSIX_ACL_HEADER_SIZE;
+
+ if ( data_size_in < size_needed) {
+ DBG_INFO("data_size too small (%u) need %u\n",
+ data_size_in,
+ size_needed);
+ status = NT_STATUS_BUFFER_TOO_SMALL;
+ goto out;
+ }
+
+ SSVAL(pdata,0,SMB_POSIX_ACL_VERSION);
+ SSVAL(pdata,2,num_file_acls);
+ SSVAL(pdata,4,num_def_acls);
+ pdata += SMB_POSIX_ACL_HEADER_SIZE;
+
+ ok = marshall_posix_acl(conn,
+ pdata,
+ &fsp->fsp_name->st,
+ file_acl);
+ if (!ok) {
+ status = NT_STATUS_INTERNAL_ERROR;
+ goto out;
+ }
+ pdata += (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE);
+
+ ok = marshall_posix_acl(conn,
+ pdata,
+ &fsp->fsp_name->st,
+ def_acl);
+ if (!ok) {
+ status = NT_STATUS_INTERNAL_ERROR;
+ goto out;
+ }
+
+ *pdata_size_out = size_needed;
+ status = NT_STATUS_OK;
+
+ out:
+
+ if (close_fsp) {
+ /*
+ * Ensure the stat struct in smb_fname is up to
+ * date. Structure copy.
+ */
+ smb_fname->st = fsp->fsp_name->st;
+ (void)close_file(req, fsp, NORMAL_CLOSE);
+ fsp = NULL;
+ }
+
+ TALLOC_FREE(file_acl);
+ TALLOC_FREE(def_acl);
+ return status;
+}
+#endif
+
/****************************************************************************
Reply to a TRANSACT2_QFILEINFO on a PIPE !
****************************************************************************/
NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
TALLOC_CTX *mem_ctx,
+ struct smb_request *req,
uint16_t info_level,
files_struct *fsp,
struct smb_filename *smb_fname,
uint64_t file_size = 0;
uint64_t pos = 0;
uint64_t allocation_size = 0;
- uint64_t file_index = 0;
+ uint64_t file_id = 0;
uint32_t access_mask = 0;
size_t len = 0;
dstart = pdata;
dend = dstart + data_size - 1;
- if (!null_timespec(write_time_ts) && !INFO_LEVEL_IS_UNIX(info_level)) {
+ if (!is_omit_timespec(&write_time_ts) &&
+ !INFO_LEVEL_IS_UNIX(info_level))
+ {
update_stat_ex_mtime(psbuf, write_time_ts);
}
I think this causes us to fail the IFSKIT
BasicFileInformationTest. -tpot */
- file_index = get_FileIndex(conn, psbuf);
+ file_id = SMB_VFS_FS_FILE_ID(conn, psbuf);
*fixed_portion = 0;
data_size = 40;
SIVAL(pdata,36,0);
}
- put_long_date_timespec(conn->ts_res,pdata,create_time_ts);
- put_long_date_timespec(conn->ts_res,pdata+8,atime_ts);
- put_long_date_timespec(conn->ts_res,pdata+16,mtime_ts); /* write time */
- put_long_date_timespec(conn->ts_res,pdata+24,ctime_ts); /* change time */
+ put_long_date_full_timespec(conn->ts_res,pdata,&create_time_ts);
+ put_long_date_full_timespec(conn->ts_res,pdata+8,&atime_ts);
+ put_long_date_full_timespec(conn->ts_res,pdata+16,&mtime_ts); /* write time */
+ put_long_date_full_timespec(conn->ts_res,pdata+24,&ctime_ts); /* change time */
SIVAL(pdata,32,mode);
DEBUG(5,("SMB_QFBI - "));
break;
}
+ case SMB_FILE_NORMALIZED_NAME_INFORMATION:
+ {
+ char *nfname = NULL;
+
+ if (fsp == NULL || !fsp->conn->sconn->using_smb2) {
+ return NT_STATUS_INVALID_LEVEL;
+ }
+
+ nfname = talloc_strdup(mem_ctx, smb_fname->base_name);
+ if (nfname == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (ISDOT(nfname)) {
+ nfname[0] = '\0';
+ }
+ string_replace(nfname, '/', '\\');
+
+ if (smb_fname->stream_name != NULL) {
+ const char *s = smb_fname->stream_name;
+ const char *e = NULL;
+ size_t n;
+
+ SMB_ASSERT(s[0] != '\0');
+
+ /*
+ * smb_fname->stream_name is in form
+ * of ':StrEam:$DATA', but we should only
+ * append ':StrEam' here.
+ */
+
+ e = strchr(&s[1], ':');
+ if (e == NULL) {
+ n = strlen(s);
+ } else {
+ n = PTR_DIFF(e, s);
+ }
+ nfname = talloc_strndup_append(nfname, s, n);
+ if (nfname == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ status = srvstr_push(dstart, flags2,
+ pdata+4, nfname,
+ PTR_DIFF(dend, pdata+4),
+ STR_UNICODE, &len);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_NORMALIZED_NAME_INFORMATION\n"));
+ data_size = 4 + len;
+ SIVAL(pdata,0,len);
+ *fixed_portion = 8;
+ break;
+ }
+
case SMB_FILE_ALLOCATION_INFORMATION:
case SMB_QUERY_FILE_ALLOCATION_INFO:
DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALLOCATION_INFORMATION\n"));
unsigned int ea_size =
estimate_ea_size(conn, fsp, smb_fname);
DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALL_INFORMATION\n"));
- put_long_date_timespec(conn->ts_res,pdata,create_time_ts);
- put_long_date_timespec(conn->ts_res,pdata+8,atime_ts);
- put_long_date_timespec(conn->ts_res,pdata+16,mtime_ts); /* write time */
- put_long_date_timespec(conn->ts_res,pdata+24,ctime_ts); /* change time */
+ put_long_date_full_timespec(conn->ts_res,pdata,&create_time_ts);
+ put_long_date_full_timespec(conn->ts_res,pdata+8,&atime_ts);
+ put_long_date_full_timespec(conn->ts_res,pdata+16,&mtime_ts); /* write time */
+ put_long_date_full_timespec(conn->ts_res,pdata+24,&ctime_ts); /* change time */
SIVAL(pdata,32,mode);
SIVAL(pdata,36,0); /* padding. */
pdata += 40;
unsigned int ea_size =
estimate_ea_size(conn, fsp, smb_fname);
DEBUG(10,("smbd_do_qfilepathinfo: SMB2_FILE_ALL_INFORMATION\n"));
- put_long_date_timespec(conn->ts_res,pdata+0x00,create_time_ts);
- put_long_date_timespec(conn->ts_res,pdata+0x08,atime_ts);
- put_long_date_timespec(conn->ts_res,pdata+0x10,mtime_ts); /* write time */
- put_long_date_timespec(conn->ts_res,pdata+0x18,ctime_ts); /* change time */
+ put_long_date_full_timespec(conn->ts_res,pdata+0x00,&create_time_ts);
+ put_long_date_full_timespec(conn->ts_res,pdata+0x08,&atime_ts);
+ put_long_date_full_timespec(conn->ts_res,pdata+0x10,&mtime_ts); /* write time */
+ put_long_date_full_timespec(conn->ts_res,pdata+0x18,&ctime_ts); /* change time */
SIVAL(pdata, 0x20, mode);
SIVAL(pdata, 0x24, 0); /* padding. */
SBVAL(pdata, 0x28, allocation_size);
SCVAL(pdata, 0x3C, delete_pending);
SCVAL(pdata, 0x3D, (mode&FILE_ATTRIBUTE_DIRECTORY)?1:0);
SSVAL(pdata, 0x3E, 0); /* padding */
- SBVAL(pdata, 0x40, file_index);
+ SBVAL(pdata, 0x40, file_id);
SIVAL(pdata, 0x48, ea_size);
SIVAL(pdata, 0x4C, access_mask);
SBVAL(pdata, 0x50, pos);
case SMB_FILE_INTERNAL_INFORMATION:
DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_INTERNAL_INFORMATION\n"));
- SBVAL(pdata, 0, file_index);
+ SBVAL(pdata, 0, file_id);
data_size = 8;
*fixed_portion = 8;
break;
case SMB_FILE_NETWORK_OPEN_INFORMATION:
DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_NETWORK_OPEN_INFORMATION\n"));
- put_long_date_timespec(conn->ts_res,pdata,create_time_ts);
- put_long_date_timespec(conn->ts_res,pdata+8,atime_ts);
- put_long_date_timespec(conn->ts_res,pdata+16,mtime_ts); /* write time */
- put_long_date_timespec(conn->ts_res,pdata+24,ctime_ts); /* change time */
+ put_long_date_full_timespec(conn->ts_res,pdata,&create_time_ts);
+ put_long_date_full_timespec(conn->ts_res,pdata+8,&atime_ts);
+ put_long_date_full_timespec(conn->ts_res,pdata+16,&mtime_ts); /* write time */
+ put_long_date_full_timespec(conn->ts_res,pdata+24,&ctime_ts); /* change time */
SOFF_T(pdata,32,allocation_size);
SOFF_T(pdata,40,file_size);
SIVAL(pdata,48,mode);
#else
return NT_STATUS_DOS(ERRDOS, ERRbadlink);
#endif
- link_len = SMB_VFS_READLINK(conn,
- smb_fname,
- buffer, PATH_MAX);
+ link_len = SMB_VFS_READLINKAT(conn,
+ conn->cwd_fsp,
+ smb_fname,
+ buffer,
+ PATH_MAX);
+
if (link_len == -1) {
return map_nt_error_from_unix(errno);
}
#if defined(HAVE_POSIX_ACLS)
case SMB_QUERY_POSIX_ACL:
{
- SMB_ACL_T file_acl = NULL;
- SMB_ACL_T def_acl = NULL;
- uint16_t num_file_acls = 0;
- uint16_t num_def_acls = 0;
-
- status = refuse_symlink(conn,
- fsp,
- smb_fname);
+ status = smb_query_posix_acl(conn,
+ req,
+ fsp,
+ smb_fname,
+ pdata,
+ data_size,
+ &data_size);
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());
- } else {
- file_acl =
- SMB_VFS_SYS_ACL_GET_FILE(conn,
- smb_fname,
- SMB_ACL_TYPE_ACCESS,
- talloc_tos());
- }
-
- if (file_acl == NULL && no_acl_syscall_error(errno)) {
- DEBUG(5,("smbd_do_qfilepathinfo: ACLs "
- "not implemented on "
- "filesystem containing %s\n",
- smb_fname->base_name));
- return NT_STATUS_NOT_IMPLEMENTED;
- }
-
- if (S_ISDIR(psbuf->st_ex_mode)) {
- if (fsp && fsp->is_directory) {
- def_acl =
- SMB_VFS_SYS_ACL_GET_FILE(
- conn,
- fsp->fsp_name,
- SMB_ACL_TYPE_DEFAULT,
- talloc_tos());
- } else {
- def_acl =
- SMB_VFS_SYS_ACL_GET_FILE(
- conn,
- smb_fname,
- SMB_ACL_TYPE_DEFAULT,
- talloc_tos());
- }
- def_acl = free_empty_sys_acl(conn, def_acl);
- }
-
- num_file_acls = count_acl_entries(conn, file_acl);
- num_def_acls = count_acl_entries(conn, def_acl);
-
- if ( data_size < (num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE + SMB_POSIX_ACL_HEADER_SIZE) {
- DEBUG(5,("smbd_do_qfilepathinfo: data_size too small (%u) need %u\n",
- data_size,
- (unsigned int)((num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE +
- SMB_POSIX_ACL_HEADER_SIZE) ));
- if (file_acl) {
- TALLOC_FREE(file_acl);
- }
- if (def_acl) {
- TALLOC_FREE(def_acl);
- }
- return NT_STATUS_BUFFER_TOO_SMALL;
- }
-
- SSVAL(pdata,0,SMB_POSIX_ACL_VERSION);
- SSVAL(pdata,2,num_file_acls);
- SSVAL(pdata,4,num_def_acls);
- if (!marshall_posix_acl(conn, pdata + SMB_POSIX_ACL_HEADER_SIZE, psbuf, file_acl)) {
- if (file_acl) {
- TALLOC_FREE(file_acl);
- }
- if (def_acl) {
- TALLOC_FREE(def_acl);
- }
- return NT_STATUS_INTERNAL_ERROR;
- }
- if (!marshall_posix_acl(conn, pdata + SMB_POSIX_ACL_HEADER_SIZE + (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE), psbuf, def_acl)) {
- if (file_acl) {
- TALLOC_FREE(file_acl);
- }
- if (def_acl) {
- TALLOC_FREE(def_acl);
- }
- return NT_STATUS_INTERNAL_ERROR;
- }
-
- if (file_acl) {
- TALLOC_FREE(file_acl);
- }
- if (def_acl) {
- TALLOC_FREE(def_acl);
- }
- data_size = (num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE + SMB_POSIX_ACL_HEADER_SIZE;
break;
}
#endif
return;
}
- status = smbd_do_qfilepathinfo(conn, req, info_level,
+ status = smbd_do_qfilepathinfo(conn, req, req, info_level,
fsp, smb_fname,
delete_pending, write_time_ts,
ea_list,
&fixed_portion,
ppdata, &data_size);
if (!NT_STATUS_IS_OK(status)) {
+ if (open_was_deferred(req->xconn, req->mid)) {
+ /* We have re-scheduled this call. */
+ return;
+ }
+ if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
+ bool ok = defer_smb1_sharing_violation(req);
+ if (ok) {
+ return;
+ }
+ }
reply_nterror(req, status);
return;
}
struct smb_filename *smb_fname_new)
{
NTSTATUS status = NT_STATUS_OK;
+ int ret;
+ bool ok;
/* source must already exist. */
if (!VALID_STAT(smb_fname_old->st)) {
}
/* Setting a hardlink to/from a stream isn't currently supported. */
- if (is_ntfs_stream_smb_fname(smb_fname_old) ||
- is_ntfs_stream_smb_fname(smb_fname_new)) {
+ ok = is_ntfs_stream_smb_fname(smb_fname_old);
+ if (ok) {
+ DBG_DEBUG("Old name has streams\n");
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ ok = is_ntfs_stream_smb_fname(smb_fname_new);
+ if (ok) {
+ DBG_DEBUG("New name has streams\n");
return NT_STATUS_INVALID_PARAMETER;
}
DEBUG(10,("hardlink_internals: doing hard link %s -> %s\n",
smb_fname_old->base_name, smb_fname_new->base_name));
- if (SMB_VFS_LINK(conn, smb_fname_old, smb_fname_new) != 0) {
+ ret = SMB_VFS_LINKAT(conn,
+ conn->cwd_fsp,
+ smb_fname_old,
+ conn->cwd_fsp,
+ smb_fname_new,
+ 0);
+
+ if (ret != 0) {
status = map_nt_error_from_unix(errno);
DEBUG(3,("hardlink_internals: Error %s hard link %s -> %s\n",
nt_errstr(status), smb_fname_old->base_name,
bool setting_write_time)
{
struct smb_filename smb_fname_base;
+ struct timeval_buf tbuf[4];
uint32_t action =
FILE_NOTIFY_CHANGE_LAST_ACCESS
|FILE_NOTIFY_CHANGE_LAST_WRITE
}
/* get some defaults (no modifications) if any info is zero or -1. */
- if (null_timespec(ft->create_time)) {
+ if (is_omit_timespec(&ft->create_time)) {
action &= ~FILE_NOTIFY_CHANGE_CREATION;
}
- if (null_timespec(ft->atime)) {
+ if (is_omit_timespec(&ft->atime)) {
action &= ~FILE_NOTIFY_CHANGE_LAST_ACCESS;
}
- if (null_timespec(ft->mtime)) {
+ if (is_omit_timespec(&ft->mtime)) {
action &= ~FILE_NOTIFY_CHANGE_LAST_WRITE;
}
round_timespec(conn->ts_res, &ft->atime);
round_timespec(conn->ts_res, &ft->mtime);
- DEBUG(5,("smb_set_filetime: actime: %s\n ",
- time_to_asc(convert_timespec_to_time_t(ft->atime))));
- DEBUG(5,("smb_set_filetime: modtime: %s\n ",
- time_to_asc(convert_timespec_to_time_t(ft->mtime))));
- DEBUG(5,("smb_set_filetime: ctime: %s\n ",
- time_to_asc(convert_timespec_to_time_t(ft->ctime))));
- DEBUG(5,("smb_set_file_time: createtime: %s\n ",
- time_to_asc(convert_timespec_to_time_t(ft->create_time))));
+ DBG_DEBUG("smb_set_filetime: actime: %s\n ",
+ timespec_string_buf(&ft->atime, true, &tbuf[0]));
+ DBG_DEBUG("smb_set_filetime: modtime: %s\n ",
+ timespec_string_buf(&ft->mtime, true, &tbuf[1]));
+ DBG_DEBUG("smb_set_filetime: ctime: %s\n ",
+ timespec_string_buf(&ft->ctime, true, &tbuf[2]));
+ DBG_DEBUG("smb_set_file_time: createtime: %s\n ",
+ timespec_string_buf(&ft->create_time, true, &tbuf[3]));
if (setting_write_time) {
/*
* away and will set it on file close and after a write. JRA.
*/
- DEBUG(10,("smb_set_file_time: setting pending modtime to %s\n",
- time_to_asc(convert_timespec_to_time_t(ft->mtime))));
+ DBG_DEBUG("setting pending modtime to %s\n",
+ timespec_string_buf(&ft->mtime, true, &tbuf[0]));
if (fsp != NULL) {
if (fsp->base_fsp) {
get_file_size_stat(psbuf));
if (size == get_file_size_stat(psbuf)) {
+ if (fsp == NULL) {
+ return NT_STATUS_OK;
+ }
+ if (!fsp->fsp_flags.modified) {
+ return NT_STATUS_OK;
+ }
+ trigger_write_time_update_immediate(fsp);
return NT_STATUS_OK;
}
{
char *link_target = NULL;
TALLOC_CTX *ctx = talloc_tos();
+ int ret;
/* Set a symbolic link. */
/* Don't allow this if follow links is false. */
DEBUG(10,("smb_set_file_unix_link: SMB_SET_FILE_UNIX_LINK doing symlink %s -> %s\n",
new_smb_fname->base_name, link_target ));
- if (SMB_VFS_SYMLINK(conn,link_target,new_smb_fname) != 0) {
+ ret = SMB_VFS_SYMLINKAT(conn,
+ link_target,
+ conn->cwd_fsp,
+ new_smb_fname);
+ if (ret != 0) {
return map_nt_error_from_unix(errno);
}
uint32_t len;
char *newname = NULL;
struct smb_filename *smb_fname_dst = NULL;
- uint32_t ucf_flags = UCF_SAVE_LCOMP |
- ucf_flags_from_smb_request(req);
+ const char *dst_original_lcomp = NULL;
+ uint32_t ucf_flags = ucf_flags_from_smb_request(req);
NTSTATUS status = NT_STATUS_OK;
TALLOC_CTX *ctx = talloc_tos();
status = NT_STATUS_NO_MEMORY;
goto out;
}
+ }
- /*
- * Set the original last component, since
- * rename_internals_fsp() requires it.
- */
- smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
- newname);
- if (smb_fname_dst->original_lcomp == NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto out;
- }
-
+ /*
+ * Set the original last component, since
+ * rename_internals_fsp() requires it.
+ */
+ dst_original_lcomp = get_original_lcomp(smb_fname_dst,
+ conn,
+ newname,
+ ucf_flags);
+ if (dst_original_lcomp == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto out;
}
DEBUG(10,("smb2_file_rename_information: "
"SMB_FILE_RENAME_INFORMATION (%s) %s -> %s\n",
fsp_fnum_dbg(fsp), fsp_str_dbg(fsp),
smb_fname_str_dbg(smb_fname_dst)));
- status = rename_internals_fsp(conn, fsp, smb_fname_dst,
+ status = rename_internals_fsp(conn,
+ fsp,
+ smb_fname_dst,
+ dst_original_lcomp,
(FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM),
overwrite);
char *newname = NULL;
struct smb_filename *smb_fname_dst = NULL;
NTSTATUS status = NT_STATUS_OK;
- uint32_t ucf_flags = UCF_SAVE_LCOMP |
- ucf_flags_from_smb_request(req);
+ uint32_t ucf_flags = ucf_flags_from_smb_request(req);
TALLOC_CTX *ctx = talloc_tos();
if (!fsp) {
return NT_STATUS_INVALID_PARAMETER;
}
- if (req->posix_pathnames) {
+ if (smb_fname_src->flags & SMB_FILENAME_POSIX_PATH) {
srvstr_get_path_posix(ctx,
pdata,
req->flags2,
len,
STR_TERMINATE,
&status);
+ ucf_flags |= UCF_POSIX_PATHNAMES;
} else {
srvstr_get_path(ctx,
pdata,
uint32_t len;
char *newname = NULL;
struct smb_filename *smb_fname_dst = NULL;
+ const char *dst_original_lcomp = NULL;
bool dest_has_wcard = False;
NTSTATUS status = NT_STATUS_OK;
char *p;
DEBUG(10,("smb_file_rename_information: got name |%s|\n",
newname));
- if (req->flags2 & FLAGS2_DFS_PATHNAMES) {
- status = resolve_dfspath_wcard(ctx, conn,
- newname,
- UCF_COND_ALLOW_WCARD_LCOMP,
- !conn->sconn->using_smb2,
- &newname,
- &dest_has_wcard);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
- }
-
/* Check the new name has no '/' characters. */
if (strchr_m(newname, '/')) {
return NT_STATUS_NOT_SUPPORTED;
}
/*
- * Set the original last component, since
+ * Get the original last component, since
* rename_internals_fsp() requires it.
*/
- smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
- newname);
- if (smb_fname_dst->original_lcomp == NULL) {
+ dst_original_lcomp = get_original_lcomp(smb_fname_dst,
+ conn,
+ newname,
+ 0);
+ if (dst_original_lcomp == NULL) {
status = NT_STATUS_NO_MEMORY;
goto out;
}
* the newname instead.
*/
char *base_name = NULL;
- uint32_t ucf_flags = UCF_SAVE_LCOMP |
- ucf_flags_from_smb_request(req);
+ uint32_t ucf_flags = ucf_flags_from_smb_request(req);
if (dest_has_wcard) {
ucf_flags |= UCF_ALWAYS_ALLOW_WCARD_LCOMP;
return NT_STATUS_NO_MEMORY;
}
- status = unix_convert(ctx, conn, base_name, &smb_fname_dst,
- ucf_flags);
+ status = filename_convert(ctx,
+ conn,
+ base_name,
+ ucf_flags,
+ NULL,
+ NULL,
+ &smb_fname_dst);
/* If an error we expect this to be
* NT_STATUS_OBJECT_PATH_NOT_FOUND */
goto out;
}
}
+ dst_original_lcomp = get_original_lcomp(smb_fname_dst,
+ conn,
+ newname,
+ ucf_flags);
+ if (dst_original_lcomp == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
}
if (fsp) {
"SMB_FILE_RENAME_INFORMATION (%s) %s -> %s\n",
fsp_fnum_dbg(fsp), fsp_str_dbg(fsp),
smb_fname_str_dbg(smb_fname_dst)));
- status = rename_internals_fsp(conn, fsp, smb_fname_dst, 0,
- overwrite);
+ status = rename_internals_fsp(conn,
+ fsp,
+ smb_fname_dst,
+ dst_original_lcomp,
+ 0,
+ overwrite);
} else {
DEBUG(10,("smb_file_rename_information: "
"SMB_FILE_RENAME_INFORMATION %s -> %s\n",
smb_fname_str_dbg(smb_fname_src),
smb_fname_str_dbg(smb_fname_dst)));
- status = rename_internals(ctx, conn, req, smb_fname_src,
- smb_fname_dst, 0, overwrite, false,
- dest_has_wcard,
- FILE_WRITE_ATTRIBUTES);
+ status = rename_internals(ctx,
+ conn,
+ req,
+ smb_fname_src,
+ smb_fname_dst,
+ dst_original_lcomp,
+ 0,
+ overwrite,
+ false,
+ dest_has_wcard,
+ FILE_WRITE_ATTRIBUTES);
}
out:
TALLOC_FREE(smb_fname_dst);
#if defined(HAVE_POSIX_ACLS)
static NTSTATUS smb_set_posix_acl(connection_struct *conn,
+ struct smb_request *req,
const char *pdata,
- int total_data,
+ int total_data_in,
files_struct *fsp,
const struct smb_filename *smb_fname)
{
uint16_t posix_acl_version;
uint16_t num_file_acls;
uint16_t num_def_acls;
- bool valid_file_acls = True;
- bool valid_def_acls = True;
+ bool valid_file_acls = true;
+ bool valid_def_acls = true;
NTSTATUS status;
+ unsigned int size_needed;
+ unsigned int total_data;
+ bool close_fsp = false;
+
+ if (total_data_in < 0) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto out;
+ }
+
+ total_data = total_data_in;
if (total_data < SMB_POSIX_ACL_HEADER_SIZE) {
- return NT_STATUS_INVALID_PARAMETER;
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto out;
}
posix_acl_version = SVAL(pdata,0);
num_file_acls = SVAL(pdata,2);
num_def_acls = SVAL(pdata,4);
if (num_file_acls == SMB_POSIX_IGNORE_ACE_ENTRIES) {
- valid_file_acls = False;
+ valid_file_acls = false;
num_file_acls = 0;
}
if (num_def_acls == SMB_POSIX_IGNORE_ACE_ENTRIES) {
- valid_def_acls = False;
+ valid_def_acls = false;
num_def_acls = 0;
}
if (posix_acl_version != SMB_POSIX_ACL_VERSION) {
- return NT_STATUS_INVALID_PARAMETER;
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto out;
}
- if (total_data < SMB_POSIX_ACL_HEADER_SIZE +
- (num_file_acls+num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE) {
- return NT_STATUS_INVALID_PARAMETER;
+ /* Wrap checks. */
+ if (num_file_acls + num_def_acls < num_file_acls) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto out;
}
- status = refuse_symlink(conn, fsp, smb_fname);
+ size_needed = num_file_acls + num_def_acls;
+
+ /*
+ * (size_needed * SMB_POSIX_ACL_ENTRY_SIZE) must be less
+ * than UINT_MAX, so check by division.
+ */
+ if (size_needed > (UINT_MAX/SMB_POSIX_ACL_ENTRY_SIZE)) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto out;
+ }
+
+ size_needed = size_needed*SMB_POSIX_ACL_ENTRY_SIZE;
+ if (size_needed + SMB_POSIX_ACL_HEADER_SIZE < size_needed) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto out;
+ }
+ size_needed += SMB_POSIX_ACL_HEADER_SIZE;
+
+ if (total_data < size_needed) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto out;
+ }
+
+ /*
+ * Ensure we always operate on a file descriptor, not just
+ * the filename.
+ */
+ if (fsp == NULL) {
+ uint32_t access_mask = SEC_STD_WRITE_OWNER|
+ SEC_STD_WRITE_DAC|
+ SEC_STD_READ_CONTROL|
+ FILE_READ_ATTRIBUTES|
+ FILE_WRITE_ATTRIBUTES;
+
+ status = get_posix_fsp(conn,
+ req,
+ smb_fname,
+ access_mask,
+ &fsp);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ goto out;
+ }
+ close_fsp = true;
+ }
+
+ /* Here we know fsp != NULL */
+ SMB_ASSERT(fsp != NULL);
+
+ status = refuse_symlink(conn, fsp, fsp->fsp_name);
if (!NT_STATUS_IS_OK(status)) {
- return status;
+ goto out;
+ }
+
+ /* If we have a default acl, this *must* be a directory. */
+ if (valid_def_acls && !fsp->fsp_flags.is_directory) {
+ DBG_INFO("Can't set default acls on "
+ "non-directory %s\n",
+ fsp_str_dbg(fsp));
+ return NT_STATUS_INVALID_HANDLE;
}
- 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,
- (unsigned int)num_def_acls));
+ DBG_DEBUG("file %s num_file_acls = %"PRIu16", "
+ "num_def_acls = %"PRIu16"\n",
+ fsp_str_dbg(fsp),
+ num_file_acls,
+ num_def_acls);
- if (valid_file_acls && !set_unix_posix_acl(conn, fsp,
- smb_fname, num_file_acls,
- pdata + SMB_POSIX_ACL_HEADER_SIZE)) {
- return map_nt_error_from_unix(errno);
+ /* Move pdata to the start of the file ACL entries. */
+ pdata += SMB_POSIX_ACL_HEADER_SIZE;
+
+ if (valid_file_acls) {
+ status = set_unix_posix_acl(conn,
+ fsp,
+ num_file_acls,
+ pdata);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto out;
+ }
}
- if (valid_def_acls && !set_unix_posix_default_acl(conn,
- smb_fname, num_def_acls,
- pdata + SMB_POSIX_ACL_HEADER_SIZE +
- (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE))) {
- return map_nt_error_from_unix(errno);
+ /* Move pdata to the start of the default ACL entries. */
+ pdata += (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE);
+
+ if (valid_def_acls) {
+ status = set_unix_posix_default_acl(conn,
+ fsp,
+ num_def_acls,
+ pdata);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto out;
+ }
}
- return NT_STATUS_OK;
+
+ status = NT_STATUS_OK;
+
+ out:
+
+ if (close_fsp) {
+ (void)close_file(req, fsp, NORMAL_CLOSE);
+ fsp = NULL;
+ }
+ return status;
}
#endif
Deal with SMB_SET_POSIX_LOCK.
****************************************************************************/
+static void smb_set_posix_lock_done(struct tevent_req *subreq);
+
static NTSTATUS smb_set_posix_lock(connection_struct *conn,
struct smb_request *req,
const char *pdata,
int total_data,
files_struct *fsp)
{
+ struct tevent_req *subreq = NULL;
+ struct smbd_lock_element *lck = NULL;
uint64_t count;
uint64_t offset;
uint64_t smblctx;
break;
case POSIX_LOCK_TYPE_WRITE:
/* Return the right POSIX-mappable error code for files opened read-only. */
- if (!fsp->can_write) {
+ if (!fsp->fsp_flags.can_write) {
return NT_STATUS_INVALID_HANDLE;
}
lock_type = WRITE_LOCK;
return NT_STATUS_INVALID_PARAMETER;
}
- if (SVAL(pdata,POSIX_LOCK_FLAGS_OFFSET) == POSIX_LOCK_FLAG_NOWAIT) {
- blocking_lock = False;
- } else if (SVAL(pdata,POSIX_LOCK_FLAGS_OFFSET) == POSIX_LOCK_FLAG_WAIT) {
- blocking_lock = True;
- } else {
+ switch (SVAL(pdata, POSIX_LOCK_FLAGS_OFFSET)) {
+ case POSIX_LOCK_FLAG_NOWAIT:
+ blocking_lock = false;
+ break;
+ case POSIX_LOCK_FLAG_WAIT:
+ blocking_lock = true;
+ break;
+ default:
return NT_STATUS_INVALID_PARAMETER;
}
count = (((uint64_t) IVAL(pdata,(POSIX_LOCK_LEN_OFFSET+4))) << 32) |
((uint64_t) IVAL(pdata,POSIX_LOCK_LEN_OFFSET));
- DEBUG(10,("smb_set_posix_lock: file %s, lock_type = %u,"
- "smblctx = %llu, count = %.0f, offset = %.0f\n",
- fsp_str_dbg(fsp),
- (unsigned int)lock_type,
- (unsigned long long)smblctx,
- (double)count,
- (double)offset ));
+ DBG_DEBUG("file %s, lock_type = %u, smblctx = %"PRIu64", "
+ "count = %"PRIu64", offset = %"PRIu64"\n",
+ fsp_str_dbg(fsp),
+ (unsigned int)lock_type,
+ smblctx,
+ count,
+ offset);
if (lock_type == UNLOCK_LOCK) {
- status = do_unlock(req->sconn->msg_ctx,
- fsp,
- smblctx,
- count,
- offset,
- POSIX_LOCK);
- } else {
- uint64_t block_smblctx;
+ struct smbd_lock_element l = {
+ .req_guid = smbd_request_guid(req, 0),
+ .smblctx = smblctx,
+ .brltype = UNLOCK_LOCK,
+ .offset = offset,
+ .count = count,
+ };
+ status = smbd_do_unlocking(req, fsp, 1, &l, POSIX_LOCK);
+ return status;
+ }
- struct byte_range_lock *br_lck = do_lock(req->sconn->msg_ctx,
- fsp,
- smblctx,
- count,
- offset,
- lock_type,
- POSIX_LOCK,
- blocking_lock,
- &status,
- &block_smblctx);
-
- if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
- /*
- * A blocking lock was requested. Package up
- * this smb into a queued request and push it
- * onto the blocking lock queue.
- */
- if(push_blocking_lock_request(br_lck,
- req,
- fsp,
- -1, /* infinite timeout. */
- 0,
- smblctx,
- lock_type,
- POSIX_LOCK,
- offset,
- count,
- block_smblctx)) {
- TALLOC_FREE(br_lck);
- return status;
- }
+ lck = talloc(req, struct smbd_lock_element);
+ if (lck == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ *lck = (struct smbd_lock_element) {
+ .req_guid = smbd_request_guid(req, 0),
+ .smblctx = smblctx,
+ .brltype = lock_type,
+ .count = count,
+ .offset = offset,
+ };
+
+ subreq = smbd_smb1_do_locks_send(
+ fsp,
+ req->sconn->ev_ctx,
+ &req,
+ fsp,
+ blocking_lock ? UINT32_MAX : 0,
+ true, /* large_offset */
+ POSIX_LOCK,
+ 1,
+ lck);
+ if (subreq == NULL) {
+ TALLOC_FREE(lck);
+ return NT_STATUS_NO_MEMORY;
+ }
+ tevent_req_set_callback(subreq, smb_set_posix_lock_done, req);
+ return NT_STATUS_EVENT_PENDING;
+}
+
+static void smb_set_posix_lock_done(struct tevent_req *subreq)
+{
+ struct smb_request *req = NULL;
+ NTSTATUS status;
+ bool ok;
+
+ ok = smbd_smb1_do_locks_extract_smbreq(subreq, talloc_tos(), &req);
+ SMB_ASSERT(ok);
+
+ status = smbd_smb1_do_locks_recv(subreq);
+ TALLOC_FREE(subreq);
+
+ if (NT_STATUS_IS_OK(status)) {
+ char params[2] = {0};
+ /* Fake up max_data_bytes here - we know it fits. */
+ send_trans2_replies(
+ req->conn,
+ req,
+ NT_STATUS_OK,
+ params,
+ 2,
+ NULL,
+ 0,
+ 0xffff);
+ } else {
+ reply_nterror(req, status);
+ ok = srv_send_smb(
+ req->xconn,
+ (char *)req->outbuf,
+ true,
+ req->seqnum+1,
+ IS_CONN_ENCRYPTED(req->conn),
+ NULL);
+ if (!ok) {
+ exit_server_cleanly("smb_set_posix_lock_done: "
+ "srv_send_smb failed.");
}
- TALLOC_FREE(br_lck);
}
- return status;
+ TALLOC_FREE(req);
+ return;
}
/****************************************************************************
uint32_t dosmode = 0;
NTSTATUS status = NT_STATUS_OK;
- ZERO_STRUCT(ft);
+ init_smb_file_time(&ft);
if (total_data < 36) {
return NT_STATUS_INVALID_PARAMETER;
}
- status = check_access(conn, fsp, smb_fname, FILE_WRITE_ATTRIBUTES);
+ if (fsp != NULL) {
+ status = check_access_fsp(fsp, FILE_WRITE_ATTRIBUTES);
+ } else {
+ status = check_access(conn,
+ conn->cwd_fsp,
+ smb_fname,
+ FILE_WRITE_ATTRIBUTES);
+ }
if (!NT_STATUS_IS_OK(status)) {
return status;
}
}
/* create time */
- ft.create_time = interpret_long_date(pdata);
+ ft.create_time = pull_long_date_full_timespec(pdata);
/* access time */
- ft.atime = interpret_long_date(pdata+8);
+ ft.atime = pull_long_date_full_timespec(pdata+8);
/* write time. */
- ft.mtime = interpret_long_date(pdata+16);
+ ft.mtime = pull_long_date_full_timespec(pdata+16);
/* change time. */
- ft.ctime = interpret_long_date(pdata+24);
+ ft.ctime = pull_long_date_full_timespec(pdata+24);
DEBUG(10, ("smb_set_file_basic_info: file %s\n",
smb_fname_str_dbg(smb_fname)));
- return smb_set_file_time(conn, fsp, smb_fname, &ft,
- true);
+ status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (fsp != NULL && fsp->fsp_flags.modified) {
+ trigger_write_time_update_immediate(fsp);
+ }
+ return NT_STATUS_OK;
}
/****************************************************************************
NTSTATUS status;
struct smb_file_time ft;
- ZERO_STRUCT(ft);
+ init_smb_file_time(&ft);
if (total_data < 12) {
return NT_STATUS_INVALID_PARAMETER;
}
/* create time */
- ft.create_time = convert_time_t_to_timespec(srv_make_unix_date2(pdata));
+ ft.create_time = time_t_to_full_timespec(srv_make_unix_date2(pdata));
/* access time */
- ft.atime = convert_time_t_to_timespec(srv_make_unix_date2(pdata+4));
+ ft.atime = time_t_to_full_timespec(srv_make_unix_date2(pdata+4));
/* write time */
- ft.mtime = convert_time_t_to_timespec(srv_make_unix_date2(pdata+8));
+ ft.mtime = time_t_to_full_timespec(srv_make_unix_date2(pdata+8));
DEBUG(10,("smb_set_info_standard: file %s\n",
smb_fname_str_dbg(smb_fname)));
- status = check_access(conn, fsp, smb_fname, FILE_WRITE_ATTRIBUTES);
+ if (fsp != NULL) {
+ status = check_access_fsp(fsp, FILE_WRITE_ATTRIBUTES);
+ } else {
+ status = check_access(conn,
+ conn->cwd_fsp,
+ smb_fname,
+ FILE_WRITE_ATTRIBUTES);
+ }
if (!NT_STATUS_IS_OK(status)) {
return status;
}
- return smb_set_file_time(conn,
- fsp,
- smb_fname,
- &ft,
- true);
+ status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (fsp != NULL && fsp->fsp_flags.modified) {
+ trigger_write_time_update_immediate(fsp);
+ }
+ return NT_STATUS_OK;
}
/****************************************************************************
uint32_t raw_unixmode = IVAL(pdata,84);
NTSTATUS status;
mode_t unixmode;
+ int ret;
if (total_data < 100) {
return NT_STATUS_INVALID_PARAMETER;
#endif
switch (file_type) {
+ /* We can't create other objects here. */
+ case UNIX_TYPE_FILE:
+ case UNIX_TYPE_DIR:
+ case UNIX_TYPE_SYMLINK:
+ return NT_STATUS_ACCESS_DENIED;
#if defined(S_IFIFO)
case UNIX_TYPE_FIFO:
unixmode |= S_IFIFO;
#endif
#if defined(S_IFCHR)
case UNIX_TYPE_CHARDEV:
+ /* This is only allowed for root. */
+ if (get_current_uid(conn) != sec_initial_uid()) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
unixmode |= S_IFCHR;
break;
#endif
#if defined(S_IFBLK)
case UNIX_TYPE_BLKDEV:
+ if (get_current_uid(conn) != sec_initial_uid()) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
unixmode |= S_IFBLK;
break;
#endif
(unsigned int)unixmode, smb_fname_str_dbg(smb_fname)));
/* Ok - do the mknod. */
- if (SMB_VFS_MKNOD(conn, smb_fname, unixmode, dev) != 0) {
+ ret = SMB_VFS_MKNODAT(conn,
+ conn->cwd_fsp,
+ smb_fname,
+ unixmode,
+ dev);
+
+ if (ret != 0) {
return map_nt_error_from_unix(errno);
}
*/
if (lp_inherit_permissions(SNUM(conn))) {
- char *parent;
- if (!parent_dirname(talloc_tos(), smb_fname->base_name,
- &parent, NULL)) {
+ struct smb_filename *parent_fname = NULL;
+ bool ok;
+
+ ok = parent_smb_fname(talloc_tos(),
+ smb_fname,
+ &parent_fname,
+ NULL);
+ if (!ok) {
return NT_STATUS_NO_MEMORY;
}
- inherit_access_posix_acl(conn, parent, smb_fname,
+ inherit_access_posix_acl(conn,
+ parent_fname,
+ smb_fname,
unixmode);
- TALLOC_FREE(parent);
+ TALLOC_FREE(parent_fname);
}
return NT_STATUS_OK;
uid_t set_owner = (uid_t)SMB_UID_NO_CHANGE;
gid_t set_grp = (uid_t)SMB_GID_NO_CHANGE;
NTSTATUS status = NT_STATUS_OK;
- bool delete_on_fail = False;
enum perm_type ptype;
files_struct *all_fsps = NULL;
bool modify_mtime = true;
struct file_id id;
- struct smb_filename *smb_fname_tmp = NULL;
SMB_STRUCT_STAT sbuf;
- ZERO_STRUCT(ft);
+ init_smb_file_time(&ft);
if (total_data < 100) {
return NT_STATUS_INVALID_PARAMETER;
size |= (((off_t)IVAL(pdata,4)) << 32);
}
- ft.atime = interpret_long_date(pdata+24); /* access_time */
- ft.mtime = interpret_long_date(pdata+32); /* modification_time */
+ ft.atime = pull_long_date_full_timespec(pdata+24); /* access_time */
+ ft.mtime = pull_long_date_full_timespec(pdata+32); /* modification_time */
set_owner = (uid_t)IVAL(pdata,40);
set_grp = (gid_t)IVAL(pdata,48);
raw_unixmode = IVAL(pdata,84);
* a new info level should be used for mknod. JRA.
*/
- status = smb_unix_mknod(conn,
+ return smb_unix_mknod(conn,
pdata,
total_data,
smb_fname);
- 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) {
- status = map_nt_error_from_unix(errno);
- TALLOC_FREE(smb_fname_tmp);
- SMB_VFS_UNLINK(conn, smb_fname);
- return status;
- }
-
- sbuf = smb_fname_tmp->st;
- smb_fname = smb_fname_tmp;
-
- /* Ensure we don't try and change anything else. */
- raw_unixmode = SMB_MODE_NO_CHANGE;
- size = get_file_size_stat(&sbuf);
- ft.atime = sbuf.st_ex_atime;
- ft.mtime = sbuf.st_ex_mtime;
- /*
- * We continue here as we might want to change the
- * owner uid/gid.
- */
- delete_on_fail = True;
}
#if 1
if (ret != 0) {
status = map_nt_error_from_unix(errno);
- if (delete_on_fail) {
- SMB_VFS_UNLINK(conn, smb_fname);
- }
return status;
}
}
}
if (ret != 0) {
status = map_nt_error_from_unix(errno);
- if (delete_on_fail) {
- SMB_VFS_UNLINK(conn, smb_fname);
- }
return status;
}
}
/* Deal with any size changes. */
- status = smb_set_file_size(conn, req,
- fsp,
- smb_fname,
- &sbuf,
- size,
- false);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
+ if (S_ISREG(sbuf.st_ex_mode)) {
+ status = smb_set_file_size(conn, req,
+ fsp,
+ smb_fname,
+ &sbuf,
+ size,
+ false);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
}
/* Deal with any time changes. */
- if (null_timespec(ft.mtime) && null_timespec(ft.atime)) {
+ if (is_omit_timespec(&ft.mtime) && is_omit_timespec(&ft.atime)) {
/* No change, don't cancel anything. */
return status;
}
* We're setting the time explicitly for UNIX.
* Cancel any pending changes over all handles.
*/
- all_fsps->update_write_time_on_close = false;
+ all_fsps->fsp_flags.update_write_time_on_close = false;
TALLOC_FREE(all_fsps->update_write_time_event);
}
* we need. Just remember if we modified
* mtime and send the notify ourselves.
*/
- if (null_timespec(ft.mtime)) {
+ if (is_omit_timespec(&ft.mtime)) {
modify_mtime = false;
}
{
NTSTATUS status = NT_STATUS_OK;
uint32_t raw_unixmode = 0;
- uint32_t mod_unixmode = 0;
mode_t unixmode = (mode_t)0;
files_struct *fsp = NULL;
uint16_t info_level_return = 0;
int info;
char *pdata = *ppdata;
+ struct smb2_create_blobs *posx = NULL;
if (total_data < 18) {
return NT_STATUS_INVALID_PARAMETER;
return status;
}
- mod_unixmode = (uint32_t)unixmode | FILE_FLAG_POSIX_SEMANTICS;
+ status = make_smb2_posix_create_ctx(talloc_tos(), &posx, unixmode);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
+ nt_errstr(status));
+ return status;
+ }
DEBUG(10,("smb_posix_mkdir: file %s, mode 0%o\n",
smb_fname_str_dbg(smb_fname), (unsigned int)unixmode));
FILE_SHARE_NONE, /* share_access */
FILE_CREATE, /* create_disposition*/
FILE_DIRECTORY_FILE, /* create_options */
- mod_unixmode, /* file_attributes */
+ 0, /* file_attributes */
0, /* oplock_request */
NULL, /* lease */
0, /* allocation_size */
NULL, /* ea_list */
&fsp, /* result */
&info, /* pinfo */
- NULL, NULL); /* create context */
+ posx, /* in_context_blobs */
+ NULL); /* out_context_blobs */
+
+ TALLOC_FREE(posx);
if (NT_STATUS_IS_OK(status)) {
close_file(req, fsp, NORMAL_CLOSE);
uint32_t flags = 0;
uint32_t wire_open_mode = 0;
uint32_t raw_unixmode = 0;
- uint32_t mod_unixmode = 0;
+ uint32_t attributes = 0;
uint32_t create_disp = 0;
uint32_t access_mask = 0;
uint32_t create_options = FILE_NON_DIRECTORY_FILE;
int oplock_request = 0;
int info = 0;
uint16_t info_level_return = 0;
+ struct smb2_create_blobs *posx = NULL;
if (total_data < 18) {
return NT_STATUS_INVALID_PARAMETER;
return status;
}
- mod_unixmode = (uint32_t)unixmode | FILE_FLAG_POSIX_SEMANTICS;
+ status = make_smb2_posix_create_ctx(talloc_tos(), &posx, unixmode);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
+ nt_errstr(status));
+ return status;
+ }
if (wire_open_mode & SMB_O_SYNC) {
create_options |= FILE_WRITE_THROUGH;
access_mask |= FILE_APPEND_DATA;
}
if (wire_open_mode & SMB_O_DIRECT) {
- mod_unixmode |= FILE_FLAG_NO_BUFFERING;
+ attributes |= FILE_FLAG_NO_BUFFERING;
}
if ((wire_open_mode & SMB_O_DIRECTORY) ||
FILE_SHARE_DELETE),
create_disp, /* create_disposition*/
create_options, /* create_options */
- mod_unixmode, /* file_attributes */
+ attributes, /* file_attributes */
oplock_request, /* oplock_request */
NULL, /* lease */
0, /* allocation_size */
NULL, /* ea_list */
&fsp, /* result */
&info, /* pinfo */
- NULL, NULL); /* create context */
+ posx, /* in_context_blobs */
+ NULL); /* out_context_blobs */
+
+ TALLOC_FREE(posx);
if (!NT_STATUS_IS_OK(status)) {
return status;
int total_data,
struct smb_filename *smb_fname)
{
- struct server_id self = messaging_server_id(conn->sconn->msg_ctx);
NTSTATUS status = NT_STATUS_OK;
files_struct *fsp = NULL;
uint16_t flags = 0;
int create_options = 0;
struct share_mode_lock *lck = NULL;
bool other_nonposix_opens;
+ struct smb2_create_blobs *posx = NULL;
if (total_data < 2) {
return NT_STATUS_INVALID_PARAMETER;
create_options |= FILE_DIRECTORY_FILE;
}
+ status = make_smb2_posix_create_ctx(talloc_tos(), &posx, 0777);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
+ nt_errstr(status));
+ return status;
+ }
+
status = SMB_VFS_CREATE_FILE(
conn, /* conn */
req, /* req */
FILE_SHARE_DELETE),
FILE_OPEN, /* create_disposition*/
create_options, /* create_options */
- FILE_FLAG_POSIX_SEMANTICS|0777, /* file_attributes */
+ 0, /* file_attributes */
0, /* oplock_request */
NULL, /* lease */
0, /* allocation_size */
NULL, /* ea_list */
&fsp, /* result */
&info, /* pinfo */
- NULL, NULL); /* create context */
+ posx, /* in_context_blobs */
+ NULL); /* out_context_blobs */
+
+ TALLOC_FREE(posx);
if (!NT_STATUS_IS_OK(status)) {
return status;
return NT_STATUS_INVALID_PARAMETER;
}
- other_nonposix_opens = has_other_nonposix_opens(lck, fsp, self);
+ other_nonposix_opens = has_other_nonposix_opens(lck, fsp);
if (other_nonposix_opens) {
/* Fail with sharing violation. */
TALLOC_FREE(lck);
case SMB_SET_POSIX_ACL:
{
status = smb_set_posix_acl(conn,
+ req,
pdata,
total_data,
fsp,
/* We have re-scheduled this call. */
return;
}
- if (blocking_lock_was_deferred_smb1(req->sconn, req->mid)) {
+ if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
+ bool ok = defer_smb1_sharing_violation(req);
+ if (ok) {
+ return;
+ }
+ }
+ if (NT_STATUS_EQUAL(status, NT_STATUS_EVENT_PENDING)) {
/* We have re-scheduled this call. */
return;
}
char **ppdata, int total_data,
unsigned int max_data_bytes)
{
+ const struct loadparm_substitution *lp_sub =
+ loadparm_s3_global_substitution();
char *pdata = *ppdata;
files_struct *fsp = file_fsp(req, SVAL(req->vwv+15, 0));
NTSTATUS status;
return;
}
status = srvstr_push(pdata, req->flags2, pdata+18,
- lp_servicename(talloc_tos(), SNUM(conn)), 13,
+ lp_servicename(talloc_tos(), lp_sub, SNUM(conn)), 13,
STR_ASCII|STR_TERMINATE, &len); /* Service name */
if (!NT_STATUS_IS_OK(status)) {
reply_nterror(req, status);
{
int dptr_num;
struct smbd_server_connection *sconn = req->sconn;
+ files_struct *fsp = NULL;
START_PROFILE(SMBfindclose);
DEBUG(3,("reply_findclose, dptr_num = %d\n", dptr_num));
- dptr_close(sconn, &dptr_num);
+ /*
+ * OS/2 seems to use -1 to indicate "close all directories"
+ * This has to mean on this specific connection struct.
+ */
+ if (dptr_num == -1) {
+ dptr_closecnum(req->conn);
+ } else {
+ fsp = dptr_fetch_lanman2_fsp(sconn, dptr_num);
+ dptr_num = -1;
+ if (fsp != NULL) {
+ close_file(NULL, fsp, NORMAL_CLOSE);
+ fsp = NULL;
+ }
+ }
reply_outbuf(req, 0, 0);