*/
#include "includes.h"
+#include "../libcli/security/security.h"
-extern struct current_user current_user;
extern const struct generic_mapping file_generic_mapping;
#undef DBGC_CLASS
struct canon_ace *next, *prev;
SMB_ACL_TAG_T type;
mode_t perms; /* Only use S_I(R|W|X)USR mode bits here. */
- DOM_SID trustee;
+ struct dom_sid trustee;
enum ace_owner owner_type;
enum ace_attribute attr;
posix_id unix_ug;
char *entry_offset = NULL;
unsigned int num_entries = 0;
unsigned int num_def_entries = 0;
+ unsigned int i;
for (ace_list = file_ace_list; ace_list; ace_list = ace_list->next) {
num_entries++;
SSVAL(pai_buf,PAI_V2_NUM_ENTRIES_OFFSET,num_entries);
SSVAL(pai_buf,PAI_V2_NUM_DEFAULT_ENTRIES_OFFSET,num_def_entries);
+ DEBUG(10,("create_pai_buf_v2: sd_type = 0x%x\n",
+ (unsigned int)sd_type ));
+
entry_offset = pai_buf + PAI_V2_ENTRIES_BASE;
+ i = 0;
for (ace_list = file_ace_list; ace_list; ace_list = ace_list->next) {
uint8_t type_val = (uint8_t)ace_list->owner_type;
uint32_t entry_val = get_entry_val(ace_list);
SCVAL(entry_offset,0,ace_list->ace_flags);
SCVAL(entry_offset,1,type_val);
SIVAL(entry_offset,2,entry_val);
+ DEBUG(10,("create_pai_buf_v2: entry %u [0x%x] [0x%x] [0x%x]\n",
+ i,
+ (unsigned int)ace_list->ace_flags,
+ (unsigned int)type_val,
+ (unsigned int)entry_val ));
+ i++;
entry_offset += PAI_V2_ENTRY_LENGTH;
}
SCVAL(entry_offset,0,ace_list->ace_flags);
SCVAL(entry_offset,1,type_val);
SIVAL(entry_offset,2,entry_val);
+ DEBUG(10,("create_pai_buf_v2: entry %u [0x%x] [0x%x] [0x%x]\n",
+ i,
+ (unsigned int)ace_list->ace_flags,
+ (unsigned int)type_val,
+ (unsigned int)entry_val ));
+ i++;
entry_offset += PAI_V2_ENTRY_LENGTH;
}
DEBUG(10,("get_pai_owner_type: world ace\n"));
break;
default:
+ DEBUG(10,("get_pai_owner_type: unknown type %u\n",
+ (unsigned int)paie->owner_type ));
return false;
}
return true;
paie->ace_flags = SEC_ACE_FLAG_INHERITED_ACE;
if (!get_pai_owner_type(paie, entry_offset)) {
+ SAFE_FREE(paie);
return NULL;
}
memset(paiv, '\0', sizeof(struct pai_val));
paiv->sd_type = (CVAL(buf,PAI_V1_FLAG_OFFSET) == PAI_V1_ACL_FLAG_PROTECTED) ?
- SE_DESC_DACL_PROTECTED : 0;
+ SEC_DESC_DACL_PROTECTED : 0;
paiv->num_entries = SVAL(buf,PAI_V1_NUM_ENTRIES_OFFSET);
paiv->num_def_entries = SVAL(buf,PAI_V1_NUM_DEFAULT_ENTRIES_OFFSET);
************************************************************************/
static const char *create_pai_v2_entries(struct pai_val *paiv,
+ unsigned int num_entries,
const char *entry_offset,
bool def_entry)
{
- int i;
+ unsigned int i;
- for (i = 0; i < paiv->num_entries; i++) {
+ for (i = 0; i < num_entries; i++) {
struct pai_entry *paie = SMB_MALLOC_P(struct pai_entry);
if (!paie) {
return NULL;
paie->ace_flags = CVAL(entry_offset,0);
- entry_offset++;
-
- if (!get_pai_owner_type(paie, entry_offset)) {
+ if (!get_pai_owner_type(paie, entry_offset+1)) {
+ SAFE_FREE(paie);
return NULL;
}
if (!def_entry) {
entry_offset = buf + PAI_V2_ENTRIES_BASE;
- DEBUG(10,("create_pai_val_v2: num_entries = %u, num_def_entries = %u\n",
+ DEBUG(10,("create_pai_val_v2: sd_type = 0x%x num_entries = %u, num_def_entries = %u\n",
+ (unsigned int)paiv->sd_type,
paiv->num_entries, paiv->num_def_entries ));
- entry_offset = create_pai_v2_entries(paiv, entry_offset, false);
+ entry_offset = create_pai_v2_entries(paiv, paiv->num_entries,
+ entry_offset, false);
if (entry_offset == NULL) {
free_inherited_info(paiv);
return NULL;
}
- entry_offset = create_pai_v2_entries(paiv, entry_offset, true);
+ entry_offset = create_pai_v2_entries(paiv, paiv->num_def_entries,
+ entry_offset, true);
if (entry_offset == NULL) {
free_inherited_info(paiv);
return NULL;
Function to create owner and group SIDs from a SMB_STRUCT_STAT.
****************************************************************************/
-void create_file_sids(const SMB_STRUCT_STAT *psbuf, DOM_SID *powner_sid, DOM_SID *pgroup_sid)
+void create_file_sids(const SMB_STRUCT_STAT *psbuf, struct dom_sid *powner_sid, struct dom_sid *pgroup_sid)
{
uid_to_sid( powner_sid, psbuf->st_ex_uid );
gid_to_sid( pgroup_sid, psbuf->st_ex_gid );
}
-/****************************************************************************
- Is the identity in two ACEs equal ? Check both SID and uid/gid.
-****************************************************************************/
-
-static bool identity_in_ace_equal(canon_ace *ace1, canon_ace *ace2)
-{
- if (sid_equal(&ace1->trustee, &ace2->trustee)) {
- return True;
- }
- if (ace1->owner_type == ace2->owner_type) {
- if (ace1->owner_type == UID_ACE &&
- ace1->unix_ug.uid == ace2->unix_ug.uid) {
- return True;
- } else if (ace1->owner_type == GID_ACE &&
- ace1->unix_ug.gid == ace2->unix_ug.gid) {
- return True;
- }
- }
- return False;
-}
-
/****************************************************************************
Merge aces with a common sid - if both are allow or deny, OR the permissions together and
delete the second one. If the first is deny, mask the permissions off and delete the allow
if the permissions become zero, delete the deny if the permissions are non zero.
****************************************************************************/
-static void merge_aces( canon_ace **pp_list_head )
+static void merge_aces( canon_ace **pp_list_head, bool dir_acl)
{
canon_ace *l_head = *pp_list_head;
canon_ace *curr_ace_outer;
curr_ace_outer_next = curr_ace_outer->next; /* Save the link in case we delete. */
for (curr_ace = curr_ace_outer->next; curr_ace; curr_ace = curr_ace_next) {
+ bool can_merge = false;
curr_ace_next = curr_ace->next; /* Save the link in case of delete. */
- if (identity_in_ace_equal(curr_ace, curr_ace_outer) &&
- (curr_ace->attr == curr_ace_outer->attr)) {
+ /* For file ACLs we can merge if the SIDs and ALLOW/DENY
+ * types are the same. For directory acls we must also
+ * ensure the POSIX ACL types are the same. */
+ if (!dir_acl) {
+ can_merge = (dom_sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
+ (curr_ace->attr == curr_ace_outer->attr));
+ } else {
+ 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));
+ }
+
+ if (can_merge) {
if( DEBUGLVL( 10 )) {
dbgtext("merge_aces: Merging ACE's\n");
print_canon_ace( curr_ace_outer, 0);
/* Merge two allow or two deny ACE's. */
+ /* Theoretically we shouldn't merge a dir ACE if
+ * one ACE has the CI flag set, and the other
+ * ACE has the OI flag set, but this is rare
+ * enough we can ignore it. */
+
curr_ace_outer->perms |= curr_ace->perms;
+ curr_ace_outer->ace_flags |= curr_ace->ace_flags;
DLIST_REMOVE(l_head, curr_ace);
SAFE_FREE(curr_ace);
curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */
* we've put on the ACL, we know the deny must be the first one.
*/
- if (identity_in_ace_equal(curr_ace, curr_ace_outer) &&
+ 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 )) {
not get. Deny entries are implicit on get with ace->perms = 0.
****************************************************************************/
-static uint32_t map_canon_ace_perms(int snum,
+uint32_t map_canon_ace_perms(int snum,
enum security_ace_type *pacl_type,
mode_t perms,
bool directory_ace)
}
}
+ if ((perms & S_IWUSR) && lp_dos_filemode(snum)) {
+ nt_mask |= (SEC_STD_WRITE_DAC|SEC_STD_WRITE_OWNER|DELETE_ACCESS);
+ }
+
DEBUG(10,("map_canon_ace_perms: Mapped (UNIX) %x to (NT) %x\n",
(unsigned int)perms, (unsigned int)nt_mask ));
}
/****************************************************************************
- Unpack a SEC_DESC into a UNIX owner and group.
+ Unpack a struct security_descriptor into a UNIX owner and group.
****************************************************************************/
-NTSTATUS unpack_nt_owners(int snum, uid_t *puser, gid_t *pgrp, uint32 security_info_sent, const SEC_DESC *psd)
+NTSTATUS unpack_nt_owners(struct connection_struct *conn,
+ uid_t *puser, gid_t *pgrp,
+ uint32 security_info_sent, const struct
+ security_descriptor *psd)
{
- DOM_SID owner_sid;
- DOM_SID grp_sid;
+ struct dom_sid owner_sid;
+ struct dom_sid grp_sid;
*puser = (uid_t)-1;
*pgrp = (gid_t)-1;
* 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)) {
+ if (lp_force_unknown_acl_user(SNUM(conn))) {
/* this allows take ownership to work
* reasonably */
- *puser = current_user.ut.uid;
+ *puser = get_current_uid(conn);
} else {
DEBUG(3,("unpack_nt_owners: unable to validate"
" owner sid for %s\n",
* 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)) {
+ if (lp_force_unknown_acl_user(SNUM(conn))) {
/* this allows take group ownership to work
* reasonably */
- *pgrp = current_user.ut.gid;
+ *pgrp = get_current_gid(conn);
} else {
DEBUG(3,("unpack_nt_owners: unable to validate"
" group sid.\n"));
expensive and will need optimisation. A *lot* of optimisation :-). JRA.
****************************************************************************/
-static bool uid_entry_in_group( canon_ace *uid_ace, canon_ace *group_ace )
+static bool uid_entry_in_group(connection_struct *conn, canon_ace *uid_ace, canon_ace *group_ace )
{
const char *u_name = NULL;
/* "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;
/*
* if it's the current user, we already have the unix token
* and don't need to do the complex user_in_group_sid() call
*/
- if (uid_ace->unix_ug.uid == current_user.ut.uid) {
+ if (uid_ace->unix_ug.uid == get_current_uid(conn)) {
+ const struct security_unix_token *curr_utok = NULL;
size_t i;
- if (group_ace->unix_ug.gid == current_user.ut.gid) {
+ if (group_ace->unix_ug.gid == get_current_gid(conn)) {
return True;
}
- for (i=0; i < current_user.ut.ngroups; i++) {
- if (group_ace->unix_ug.gid == current_user.ut.groups[i]) {
+ curr_utok = get_current_utok(conn);
+ for (i=0; i < curr_utok->ngroups; i++) {
+ if (group_ace->unix_ug.gid == curr_utok->groups[i]) {
return True;
}
}
type.
****************************************************************************/
-static bool ensure_canon_entry_valid(canon_ace **pp_ace,
+static bool ensure_canon_entry_valid(connection_struct *conn, canon_ace **pp_ace,
const struct share_params *params,
const bool is_directory,
- const DOM_SID *pfile_owner_sid,
- const DOM_SID *pfile_grp_sid,
+ const struct dom_sid *pfile_owner_sid,
+ const struct dom_sid *pfile_grp_sid,
const SMB_STRUCT_STAT *pst,
bool setting_acl)
{
for (pace_iter = *pp_ace; pace_iter; pace_iter = pace_iter->next) {
if (pace_iter->type == SMB_ACL_GROUP_OBJ || pace_iter->type == SMB_ACL_GROUP) {
- if (uid_entry_in_group(pace, pace_iter)) {
+ if (uid_entry_in_group(conn, pace, pace_iter)) {
pace->perms |= pace_iter->perms;
group_matched = True;
}
file owner or the owning group, and map these to SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ.
****************************************************************************/
-static void check_owning_objs(canon_ace *ace, DOM_SID *pfile_owner_sid, DOM_SID *pfile_grp_sid)
+static void check_owning_objs(canon_ace *ace, struct dom_sid *pfile_owner_sid, struct dom_sid *pfile_grp_sid)
{
bool got_user_obj, got_group_obj;
canon_ace *current_ace;
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;
}
}
/****************************************************************************
- Unpack a SEC_DESC into two canonical ace lists.
+ If an ACE entry is SMB_ACL_USER_OBJ and not CREATOR_OWNER, map to SMB_ACL_USER.
+ If an ACE entry is SMB_ACL_GROUP_OBJ and not CREATOR_GROUP, map to SMB_ACL_GROUP
+****************************************************************************/
+
+static bool dup_owning_ace(canon_ace *dir_ace, canon_ace *ace)
+{
+ /* dir ace must be followings.
+ SMB_ACL_USER_OBJ : trustee(CREATOR_OWNER) -> Posix ACL d:u::perm
+ SMB_ACL_USER : not trustee -> Posix ACL u:user:perm
+ SMB_ACL_USER_OBJ : trustee -> convert to SMB_ACL_USER : trustee
+ Posix ACL u:trustee:perm
+
+ SMB_ACL_GROUP_OBJ: trustee(CREATOR_GROUP) -> Posix ACL d:g::perm
+ SMB_ACL_GROUP : not trustee -> Posix ACL g:group:perm
+ SMB_ACL_GROUP_OBJ: trustee -> convert to SMB_ACL_GROUP : trustee
+ Posix ACL g:trustee:perm
+ */
+
+ if (ace->type == SMB_ACL_USER_OBJ &&
+ !(dom_sid_equal(&ace->trustee, &global_sid_Creator_Owner))) {
+ canon_ace *dup_ace = dup_canon_ace(ace);
+
+ if (dup_ace == NULL) {
+ return false;
+ }
+ dup_ace->type = SMB_ACL_USER;
+ DLIST_ADD_END(dir_ace, dup_ace, canon_ace *);
+ }
+
+ if (ace->type == SMB_ACL_GROUP_OBJ &&
+ !(dom_sid_equal(&ace->trustee, &global_sid_Creator_Group))) {
+ canon_ace *dup_ace = dup_canon_ace(ace);
+
+ if (dup_ace == NULL) {
+ return false;
+ }
+ dup_ace->type = SMB_ACL_GROUP;
+ DLIST_ADD_END(dir_ace, dup_ace, canon_ace *);
+ }
+
+ return true;
+}
+
+/****************************************************************************
+ Unpack a struct security_descriptor into two canonical ace lists.
****************************************************************************/
static bool create_canon_ace_lists(files_struct *fsp,
- SMB_STRUCT_STAT *pst,
- DOM_SID *pfile_owner_sid,
- DOM_SID *pfile_grp_sid,
+ const SMB_STRUCT_STAT *pst,
+ struct dom_sid *pfile_owner_sid,
+ struct dom_sid *pfile_grp_sid,
canon_ace **ppfile_ace,
canon_ace **ppdir_ace,
- const SEC_ACL *dacl)
+ const struct security_acl *dacl)
{
bool all_aces_are_inherit_only = (fsp->is_directory ? True : False);
canon_ace *file_ace = NULL;
*/
for(i = 0; i < dacl->num_aces; i++) {
- SEC_ACE *psa = &dacl->aces[i];
+ struct security_ace *psa = &dacl->aces[i];
if((psa->type != SEC_ACE_TYPE_ACCESS_ALLOWED) && (psa->type != SEC_ACE_TYPE_ACCESS_DENIED)) {
DEBUG(3,("create_canon_ace_lists: unable to set anything but an ALLOW or DENY ACE.\n"));
*/
for(i = 0; i < dacl->num_aces; i++) {
- SEC_ACE *psa1 = &dacl->aces[i];
+ struct security_ace *psa1 = &dacl->aces[i];
for (j = i + 1; j < dacl->num_aces; j++) {
- SEC_ACE *psa2 = &dacl->aces[j];
+ struct security_ace *psa2 = &dacl->aces[j];
if (psa1->access_mask != psa2->access_mask)
continue;
- if (!sid_equal(&psa1->trustee, &psa2->trustee))
+ if (!dom_sid_equal(&psa1->trustee, &psa2->trustee))
continue;
/*
}
for(i = 0; i < dacl->num_aces; i++) {
- SEC_ACE *psa = &dacl->aces[i];
+ 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;
/*
* The Creator Owner entry only specifies inheritable permissions,
* never access permissions. WinNT doesn't always set the ACE to
- *INHERIT_ONLY, though.
+ * INHERIT_ONLY, though.
*/
- if (nt4_compatible_acls())
- psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
- } else if (sid_equal(¤t_ace->trustee, &global_sid_Creator_Group)) {
+ psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
+
+ } 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;
/*
* The Creator Group entry only specifies inheritable permissions,
* never access permissions. WinNT doesn't always set the ACE to
- *INHERIT_ONLY, though.
+ * INHERIT_ONLY, though.
*/
- if (nt4_compatible_acls())
- psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
+ psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
} else if (sid_to_uid( ¤t_ace->trustee, ¤t_ace->unix_ug.uid)) {
current_ace->owner_type = UID_ACE;
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 "
print_canon_ace( current_ace, 0);
}
+ /*
+ * We have a lossy mapping: directory ACE entries
+ * CREATOR_OWNER ------\
+ * (map to) +---> SMB_ACL_USER_OBJ
+ * owning sid ------/
+ *
+ * CREATOR_GROUP ------\
+ * (map to) +---> SMB_ACL_GROUP_OBJ
+ * primary group sid --/
+ *
+ * on set. And on read of a directory ACL
+ *
+ * SMB_ACL_USER_OBJ ----> CREATOR_OWNER
+ * SMB_ACL_GROUP_OBJ ---> CREATOR_GROUP.
+ *
+ * Deal with this on set by duplicating
+ * owning sid and primary group sid ACE
+ * entries into the directory ACL.
+ * Fix from Tsukasa Hamano <hamano@osstech.co.jp>.
+ */
+
+ if (!dup_owning_ace(dir_ace, current_ace)) {
+ DEBUG(0,("create_canon_ace_lists: malloc fail !\n"));
+ free_canon_ace_list(file_ace);
+ free_canon_ace_list(dir_ace);
+ return false;
+ }
+
/*
* If this is not an inherit only ACE we need to add a duplicate
* to the file acl.
* pointer is now owned by the dir_ace list.
*/
current_ace = dup_ace;
+ /* We've essentially split this ace into two,
+ * and added the ace with inheritance request
+ * bits to the directory ACL. Drop those bits for
+ * the ACE we're adding to the file list. */
+ current_ace->ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
+ SEC_ACE_FLAG_CONTAINER_INHERIT|
+ SEC_ACE_FLAG_INHERIT_ONLY);
} else {
/*
* We must not free current_ace here as its
allow entries.
****************************************************************************/
-static void process_deny_list( canon_ace **pp_ace_list )
+static void process_deny_list(connection_struct *conn, canon_ace **pp_ace_list )
{
canon_ace *ace_list = *pp_ace_list;
canon_ace *curr_ace = NULL;
continue;
}
- if (!sid_equal(&curr_ace->trustee, &global_sid_World))
+ if (!dom_sid_equal(&curr_ace->trustee, &global_sid_World))
continue;
/* JRATEST - assert. */
* list at this point including this entry.
*/
- canon_ace *prev_entry = curr_ace->prev;
+ canon_ace *prev_entry = DLIST_PREV(curr_ace);
free_canon_ace_list( curr_ace );
if (prev_entry)
- prev_entry->next = NULL;
+ DLIST_REMOVE(ace_list, prev_entry);
else {
/* We deleted the entire list. */
ace_list = NULL;
if (allow_ace_p->owner_type == UID_ACE)
continue;
- if (uid_entry_in_group( curr_ace, allow_ace_p))
+ if (uid_entry_in_group(conn, curr_ace, allow_ace_p))
new_perms |= allow_ace_p->perms;
}
/* Mask off the deny group perms. */
- if (uid_entry_in_group( allow_ace_p, curr_ace))
+ if (uid_entry_in_group(conn, allow_ace_p, curr_ace))
allow_ace_p->perms &= ~curr_ace->perms;
}
/* OR in the group perms. */
- if (uid_entry_in_group( curr_ace, allow_ace_p))
+ if (uid_entry_in_group(conn, curr_ace, allow_ace_p))
curr_ace->perms |= allow_ace_p->perms;
}
}
}
/****************************************************************************
- Unpack a SEC_DESC into two canonical ace lists. We don't depend on this
+ Unpack a struct security_descriptor into two canonical ace lists. We don't depend on this
succeeding.
****************************************************************************/
static bool unpack_canon_ace(files_struct *fsp,
- SMB_STRUCT_STAT *pst,
- DOM_SID *pfile_owner_sid,
- DOM_SID *pfile_grp_sid,
+ const SMB_STRUCT_STAT *pst,
+ struct dom_sid *pfile_owner_sid,
+ struct dom_sid *pfile_grp_sid,
canon_ace **ppfile_ace,
canon_ace **ppdir_ace,
uint32 security_info_sent,
- const SEC_DESC *psd)
+ const struct security_descriptor *psd)
{
+ SMB_STRUCT_STAT st;
canon_ace *file_ace = NULL;
canon_ace *dir_ace = NULL;
* 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;
/*
*/
print_canon_ace_list( "file ace - before merge", file_ace);
- merge_aces( &file_ace );
+ merge_aces( &file_ace, false);
print_canon_ace_list( "dir ace - before merge", dir_ace);
- merge_aces( &dir_ace );
+ merge_aces( &dir_ace, true);
/*
* NT ACLs are order dependent. Go through the acl lists and
*/
print_canon_ace_list( "file ace - before deny", file_ace);
- process_deny_list( &file_ace);
+ process_deny_list(fsp->conn, &file_ace);
print_canon_ace_list( "dir ace - before deny", dir_ace);
- process_deny_list( &dir_ace);
+ process_deny_list(fsp->conn, &dir_ace);
/*
* A well formed POSIX file or default ACL has at least 3 entries, a
print_canon_ace_list( "file ace - before valid", file_ace);
+ st = *pst;
+
/*
* A default 3 element mode entry for a file should be r-- --- ---.
* A default 3 element mode entry for a directory should be rwx --- ---.
*/
- pst->st_ex_mode = create_default_mode(fsp, False);
+ st.st_ex_mode = create_default_mode(fsp, False);
- if (!ensure_canon_entry_valid(&file_ace, fsp->conn->params, fsp->is_directory, pfile_owner_sid, pfile_grp_sid, pst, True)) {
+ if (!ensure_canon_entry_valid(fsp->conn, &file_ace, fsp->conn->params,
+ fsp->is_directory, pfile_owner_sid, pfile_grp_sid, &st, True)) {
free_canon_ace_list(file_ace);
free_canon_ace_list(dir_ace);
return False;
* it's a directory.
*/
- pst->st_ex_mode = create_default_mode(fsp, True);
+ st.st_ex_mode = create_default_mode(fsp, True);
- if (dir_ace && !ensure_canon_entry_valid(&dir_ace, fsp->conn->params, fsp->is_directory, pfile_owner_sid, pfile_grp_sid, pst, True)) {
+ if (dir_ace && !ensure_canon_entry_valid(fsp->conn, &dir_ace, fsp->conn->params,
+ fsp->is_directory, pfile_owner_sid, pfile_grp_sid, &st, True)) {
free_canon_ace_list(file_ace);
free_canon_ace_list(dir_ace);
return False;
static canon_ace *canonicalise_acl(struct connection_struct *conn,
const char *fname, SMB_ACL_T posix_acl,
const SMB_STRUCT_STAT *psbuf,
- const DOM_SID *powner, const DOM_SID *pgroup, struct pai_val *pal, SMB_ACL_TYPE_T the_acl_type)
+ const struct dom_sid *powner, const struct dom_sid *pgroup, struct pai_val *pal, SMB_ACL_TYPE_T the_acl_type)
{
mode_t acl_mask = (S_IRUSR|S_IWUSR|S_IXUSR);
canon_ace *l_head = NULL;
while ( posix_acl && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1)) {
SMB_ACL_TAG_T tagtype;
SMB_ACL_PERMSET_T permset;
- DOM_SID sid;
+ struct dom_sid sid;
posix_id unix_ug;
enum ace_owner owner_type;
DEBUG(0,("canonicalise_acl: Failed to get uid.\n"));
continue;
}
- /*
- * A SMB_ACL_USER entry for the owner is shadowed by the
- * SMB_ACL_USER_OBJ entry and Windows also cannot represent
- * that entry, so we ignore it. We also don't create such
- * entries out of the blue when setting ACLs, so a get/set
- * cycle will drop them.
- */
- if (the_acl_type == SMB_ACL_TYPE_ACCESS && *puid == psbuf->st_ex_uid) {
- SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)puid,tagtype);
- continue;
- }
uid_to_sid( &sid, *puid);
unix_ug.uid = *puid;
owner_type = UID_ACE;
* This next call will ensure we have at least a user/group/world set.
*/
- if (!ensure_canon_entry_valid(&l_head, conn->params,
+ if (!ensure_canon_entry_valid(conn, &l_head, conn->params,
S_ISDIR(psbuf->st_ex_mode), powner, pgroup,
psbuf, False))
goto fail;
Check if the current user group list contains a given group.
****************************************************************************/
-static bool current_user_in_group(gid_t gid)
+static bool current_user_in_group(connection_struct *conn, gid_t gid)
{
int i;
+ const struct security_unix_token *utok = get_current_utok(conn);
- for (i = 0; i < current_user.ut.ngroups; i++) {
- if (current_user.ut.groups[i] == gid) {
+ for (i = 0; i < utok->ngroups; i++) {
+ if (utok->groups[i] == gid) {
return True;
}
}
/* file primary group == user primary or supplementary group */
if (lp_acl_group_control(SNUM(conn)) &&
- current_user_in_group(smb_fname->st.st_ex_gid)) {
+ current_user_in_group(conn, smb_fname->st.st_ex_gid)) {
return true;
}
mode_t mask_perms = 0;
/* Use the psbuf that was passed in. */
- fsp->fsp_name->st = *psbuf;
+ if (psbuf != &fsp->fsp_name->st) {
+ fsp->fsp_name->st = *psbuf;
+ }
#if defined(POSIX_ACL_NEEDS_MASK)
/* HP-UX always wants to have a mask (called "class" there). */
Based on code from "Jim McDonough" <jmcd@us.ibm.com>.
****************************************************************************/
-static size_t merge_default_aces( SEC_ACE *nt_ace_list, size_t num_aces)
+static size_t merge_default_aces( struct security_ace *nt_ace_list, size_t num_aces)
{
size_t i, j;
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|
(i_inh ? SEC_ACE_FLAG_INHERITED_ACE : 0);
if (num_aces - i - 1 > 0)
memmove(&nt_ace_list[i], &nt_ace_list[i+1], (num_aces-i-1) *
- sizeof(SEC_ACE));
+ sizeof(struct security_ace));
DEBUG(10,("merge_default_aces: Merging zero access ACE %u onto ACE %u.\n",
(unsigned int)i, (unsigned int)j ));
(i_inh ? SEC_ACE_FLAG_INHERITED_ACE : 0);
if (num_aces - j - 1 > 0)
memmove(&nt_ace_list[j], &nt_ace_list[j+1], (num_aces-j-1) *
- sizeof(SEC_ACE));
+ sizeof(struct security_ace));
DEBUG(10,("merge_default_aces: Merging ACE %u onto ACE %u.\n",
(unsigned int)j, (unsigned int)i ));
* any reallocation of memory.
*/
-static void add_or_replace_ace(SEC_ACE *nt_ace_list, size_t *num_aces,
- const DOM_SID *sid, enum security_ace_type type,
+static void add_or_replace_ace(struct security_ace *nt_ace_list, size_t *num_aces,
+ const struct dom_sid *sid, enum security_ace_type type,
uint32_t mask, uint8_t flags)
{
int i;
/* 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;
}
SMB_ACL_T posix_acl,
SMB_ACL_T def_acl,
uint32_t security_info,
- SEC_DESC **ppdesc)
+ struct security_descriptor **ppdesc)
{
- DOM_SID owner_sid;
- DOM_SID group_sid;
+ struct dom_sid owner_sid;
+ struct dom_sid group_sid;
size_t sd_size = 0;
- SEC_ACL *psa = NULL;
+ struct security_acl *psa = NULL;
size_t num_acls = 0;
size_t num_def_acls = 0;
size_t num_aces = 0;
canon_ace *file_ace = NULL;
canon_ace *dir_ace = NULL;
- SEC_ACE *nt_ace_list = NULL;
+ struct security_ace *nt_ace_list = NULL;
size_t num_profile_acls = 0;
- DOM_SID orig_owner_sid;
- SEC_DESC *psd = NULL;
+ struct dom_sid orig_owner_sid;
+ struct security_descriptor *psd = NULL;
int i;
/*
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
num_def_acls = count_canon_ace_list(dir_ace);
/* Allocate the ace list. */
- if ((nt_ace_list = SMB_MALLOC_ARRAY(SEC_ACE,num_acls + num_profile_acls + num_def_acls)) == NULL) {
+ if ((nt_ace_list = SMB_MALLOC_ARRAY(struct security_ace,num_acls + num_profile_acls + num_def_acls)) == NULL) {
DEBUG(0,("get_nt_acl: Unable to malloc space for nt_ace_list.\n"));
goto done;
}
- memset(nt_ace_list, '\0', (num_acls + num_def_acls) * sizeof(SEC_ACE) );
+ memset(nt_ace_list, '\0', (num_acls + num_def_acls) * sizeof(struct security_ace) );
/*
* Create the NT ACE list from the canonical ace lists.
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);
}
NTSTATUS posix_fget_nt_acl(struct files_struct *fsp, uint32_t security_info,
- SEC_DESC **ppdesc)
+ struct security_descriptor **ppdesc)
{
SMB_STRUCT_STAT sbuf;
SMB_ACL_T posix_acl = NULL;
}
NTSTATUS posix_get_nt_acl(struct connection_struct *conn, const char *name,
- uint32_t security_info, SEC_DESC **ppdesc)
+ uint32_t security_info, struct security_descriptor **ppdesc)
{
SMB_ACL_T posix_acl = NULL;
SMB_ACL_T def_acl = NULL;
struct pai_val *pal;
- struct smb_filename *smb_fname = NULL;
- NTSTATUS status;
+ struct smb_filename smb_fname;
+ int ret;
*ppdesc = NULL;
DEBUG(10,("posix_get_nt_acl: called for file %s\n", name ));
- status = create_synthetic_smb_fname(talloc_tos(), name, NULL, NULL,
- &smb_fname);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
+ ZERO_STRUCT(smb_fname);
+ smb_fname.base_name = discard_const_p(char, name);
/* Get the stat struct for the owner info. */
- if(SMB_VFS_STAT(conn, smb_fname) != 0) {
- status = map_nt_error_from_unix(errno);
- goto out;
+ if (lp_posix_pathnames()) {
+ ret = SMB_VFS_LSTAT(conn, &smb_fname);
+ } else {
+ ret = SMB_VFS_STAT(conn, &smb_fname);
+ }
+
+ if (ret == -1) {
+ return map_nt_error_from_unix(errno);
}
/* Get the ACL from the path. */
posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, name, SMB_ACL_TYPE_ACCESS);
/* If it's a directory get the default POSIX ACL. */
- if(S_ISDIR(smb_fname->st.st_ex_mode)) {
+ if(S_ISDIR(smb_fname.st.st_ex_mode)) {
def_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, name, SMB_ACL_TYPE_DEFAULT);
def_acl = free_empty_sys_acl(conn, def_acl);
}
pal = load_inherited_info(conn, name);
- status = posix_get_nt_acl_common(conn, name, &smb_fname->st, pal,
- posix_acl, def_acl, security_info,
- ppdesc);
- out:
- TALLOC_FREE(smb_fname);
- return status;
+ return posix_get_nt_acl_common(conn, name, &smb_fname.st, pal,
+ posix_acl, def_acl, security_info,
+ ppdesc);
}
/****************************************************************************
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 */
- ret = SMB_VFS_CHOWN(conn, smb_fname->base_name, uid, gid);
- if (ret == 0)
- return 0;
+ status = vfs_chown_fsp(fsp, uid, gid);
+ if (NT_STATUS_IS_OK(status)) {
+ return status;
+ }
/* Case (2) / (3) */
if (lp_enable_privileges()) {
+ 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 {
+ has_take_ownership_priv = false;
+ }
+ }
- bool has_take_ownership_priv = user_has_privileges(current_user.nt_user_token,
- &se_take_ownership);
- bool has_restore_priv = user_has_privileges(current_user.nt_user_token,
- &se_restore);
-
- /* Case (2) */
- if ( ( has_take_ownership_priv && ( uid == current_user.ut.uid ) ) ||
- /* Case (3) */
- ( has_restore_priv ) ) {
-
+ if (has_take_ownership_priv || has_restore_priv) {
become_root();
- /* Keep the current file gid the same - take ownership doesn't imply group change. */
- ret = SMB_VFS_CHOWN(conn, smb_fname->base_name, uid,
- (gid_t)-1);
+ 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 != current_user.ut.uid) {
- errno = EPERM;
- return -1;
- }
-
- if (SMB_VFS_STAT(conn, smb_fname)) {
- 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. */
- 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
****************************************************************************/
NTSTATUS append_parent_acl(files_struct *fsp,
- const SEC_DESC *pcsd,
- SEC_DESC **pp_new_sd)
+ const struct security_descriptor *pcsd,
+ struct security_descriptor **pp_new_sd)
{
struct smb_filename *smb_dname = NULL;
- SEC_DESC *parent_sd = NULL;
+ struct security_descriptor *parent_sd = NULL;
files_struct *parent_fsp = NULL;
TALLOC_CTX *mem_ctx = talloc_tos();
char *parent_name = NULL;
- SEC_ACE *new_ace = NULL;
+ struct security_ace *new_ace = NULL;
unsigned int num_aces = pcsd->dacl->num_aces;
NTSTATUS status;
int info;
unsigned int i, j;
- SEC_DESC *psd = dup_sec_desc(talloc_tos(), pcsd);
+ struct security_descriptor *psd = dup_sec_desc(talloc_tos(), pcsd);
bool is_dacl_protected = (pcsd->type & SEC_DESC_DACL_PROTECTED);
if (psd == NULL) {
}
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);
num_aces += parent_sd->dacl->num_aces;
- if((new_ace = TALLOC_ZERO_ARRAY(mem_ctx, SEC_ACE,
+ if((new_ace = TALLOC_ZERO_ARRAY(mem_ctx, struct security_ace,
num_aces)) == NULL) {
return NT_STATUS_NO_MEMORY;
}
/* Finally append any inherited ACEs. */
for (j = 0; j < parent_sd->dacl->num_aces; j++) {
- SEC_ACE *se = &parent_sd->dacl->aces[j];
+ struct security_ace *se = &parent_sd->dacl->aces[j];
if (fsp->is_directory) {
if (!(se->flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
* 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;
}
psd->dacl->aces = new_ace;
psd->dacl->num_aces = i;
- psd->type &= ~(SE_DESC_DACL_AUTO_INHERITED|
- SE_DESC_DACL_AUTO_INHERIT_REQ);
+ psd->type &= ~(SEC_DESC_DACL_AUTO_INHERITED|
+ SEC_DESC_DACL_AUTO_INHERIT_REQ);
*pp_new_sd = psd;
return status;
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 SEC_DESC *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;
gid_t grp = (gid_t)-1;
- DOM_SID file_owner_sid;
- DOM_SID file_grp_sid;
+ struct dom_sid file_owner_sid;
+ struct dom_sid file_grp_sid;
canon_ace *file_ace_list = NULL;
canon_ace *dir_ace_list = NULL;
bool acl_perms = False;
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.
*/
- if(fsp->is_directory || fsp->fh->fd == -1) {
- if(SMB_VFS_STAT(fsp->conn, fsp->fsp_name) != 0) {
- return map_nt_error_from_unix(errno);
- }
- } else {
- if(SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st) != 0) {
- return map_nt_error_from_unix(errno);
- }
+ status = vfs_stat_fsp(fsp);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
}
/* Save the original element we check against. */
* Unpack the user/group/world id's.
*/
- status = unpack_nt_owners( SNUM(conn), &user, &grp, security_info_sent, psd);
+ /* 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;
}
/*
* (suid/sgid bits, for instance)
*/
- if(fsp->is_directory) {
- if(SMB_VFS_STAT(fsp->conn, fsp->fsp_name) != 0) {
- return map_nt_error_from_unix(errno);
- }
- } else {
-
- int sret;
-
- if(fsp->fh->fd == -1)
- sret = SMB_VFS_STAT(fsp->conn, fsp->fsp_name);
- else
- sret = SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st);
-
- if(sret != 0)
- return map_nt_error_from_unix(errno);
+ status = vfs_stat_fsp(fsp);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
}
/* Save the original element we check against. */
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;
free_canon_ace_list(file_ace_list);
free_canon_ace_list(dir_ace_list);
+ /* Ensure the stat struct in the fsp is correct. */
+ status = vfs_stat_fsp(fsp);
+
return NT_STATUS_OK;
}
Assume we are dealing with files (for now)
********************************************************************/
-SEC_DESC *get_nt_acl_no_snum( TALLOC_CTX *ctx, const char *fname)
+struct security_descriptor *get_nt_acl_no_snum( TALLOC_CTX *ctx, const char *fname)
{
- SEC_DESC *psd, *ret_sd;
+ struct security_descriptor *psd, *ret_sd;
connection_struct *conn;
files_struct finfo;
struct fd_handle fh;
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;
+}