*/
#include "includes.h"
+#include "smbd/smbd.h"
+#include "system/filesys.h"
+#include "../libcli/security/security.h"
+#include "trans2.h"
+#include "passdb/lookup_sid.h"
extern const struct generic_mapping file_generic_mapping;
paie->ace_flags = SEC_ACE_FLAG_INHERITED_ACE;
if (!get_pai_owner_type(paie, entry_offset)) {
+ SAFE_FREE(paie);
return NULL;
}
paie->ace_flags = CVAL(entry_offset,0);
if (!get_pai_owner_type(paie, entry_offset+1)) {
+ SAFE_FREE(paie);
return NULL;
}
if (!def_entry) {
* ensure the POSIX ACL types are the same. */
if (!dir_acl) {
- can_merge = (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
+ can_merge = (dom_sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
(curr_ace->attr == curr_ace_outer->attr));
} else {
- can_merge = (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
+ can_merge = (dom_sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
(curr_ace->type == curr_ace_outer->type) &&
(curr_ace->attr == curr_ace_outer->attr));
}
* we've put on the ACL, we know the deny must be the first one.
*/
- if (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
+ if (dom_sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
(curr_ace_outer->attr == DENY_ACE) && (curr_ace->attr == ALLOW_ACE)) {
if( DEBUGLVL( 10 )) {
* This may be a group chown only set.
*/
- if (security_info_sent & OWNER_SECURITY_INFORMATION) {
+ if (security_info_sent & SECINFO_OWNER) {
sid_copy(&owner_sid, psd->owner_sid);
if (!sid_to_uid(&owner_sid, puser)) {
if (lp_force_unknown_acl_user(SNUM(conn))) {
* This may be an owner chown only set.
*/
- if (security_info_sent & GROUP_SECURITY_INFORMATION) {
+ if (security_info_sent & SECINFO_GROUP) {
sid_copy(&grp_sid, psd->group_sid);
if (!sid_to_gid( &grp_sid, pgrp)) {
if (lp_force_unknown_acl_user(SNUM(conn))) {
/* "Everyone" always matches every uid. */
- if (sid_equal(&group_ace->trustee, &global_sid_World))
+ if (dom_sid_equal(&group_ace->trustee, &global_sid_World))
return True;
/*
* and don't need to do the complex user_in_group_sid() call
*/
if (uid_ace->unix_ug.uid == get_current_uid(conn)) {
- const UNIX_USER_TOKEN *curr_utok = NULL;
+ const struct security_unix_token *curr_utok = NULL;
size_t i;
if (group_ace->unix_ug.gid == get_current_gid(conn)) {
for (i=0, current_ace = ace; i < entries; i++, current_ace = current_ace->next) {
if (!got_user_obj && current_ace->owner_type == UID_ACE &&
- sid_equal(¤t_ace->trustee, pfile_owner_sid)) {
+ dom_sid_equal(¤t_ace->trustee, pfile_owner_sid)) {
current_ace->type = SMB_ACL_USER_OBJ;
got_user_obj = True;
}
if (!got_group_obj && current_ace->owner_type == GID_ACE &&
- sid_equal(¤t_ace->trustee, pfile_grp_sid)) {
+ dom_sid_equal(¤t_ace->trustee, pfile_grp_sid)) {
current_ace->type = SMB_ACL_GROUP_OBJ;
got_group_obj = True;
}
*/
if (ace->type == SMB_ACL_USER_OBJ &&
- !(sid_equal(&ace->trustee, &global_sid_Creator_Owner))) {
+ !(dom_sid_equal(&ace->trustee, &global_sid_Creator_Owner))) {
canon_ace *dup_ace = dup_canon_ace(ace);
if (dup_ace == NULL) {
}
if (ace->type == SMB_ACL_GROUP_OBJ &&
- !(sid_equal(&ace->trustee, &global_sid_Creator_Group))) {
+ !(dom_sid_equal(&ace->trustee, &global_sid_Creator_Group))) {
canon_ace *dup_ace = dup_canon_ace(ace);
if (dup_ace == NULL) {
if (psa1->access_mask != psa2->access_mask)
continue;
- if (!sid_equal(&psa1->trustee, &psa2->trustee))
+ if (!dom_sid_equal(&psa1->trustee, &psa2->trustee))
continue;
/*
struct security_ace *psa = &dacl->aces[i];
/*
- * Create a cannon_ace entry representing this NT DACL ACE.
+ * Create a canon_ace entry representing this NT DACL ACE.
*/
if ((current_ace = SMB_MALLOC_P(canon_ace)) == NULL) {
* Note what kind of a POSIX ACL this should map to.
*/
- if( sid_equal(¤t_ace->trustee, &global_sid_World)) {
+ if( dom_sid_equal(¤t_ace->trustee, &global_sid_World)) {
current_ace->owner_type = WORLD_ACE;
current_ace->unix_ug.world = -1;
current_ace->type = SMB_ACL_OTHER;
- } else if (sid_equal(¤t_ace->trustee, &global_sid_Creator_Owner)) {
+ } else if (dom_sid_equal(¤t_ace->trustee, &global_sid_Creator_Owner)) {
current_ace->owner_type = UID_ACE;
current_ace->unix_ug.uid = pst->st_ex_uid;
current_ace->type = SMB_ACL_USER_OBJ;
psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
- } else if (sid_equal(¤t_ace->trustee, &global_sid_Creator_Group)) {
+ } else if (dom_sid_equal(¤t_ace->trustee, &global_sid_Creator_Group)) {
current_ace->owner_type = GID_ACE;
current_ace->unix_ug.gid = pst->st_ex_gid;
current_ace->type = SMB_ACL_GROUP_OBJ;
continue;
}
+ if (lp_force_unknown_acl_user(SNUM(fsp->conn))) {
+ DEBUG(10, ("create_canon_ace_lists: ignoring "
+ "unknown or foreign SID %s\n",
+ sid_string_dbg(&psa->trustee)));
+ SAFE_FREE(current_ace);
+ continue;
+ }
+
free_canon_ace_list(file_ace);
free_canon_ace_list(dir_ace);
DEBUG(0, ("create_canon_ace_lists: unable to map SID "
continue;
}
- if (!sid_equal(&curr_ace->trustee, &global_sid_World))
+ if (!dom_sid_equal(&curr_ace->trustee, &global_sid_World))
continue;
/* JRATEST - assert. */
* If no DACL then this is a chown only security descriptor.
*/
- if(!(security_info_sent & DACL_SECURITY_INFORMATION) || !psd->dacl)
+ if(!(security_info_sent & SECINFO_DACL) || !psd->dacl)
return True;
/*
static bool current_user_in_group(connection_struct *conn, gid_t gid)
{
int i;
- const UNIX_USER_TOKEN *utok = get_current_utok(conn);
+ const struct security_unix_token *utok = get_current_utok(conn);
for (i = 0; i < utok->ngroups; i++) {
if (utok->groups[i] == gid) {
if ((nt_ace_list[i].type == nt_ace_list[j].type) &&
(nt_ace_list[i].size == nt_ace_list[j].size) &&
(nt_ace_list[i].access_mask == nt_ace_list[j].access_mask) &&
- sid_equal(&nt_ace_list[i].trustee, &nt_ace_list[j].trustee) &&
+ dom_sid_equal(&nt_ace_list[i].trustee, &nt_ace_list[j].trustee) &&
(i_inh == j_inh) &&
(i_flags_ni == 0) &&
(j_flags_ni == (SEC_ACE_FLAG_OBJECT_INHERIT|
/* first search for a duplicate */
for (i = 0; i < *num_aces; i++) {
- if (sid_equal(&nt_ace_list[i].trustee, sid) &&
+ if (dom_sid_equal(&nt_ace_list[i].trustee, sid) &&
(nt_ace_list[i].flags == flags)) break;
}
num_profile_acls = 3;
}
- if ((security_info & DACL_SECURITY_INFORMATION) && !(security_info & PROTECTED_DACL_SECURITY_INFORMATION)) {
+ if ((security_info & SECINFO_DACL) && !(security_info & SECINFO_PROTECTED_DACL)) {
/*
* In the optimum case Creator Owner and Creator Group would be used for
if (lp_profile_acls(SNUM(conn))) {
for (i = 0; i < num_aces; i++) {
- if (sid_equal(&nt_ace_list[i].trustee, &owner_sid)) {
+ if (dom_sid_equal(&nt_ace_list[i].trustee, &owner_sid)) {
add_or_replace_ace(nt_ace_list, &num_aces,
&orig_owner_sid,
nt_ace_list[i].type,
goto done;
}
}
- } /* security_info & DACL_SECURITY_INFORMATION */
+ } /* security_info & SECINFO_DACL */
psd = make_standard_sec_desc( talloc_tos(),
- (security_info & OWNER_SECURITY_INFORMATION) ? &owner_sid : NULL,
- (security_info & GROUP_SECURITY_INFORMATION) ? &group_sid : NULL,
+ (security_info & SECINFO_OWNER) ? &owner_sid : NULL,
+ (security_info & SECINFO_GROUP) ? &group_sid : NULL,
psa,
&sd_size);
Try to chown a file. We will be able to chown it under the following conditions.
1) If we have root privileges, then it will just work.
- 2) If we have SeTakeOwnershipPrivilege we can change the user to the current user.
- 3) If we have SeRestorePrivilege we can change the user to any other user.
+ 2) If we have SeRestorePrivilege we can change the user + group to any other user.
+ 3) If we have SeTakeOwnershipPrivilege we can change the user to the current user.
4) If we have write permission to the file and dos_filemodes is set
then allow chown to the currently authenticated user.
****************************************************************************/
-int try_chown(connection_struct *conn, struct smb_filename *smb_fname,
- uid_t uid, gid_t gid)
+NTSTATUS try_chown(files_struct *fsp, uid_t uid, gid_t gid)
{
- int ret;
- files_struct *fsp;
+ NTSTATUS status;
- if(!CAN_WRITE(conn)) {
- return -1;
+ if(!CAN_WRITE(fsp->conn)) {
+ return NT_STATUS_MEDIA_WRITE_PROTECTED;
}
/* Case (1). */
- /* try the direct way first */
- if (lp_posix_pathnames()) {
- ret = SMB_VFS_LCHOWN(conn, smb_fname->base_name, uid, gid);
- } else {
- ret = SMB_VFS_CHOWN(conn, smb_fname->base_name, uid, gid);
+ status = vfs_chown_fsp(fsp, uid, gid);
+ if (NT_STATUS_IS_OK(status)) {
+ return status;
}
- if (ret == 0)
- return 0;
-
/* Case (2) / (3) */
if (lp_enable_privileges()) {
-
- bool has_take_ownership_priv = user_has_privileges(get_current_nttok(conn),
- &se_take_ownership);
- bool has_restore_priv = user_has_privileges(get_current_nttok(conn),
- &se_restore);
-
- /* Case (2) */
- if ( ( has_take_ownership_priv && ( uid == get_current_uid(conn) ) ) ||
- /* Case (3) */
- ( has_restore_priv ) ) {
-
- become_root();
- /* Keep the current file gid the same - take ownership doesn't imply group change. */
- if (lp_posix_pathnames()) {
- ret = SMB_VFS_LCHOWN(conn, smb_fname->base_name, uid,
- (gid_t)-1);
+ bool has_take_ownership_priv = security_token_has_privilege(
+ get_current_nttok(fsp->conn),
+ SEC_PRIV_TAKE_OWNERSHIP);
+ bool has_restore_priv = security_token_has_privilege(
+ get_current_nttok(fsp->conn),
+ SEC_PRIV_RESTORE);
+
+ if (has_restore_priv) {
+ ; /* Case (2) */
+ } else if (has_take_ownership_priv) {
+ /* Case (3) */
+ if (uid == get_current_uid(fsp->conn)) {
+ gid = (gid_t)-1;
} else {
- ret = SMB_VFS_CHOWN(conn, smb_fname->base_name, uid,
- (gid_t)-1);
+ has_take_ownership_priv = false;
}
+ }
+
+ if (has_take_ownership_priv || has_restore_priv) {
+ become_root();
+ status = vfs_chown_fsp(fsp, uid, gid);
unbecome_root();
- return ret;
+ return status;
}
}
/* Case (4). */
- if (!lp_dos_filemode(SNUM(conn))) {
- errno = EPERM;
- return -1;
+ if (!lp_dos_filemode(SNUM(fsp->conn))) {
+ return NT_STATUS_ACCESS_DENIED;
}
/* only allow chown to the current user. This is more secure,
and also copes with the case where the SID in a take ownership ACL is
a local SID on the users workstation
*/
- if (uid != get_current_uid(conn)) {
- errno = EPERM;
- return -1;
- }
-
- if (lp_posix_pathnames()) {
- ret = SMB_VFS_LSTAT(conn, smb_fname);
- } else {
- ret = SMB_VFS_STAT(conn, smb_fname);
- }
-
- if (ret == -1) {
- return -1;
- }
-
- if (!NT_STATUS_IS_OK(open_file_fchmod(NULL, conn, smb_fname, &fsp))) {
- return -1;
+ if (uid != get_current_uid(fsp->conn)) {
+ return NT_STATUS_ACCESS_DENIED;
}
become_root();
/* Keep the current file gid the same. */
- if (fsp->fh->fd == -1) {
- if (lp_posix_pathnames()) {
- ret = SMB_VFS_LCHOWN(conn, smb_fname->base_name, uid,
- (gid_t)-1);
- } else {
- ret = SMB_VFS_CHOWN(conn, smb_fname->base_name, uid,
- (gid_t)-1);
- }
- } else {
- ret = SMB_VFS_FCHOWN(fsp, uid, (gid_t)-1);
- }
+ status = vfs_chown_fsp(fsp, uid, (gid_t)-1);
unbecome_root();
- close_file_fchmod(NULL, fsp);
-
- return ret;
+ return status;
}
#if 0
}
status = SMB_VFS_GET_NT_ACL(parent_fsp->conn, smb_dname->base_name,
- DACL_SECURITY_INFORMATION, &parent_sd );
+ SECINFO_DACL, &parent_sd );
close_file(NULL, parent_fsp, NORMAL_CLOSE);
TALLOC_FREE(smb_dname);
* same SID. This is order N^2. Ouch :-(. JRA. */
unsigned int k;
for (k = 0; k < psd->dacl->num_aces; k++) {
- if (sid_equal(&psd->dacl->aces[k].trustee,
+ if (dom_sid_equal(&psd->dacl->aces[k].trustee,
&se->trustee)) {
break;
}
Reply to set a security descriptor on an fsp. security_info_sent is the
description of the following NT ACL.
This should be the only external function needed for the UNIX style set ACL.
+ We make a copy of psd_orig as internal functions modify the elements inside
+ it, even though it's a const pointer.
****************************************************************************/
-NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const struct security_descriptor *psd)
+NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const struct security_descriptor *psd_orig)
{
connection_struct *conn = fsp->conn;
uid_t user = (uid_t)-1;
bool set_acl_as_root = false;
bool acl_set_support = false;
bool ret = false;
+ struct security_descriptor *psd = NULL;
DEBUG(10,("set_nt_acl: called for file %s\n",
fsp_str_dbg(fsp)));
return NT_STATUS_MEDIA_WRITE_PROTECTED;
}
+ if (!psd_orig) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ psd = dup_sec_desc(talloc_tos(), psd_orig);
+ if (!psd) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
/*
* Get the current state of the file.
*/
* Unpack the user/group/world id's.
*/
+ /* POSIX can't cope with missing owner/group. */
+ if ((security_info_sent & SECINFO_OWNER) && (psd->owner_sid == NULL)) {
+ security_info_sent &= ~SECINFO_OWNER;
+ }
+ if ((security_info_sent & SECINFO_GROUP) && (psd->group_sid == NULL)) {
+ security_info_sent &= ~SECINFO_GROUP;
+ }
+
status = unpack_nt_owners( conn, &user, &grp, security_info_sent, psd);
if (!NT_STATUS_IS_OK(status)) {
return status;
fsp_str_dbg(fsp), (unsigned int)user,
(unsigned int)grp));
- if(try_chown(fsp->conn, fsp->fsp_name, user, grp) == -1) {
+ status = try_chown(fsp, user, grp);
+ if(!NT_STATUS_IS_OK(status)) {
DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error "
- "= %s.\n", fsp_str_dbg(fsp),
- (unsigned int)user, (unsigned int)grp,
- strerror(errno)));
- if (errno == EPERM) {
- return NT_STATUS_INVALID_OWNER;
- }
- return map_nt_error_from_unix(errno);
+ "= %s.\n", fsp_str_dbg(fsp),
+ (unsigned int)user,
+ (unsigned int)grp,
+ nt_errstr(status)));
+ return status;
}
/*
create_file_sids(&fsp->fsp_name->st, &file_owner_sid, &file_grp_sid);
+ if((security_info_sent & SECINFO_DACL) &&
+ (psd->type & SEC_DESC_DACL_PRESENT) &&
+ (psd->dacl == NULL)) {
+ struct security_ace ace[3];
+
+ /* We can't have NULL DACL in POSIX.
+ Use owner/group/Everyone -> full access. */
+
+ init_sec_ace(&ace[0],
+ &file_owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ GENERIC_ALL_ACCESS,
+ 0);
+ init_sec_ace(&ace[1],
+ &file_grp_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ GENERIC_ALL_ACCESS,
+ 0);
+ init_sec_ace(&ace[2],
+ &global_sid_World,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ GENERIC_ALL_ACCESS,
+ 0);
+ psd->dacl = make_sec_acl(talloc_tos(),
+ NT4_ACL_REVISION,
+ 3,
+ ace);
+ if (psd->dacl == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ security_acl_map_generic(psd->dacl, &file_generic_mapping);
+ }
+
acl_perms = unpack_canon_ace(fsp, &fsp->fsp_name->st, &file_owner_sid,
&file_grp_sid, &file_ace_list,
&dir_ace_list, security_info_sent, psd);
* Only change security if we got a DACL.
*/
- if(!(security_info_sent & DACL_SECURITY_INFORMATION) || (psd->dacl == NULL)) {
+ if(!(security_info_sent & SECINFO_DACL) || (psd->dacl == NULL)) {
free_canon_ace_list(file_ace_list);
free_canon_ace_list(dir_ace_list);
return NT_STATUS_OK;
return NULL;
}
- if (!NT_STATUS_IS_OK(SMB_VFS_FGET_NT_ACL( &finfo, DACL_SECURITY_INFORMATION, &psd))) {
+ if (!NT_STATUS_IS_OK(SMB_VFS_FGET_NT_ACL( &finfo, SECINFO_DACL, &psd))) {
DEBUG(0,("get_nt_acl_no_snum: get_nt_acl returned zero.\n"));
TALLOC_FREE(finfo.fsp_name);
conn_free(conn);
return ret_sd;
}
+
+/* Stolen shamelessly from pvfs_default_acl() in source4 :-). */
+
+NTSTATUS make_default_filesystem_acl(TALLOC_CTX *ctx,
+ const char *name,
+ SMB_STRUCT_STAT *psbuf,
+ struct security_descriptor **ppdesc)
+{
+ struct dom_sid owner_sid, group_sid;
+ size_t size = 0;
+ struct security_ace aces[4];
+ uint32_t access_mask = 0;
+ mode_t mode = psbuf->st_ex_mode;
+ struct security_acl *new_dacl = NULL;
+ int idx = 0;
+
+ DEBUG(10,("make_default_filesystem_acl: file %s mode = 0%o\n",
+ name, (int)mode ));
+
+ uid_to_sid(&owner_sid, psbuf->st_ex_uid);
+ gid_to_sid(&group_sid, psbuf->st_ex_gid);
+
+ /*
+ We provide up to 4 ACEs
+ - Owner
+ - Group
+ - Everyone
+ - NT System
+ */
+
+ if (mode & S_IRUSR) {
+ if (mode & S_IWUSR) {
+ access_mask |= SEC_RIGHTS_FILE_ALL;
+ } else {
+ access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
+ }
+ }
+ if (mode & S_IWUSR) {
+ access_mask |= SEC_RIGHTS_FILE_WRITE | SEC_STD_DELETE;
+ }
+
+ init_sec_ace(&aces[idx],
+ &owner_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ access_mask,
+ 0);
+ idx++;
+
+ access_mask = 0;
+ if (mode & S_IRGRP) {
+ access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
+ }
+ if (mode & S_IWGRP) {
+ /* note that delete is not granted - this matches posix behaviour */
+ access_mask |= SEC_RIGHTS_FILE_WRITE;
+ }
+ if (access_mask) {
+ init_sec_ace(&aces[idx],
+ &group_sid,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ access_mask,
+ 0);
+ idx++;
+ }
+
+ access_mask = 0;
+ if (mode & S_IROTH) {
+ access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
+ }
+ if (mode & S_IWOTH) {
+ access_mask |= SEC_RIGHTS_FILE_WRITE;
+ }
+ if (access_mask) {
+ init_sec_ace(&aces[idx],
+ &global_sid_World,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ access_mask,
+ 0);
+ idx++;
+ }
+
+ init_sec_ace(&aces[idx],
+ &global_sid_System,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_RIGHTS_FILE_ALL,
+ 0);
+ idx++;
+
+ new_dacl = make_sec_acl(ctx,
+ NT4_ACL_REVISION,
+ idx,
+ aces);
+
+ if (!new_dacl) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ *ppdesc = make_sec_desc(ctx,
+ SECURITY_DESCRIPTOR_REVISION_1,
+ SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT,
+ &owner_sid,
+ &group_sid,
+ NULL,
+ new_dacl,
+ &size);
+ if (!*ppdesc) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ return NT_STATUS_OK;
+}