mirror of
https://github.com/samba-team/samba.git
synced 2025-01-22 22:04:08 +03:00
r5792: Added new parameter "inherit owner". If set on a share, the created file/directory
will be owned by the same uid as the containing directory. Doing this for directories in a race-free mannor has only been tested on Linux (it depends on being able to open a directory and then do a fchown on that file descriptor). If this functionality is not available then the code silently downgrades to not changing the ownership of a new directory. This new parameter (docs to follow) finally makes it possible to create "drop boxes" on Samba, which requires all files within a directory to be commonly owned. A HOWTO on how to use this will follow. Jeremy. (This used to be commit 2e1f727184b9d025d2e3413bdd3d01d5ca803a41)
This commit is contained in:
parent
00a62a7f6d
commit
cc5ba986bf
@ -413,6 +413,7 @@ typedef struct
|
||||
BOOL bBlockingLocks;
|
||||
BOOL bInheritPerms;
|
||||
BOOL bInheritACLS;
|
||||
BOOL bInheritOwner;
|
||||
BOOL bMSDfsRoot;
|
||||
BOOL bUseClientDriver;
|
||||
BOOL bDefaultDevmode;
|
||||
@ -539,6 +540,7 @@ static service sDefault = {
|
||||
True, /* bBlockingLocks */
|
||||
False, /* bInheritPerms */
|
||||
False, /* bInheritACLS */
|
||||
False, /* bInheritOwner */
|
||||
False, /* bMSDfsRoot */
|
||||
False, /* bUseClientDriver */
|
||||
False, /* bDefaultDevmode */
|
||||
@ -864,6 +866,7 @@ static struct parm_struct parm_table[] = {
|
||||
{"force unknown acl user", P_BOOL, P_LOCAL, &sDefault.bForceUnknownAclUser, NULL, NULL, FLAG_ADVANCED | FLAG_GLOBAL | FLAG_SHARE},
|
||||
{"inherit permissions", P_BOOL, P_LOCAL, &sDefault.bInheritPerms, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE},
|
||||
{"inherit acls", P_BOOL, P_LOCAL, &sDefault.bInheritACLS, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE},
|
||||
{"inherit owner", P_BOOL, P_LOCAL, &sDefault.bInheritOwner, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE},
|
||||
{"guest only", P_BOOL, P_LOCAL, &sDefault.bGuest_only, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE},
|
||||
{"only guest", P_BOOL, P_LOCAL, &sDefault.bGuest_only, NULL, NULL, FLAG_HIDE},
|
||||
|
||||
@ -1907,6 +1910,7 @@ FN_LOCAL_BOOL(lp_fake_dir_create_times, bFakeDirCreateTimes)
|
||||
FN_LOCAL_BOOL(lp_blocking_locks, bBlockingLocks)
|
||||
FN_LOCAL_BOOL(lp_inherit_perms, bInheritPerms)
|
||||
FN_LOCAL_BOOL(lp_inherit_acls, bInheritACLS)
|
||||
FN_LOCAL_BOOL(lp_inherit_owner, bInheritOwner)
|
||||
FN_LOCAL_BOOL(lp_use_client_driver, bUseClientDriver)
|
||||
FN_LOCAL_BOOL(lp_default_devmode, bDefaultDevmode)
|
||||
FN_LOCAL_BOOL(lp_force_printername, bForcePrintername)
|
||||
|
@ -1494,7 +1494,7 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
|
||||
DEBUG(5,("Creating first directory\n"));
|
||||
slprintf(new_dir, sizeof(new_dir)-1, "%s/%d", architecture, driver->cversion);
|
||||
driver_unix_convert(new_dir, conn, NULL, &bad_path, &st);
|
||||
mkdir_internal(conn, new_dir);
|
||||
mkdir_internal(conn, new_dir, bad_path);
|
||||
|
||||
/* For each driver file, archi\filexxx.yyy, if there is a duplicate file
|
||||
* listed for this driver which has already been moved, skip it (note:
|
||||
|
@ -397,7 +397,7 @@ BOOL unix_convert(pstring name,connection_struct *conn,char *saved_last_componen
|
||||
a valid one for the user to access.
|
||||
****************************************************************************/
|
||||
|
||||
BOOL check_name(pstring name,connection_struct *conn)
|
||||
BOOL check_name(const pstring name,connection_struct *conn)
|
||||
{
|
||||
BOOL ret = True;
|
||||
|
||||
|
@ -82,6 +82,103 @@ static void check_for_pipe(const char *fname)
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Change the ownership of a file to that of the parent directory.
|
||||
Do this by fd if possible.
|
||||
****************************************************************************/
|
||||
|
||||
void change_owner_to_parent(connection_struct *conn, files_struct *fsp, const char *fname, SMB_STRUCT_STAT *psbuf)
|
||||
{
|
||||
const char *parent_path = parent_dirname(fname);
|
||||
SMB_STRUCT_STAT parent_st;
|
||||
int ret;
|
||||
|
||||
ret = SMB_VFS_STAT(conn, parent_path, &parent_st);
|
||||
if (ret == -1) {
|
||||
DEBUG(0,("change_owner_to_parent: failed to stat parent directory %s. Error was %s\n",
|
||||
parent_path, strerror(errno) ));
|
||||
return;
|
||||
}
|
||||
|
||||
if (fsp && fsp->fd != -1) {
|
||||
become_root();
|
||||
ret = SMB_VFS_FCHOWN(fsp, fsp->fd, parent_st.st_uid, (gid_t)-1);
|
||||
unbecome_root();
|
||||
if (ret == -1) {
|
||||
DEBUG(0,("change_owner_to_parent: failed to fchown file %s to parent directory uid %u. \
|
||||
Error was %s\n",
|
||||
fname, (unsigned int)parent_st.st_uid, strerror(errno) ));
|
||||
}
|
||||
|
||||
DEBUG(10,("change_owner_to_parent: changed new file %s to parent directory uid %u.\n",
|
||||
fname, (unsigned int)parent_st.st_uid ));
|
||||
|
||||
} else {
|
||||
/* We've already done an lstat into psbuf, and we know it's a directory. If
|
||||
we can do an open/fstat and the dev/ino are the same then we can safely
|
||||
fchown without races. This works under Linux - but should just fail gracefully
|
||||
if any step on the way fails. JRA */
|
||||
|
||||
BOOL need_close_fsp = False;
|
||||
SMB_STRUCT_STAT sbuf;
|
||||
int fd = -1;
|
||||
|
||||
if (!fsp) {
|
||||
int action;
|
||||
fsp = open_directory(conn, fname, psbuf, FILE_GENERIC_READ,
|
||||
SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDONLY),
|
||||
FILE_EXISTS_OPEN, &action);
|
||||
if (!fsp) {
|
||||
DEBUG(10,("change_owner_to_parent: open_directory on %s failed. Error was %s\n",
|
||||
fname, strerror(errno) ));
|
||||
return;
|
||||
}
|
||||
need_close_fsp = True;
|
||||
}
|
||||
fd = SMB_VFS_OPEN(conn,fname,O_RDONLY,0);
|
||||
if (fd == -1) {
|
||||
DEBUG(10,("change_owner_to_parent: failed to VFS_OPEN directory %s. Error was %s\n",
|
||||
fname, strerror(errno) ));
|
||||
goto out;
|
||||
}
|
||||
ret = SMB_VFS_FSTAT(fsp,fd,&sbuf);
|
||||
if (ret == -1) {
|
||||
DEBUG(10,("change_owner_to_parent: failed to VFS_STAT directory %s. Error was %s\n",
|
||||
fname, strerror(errno) ));
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Ensure we're pointing at the same place. */
|
||||
if (sbuf.st_dev != psbuf->st_dev || sbuf.st_ino != psbuf->st_ino || !S_ISDIR(sbuf.st_mode)) {
|
||||
DEBUG(0,("change_owner_to_parent: device/inode/mode on director %s changed. Refusing to fchown !\n",
|
||||
fname ));
|
||||
goto out;
|
||||
}
|
||||
|
||||
become_root();
|
||||
ret = SMB_VFS_FCHOWN(fsp, fd, parent_st.st_uid, (gid_t)-1);
|
||||
unbecome_root();
|
||||
if (ret == -1) {
|
||||
DEBUG(10,("change_owner_to_parent: failed to fchown directory %s to parent directory uid %u. \
|
||||
Error was %s\n",
|
||||
fname, (unsigned int)parent_st.st_uid, strerror(errno) ));
|
||||
goto out;
|
||||
}
|
||||
|
||||
DEBUG(10,("change_owner_to_parent: changed new directory %s to parent directory uid %u.\n",
|
||||
fname, (unsigned int)parent_st.st_uid ));
|
||||
|
||||
out:
|
||||
|
||||
if (fd != -1) {
|
||||
SMB_VFS_CLOSE(fsp,fd);
|
||||
}
|
||||
if (need_close_fsp) {
|
||||
close_file(fsp, False);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Open a file.
|
||||
****************************************************************************/
|
||||
@ -1391,8 +1488,13 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n",
|
||||
action = FILE_WAS_OPENED;
|
||||
if (file_existed && (flags2 & O_TRUNC))
|
||||
action = FILE_WAS_OVERWRITTEN;
|
||||
if (!file_existed)
|
||||
if (!file_existed) {
|
||||
action = FILE_WAS_CREATED;
|
||||
/* Change the owner if required. */
|
||||
if (lp_inherit_owner(SNUM(conn))) {
|
||||
change_owner_to_parent(conn, fsp, fsp->fsp_name, psbuf);
|
||||
}
|
||||
}
|
||||
|
||||
if (paction) {
|
||||
*paction = action;
|
||||
@ -1547,7 +1649,7 @@ int close_file_fchmod(files_struct *fsp)
|
||||
Open a directory from an NT SMB call.
|
||||
****************************************************************************/
|
||||
|
||||
files_struct *open_directory(connection_struct *conn, char *fname, SMB_STRUCT_STAT *psbuf,
|
||||
files_struct *open_directory(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf,
|
||||
uint32 desired_access, int share_mode, int smb_ofun, int *action)
|
||||
{
|
||||
extern struct current_user current_user;
|
||||
@ -1585,39 +1687,29 @@ files_struct *open_directory(connection_struct *conn, char *fname, SMB_STRUCT_ST
|
||||
* Try and create the directory.
|
||||
*/
|
||||
|
||||
if(!CAN_WRITE(conn)) {
|
||||
DEBUG(2,("open_directory: failing create on read-only share\n"));
|
||||
file_free(fsp);
|
||||
errno = EACCES;
|
||||
return NULL;
|
||||
}
|
||||
/* We know bad_path is false as it's caught earlier. */
|
||||
|
||||
if (ms_has_wild(fname)) {
|
||||
file_free(fsp);
|
||||
DEBUG(5,("open_directory: failing create on filename %s with wildcards\n", fname));
|
||||
unix_ERR_class = ERRDOS;
|
||||
unix_ERR_code = ERRinvalidname;
|
||||
unix_ERR_ntstatus = NT_STATUS_OBJECT_NAME_INVALID;
|
||||
return NULL;
|
||||
}
|
||||
NTSTATUS status = mkdir_internal(conn, fname, False);
|
||||
|
||||
if( strchr_m(fname, ':')) {
|
||||
file_free(fsp);
|
||||
DEBUG(5,("open_directory: failing create on filename %s with colon in name\n", fname));
|
||||
unix_ERR_class = ERRDOS;
|
||||
unix_ERR_code = ERRinvalidname;
|
||||
unix_ERR_ntstatus = NT_STATUS_NOT_A_DIRECTORY;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(vfs_MkDir(conn,fname, unix_mode(conn,aDIR, fname, True)) < 0) {
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(2,("open_directory: unable to create %s. Error was %s\n",
|
||||
fname, strerror(errno) ));
|
||||
file_free(fsp);
|
||||
/* Ensure we return the correct NT status to the client. */
|
||||
unix_ERR_ntstatus = status;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(SMB_VFS_STAT(conn,fname, psbuf) != 0) {
|
||||
/* Ensure we're checking for a symlink here.... */
|
||||
/* We don't want to get caught by a symlink racer. */
|
||||
|
||||
if(SMB_VFS_LSTAT(conn,fname, psbuf) != 0) {
|
||||
file_free(fsp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(!S_ISDIR(psbuf->st_mode)) {
|
||||
DEBUG(0,("open_directory: %s is not a directory !\n", fname ));
|
||||
file_free(fsp);
|
||||
return NULL;
|
||||
}
|
||||
@ -1674,13 +1766,19 @@ files_struct *open_directory(connection_struct *conn, char *fname, SMB_STRUCT_ST
|
||||
string_set(&fsp->fsp_name,fname);
|
||||
|
||||
if (delete_on_close) {
|
||||
NTSTATUS result = set_delete_on_close_internal(fsp, delete_on_close, 0);
|
||||
NTSTATUS status = set_delete_on_close_internal(fsp, delete_on_close, 0);
|
||||
|
||||
if (NT_STATUS_V(result) != NT_STATUS_V(NT_STATUS_OK)) {
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
file_free(fsp);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Change the owner if required. */
|
||||
if ((*action == FILE_WAS_CREATED) && lp_inherit_owner(SNUM(conn))) {
|
||||
change_owner_to_parent(conn, fsp, fsp->fsp_name, psbuf);
|
||||
}
|
||||
|
||||
conn->num_files_open++;
|
||||
|
||||
return fsp;
|
||||
|
@ -3303,29 +3303,47 @@ int reply_printwrite(connection_struct *conn, char *inbuf,char *outbuf, int dum_
|
||||
code.
|
||||
****************************************************************************/
|
||||
|
||||
NTSTATUS mkdir_internal(connection_struct *conn, pstring directory)
|
||||
NTSTATUS mkdir_internal(connection_struct *conn, const pstring directory, BOOL bad_path)
|
||||
{
|
||||
BOOL bad_path = False;
|
||||
SMB_STRUCT_STAT sbuf;
|
||||
int ret= -1;
|
||||
|
||||
unix_convert(directory,conn,0,&bad_path,&sbuf);
|
||||
|
||||
if( strchr_m(directory, ':')) {
|
||||
return NT_STATUS_NOT_A_DIRECTORY;
|
||||
if(!CAN_WRITE(conn)) {
|
||||
DEBUG(5,("mkdir_internal: failing create on read-only share %s\n", lp_servicename(SNUM(conn))));
|
||||
errno = EACCES;
|
||||
return map_nt_error_from_unix(errno);
|
||||
}
|
||||
|
||||
/* The following 2 clauses set explicit DOS error codes. JRA. */
|
||||
if (ms_has_wild(directory)) {
|
||||
DEBUG(5,("mkdir_internal: failing create on filename %s with wildcards\n", directory));
|
||||
unix_ERR_class = ERRDOS;
|
||||
unix_ERR_code = ERRinvalidname;
|
||||
return NT_STATUS_OBJECT_NAME_INVALID;
|
||||
}
|
||||
|
||||
if( strchr_m(directory, ':')) {
|
||||
DEBUG(5,("mkdir_internal: failing create on filename %s with colon in name\n", directory));
|
||||
unix_ERR_class = ERRDOS;
|
||||
unix_ERR_code = ERRinvalidname;
|
||||
return NT_STATUS_NOT_A_DIRECTORY;
|
||||
}
|
||||
|
||||
if (bad_path) {
|
||||
return NT_STATUS_OBJECT_PATH_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (check_name(directory, conn))
|
||||
ret = vfs_MkDir(conn,directory,unix_mode(conn,aDIR,directory,True));
|
||||
|
||||
if (!check_name(directory, conn)) {
|
||||
if(errno == ENOENT) {
|
||||
if (bad_path) {
|
||||
return NT_STATUS_OBJECT_PATH_NOT_FOUND;
|
||||
} else {
|
||||
return NT_STATUS_OBJECT_NAME_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
return map_nt_error_from_unix(errno);
|
||||
}
|
||||
|
||||
ret = vfs_MkDir(conn,directory,unix_mode(conn,aDIR,directory,True));
|
||||
if (ret == -1) {
|
||||
if(errno == ENOENT) {
|
||||
return NT_STATUS_OBJECT_NAME_NOT_FOUND;
|
||||
@ -3345,6 +3363,9 @@ int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
|
||||
pstring directory;
|
||||
int outsize;
|
||||
NTSTATUS status;
|
||||
BOOL bad_path = False;
|
||||
SMB_STRUCT_STAT sbuf;
|
||||
|
||||
START_PROFILE(SMBmkdir);
|
||||
|
||||
srvstr_get_path(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), 0, STR_TERMINATE, &status, False);
|
||||
@ -3355,12 +3376,32 @@ int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
|
||||
|
||||
RESOLVE_DFSPATH(directory, conn, inbuf, outbuf);
|
||||
|
||||
status = mkdir_internal(conn, directory);
|
||||
unix_convert(directory,conn,0,&bad_path,&sbuf);
|
||||
|
||||
status = mkdir_internal(conn, directory,bad_path);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
END_PROFILE(SMBmkdir);
|
||||
return ERROR_NT(status);
|
||||
}
|
||||
|
||||
if (lp_inherit_owner(SNUM(conn))) {
|
||||
/* Ensure we're checking for a symlink here.... */
|
||||
/* We don't want to get caught by a symlink racer. */
|
||||
|
||||
if(SMB_VFS_LSTAT(conn,directory, &sbuf) != 0) {
|
||||
END_PROFILE(SMBmkdir);
|
||||
return(UNIXERROR(ERRDOS,ERRnoaccess));
|
||||
}
|
||||
|
||||
if(!S_ISDIR(sbuf.st_mode)) {
|
||||
DEBUG(0,("reply_mkdir: %s is not a directory !\n", directory ));
|
||||
END_PROFILE(SMBmkdir);
|
||||
return(UNIXERROR(ERRDOS,ERRnoaccess));
|
||||
}
|
||||
|
||||
change_owner_to_parent(conn, NULL, directory, &sbuf);
|
||||
}
|
||||
|
||||
outsize = set_message(outbuf,0,0,True);
|
||||
|
||||
DEBUG( 3, ( "mkdir %s ret=%d\n", directory, outsize ) );
|
||||
|
Loading…
x
Reference in New Issue
Block a user