*/
#include "includes.h"
+#include "smbd/smbd.h"
+#include "system/filesys.h"
+#include "../libcli/security/security.h"
+#include "trans2.h"
+#include "passdb/lookup_sid.h"
+#include "auth.h"
+#include "../librpc/gen_ndr/idmap.h"
+#include "../librpc/gen_ndr/ndr_smb_acl.h"
+#include "lib/param/loadparm.h"
extern const struct generic_mapping file_generic_mapping;
enum ace_owner {UID_ACE, GID_ACE, WORLD_ACE};
enum ace_attribute {ALLOW_ACE, DENY_ACE}; /* Used for incoming NT ACLS. */
-typedef union posix_id {
- uid_t uid;
- gid_t gid;
- int world;
-} posix_id;
-
typedef struct canon_ace {
struct canon_ace *next, *prev;
SMB_ACL_TAG_T type;
struct dom_sid trustee;
enum ace_owner owner_type;
enum ace_attribute attr;
- posix_id unix_ug;
+ struct unixid unix_ug;
uint8_t ace_flags; /* From windows ACE entry. */
} canon_ace;
struct pai_entry *next, *prev;
uint8_t ace_flags;
enum ace_owner owner_type;
- posix_id unix_ug;
+ struct unixid unix_ug;
};
struct pai_val {
{
switch (paie->owner_type) {
case UID_ACE:
- DEBUG(10,("get_pai_entry_val: uid = %u\n", (unsigned int)paie->unix_ug.uid ));
- return (uint32_t)paie->unix_ug.uid;
+ DEBUG(10,("get_pai_entry_val: uid = %u\n", (unsigned int)paie->unix_ug.id ));
+ return (uint32_t)paie->unix_ug.id;
case GID_ACE:
- DEBUG(10,("get_pai_entry_val: gid = %u\n", (unsigned int)paie->unix_ug.gid ));
- return (uint32_t)paie->unix_ug.gid;
+ DEBUG(10,("get_pai_entry_val: gid = %u\n", (unsigned int)paie->unix_ug.id ));
+ return (uint32_t)paie->unix_ug.id;
case WORLD_ACE:
default:
DEBUG(10,("get_pai_entry_val: world ace\n"));
{
switch (ace_entry->owner_type) {
case UID_ACE:
- DEBUG(10,("get_entry_val: uid = %u\n", (unsigned int)ace_entry->unix_ug.uid ));
- return (uint32_t)ace_entry->unix_ug.uid;
+ DEBUG(10,("get_entry_val: uid = %u\n", (unsigned int)ace_entry->unix_ug.id ));
+ return (uint32_t)ace_entry->unix_ug.id;
case GID_ACE:
- DEBUG(10,("get_entry_val: gid = %u\n", (unsigned int)ace_entry->unix_ug.gid ));
- return (uint32_t)ace_entry->unix_ug.gid;
+ DEBUG(10,("get_entry_val: gid = %u\n", (unsigned int)ace_entry->unix_ug.id ));
+ return (uint32_t)ace_entry->unix_ug.id;
case WORLD_ACE:
default:
DEBUG(10,("get_entry_val: world ace\n"));
*store_size = PAI_V2_ENTRIES_BASE +
((num_entries + num_def_entries)*PAI_V2_ENTRY_LENGTH);
- pai_buf = (char *)SMB_MALLOC(*store_size);
+ pai_buf = talloc_array(talloc_tos(), char, *store_size);
if (!pai_buf) {
return NULL;
}
pai_buf, store_size, 0);
}
- SAFE_FREE(pai_buf);
+ TALLOC_FREE(pai_buf);
DEBUG(10,("store_inheritance_attribute: type 0x%x for file %s\n",
(unsigned int)sd_type,
struct pai_entry *paie, *paie_next;
for (paie = pal->entry_list; paie; paie = paie_next) {
paie_next = paie->next;
- SAFE_FREE(paie);
+ TALLOC_FREE(paie);
}
for (paie = pal->def_entry_list; paie; paie = paie_next) {
paie_next = paie->next;
- SAFE_FREE(paie);
+ TALLOC_FREE(paie);
}
- SAFE_FREE(pal);
+ TALLOC_FREE(pal);
}
}
paie->owner_type = (enum ace_owner)CVAL(entry_offset,0);
switch( paie->owner_type) {
case UID_ACE:
- paie->unix_ug.uid = (uid_t)IVAL(entry_offset,1);
+ paie->unix_ug.type = ID_TYPE_UID;
+ paie->unix_ug.id = (uid_t)IVAL(entry_offset,1);
DEBUG(10,("get_pai_owner_type: uid = %u\n",
- (unsigned int)paie->unix_ug.uid ));
+ (unsigned int)paie->unix_ug.id ));
break;
case GID_ACE:
- paie->unix_ug.gid = (gid_t)IVAL(entry_offset,1);
+ paie->unix_ug.type = ID_TYPE_GID;
+ paie->unix_ug.id = (gid_t)IVAL(entry_offset,1);
DEBUG(10,("get_pai_owner_type: gid = %u\n",
- (unsigned int)paie->unix_ug.gid ));
+ (unsigned int)paie->unix_ug.id ));
break;
case WORLD_ACE:
- paie->unix_ug.world = -1;
+ paie->unix_ug.type = ID_TYPE_NOT_SPECIFIED;
+ paie->unix_ug.id = -1;
DEBUG(10,("get_pai_owner_type: world ace\n"));
break;
default:
int i;
for (i = 0; i < paiv->num_entries; i++) {
- struct pai_entry *paie = SMB_MALLOC_P(struct pai_entry);
+ struct pai_entry *paie = talloc(talloc_tos(), struct pai_entry);
if (!paie) {
return NULL;
}
paie->ace_flags = SEC_ACE_FLAG_INHERITED_ACE;
if (!get_pai_owner_type(paie, entry_offset)) {
+ TALLOC_FREE(paie);
return NULL;
}
return NULL;
}
- paiv = SMB_MALLOC_P(struct pai_val);
+ paiv = talloc(talloc_tos(), struct pai_val);
if (!paiv) {
return NULL;
}
unsigned int i;
for (i = 0; i < num_entries; i++) {
- struct pai_entry *paie = SMB_MALLOC_P(struct pai_entry);
+ struct pai_entry *paie = talloc(talloc_tos(), struct pai_entry);
if (!paie) {
return NULL;
}
paie->ace_flags = CVAL(entry_offset,0);
if (!get_pai_owner_type(paie, entry_offset+1)) {
+ TALLOC_FREE(paie);
return NULL;
}
if (!def_entry) {
return NULL;
}
- paiv = SMB_MALLOC_P(struct pai_val);
+ paiv = talloc(talloc_tos(), struct pai_val);
if (!paiv) {
return NULL;
}
return NULL;
}
- if ((pai_buf = (char *)SMB_MALLOC(pai_buf_size)) == NULL) {
+ if ((pai_buf = talloc_array(talloc_tos(), char, pai_buf_size)) == NULL) {
return NULL;
}
}
/* Buffer too small - enlarge it. */
pai_buf_size *= 2;
- SAFE_FREE(pai_buf);
+ TALLOC_FREE(pai_buf);
if (pai_buf_size > 1024*1024) {
return NULL; /* Limit malloc to 1mb. */
}
- if ((pai_buf = (char *)SMB_MALLOC(pai_buf_size)) == NULL)
+ if ((pai_buf = talloc_array(talloc_tos(), char, pai_buf_size)) == NULL)
return NULL;
}
} while (ret == -1);
if (errno != ENOSYS)
DEBUG(10,("load_inherited_info: Error %s\n", strerror(errno) ));
#endif
- SAFE_FREE(pai_buf);
+ TALLOC_FREE(pai_buf);
return NULL;
}
(unsigned int)paiv->sd_type, fsp_str_dbg(fsp)));
}
- SAFE_FREE(pai_buf);
+ TALLOC_FREE(pai_buf);
return paiv;
}
return NULL;
}
- if ((pai_buf = (char *)SMB_MALLOC(pai_buf_size)) == NULL) {
+ if ((pai_buf = talloc_array(talloc_tos(), char, pai_buf_size)) == NULL) {
return NULL;
}
}
/* Buffer too small - enlarge it. */
pai_buf_size *= 2;
- SAFE_FREE(pai_buf);
+ TALLOC_FREE(pai_buf);
if (pai_buf_size > 1024*1024) {
return NULL; /* Limit malloc to 1mb. */
}
- if ((pai_buf = (char *)SMB_MALLOC(pai_buf_size)) == NULL)
+ if ((pai_buf = talloc_array(talloc_tos(), char, pai_buf_size)) == NULL)
return NULL;
}
} while (ret == -1);
if (errno != ENOSYS)
DEBUG(10,("load_inherited_info: Error %s\n", strerror(errno) ));
#endif
- SAFE_FREE(pai_buf);
+ TALLOC_FREE(pai_buf);
return NULL;
}
fname));
}
- SAFE_FREE(pai_buf);
+ TALLOC_FREE(pai_buf);
return paiv;
}
for (list = l_head; list; list = next) {
next = list->next;
DLIST_REMOVE(l_head, list);
- SAFE_FREE(list);
+ TALLOC_FREE(list);
}
}
static canon_ace *dup_canon_ace( canon_ace *src_ace)
{
- canon_ace *dst_ace = SMB_MALLOC_P(canon_ace);
+ canon_ace *dst_ace = talloc(talloc_tos(), canon_ace);
if (dst_ace == NULL)
return NULL;
dbgtext( "canon_ace index %d. Type = %s ", num, pace->attr == ALLOW_ACE ? "allow" : "deny" );
dbgtext( "SID = %s ", sid_string_dbg(&pace->trustee));
if (pace->owner_type == UID_ACE) {
- const char *u_name = uidtoname(pace->unix_ug.uid);
- dbgtext( "uid %u (%s) ", (unsigned int)pace->unix_ug.uid, u_name );
+ const char *u_name = uidtoname(pace->unix_ug.id);
+ dbgtext( "uid %u (%s) ", (unsigned int)pace->unix_ug.id, u_name );
} else if (pace->owner_type == GID_ACE) {
- char *g_name = gidtoname(pace->unix_ug.gid);
- dbgtext( "gid %u (%s) ", (unsigned int)pace->unix_ug.gid, g_name );
+ char *g_name = gidtoname(pace->unix_ug.id);
+ dbgtext( "gid %u (%s) ", (unsigned int)pace->unix_ug.id, g_name );
} else
dbgtext( "other ");
switch (pace->type) {
Map POSIX ACL perms to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits).
****************************************************************************/
-static mode_t convert_permset_to_mode_t(connection_struct *conn, SMB_ACL_PERMSET_T permset)
+static mode_t convert_permset_to_mode_t(SMB_ACL_PERMSET_T permset)
{
mode_t ret = 0;
- ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ) ? S_IRUSR : 0);
- ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE) ? S_IWUSR : 0);
- ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_EXECUTE) ? S_IXUSR : 0);
+ ret |= (sys_acl_get_perm(permset, SMB_ACL_READ) ? S_IRUSR : 0);
+ ret |= (sys_acl_get_perm(permset, SMB_ACL_WRITE) ? S_IWUSR : 0);
+ ret |= (sys_acl_get_perm(permset, SMB_ACL_EXECUTE) ? S_IXUSR : 0);
return ret;
}
static int map_acl_perms_to_permset(connection_struct *conn, mode_t mode, SMB_ACL_PERMSET_T *p_permset)
{
- if (SMB_VFS_SYS_ACL_CLEAR_PERMS(conn, *p_permset) == -1)
+ if (sys_acl_clear_perms(*p_permset) == -1)
return -1;
if (mode & S_IRUSR) {
- if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_READ) == -1)
+ if (sys_acl_add_perm(*p_permset, SMB_ACL_READ) == -1)
return -1;
}
if (mode & S_IWUSR) {
- if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_WRITE) == -1)
+ if (sys_acl_add_perm(*p_permset, SMB_ACL_WRITE) == -1)
return -1;
}
if (mode & S_IXUSR) {
- if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_EXECUTE) == -1)
+ if (sys_acl_add_perm(*p_permset, SMB_ACL_EXECUTE) == -1)
return -1;
}
return 0;
}
/****************************************************************************
- Merge aces with a common sid - if both are allow or deny, OR the permissions together and
+ Merge aces with a common UID or GID - 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.
****************************************************************************/
/* 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. */
+ * ensure the POSIX ACL types are the same.
+ *
+ * For the IDMAP_BOTH case, we must not merge
+ * the UID and GID ACE values for same SID
+ */
if (!dir_acl) {
- can_merge = (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
- (curr_ace->attr == curr_ace_outer->attr));
+ can_merge = (curr_ace->unix_ug.id == curr_ace_outer->unix_ug.id &&
+ curr_ace->owner_type == curr_ace_outer->owner_type &&
+ (curr_ace->attr == curr_ace_outer->attr));
} else {
- can_merge = (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
- (curr_ace->type == curr_ace_outer->type) &&
- (curr_ace->attr == curr_ace_outer->attr));
+ can_merge = (curr_ace->unix_ug.id == curr_ace_outer->unix_ug.id &&
+ curr_ace->owner_type == curr_ace_outer->owner_type &&
+ (curr_ace->type == curr_ace_outer->type) &&
+ (curr_ace->attr == curr_ace_outer->attr));
}
if (can_merge) {
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);
+ TALLOC_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 (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
- (curr_ace_outer->attr == DENY_ACE) && (curr_ace->attr == ALLOW_ACE)) {
+ if (curr_ace->unix_ug.id == curr_ace_outer->unix_ug.id &&
+ (curr_ace->owner_type == curr_ace_outer->owner_type) &&
+ (curr_ace_outer->attr == DENY_ACE) && (curr_ace->attr == ALLOW_ACE)) {
if( DEBUGLVL( 10 )) {
dbgtext("merge_aces: Masking ACE's\n");
*/
DLIST_REMOVE(l_head, curr_ace);
- SAFE_FREE(curr_ace);
+ TALLOC_FREE(curr_ace);
curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */
} else {
*/
DLIST_REMOVE(l_head, curr_ace_outer);
- SAFE_FREE(curr_ace_outer);
+ TALLOC_FREE(curr_ace_outer);
break;
}
}
*pp_list_head = l_head;
}
-/****************************************************************************
- Check if we need to return NT4.x compatible ACL entries.
-****************************************************************************/
-
-bool nt4_compatible_acls(void)
-{
- int compat = lp_acl_compatibility();
-
- if (compat == ACL_COMPAT_AUTO) {
- enum remote_arch_types ra_type = get_remote_arch();
-
- /* Automatically adapt to client */
- return (ra_type <= RA_WINNT);
- } else
- return (compat == ACL_COMPAT_WINNT);
-}
-
-
/****************************************************************************
Map canon_ace perms to permission bits NT.
The attr element is not used here - we only process deny entries on set,
* to be changed in the future.
*/
- if (nt4_compatible_acls())
- nt_mask = UNIX_ACCESS_NONE;
- else
- nt_mask = 0;
+ nt_mask = 0;
} else {
if (directory_ace) {
nt_mask |= ((perms & S_IRUSR) ? UNIX_DIRECTORY_ACCESS_R : 0 );
Map NT perms to a UNIX mode_t.
****************************************************************************/
-#define FILE_SPECIFIC_READ_BITS (FILE_READ_DATA|FILE_READ_EA|FILE_READ_ATTRIBUTES)
-#define FILE_SPECIFIC_WRITE_BITS (FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_WRITE_EA|FILE_WRITE_ATTRIBUTES)
+#define FILE_SPECIFIC_READ_BITS (FILE_READ_DATA|FILE_READ_EA)
+#define FILE_SPECIFIC_WRITE_BITS (FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_WRITE_EA)
#define FILE_SPECIFIC_EXECUTE_BITS (FILE_EXECUTE)
static mode_t map_nt_perms( uint32 *mask, int type)
/* Get the initial bits to apply. */
if (is_directory) {
- and_bits = lp_dir_security_mask(params->service);
- or_bits = lp_force_dir_security_mode(params->service);
+ and_bits = lp_dir_mask(params->service);
+ or_bits = lp_force_dir_mode(params->service);
} else {
- and_bits = lp_security_mask(params->service);
- or_bits = lp_force_security_mode(params->service);
+ and_bits = lp_create_mask(params->service);
+ or_bits = lp_force_create_mode(params->service);
}
/* Now bounce them into the S_USR space. */
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 == get_current_uid(conn)) {
- const UNIX_USER_TOKEN *curr_utok = NULL;
+ if (uid_ace->unix_ug.id == get_current_uid(conn)) {
+ const struct security_unix_token *curr_utok = NULL;
size_t i;
- if (group_ace->unix_ug.gid == get_current_gid(conn)) {
+ if (group_ace->unix_ug.id == get_current_gid(conn)) {
return True;
}
curr_utok = get_current_utok(conn);
for (i=0; i < curr_utok->ngroups; i++) {
- if (group_ace->unix_ug.gid == curr_utok->groups[i]) {
+ if (group_ace->unix_ug.id == curr_utok->groups[i]) {
return True;
}
}
}
- /* u_name talloc'ed off tos. */
- u_name = uidtoname(uid_ace->unix_ug.uid);
- if (!u_name) {
- return False;
- }
-
/*
- * user_in_group_sid() uses create_token_from_username()
+ * user_in_group_sid() uses create_token_from_sid()
* which creates an artificial NT token given just a username,
* so this is not reliable for users from foreign domains
* exported by winbindd!
*/
- return user_in_group_sid(u_name, &group_ace->trustee);
+ return user_sid_in_group_sid(&uid_ace->trustee, &group_ace->trustee);
}
/****************************************************************************
- A well formed POSIX file or default ACL has at least 3 entries, a
+ A well formed POSIX file or default ACL has at least 3 entries, a
SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ.
In addition, the owner must always have at least read access.
When using this call on get_acl, the pst struct is valid and contains
- the mode of the file. When using this call on set_acl, the pst struct has
+ the mode of the file.
+****************************************************************************/
+
+static bool ensure_canon_entry_valid_on_get(connection_struct *conn,
+ canon_ace **pp_ace,
+ const struct dom_sid *pfile_owner_sid,
+ const struct dom_sid *pfile_grp_sid,
+ const SMB_STRUCT_STAT *pst)
+{
+ canon_ace *pace;
+ bool got_user = false;
+ bool got_group = false;
+ bool got_other = false;
+
+ for (pace = *pp_ace; pace; pace = pace->next) {
+ if (pace->type == SMB_ACL_USER_OBJ) {
+ got_user = true;
+ } else if (pace->type == SMB_ACL_GROUP_OBJ) {
+ got_group = true;
+ } else if (pace->type == SMB_ACL_OTHER) {
+ got_other = true;
+ }
+ }
+
+ if (!got_user) {
+ if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
+ DEBUG(0,("malloc fail.\n"));
+ return false;
+ }
+
+ ZERO_STRUCTP(pace);
+ pace->type = SMB_ACL_USER_OBJ;
+ pace->owner_type = UID_ACE;
+ pace->unix_ug.type = ID_TYPE_UID;
+ pace->unix_ug.id = pst->st_ex_uid;
+ pace->trustee = *pfile_owner_sid;
+ pace->attr = ALLOW_ACE;
+ pace->perms = unix_perms_to_acl_perms(pst->st_ex_mode, S_IRUSR, S_IWUSR, S_IXUSR);
+ DLIST_ADD(*pp_ace, pace);
+ }
+
+ if (!got_group) {
+ if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
+ DEBUG(0,("malloc fail.\n"));
+ return false;
+ }
+
+ ZERO_STRUCTP(pace);
+ pace->type = SMB_ACL_GROUP_OBJ;
+ pace->owner_type = GID_ACE;
+ pace->unix_ug.type = ID_TYPE_GID;
+ pace->unix_ug.id = pst->st_ex_gid;
+ pace->trustee = *pfile_grp_sid;
+ pace->attr = ALLOW_ACE;
+ pace->perms = unix_perms_to_acl_perms(pst->st_ex_mode, S_IRGRP, S_IWGRP, S_IXGRP);
+ DLIST_ADD(*pp_ace, pace);
+ }
+
+ if (!got_other) {
+ if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
+ DEBUG(0,("malloc fail.\n"));
+ return false;
+ }
+
+ ZERO_STRUCTP(pace);
+ pace->type = SMB_ACL_OTHER;
+ pace->owner_type = WORLD_ACE;
+ pace->unix_ug.type = ID_TYPE_NOT_SPECIFIED;
+ pace->unix_ug.id = -1;
+ pace->trustee = global_sid_World;
+ pace->attr = ALLOW_ACE;
+ pace->perms = unix_perms_to_acl_perms(pst->st_ex_mode, S_IROTH, S_IWOTH, S_IXOTH);
+ DLIST_ADD(*pp_ace, pace);
+ }
+
+ return true;
+}
+
+/****************************************************************************
+ A well formed POSIX file or default ACL has at least 3 entries, a
+ SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ.
+ In addition, the owner must always have at least read access.
+ When using this call on set_acl, the pst struct has
been modified to have a mode containing the default for this file or directory
type.
****************************************************************************/
-static bool ensure_canon_entry_valid(connection_struct *conn, canon_ace **pp_ace,
- const struct share_params *params,
- const bool is_directory,
- const struct dom_sid *pfile_owner_sid,
- const struct dom_sid *pfile_grp_sid,
- const SMB_STRUCT_STAT *pst,
- bool setting_acl)
+static bool ensure_canon_entry_valid_on_set(connection_struct *conn,
+ canon_ace **pp_ace,
+ bool is_default_acl,
+ const struct share_params *params,
+ const bool is_directory,
+ const struct dom_sid *pfile_owner_sid,
+ const struct dom_sid *pfile_grp_sid,
+ const SMB_STRUCT_STAT *pst)
{
canon_ace *pace;
- bool got_user = False;
- bool got_grp = False;
- bool got_other = False;
+ canon_ace *pace_user = NULL;
+ canon_ace *pace_group = NULL;
canon_ace *pace_other = NULL;
+ bool got_duplicate_user = false;
+ bool got_duplicate_group = false;
for (pace = *pp_ace; pace; pace = pace->next) {
if (pace->type == SMB_ACL_USER_OBJ) {
- if (setting_acl)
+ if (!is_default_acl) {
apply_default_perms(params, is_directory, pace, S_IRUSR);
- got_user = True;
+ }
+ pace_user = pace;
} else if (pace->type == SMB_ACL_GROUP_OBJ) {
* Ensure create mask/force create mode is respected on set.
*/
- if (setting_acl)
+ if (!is_default_acl) {
apply_default_perms(params, is_directory, pace, S_IRGRP);
- got_grp = True;
+ }
+ pace_group = pace;
} else if (pace->type == SMB_ACL_OTHER) {
* Ensure create mask/force create mode is respected on set.
*/
- if (setting_acl)
+ if (!is_default_acl) {
apply_default_perms(params, is_directory, pace, S_IROTH);
- got_other = True;
+ }
pace_other = pace;
+
+ } else if (pace->type == SMB_ACL_USER || pace->type == SMB_ACL_GROUP) {
+
+ /*
+ * Ensure create mask/force create mode is respected on set.
+ */
+
+ if (!is_default_acl) {
+ apply_default_perms(params, is_directory, pace, S_IRGRP);
+ }
}
}
- if (!got_user) {
- if ((pace = SMB_MALLOC_P(canon_ace)) == NULL) {
- DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
- return False;
+ if (!pace_user) {
+ canon_ace *pace_iter;
+
+ if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
+ DEBUG(0,("talloc fail.\n"));
+ return false;
}
ZERO_STRUCTP(pace);
pace->type = SMB_ACL_USER_OBJ;
pace->owner_type = UID_ACE;
- pace->unix_ug.uid = pst->st_ex_uid;
+ pace->unix_ug.type = ID_TYPE_UID;
+ pace->unix_ug.id = pst->st_ex_uid;
pace->trustee = *pfile_owner_sid;
pace->attr = ALLOW_ACE;
-
- if (setting_acl) {
- /* See if the owning user is in any of the other groups in
- the ACE. If so, OR in the permissions from that group. */
-
- bool group_matched = False;
- canon_ace *pace_iter;
-
- 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(conn, pace, pace_iter)) {
- pace->perms |= pace_iter->perms;
- group_matched = True;
- }
+ /* Start with existing user permissions, principle of least
+ surprises for the user. */
+ pace->perms = unix_perms_to_acl_perms(pst->st_ex_mode, S_IRUSR, S_IWUSR, S_IXUSR);
+
+ /* See if the owning user is in any of the other groups in
+ the ACE, or if there's a matching user entry (by uid
+ or in the case of ID_TYPE_BOTH by SID).
+ If so, OR in the permissions from that entry. */
+
+
+ for (pace_iter = *pp_ace; pace_iter; pace_iter = pace_iter->next) {
+ if (pace_iter->type == SMB_ACL_USER &&
+ pace_iter->unix_ug.id == pace->unix_ug.id) {
+ pace->perms |= pace_iter->perms;
+ } else if (pace_iter->type == SMB_ACL_GROUP_OBJ || pace_iter->type == SMB_ACL_GROUP) {
+ if (dom_sid_equal(&pace->trustee, &pace_iter->trustee)) {
+ pace->perms |= pace_iter->perms;
+ } else if (uid_entry_in_group(conn, pace, pace_iter)) {
+ pace->perms |= pace_iter->perms;
}
}
+ }
+ if (pace->perms == 0) {
/* If we only got an "everyone" perm, just use that. */
- if (!group_matched) {
- if (got_other)
- pace->perms = pace_other->perms;
- else
- pace->perms = 0;
- }
+ if (pace_other)
+ pace->perms = pace_other->perms;
+ }
+ if (!is_default_acl) {
apply_default_perms(params, is_directory, pace, S_IRUSR);
- } else {
- pace->perms = unix_perms_to_acl_perms(pst->st_ex_mode, S_IRUSR, S_IWUSR, S_IXUSR);
}
DLIST_ADD(*pp_ace, pace);
+ pace_user = pace;
}
- if (!got_grp) {
- if ((pace = SMB_MALLOC_P(canon_ace)) == NULL) {
- DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
- return False;
+ if (!pace_group) {
+ if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
+ DEBUG(0,("talloc fail.\n"));
+ return false;
}
ZERO_STRUCTP(pace);
pace->type = SMB_ACL_GROUP_OBJ;
pace->owner_type = GID_ACE;
- pace->unix_ug.uid = pst->st_ex_gid;
+ pace->unix_ug.type = ID_TYPE_GID;
+ pace->unix_ug.id = pst->st_ex_gid;
pace->trustee = *pfile_grp_sid;
pace->attr = ALLOW_ACE;
- if (setting_acl) {
- /* If we only got an "everyone" perm, just use that. */
- if (got_other)
- pace->perms = pace_other->perms;
- else
- pace->perms = 0;
- apply_default_perms(params, is_directory, pace, S_IRGRP);
+
+ /* If we only got an "everyone" perm, just use that. */
+ if (pace_other) {
+ pace->perms = pace_other->perms;
} else {
- pace->perms = unix_perms_to_acl_perms(pst->st_ex_mode, S_IRGRP, S_IWGRP, S_IXGRP);
+ pace->perms = 0;
+ }
+ if (!is_default_acl) {
+ apply_default_perms(params, is_directory, pace, S_IRGRP);
}
DLIST_ADD(*pp_ace, pace);
+ pace_group = pace;
}
- if (!got_other) {
- if ((pace = SMB_MALLOC_P(canon_ace)) == NULL) {
- DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
- return False;
+ if (!pace_other) {
+ if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
+ DEBUG(0,("talloc fail.\n"));
+ return false;
}
ZERO_STRUCTP(pace);
pace->type = SMB_ACL_OTHER;
pace->owner_type = WORLD_ACE;
- pace->unix_ug.world = -1;
+ pace->unix_ug.type = ID_TYPE_NOT_SPECIFIED;
+ pace->unix_ug.id = -1;
pace->trustee = global_sid_World;
pace->attr = ALLOW_ACE;
- if (setting_acl) {
- pace->perms = 0;
+ pace->perms = 0;
+ if (!is_default_acl) {
apply_default_perms(params, is_directory, pace, S_IROTH);
- } else
- pace->perms = unix_perms_to_acl_perms(pst->st_ex_mode, S_IROTH, S_IWOTH, S_IXOTH);
+ }
DLIST_ADD(*pp_ace, pace);
+ pace_other = pace;
}
- return True;
+ /* Ensure when setting a POSIX ACL, that the uid for a
+ SMB_ACL_USER_OBJ ACE (the owner ACE entry) has a duplicate
+ permission entry as an SMB_ACL_USER, and a gid for a
+ SMB_ACL_GROUP_OBJ ACE (the primary group ACE entry) also has
+ a duplicate permission entry as an SMB_ACL_GROUP. If not,
+ then if the ownership or group ownership of this file or
+ directory gets changed, the user or group can lose their
+ access. */
+
+ for (pace = *pp_ace; pace; pace = pace->next) {
+ if (pace->type == SMB_ACL_USER &&
+ pace->unix_ug.id == pace_user->unix_ug.id) {
+ /* Already got one. */
+ got_duplicate_user = true;
+ } else if (pace->type == SMB_ACL_GROUP &&
+ pace->unix_ug.id == pace_group->unix_ug.id) {
+ /* Already got one. */
+ got_duplicate_group = true;
+ } else if ((pace->type == SMB_ACL_GROUP)
+ && (dom_sid_equal(&pace->trustee, &pace_user->trustee))) {
+ /* If the SID owning the file appears
+ * in a group entry, then we have
+ * enough duplication, they will still
+ * have access */
+ got_duplicate_user = true;
+ }
+ }
+
+ /* If the SID is equal for the user and group that we need
+ to add the duplicate for, add only the group */
+ if (!got_duplicate_user && !got_duplicate_group
+ && dom_sid_equal(&pace_group->trustee,
+ &pace_user->trustee)) {
+ /* Add a duplicate SMB_ACL_GROUP entry, this
+ * will cover the owning SID as well, as it
+ * will always be mapped to both a uid and
+ * gid. */
+
+ if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
+ DEBUG(0,("talloc fail.\n"));
+ return false;
+ }
+
+ ZERO_STRUCTP(pace);
+ pace->type = SMB_ACL_GROUP;;
+ pace->owner_type = GID_ACE;
+ pace->unix_ug.type = ID_TYPE_GID;
+ pace->unix_ug.id = pace_group->unix_ug.id;
+ pace->trustee = pace_group->trustee;
+ pace->attr = pace_group->attr;
+ pace->perms = pace_group->perms;
+
+ DLIST_ADD(*pp_ace, pace);
+
+ /* We're done here, make sure the
+ statements below are not executed. */
+ got_duplicate_user = true;
+ got_duplicate_group = true;
+ }
+
+ if (!got_duplicate_user) {
+ /* Add a duplicate SMB_ACL_USER entry. */
+ if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
+ DEBUG(0,("talloc fail.\n"));
+ return false;
+ }
+
+ ZERO_STRUCTP(pace);
+ pace->type = SMB_ACL_USER;;
+ pace->owner_type = UID_ACE;
+ pace->unix_ug.type = ID_TYPE_UID;
+ pace->unix_ug.id = pace_user->unix_ug.id;
+ pace->trustee = pace_user->trustee;
+ pace->attr = pace_user->attr;
+ pace->perms = pace_user->perms;
+
+ DLIST_ADD(*pp_ace, pace);
+
+ got_duplicate_user = true;
+ }
+
+ if (!got_duplicate_group) {
+ /* Add a duplicate SMB_ACL_GROUP entry. */
+ if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
+ DEBUG(0,("talloc fail.\n"));
+ return false;
+ }
+
+ ZERO_STRUCTP(pace);
+ pace->type = SMB_ACL_GROUP;;
+ pace->owner_type = GID_ACE;
+ pace->unix_ug.type = ID_TYPE_GID;
+ pace->unix_ug.id = pace_group->unix_ug.id;
+ pace->trustee = pace_group->trustee;
+ pace->attr = pace_group->attr;
+ pace->perms = pace_group->perms;
+
+ DLIST_ADD(*pp_ace, pace);
+
+ got_duplicate_group = true;
+ }
+
+ return true;
}
/****************************************************************************
Check if a POSIX ACL has the required SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ entries.
If it does not have them, check if there are any entries where the trustee is the
file owner or the owning group, and map these to SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ.
+ Note we must not do this to default directory ACLs.
****************************************************************************/
static void check_owning_objs(canon_ace *ace, struct dom_sid *pfile_owner_sid, struct dom_sid *pfile_grp_sid)
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;
}
DEBUG(10,("check_owning_objs: ACL is missing an owning group entry.\n"));
}
-/****************************************************************************
- 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)
+static bool add_current_ace_to_acl(files_struct *fsp, struct security_ace *psa,
+ canon_ace **file_ace, canon_ace **dir_ace,
+ bool *got_file_allow, bool *got_dir_allow,
+ bool *all_aces_are_inherit_only,
+ canon_ace *current_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 &&
- !(sid_equal(&ace->trustee, &global_sid_Creator_Owner))) {
- canon_ace *dup_ace = dup_canon_ace(ace);
+ /*
+ * Map the given NT permissions into a UNIX mode_t containing only
+ * S_I(R|W|X)USR bits.
+ */
+
+ current_ace->perms |= map_nt_perms( &psa->access_mask, S_IRUSR);
+ current_ace->attr = (psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED) ? ALLOW_ACE : DENY_ACE;
- if (dup_ace == NULL) {
- return false;
+ /* Store the ace_flag. */
+ current_ace->ace_flags = psa->flags;
+
+ /*
+ * Now add the created ace to either the file list, the directory
+ * list, or both. We *MUST* preserve the order here (hence we use
+ * DLIST_ADD_END) as NT ACLs are order dependent.
+ */
+
+ if (fsp->is_directory) {
+
+ /*
+ * We can only add to the default POSIX ACE list if the ACE is
+ * designed to be inherited by both files and directories.
+ */
+
+ if ((psa->flags & (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) ==
+ (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) {
+
+ canon_ace *current_dir_ace = current_ace;
+ DLIST_ADD_END(*dir_ace, current_ace, canon_ace *);
+
+ /*
+ * Note if this was an allow ace. We can't process
+ * any further deny ace's after this.
+ */
+
+ if (current_ace->attr == ALLOW_ACE)
+ *got_dir_allow = True;
+
+ if ((current_ace->attr == DENY_ACE) && *got_dir_allow) {
+ DEBUG(0,("add_current_ace_to_acl: "
+ "malformed ACL in "
+ "inheritable ACL! Deny entry "
+ "after Allow entry. Failing "
+ "to set on file %s.\n",
+ fsp_str_dbg(fsp)));
+ return False;
+ }
+
+ if( DEBUGLVL( 10 )) {
+ dbgtext("add_current_ace_to_acl: adding dir ACL:\n");
+ print_canon_ace( current_ace, 0);
+ }
+
+ /*
+ * If this is not an inherit only ACE we need to add a duplicate
+ * to the file acl.
+ */
+
+ if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
+ canon_ace *dup_ace = dup_canon_ace(current_ace);
+
+ if (!dup_ace) {
+ DEBUG(0,("add_current_ace_to_acl: malloc fail !\n"));
+ return False;
+ }
+
+ /*
+ * We must not free current_ace here as its
+ * 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
+ * pointer is now owned by the dir_ace list.
+ */
+ current_ace = NULL;
+ }
+
+ /*
+ * current_ace is now either owned by file_ace
+ * or is NULL. We can safely operate on current_dir_ace
+ * to treat mapping for default acl entries differently
+ * than access acl entries.
+ */
+
+ if (current_dir_ace->owner_type == UID_ACE) {
+ /*
+ * We already decided above this is a uid,
+ * for default acls ace's only CREATOR_OWNER
+ * maps to ACL_USER_OBJ. All other uid
+ * ace's are ACL_USER.
+ */
+ if (dom_sid_equal(¤t_dir_ace->trustee,
+ &global_sid_Creator_Owner)) {
+ current_dir_ace->type = SMB_ACL_USER_OBJ;
+ } else {
+ current_dir_ace->type = SMB_ACL_USER;
+ }
+ }
+
+ if (current_dir_ace->owner_type == GID_ACE) {
+ /*
+ * We already decided above this is a gid,
+ * for default acls ace's only CREATOR_GROUP
+ * maps to ACL_GROUP_OBJ. All other uid
+ * ace's are ACL_GROUP.
+ */
+ if (dom_sid_equal(¤t_dir_ace->trustee,
+ &global_sid_Creator_Group)) {
+ current_dir_ace->type = SMB_ACL_GROUP_OBJ;
+ } else {
+ current_dir_ace->type = SMB_ACL_GROUP;
+ }
+ }
}
- dup_ace->type = SMB_ACL_USER;
- DLIST_ADD_END(dir_ace, dup_ace, canon_ace *);
}
- if (ace->type == SMB_ACL_GROUP_OBJ &&
- !(sid_equal(&ace->trustee, &global_sid_Creator_Group))) {
- canon_ace *dup_ace = dup_canon_ace(ace);
+ /*
+ * Only add to the file ACL if not inherit only.
+ */
+
+ if (current_ace && !(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
+ DLIST_ADD_END(*file_ace, current_ace, canon_ace *);
- if (dup_ace == NULL) {
- return false;
+ /*
+ * Note if this was an allow ace. We can't process
+ * any further deny ace's after this.
+ */
+
+ if (current_ace->attr == ALLOW_ACE)
+ *got_file_allow = True;
+
+ if ((current_ace->attr == DENY_ACE) && got_file_allow) {
+ DEBUG(0,("add_current_ace_to_acl: malformed "
+ "ACL in file ACL ! Deny entry after "
+ "Allow entry. Failing to set on file "
+ "%s.\n", fsp_str_dbg(fsp)));
+ return False;
+ }
+
+ if( DEBUGLVL( 10 )) {
+ dbgtext("add_current_ace_to_acl: adding file ACL:\n");
+ print_canon_ace( current_ace, 0);
}
- dup_ace->type = SMB_ACL_GROUP;
- DLIST_ADD_END(dir_ace, dup_ace, canon_ace *);
+ *all_aces_are_inherit_only = False;
+ /*
+ * We must not free current_ace here as its
+ * pointer is now owned by the file_ace list.
+ */
+ current_ace = NULL;
}
+ /*
+ * Free if ACE was not added.
+ */
+
+ TALLOC_FREE(current_ace);
return true;
}
DEBUG(3,("create_canon_ace_lists: unable to set anything but an ALLOW or DENY ACE.\n"));
return False;
}
-
- if (nt4_compatible_acls()) {
- /*
- * The security mask may be UNIX_ACCESS_NONE which should map into
- * no permissions (we overload the WRITE_OWNER bit for this) or it
- * should be one of the ALL/EXECUTE/READ/WRITE bits. Arrange for this
- * to be so. Any other bits override the UNIX_ACCESS_NONE bit.
- */
-
- /*
- * Convert GENERIC bits to specific bits.
- */
-
- se_map_generic(&psa->access_mask, &file_generic_mapping);
-
- psa->access_mask &= (UNIX_ACCESS_NONE|FILE_ALL_ACCESS);
-
- if(psa->access_mask != UNIX_ACCESS_NONE)
- psa->access_mask &= ~UNIX_ACCESS_NONE;
- }
}
/*
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) {
+ if ((current_ace = talloc(talloc_tos(), canon_ace)) == NULL) {
free_canon_ace_list(file_ace);
free_canon_ace_list(dir_ace);
DEBUG(0,("create_canon_ace_lists: malloc fail.\n"));
* 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->unix_ug.type = ID_TYPE_NOT_SPECIFIED;
+ current_ace->unix_ug.id = -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->unix_ug.type = ID_TYPE_UID;
+ current_ace->unix_ug.id = 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->unix_ug.type = ID_TYPE_GID;
+ current_ace->unix_ug.id = 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.
- */
- 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;
- /* If it's the owning user, this is a user_obj, not
- * a user. */
- if (current_ace->unix_ug.uid == pst->st_ex_uid) {
- current_ace->type = SMB_ACL_USER_OBJ;
- } else {
- current_ace->type = SMB_ACL_USER;
- }
- } else if (sid_to_gid( ¤t_ace->trustee, ¤t_ace->unix_ug.gid)) {
- current_ace->owner_type = GID_ACE;
- /* If it's the primary group, this is a group_obj, not
- * a group. */
- if (current_ace->unix_ug.gid == pst->st_ex_gid) {
- current_ace->type = SMB_ACL_GROUP_OBJ;
- } else {
- current_ace->type = SMB_ACL_GROUP;
- }
- } else {
- /*
- * Silently ignore map failures in non-mappable SIDs (NT Authority, BUILTIN etc).
- */
-
- if (non_mappable_sid(&psa->trustee)) {
- DEBUG(10, ("create_canon_ace_lists: ignoring "
- "non-mappable 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 "
- "%s to uid or gid.\n",
- sid_string_dbg(¤t_ace->trustee)));
- SAFE_FREE(current_ace);
- return False;
- }
-
- /*
- * Map the given NT permissions into a UNIX mode_t containing only
- * S_I(R|W|X)USR bits.
- */
-
- current_ace->perms |= map_nt_perms( &psa->access_mask, S_IRUSR);
- current_ace->attr = (psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED) ? ALLOW_ACE : DENY_ACE;
-
- /* Store the ace_flag. */
- current_ace->ace_flags = psa->flags;
-
- /*
- * Now add the created ace to either the file list, the directory
- * list, or both. We *MUST* preserve the order here (hence we use
- * DLIST_ADD_END) as NT ACLs are order dependent.
- */
-
- if (fsp->is_directory) {
-
- /*
- * We can only add to the default POSIX ACE list if the ACE is
- * designed to be inherited by both files and directories.
- */
-
- if ((psa->flags & (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) ==
- (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) {
-
- DLIST_ADD_END(dir_ace, current_ace, canon_ace *);
-
- /*
- * Note if this was an allow ace. We can't process
- * any further deny ace's after this.
- */
-
- if (current_ace->attr == ALLOW_ACE)
- got_dir_allow = True;
-
- if ((current_ace->attr == DENY_ACE) && got_dir_allow) {
- DEBUG(0,("create_canon_ace_lists: "
- "malformed ACL in "
- "inheritable ACL! Deny entry "
- "after Allow entry. Failing "
- "to set on file %s.\n",
- fsp_str_dbg(fsp)));
- free_canon_ace_list(file_ace);
- free_canon_ace_list(dir_ace);
- return False;
- }
-
- if( DEBUGLVL( 10 )) {
- dbgtext("create_canon_ace_lists: adding dir ACL:\n");
- 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>.
- */
+ * The Creator Group entry only specifies inheritable permissions,
+ * never access permissions. WinNT doesn't always set the ACE to
+ * INHERIT_ONLY, though.
+ */
+ psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
- 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;
- }
+ } else {
+ struct unixid unixid;
- /*
- * If this is not an inherit only ACE we need to add a duplicate
- * to the file acl.
- */
+ if (!sids_to_unixids(¤t_ace->trustee, 1, &unixid)) {
+ free_canon_ace_list(file_ace);
+ free_canon_ace_list(dir_ace);
+ TALLOC_FREE(current_ace);
+ DEBUG(0, ("create_canon_ace_lists: sids_to_unixids "
+ "failed for %s (allocation failure)\n",
+ sid_string_dbg(¤t_ace->trustee)));
+ return false;
+ }
- if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
- canon_ace *dup_ace = dup_canon_ace(current_ace);
+ if (unixid.type == ID_TYPE_BOTH) {
+ /* If it's the owning user, this is a
+ * user_obj, not a user. This way, we
+ * get a valid ACL for groups that own
+ * files, without putting user ACL
+ * entries in for groups otherwise */
+ if (unixid.id == pst->st_ex_uid) {
+ current_ace->owner_type = UID_ACE;
+ current_ace->unix_ug.type = ID_TYPE_UID;
+ current_ace->unix_ug.id = unixid.id;
+ current_ace->type = SMB_ACL_USER_OBJ;
+
+ /* Add the user object to the posix ACL,
+ and proceed to the group mapping
+ below. This handles the talloc_free
+ of current_ace if not added for some
+ reason */
+ if (!add_current_ace_to_acl(fsp,
+ psa,
+ &file_ace,
+ &dir_ace,
+ &got_file_allow,
+ &got_dir_allow,
+ &all_aces_are_inherit_only,
+ current_ace)) {
+ free_canon_ace_list(file_ace);
+ free_canon_ace_list(dir_ace);
+ return false;
+ }
- if (!dup_ace) {
- DEBUG(0,("create_canon_ace_lists: malloc fail !\n"));
+ if ((current_ace = talloc(talloc_tos(),
+ canon_ace)) == NULL) {
free_canon_ace_list(file_ace);
free_canon_ace_list(dir_ace);
+ DEBUG(0,("create_canon_ace_lists: "
+ "malloc fail.\n"));
return False;
}
- /*
- * We must not free current_ace here as its
- * 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
- * pointer is now owned by the dir_ace list.
- */
- current_ace = NULL;
+ ZERO_STRUCTP(current_ace);
}
- }
- }
- /*
- * Only add to the file ACL if not inherit only.
- */
+ sid_copy(¤t_ace->trustee, &psa->trustee);
- if (current_ace && !(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
- DLIST_ADD_END(file_ace, current_ace, canon_ace *);
+ current_ace->unix_ug.type = ID_TYPE_GID;
+ current_ace->unix_ug.id = unixid.id;
+ current_ace->owner_type = GID_ACE;
+ /* If it's the primary group, this is a
+ group_obj, not a group. */
+ if (current_ace->unix_ug.id == pst->st_ex_gid) {
+ current_ace->type = SMB_ACL_GROUP_OBJ;
+ } else {
+ current_ace->type = SMB_ACL_GROUP;
+ }
- /*
- * Note if this was an allow ace. We can't process
- * any further deny ace's after this.
- */
+ } else if (unixid.type == ID_TYPE_UID) {
+ current_ace->owner_type = UID_ACE;
+ current_ace->unix_ug.type = ID_TYPE_UID;
+ current_ace->unix_ug.id = unixid.id;
+ /* If it's the owning user, this is a user_obj,
+ not a user. */
+ if (current_ace->unix_ug.id == pst->st_ex_uid) {
+ current_ace->type = SMB_ACL_USER_OBJ;
+ } else {
+ current_ace->type = SMB_ACL_USER;
+ }
+ } else if (unixid.type == ID_TYPE_GID) {
+ current_ace->unix_ug.type = ID_TYPE_GID;
+ current_ace->unix_ug.id = unixid.id;
+ current_ace->owner_type = GID_ACE;
+ /* If it's the primary group, this is a
+ group_obj, not a group. */
+ if (current_ace->unix_ug.id == pst->st_ex_gid) {
+ current_ace->type = SMB_ACL_GROUP_OBJ;
+ } else {
+ current_ace->type = SMB_ACL_GROUP;
+ }
+ } else {
+ /*
+ * Silently ignore map failures in non-mappable SIDs (NT Authority, BUILTIN etc).
+ */
- if (current_ace->attr == ALLOW_ACE)
- got_file_allow = True;
+ if (non_mappable_sid(&psa->trustee)) {
+ DEBUG(10, ("create_canon_ace_lists: ignoring "
+ "non-mappable SID %s\n",
+ sid_string_dbg(&psa->trustee)));
+ TALLOC_FREE(current_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)));
+ TALLOC_FREE(current_ace);
+ continue;
+ }
- if ((current_ace->attr == DENY_ACE) && got_file_allow) {
- DEBUG(0,("create_canon_ace_lists: malformed "
- "ACL in file ACL ! Deny entry after "
- "Allow entry. Failing to set on file "
- "%s.\n", fsp_str_dbg(fsp)));
free_canon_ace_list(file_ace);
free_canon_ace_list(dir_ace);
- return False;
- }
-
- if( DEBUGLVL( 10 )) {
- dbgtext("create_canon_ace_lists: adding file ACL:\n");
- print_canon_ace( current_ace, 0);
+ DEBUG(0, ("create_canon_ace_lists: unable to map SID "
+ "%s to uid or gid.\n",
+ sid_string_dbg(¤t_ace->trustee)));
+ TALLOC_FREE(current_ace);
+ return false;
}
- all_aces_are_inherit_only = False;
- /*
- * We must not free current_ace here as its
- * pointer is now owned by the file_ace list.
- */
- current_ace = NULL;
}
- /*
- * Free if ACE was not added.
- */
-
- SAFE_FREE(current_ace);
+ /* handles the talloc_free of current_ace if not added for some reason */
+ if (!add_current_ace_to_acl(fsp, psa, &file_ace, &dir_ace,
+ &got_file_allow, &got_dir_allow,
+ &all_aces_are_inherit_only, current_ace)) {
+ free_canon_ace_list(file_ace);
+ free_canon_ace_list(dir_ace);
+ return false;
+ }
}
if (fsp->is_directory && all_aces_are_inherit_only) {
dir_ace = NULL;
} else {
/*
- * Check if we have SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ entries in each
- * ACL. If we don't have them, check if any SMB_ACL_USER/SMB_ACL_GROUP
- * entries can be converted to *_OBJ. Usually we will already have these
- * entries in the Default ACL, and the Access ACL will not have them.
+ * Check if we have SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ entries in
+ * the file ACL. If we don't have them, check if any SMB_ACL_USER/SMB_ACL_GROUP
+ * entries can be converted to *_OBJ. Don't do this for the default
+ * ACL, we will create them separately for this if needed inside
+ * ensure_canon_entry_valid_on_set().
*/
if (file_ace) {
check_owning_objs(file_ace, pfile_owner_sid, pfile_grp_sid);
}
- if (dir_ace) {
- check_owning_objs(dir_ace, pfile_owner_sid, pfile_grp_sid);
- }
}
*ppfile_ace = file_ace;
continue;
}
- if (!sid_equal(&curr_ace->trustee, &global_sid_World))
+ if (!dom_sid_equal(&curr_ace->trustee, &global_sid_World))
continue;
/* JRATEST - assert. */
*pp_ace_list = ace_list;
}
-/****************************************************************************
- Create a default mode that will be used if a security descriptor entry has
- no user/group/world entries.
-****************************************************************************/
-
-static mode_t create_default_mode(files_struct *fsp, bool interitable_mode)
-{
- int snum = SNUM(fsp->conn);
- mode_t and_bits = (mode_t)0;
- mode_t or_bits = (mode_t)0;
- mode_t mode;
-
- if (interitable_mode) {
- mode = unix_mode(fsp->conn, FILE_ATTRIBUTE_ARCHIVE,
- fsp->fsp_name, NULL);
- } else {
- mode = S_IRUSR;
- }
-
- if (fsp->is_directory)
- mode |= (S_IWUSR|S_IXUSR);
-
- /*
- * Now AND with the create mode/directory mode bits then OR with the
- * force create mode/force directory mode bits.
- */
-
- if (fsp->is_directory) {
- and_bits = lp_dir_security_mask(snum);
- or_bits = lp_force_dir_security_mode(snum);
- } else {
- and_bits = lp_security_mask(snum);
- or_bits = lp_force_security_mode(snum);
- }
-
- return ((mode & and_bits)|or_bits);
-}
-
/****************************************************************************
Unpack a struct security_descriptor into two canonical ace lists. We don't depend on this
succeeding.
uint32 security_info_sent,
const struct security_descriptor *psd)
{
- SMB_STRUCT_STAT st;
canon_ace *file_ace = NULL;
canon_ace *dir_ace = NULL;
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 --- ---.
- */
-
- st.st_ex_mode = create_default_mode(fsp, False);
-
- if (!ensure_canon_entry_valid(fsp->conn, &file_ace, fsp->conn->params,
- fsp->is_directory, pfile_owner_sid, pfile_grp_sid, &st, True)) {
+ if (!ensure_canon_entry_valid_on_set(fsp->conn, &file_ace, false, fsp->conn->params,
+ fsp->is_directory, pfile_owner_sid, pfile_grp_sid, pst)) {
free_canon_ace_list(file_ace);
free_canon_ace_list(dir_ace);
return False;
print_canon_ace_list( "dir ace - before valid", dir_ace);
- /*
- * A default inheritable 3 element mode entry for a directory should be the
- * mode Samba will use to create a file within. Ensure user rwx bits are set if
- * it's a directory.
- */
-
- st.st_ex_mode = create_default_mode(fsp, 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)) {
+ if (dir_ace && !ensure_canon_entry_valid_on_set(fsp->conn, &dir_ace, true, fsp->conn->params,
+ fsp->is_directory, pfile_owner_sid, pfile_grp_sid, pst)) {
free_canon_ace_list(file_ace);
free_canon_ace_list(dir_ace);
return False;
canon_ace *ace = NULL;
canon_ace *next_ace = NULL;
int entry_id = SMB_ACL_FIRST_ENTRY;
+ bool is_default_acl = (the_acl_type == SMB_ACL_TYPE_DEFAULT);
SMB_ACL_ENTRY_T entry;
size_t ace_count;
- while ( posix_acl && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1)) {
+ while ( posix_acl && (sys_acl_get_entry(posix_acl, entry_id, &entry) == 1)) {
SMB_ACL_TAG_T tagtype;
SMB_ACL_PERMSET_T permset;
struct dom_sid sid;
- posix_id unix_ug;
+ struct unixid unix_ug;
enum ace_owner owner_type;
entry_id = SMB_ACL_NEXT_ENTRY;
/* Is this a MASK entry ? */
- if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1)
+ if (sys_acl_get_tag_type(entry, &tagtype) == -1)
continue;
- if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1)
+ if (sys_acl_get_permset(entry, &permset) == -1)
continue;
/* Decide which SID to use based on the ACL type. */
case SMB_ACL_USER_OBJ:
/* Get the SID from the owner. */
sid_copy(&sid, powner);
- unix_ug.uid = psbuf->st_ex_uid;
+ unix_ug.type = ID_TYPE_UID;
+ unix_ug.id = psbuf->st_ex_uid;
owner_type = UID_ACE;
break;
case SMB_ACL_USER:
{
- uid_t *puid = (uid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
+ uid_t *puid = (uid_t *)sys_acl_get_qualifier(entry);
if (puid == NULL) {
DEBUG(0,("canonicalise_acl: Failed to get uid.\n"));
continue;
}
uid_to_sid( &sid, *puid);
- unix_ug.uid = *puid;
+ unix_ug.type = ID_TYPE_UID;
+ unix_ug.id = *puid;
owner_type = UID_ACE;
- SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)puid,tagtype);
break;
}
case SMB_ACL_GROUP_OBJ:
/* Get the SID from the owning group. */
sid_copy(&sid, pgroup);
- unix_ug.gid = psbuf->st_ex_gid;
+ unix_ug.type = ID_TYPE_GID;
+ unix_ug.id = psbuf->st_ex_gid;
owner_type = GID_ACE;
break;
case SMB_ACL_GROUP:
{
- gid_t *pgid = (gid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
+ gid_t *pgid = (gid_t *)sys_acl_get_qualifier(entry);
if (pgid == NULL) {
DEBUG(0,("canonicalise_acl: Failed to get gid.\n"));
continue;
}
gid_to_sid( &sid, *pgid);
- unix_ug.gid = *pgid;
+ unix_ug.type = ID_TYPE_GID;
+ unix_ug.id = *pgid;
owner_type = GID_ACE;
- SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)pgid,tagtype);
break;
}
case SMB_ACL_MASK:
- acl_mask = convert_permset_to_mode_t(conn, permset);
+ acl_mask = convert_permset_to_mode_t(permset);
continue; /* Don't count the mask as an entry. */
case SMB_ACL_OTHER:
/* Use the Everyone SID */
sid = global_sid_World;
- unix_ug.world = -1;
+ unix_ug.type = ID_TYPE_NOT_SPECIFIED;
+ unix_ug.id = -1;
owner_type = WORLD_ACE;
break;
default:
* Add this entry to the list.
*/
- if ((ace = SMB_MALLOC_P(canon_ace)) == NULL)
+ if ((ace = talloc(talloc_tos(), canon_ace)) == NULL)
goto fail;
ZERO_STRUCTP(ace);
ace->type = tagtype;
- ace->perms = convert_permset_to_mode_t(conn, permset);
+ ace->perms = convert_permset_to_mode_t(permset);
ace->attr = ALLOW_ACE;
ace->trustee = sid;
ace->unix_ug = unix_ug;
ace->owner_type = owner_type;
- ace->ace_flags = get_pai_flags(pal, ace, (the_acl_type == SMB_ACL_TYPE_DEFAULT));
+ ace->ace_flags = get_pai_flags(pal, ace, is_default_acl);
DLIST_ADD(l_head, ace);
}
* This next call will ensure we have at least a user/group/world set.
*/
- if (!ensure_canon_entry_valid(conn, &l_head, conn->params,
- S_ISDIR(psbuf->st_ex_mode), powner, pgroup,
- psbuf, False))
+ if (!ensure_canon_entry_valid_on_get(conn, &l_head,
+ powner, pgroup,
+ psbuf))
goto fail;
/*
* acl_mask. Ensure all DENY Entries are at the start of the list.
*/
- DEBUG(10,("canonicalise_acl: %s ace entries before arrange :\n", the_acl_type == SMB_ACL_TYPE_ACCESS ? "Access" : "Default" ));
+ DEBUG(10,("canonicalise_acl: %s ace entries before arrange :\n", is_default_acl ? "Default" : "Access"));
for ( ace_count = 0, ace = l_head; ace; ace = next_ace, ace_count++) {
next_ace = ace->next;
Check if the current user group list contains a given group.
****************************************************************************/
-static bool current_user_in_group(connection_struct *conn, gid_t gid)
+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) {
{
connection_struct *conn = fsp->conn;
bool ret = False;
- SMB_ACL_T the_acl = SMB_VFS_SYS_ACL_INIT(conn, (int)count_canon_ace_list(the_ace) + 1);
+ SMB_ACL_T the_acl = sys_acl_init(talloc_tos());
canon_ace *p_ace;
int i;
SMB_ACL_ENTRY_T mask_entry;
#endif
if (the_acl == NULL) {
-
- if (!no_acl_syscall_error(errno)) {
- /*
- * Only print this error message if we have some kind of ACL
- * support that's not working. Otherwise we would always get this.
- */
- DEBUG(0,("set_canon_ace_list: Unable to init %s ACL. (%s)\n",
- default_ace ? "default" : "file", strerror(errno) ));
- }
- *pacl_set_support = False;
- goto fail;
+ DEBUG(0, ("sys_acl_init failed to allocate an ACL\n"));
+ return false;
}
if( DEBUGLVL( 10 )) {
* Get the entry for this ACE.
*/
- if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &the_entry) == -1) {
+ if (sys_acl_create_entry(&the_acl, &the_entry) == -1) {
DEBUG(0,("set_canon_ace_list: Failed to create entry %d. (%s)\n",
i, strerror(errno) ));
goto fail;
* First tell the entry what type of ACE this is.
*/
- if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, the_entry, p_ace->type) == -1) {
+ if (sys_acl_set_tag_type(the_entry, p_ace->type) == -1) {
DEBUG(0,("set_canon_ace_list: Failed to set tag type on entry %d. (%s)\n",
i, strerror(errno) ));
goto fail;
*/
if ((p_ace->type == SMB_ACL_USER) || (p_ace->type == SMB_ACL_GROUP)) {
- if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&p_ace->unix_ug.uid) == -1) {
+ if (sys_acl_set_qualifier(the_entry,(void *)&p_ace->unix_ug.id) == -1) {
DEBUG(0,("set_canon_ace_list: Failed to set qualifier on entry %d. (%s)\n",
i, strerror(errno) ));
goto fail;
* Convert the mode_t perms in the canon_ace to a POSIX permset.
*/
- if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, the_entry, &the_permset) == -1) {
+ if (sys_acl_get_permset(the_entry, &the_permset) == -1) {
DEBUG(0,("set_canon_ace_list: Failed to get permset on entry %d. (%s)\n",
i, strerror(errno) ));
goto fail;
* ..and apply them to the entry.
*/
- if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, the_entry, the_permset) == -1) {
+ if (sys_acl_set_permset(the_entry, the_permset) == -1) {
DEBUG(0,("set_canon_ace_list: Failed to add permset on entry %d. (%s)\n",
i, strerror(errno) ));
goto fail;
}
if (needs_mask && !got_mask_entry) {
- if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &mask_entry) == -1) {
+ if (sys_acl_create_entry(&the_acl, &mask_entry) == -1) {
DEBUG(0,("set_canon_ace_list: Failed to create mask entry. (%s)\n", strerror(errno) ));
goto fail;
}
- if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, mask_entry, SMB_ACL_MASK) == -1) {
+ if (sys_acl_set_tag_type(mask_entry, SMB_ACL_MASK) == -1) {
DEBUG(0,("set_canon_ace_list: Failed to set tag type on mask entry. (%s)\n",strerror(errno) ));
goto fail;
}
- if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, mask_entry, &mask_permset) == -1) {
+ if (sys_acl_get_permset(mask_entry, &mask_permset) == -1) {
DEBUG(0,("set_canon_ace_list: Failed to get mask permset. (%s)\n", strerror(errno) ));
goto fail;
}
goto fail;
}
- if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, mask_entry, mask_permset) == -1) {
+ if (sys_acl_set_permset(mask_entry, mask_permset) == -1) {
DEBUG(0,("set_canon_ace_list: Failed to add mask permset. (%s)\n", strerror(errno) ));
goto fail;
}
fail:
if (the_acl != NULL) {
- SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
+ TALLOC_FREE(the_acl);
}
return ret;
}
-/****************************************************************************
- Find a particular canon_ace entry.
-****************************************************************************/
-
-static struct canon_ace *canon_ace_entry_for(struct canon_ace *list, SMB_ACL_TAG_T type, posix_id *id)
-{
- while (list) {
- if (list->type == type && ((type != SMB_ACL_USER && type != SMB_ACL_GROUP) ||
- (type == SMB_ACL_USER && id && id->uid == list->unix_ug.uid) ||
- (type == SMB_ACL_GROUP && id && id->gid == list->unix_ug.gid)))
- break;
- list = list->next;
- }
- return list;
-}
-
/****************************************************************************
****************************************************************************/
if (!the_acl)
return NULL;
- if (SMB_VFS_SYS_ACL_GET_ENTRY(conn, the_acl, SMB_ACL_FIRST_ENTRY, &entry) != 1) {
- SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
+ if (sys_acl_get_entry(the_acl, SMB_ACL_FIRST_ENTRY, &entry) != 1) {
+ TALLOC_FREE(the_acl);
return NULL;
}
return the_acl;
/* Get the initial bits to apply. */
if (fsp->is_directory) {
- and_bits = lp_dir_security_mask(snum);
- or_bits = lp_force_dir_security_mode(snum);
+ and_bits = lp_dir_mask(snum);
+ or_bits = lp_force_dir_mode(snum);
} else {
- and_bits = lp_security_mask(snum);
- or_bits = lp_force_security_mode(snum);
+ and_bits = lp_create_mask(snum);
+ or_bits = lp_force_create_mode(snum);
}
*posix_perms = (((*posix_perms) & and_bits)|or_bits);
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;
}
SMB_ACL_T posix_acl,
SMB_ACL_T def_acl,
uint32_t security_info,
+ TALLOC_CTX *mem_ctx,
struct security_descriptor **ppdesc)
{
struct dom_sid owner_sid;
num_profile_acls = 3;
}
- if ((security_info & SECINFO_DACL) && !(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
canon_ace *ace;
enum security_ace_type nt_acl_type;
- if (nt4_compatible_acls() && dir_ace) {
- /*
- * NT 4 chokes if an ACL contains an INHERIT_ONLY entry
- * but no non-INHERIT_ONLY entry for one SID. So we only
- * remove entries from the Access ACL if the
- * corresponding Default ACL entries have also been
- * removed. ACEs for CREATOR-OWNER and CREATOR-GROUP
- * are exceptions. We can do nothing
- * intelligent if the Default ACL contains entries that
- * are not also contained in the Access ACL, so this
- * case will still fail under NT 4.
- */
-
- ace = canon_ace_entry_for(dir_ace, SMB_ACL_OTHER, NULL);
- if (ace && !ace->perms) {
- DLIST_REMOVE(dir_ace, ace);
- SAFE_FREE(ace);
-
- ace = canon_ace_entry_for(file_ace, SMB_ACL_OTHER, NULL);
- if (ace && !ace->perms) {
- DLIST_REMOVE(file_ace, ace);
- SAFE_FREE(ace);
- }
- }
-
- /*
- * WinNT doesn't usually have Creator Group
- * in browse lists, so we send this entry to
- * WinNT even if it contains no relevant
- * permissions. Once we can add
- * Creator Group to browse lists we can
- * re-enable this.
- */
-
-#if 0
- ace = canon_ace_entry_for(dir_ace, SMB_ACL_GROUP_OBJ, NULL);
- if (ace && !ace->perms) {
- DLIST_REMOVE(dir_ace, ace);
- SAFE_FREE(ace);
- }
-#endif
-
- ace = canon_ace_entry_for(file_ace, SMB_ACL_GROUP_OBJ, NULL);
- if (ace && !ace->perms) {
- DLIST_REMOVE(file_ace, ace);
- SAFE_FREE(ace);
- }
- }
-
num_acls = count_canon_ace_list(file_ace);
num_def_acls = count_canon_ace_list(dir_ace);
/* Allocate the ace list. */
- if ((nt_ace_list = SMB_MALLOC_ARRAY(struct security_ace,num_acls + num_profile_acls + num_def_acls)) == NULL) {
+ if ((nt_ace_list = talloc_array(talloc_tos(), 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;
}
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,
}
} /* security_info & SECINFO_DACL */
- psd = make_standard_sec_desc( talloc_tos(),
+ psd = make_standard_sec_desc(mem_ctx,
(security_info & SECINFO_OWNER) ? &owner_sid : NULL,
(security_info & SECINFO_GROUP) ? &group_sid : NULL,
psa,
done:
if (posix_acl) {
- SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
+ TALLOC_FREE(posix_acl);
}
if (def_acl) {
- SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
+ TALLOC_FREE(def_acl);
}
free_canon_ace_list(file_ace);
free_canon_ace_list(dir_ace);
free_inherited_info(pal);
- SAFE_FREE(nt_ace_list);
+ TALLOC_FREE(nt_ace_list);
return NT_STATUS_OK;
}
NTSTATUS posix_fget_nt_acl(struct files_struct *fsp, uint32_t security_info,
+ TALLOC_CTX *mem_ctx,
struct security_descriptor **ppdesc)
{
SMB_STRUCT_STAT sbuf;
SMB_ACL_T posix_acl = NULL;
struct pai_val *pal;
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
*ppdesc = NULL;
/* can it happen that fsp_name == NULL ? */
if (fsp->is_directory || fsp->fh->fd == -1) {
- return posix_get_nt_acl(fsp->conn, fsp->fsp_name->base_name,
- security_info, ppdesc);
+ status = posix_get_nt_acl(fsp->conn, fsp->fsp_name->base_name,
+ security_info, mem_ctx, ppdesc);
+ TALLOC_FREE(frame);
+ return status;
}
/* Get the stat struct for the owner info. */
if(SMB_VFS_FSTAT(fsp, &sbuf) != 0) {
+ TALLOC_FREE(frame);
return map_nt_error_from_unix(errno);
}
/* Get the ACL from the fd. */
- posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp);
+ posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, frame);
pal = fload_inherited_info(fsp);
- return posix_get_nt_acl_common(fsp->conn, fsp->fsp_name->base_name,
- &sbuf, pal, posix_acl, NULL,
- security_info, ppdesc);
+ status = posix_get_nt_acl_common(fsp->conn, fsp->fsp_name->base_name,
+ &sbuf, pal, posix_acl, NULL,
+ security_info, mem_ctx, ppdesc);
+ TALLOC_FREE(frame);
+ return status;
}
NTSTATUS posix_get_nt_acl(struct connection_struct *conn, const char *name,
- uint32_t security_info, struct security_descriptor **ppdesc)
+ uint32_t security_info,
+ TALLOC_CTX *mem_ctx,
+ 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;
int ret;
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
*ppdesc = NULL;
}
if (ret == -1) {
+ TALLOC_FREE(frame);
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);
+ posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, name,
+ SMB_ACL_TYPE_ACCESS, frame);
/* If it's a directory get the default POSIX ACL. */
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 = SMB_VFS_SYS_ACL_GET_FILE(conn, name,
+ SMB_ACL_TYPE_DEFAULT, frame);
def_acl = free_empty_sys_acl(conn, def_acl);
}
pal = load_inherited_info(conn, name);
- return posix_get_nt_acl_common(conn, name, &smb_fname.st, pal,
- posix_acl, def_acl, security_info,
- ppdesc);
+ status = posix_get_nt_acl_common(conn, name, &smb_fname.st, pal,
+ posix_acl, def_acl, security_info,
+ mem_ctx,
+ ppdesc);
+ TALLOC_FREE(frame);
+ return status;
}
/****************************************************************************
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
num_aces += parent_sd->dacl->num_aces;
- if((new_ace = TALLOC_ZERO_ARRAY(mem_ctx, struct security_ace,
+ if((new_ace = talloc_zero_array(mem_ctx, struct security_ace,
num_aces)) == NULL) {
return NT_STATUS_NO_MEMORY;
}
* 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);
SMB_ACL_T posix_acl;
int result = -1;
- posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS);
+ posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname,
+ SMB_ACL_TYPE_ACCESS, talloc_tos());
if (posix_acl == (SMB_ACL_T)NULL)
return -1;
- while (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
+ while (sys_acl_get_entry(posix_acl, entry_id, &entry) == 1) {
SMB_ACL_TAG_T tagtype;
SMB_ACL_PERMSET_T permset;
entry_id = SMB_ACL_NEXT_ENTRY;
- if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) ==-1)
+ if (sys_acl_get_tag_type(entry, &tagtype) ==-1)
break;
if (tagtype == SMB_ACL_GROUP_OBJ) {
- if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
+ if (sys_acl_get_permset(entry, &permset) == -1) {
break;
} else {
*mode &= ~(S_IRGRP|S_IWGRP|S_IXGRP);
- *mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ) ? S_IRGRP : 0);
- *mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE) ? S_IWGRP : 0);
- *mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_EXECUTE) ? S_IXGRP : 0);
+ *mode |= (sys_acl_get_perm(permset, SMB_ACL_READ) ? S_IRGRP : 0);
+ *mode |= (sys_acl_get_perm(permset, SMB_ACL_WRITE) ? S_IWGRP : 0);
+ *mode |= (sys_acl_get_perm(permset, SMB_ACL_EXECUTE) ? S_IXGRP : 0);
result = 0;
break;
}
}
}
- SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
+ TALLOC_FREE(posix_acl);
return result;
}
SMB_ACL_ENTRY_T entry;
int num_entries = 0;
- while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
+ while ( sys_acl_get_entry(posix_acl, entry_id, &entry) == 1) {
SMB_ACL_TAG_T tagtype;
SMB_ACL_PERMSET_T permset;
mode_t perms;
entry_id = SMB_ACL_NEXT_ENTRY;
- if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1)
+ if (sys_acl_get_tag_type(entry, &tagtype) == -1)
return -1;
- if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1)
+ if (sys_acl_get_permset(entry, &permset) == -1)
return -1;
num_entries++;
if (map_acl_perms_to_permset(conn, perms, &permset) == -1)
return -1;
- if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, entry, permset) == -1)
+ if (sys_acl_set_permset(entry, permset) == -1)
return -1;
}
SMB_ACL_T posix_acl = NULL;
int ret = -1;
- if ((posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, from, SMB_ACL_TYPE_ACCESS)) == NULL)
+ if ((posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, from,
+ SMB_ACL_TYPE_ACCESS,
+ talloc_tos())) == NULL)
return -1;
if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1)
done:
- SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
+ TALLOC_FREE(posix_acl);
return ret;
}
static bool directory_has_default_posix_acl(connection_struct *conn, const char *fname)
{
- SMB_ACL_T def_acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, SMB_ACL_TYPE_DEFAULT);
+ SMB_ACL_T def_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname,
+ SMB_ACL_TYPE_DEFAULT,
+ talloc_tos());
bool has_acl = False;
SMB_ACL_ENTRY_T entry;
- if (def_acl != NULL && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, def_acl, SMB_ACL_FIRST_ENTRY, &entry) == 1)) {
+ if (def_acl != NULL && (sys_acl_get_entry(def_acl, SMB_ACL_FIRST_ENTRY, &entry) == 1)) {
has_acl = True;
}
if (def_acl) {
- SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
+ TALLOC_FREE(def_acl);
}
return has_acl;
}
SMB_ACL_T posix_acl = NULL;
int ret = -1;
- if ((posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp)) == NULL)
+ if ((posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, talloc_tos())) == NULL)
return -1;
if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1)
done:
- SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
+ TALLOC_FREE(posix_acl);
return ret;
}
return False;
}
- if (SMB_VFS_SYS_ACL_CLEAR_PERMS(conn, *p_permset) == -1) {
+ if (sys_acl_clear_perms(*p_permset) == -1) {
return False;
}
if (wire_perm & SMB_POSIX_ACL_READ) {
- if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_READ) == -1) {
+ if (sys_acl_add_perm(*p_permset, SMB_ACL_READ) == -1) {
return False;
}
}
if (wire_perm & SMB_POSIX_ACL_WRITE) {
- if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_WRITE) == -1) {
+ if (sys_acl_add_perm(*p_permset, SMB_ACL_WRITE) == -1) {
return False;
}
}
if (wire_perm & SMB_POSIX_ACL_EXECUTE) {
- if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_EXECUTE) == -1) {
+ if (sys_acl_add_perm(*p_permset, SMB_ACL_EXECUTE) == -1) {
return False;
}
}
FIXME ! How does the share mask/mode fit into this.... ?
****************************************************************************/
-static SMB_ACL_T create_posix_acl_from_wire(connection_struct *conn, uint16 num_acls, const char *pdata)
+static SMB_ACL_T create_posix_acl_from_wire(connection_struct *conn,
+ uint16 num_acls,
+ const char *pdata,
+ TALLOC_CTX *mem_ctx)
{
unsigned int i;
- SMB_ACL_T the_acl = SMB_VFS_SYS_ACL_INIT(conn, num_acls);
+ SMB_ACL_T the_acl = sys_acl_init(mem_ctx);
if (the_acl == NULL) {
return NULL;
SMB_ACL_PERMSET_T the_permset;
SMB_ACL_TAG_T tag_type;
- if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &the_entry) == -1) {
+ if (sys_acl_create_entry(&the_acl, &the_entry) == -1) {
DEBUG(0,("create_posix_acl_from_wire: Failed to create entry %u. (%s)\n",
i, strerror(errno) ));
goto fail;
goto fail;
}
- if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, the_entry, tag_type) == -1) {
+ if (sys_acl_set_tag_type(the_entry, tag_type) == -1) {
DEBUG(0,("create_posix_acl_from_wire: Failed to set tagtype on entry %u. (%s)\n",
i, strerror(errno) ));
goto fail;
}
/* Get the permset pointer from the new ACL entry. */
- if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, the_entry, &the_permset) == -1) {
+ if (sys_acl_get_permset(the_entry, &the_permset) == -1) {
DEBUG(0,("create_posix_acl_from_wire: Failed to get permset on entry %u. (%s)\n",
i, strerror(errno) ));
goto fail;
}
/* Now apply to the new ACL entry. */
- if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, the_entry, the_permset) == -1) {
+ if (sys_acl_set_permset(the_entry, the_permset) == -1) {
DEBUG(0,("create_posix_acl_from_wire: Failed to add permset on entry %u. (%s)\n",
i, strerror(errno) ));
goto fail;
if (tag_type == SMB_ACL_USER) {
uint32 uidval = IVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
uid_t uid = (uid_t)uidval;
- if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&uid) == -1) {
+ if (sys_acl_set_qualifier(the_entry,(void *)&uid) == -1) {
DEBUG(0,("create_posix_acl_from_wire: Failed to set uid %u on entry %u. (%s)\n",
(unsigned int)uid, i, strerror(errno) ));
goto fail;
if (tag_type == SMB_ACL_GROUP) {
uint32 gidval = IVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
gid_t gid = (uid_t)gidval;
- if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&gid) == -1) {
+ if (sys_acl_set_qualifier(the_entry,(void *)&gid) == -1) {
DEBUG(0,("create_posix_acl_from_wire: Failed to set gid %u on entry %u. (%s)\n",
(unsigned int)gid, i, strerror(errno) ));
goto fail;
fail:
if (the_acl != NULL) {
- SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
+ TALLOC_FREE(the_acl);
}
return NULL;
}
return True;
}
- if ((def_acl = create_posix_acl_from_wire(conn, num_def_acls, pdata)) == NULL) {
+ if ((def_acl = create_posix_acl_from_wire(conn, num_def_acls,
+ pdata,
+ talloc_tos())) == NULL) {
return False;
}
if (SMB_VFS_SYS_ACL_SET_FILE(conn, fname, SMB_ACL_TYPE_DEFAULT, def_acl) == -1) {
DEBUG(5,("set_unix_posix_default_acl: acl_set_file failed on directory %s (%s)\n",
fname, strerror(errno) ));
- SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
+ TALLOC_FREE(def_acl);
return False;
}
DEBUG(10,("set_unix_posix_default_acl: set default acl for file %s\n", fname ));
- SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
+ TALLOC_FREE(def_acl);
return True;
}
SMB_ACL_ENTRY_T entry;
bool ret = False;
/* Create a new ACL with only 3 entries, u/g/w. */
- SMB_ACL_T new_file_acl = SMB_VFS_SYS_ACL_INIT(conn, 3);
+ SMB_ACL_T new_file_acl = sys_acl_init(talloc_tos());
SMB_ACL_ENTRY_T user_ent = NULL;
SMB_ACL_ENTRY_T group_ent = NULL;
SMB_ACL_ENTRY_T other_ent = NULL;
}
/* Now create the u/g/w entries. */
- if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &new_file_acl, &user_ent) == -1) {
+ if (sys_acl_create_entry(&new_file_acl, &user_ent) == -1) {
DEBUG(5,("remove_posix_acl: Failed to create user entry for file %s. (%s)\n",
fname, strerror(errno) ));
goto done;
}
- if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, user_ent, SMB_ACL_USER_OBJ) == -1) {
+ if (sys_acl_set_tag_type(user_ent, SMB_ACL_USER_OBJ) == -1) {
DEBUG(5,("remove_posix_acl: Failed to set user entry for file %s. (%s)\n",
fname, strerror(errno) ));
goto done;
}
- if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &new_file_acl, &group_ent) == -1) {
+ if (sys_acl_create_entry(&new_file_acl, &group_ent) == -1) {
DEBUG(5,("remove_posix_acl: Failed to create group entry for file %s. (%s)\n",
fname, strerror(errno) ));
goto done;
}
- if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, group_ent, SMB_ACL_GROUP_OBJ) == -1) {
+ if (sys_acl_set_tag_type(group_ent, SMB_ACL_GROUP_OBJ) == -1) {
DEBUG(5,("remove_posix_acl: Failed to set group entry for file %s. (%s)\n",
fname, strerror(errno) ));
goto done;
}
- if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &new_file_acl, &other_ent) == -1) {
+ if (sys_acl_create_entry(&new_file_acl, &other_ent) == -1) {
DEBUG(5,("remove_posix_acl: Failed to create other entry for file %s. (%s)\n",
fname, strerror(errno) ));
goto done;
}
- if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, other_ent, SMB_ACL_OTHER) == -1) {
+ if (sys_acl_set_tag_type(other_ent, SMB_ACL_OTHER) == -1) {
DEBUG(5,("remove_posix_acl: Failed to set other entry for file %s. (%s)\n",
fname, strerror(errno) ));
goto done;
/* Get the current file ACL. */
if (fsp && fsp->fh->fd != -1) {
- file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp);
+ file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, talloc_tos());
} else {
- file_acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, SMB_ACL_TYPE_ACCESS);
+ file_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname,
+ SMB_ACL_TYPE_ACCESS,
+ talloc_tos());
}
if (file_acl == NULL) {
goto done;
}
- while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, file_acl, entry_id, &entry) == 1) {
+ while ( sys_acl_get_entry(file_acl, entry_id, &entry) == 1) {
SMB_ACL_TAG_T tagtype;
SMB_ACL_PERMSET_T permset;
entry_id = SMB_ACL_NEXT_ENTRY;
- if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) {
+ if (sys_acl_get_tag_type(entry, &tagtype) == -1) {
DEBUG(5,("remove_posix_acl: failed to get tagtype from ACL on file %s (%s).\n",
fname, strerror(errno) ));
goto done;
}
- if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
+ if (sys_acl_get_permset(entry, &permset) == -1) {
DEBUG(5,("remove_posix_acl: failed to get permset from ACL on file %s (%s).\n",
fname, strerror(errno) ));
goto done;
}
if (tagtype == SMB_ACL_USER_OBJ) {
- if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, user_ent, permset) == -1) {
+ if (sys_acl_set_permset(user_ent, permset) == -1) {
DEBUG(5,("remove_posix_acl: failed to set permset from ACL on file %s (%s).\n",
fname, strerror(errno) ));
}
} else if (tagtype == SMB_ACL_GROUP_OBJ) {
- if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, group_ent, permset) == -1) {
+ if (sys_acl_set_permset(group_ent, permset) == -1) {
DEBUG(5,("remove_posix_acl: failed to set permset from ACL on file %s (%s).\n",
fname, strerror(errno) ));
}
} else if (tagtype == SMB_ACL_OTHER) {
- if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, other_ent, permset) == -1) {
+ if (sys_acl_set_permset(other_ent, permset) == -1) {
DEBUG(5,("remove_posix_acl: failed to set permset from ACL on file %s (%s).\n",
fname, strerror(errno) ));
}
done:
if (file_acl) {
- SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
+ TALLOC_FREE(file_acl);
}
if (new_file_acl) {
- SMB_VFS_SYS_ACL_FREE_ACL(conn, new_file_acl);
+ TALLOC_FREE(new_file_acl);
}
return ret;
}
return remove_posix_acl(conn, fsp, fname);
}
- if ((file_acl = create_posix_acl_from_wire(conn, num_acls, pdata)) == NULL) {
+ if ((file_acl = create_posix_acl_from_wire(conn, num_acls,
+ pdata,
+ talloc_tos())) == NULL) {
return False;
}
if (SMB_VFS_SYS_ACL_SET_FD(fsp, file_acl) == -1) {
DEBUG(5,("set_unix_posix_acl: acl_set_file failed on %s (%s)\n",
fname, strerror(errno) ));
- SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
+ TALLOC_FREE(file_acl);
return False;
}
} else {
if (SMB_VFS_SYS_ACL_SET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS, file_acl) == -1) {
DEBUG(5,("set_unix_posix_acl: acl_set_file failed on %s (%s)\n",
fname, strerror(errno) ));
- SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
+ TALLOC_FREE(file_acl);
return False;
}
}
DEBUG(10,("set_unix_posix_acl: set acl for file %s\n", fname ));
- SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
+ TALLOC_FREE(file_acl);
return True;
}
check. Caller is responsible for freeing the returned security
descriptor via TALLOC_FREE(). This is designed for dealing with
user space access checks in smbd outside of the VFS. For example,
- checking access rights in OpenEventlog().
+ checking access rights in OpenEventlog() or from python.
- Assume we are dealing with files (for now)
********************************************************************/
-struct security_descriptor *get_nt_acl_no_snum( TALLOC_CTX *ctx, const char *fname)
+NTSTATUS get_nt_acl_no_snum(TALLOC_CTX *ctx, const char *fname,
+ uint32 security_info_wanted,
+ struct security_descriptor **sd)
{
- struct security_descriptor *psd, *ret_sd;
+ TALLOC_CTX *frame = talloc_stackframe();
connection_struct *conn;
- files_struct finfo;
- struct fd_handle fh;
- NTSTATUS status;
+ NTSTATUS status = NT_STATUS_OK;
+
+ if (!posix_locking_init(false)) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
- conn = TALLOC_ZERO_P(ctx, connection_struct);
+ conn = talloc_zero(frame, connection_struct);
if (conn == NULL) {
+ TALLOC_FREE(frame);
DEBUG(0, ("talloc failed\n"));
- return NULL;
+ return NT_STATUS_NO_MEMORY;
}
- if (!(conn->params = TALLOC_P(conn, struct share_params))) {
- DEBUG(0,("get_nt_acl_no_snum: talloc() failed!\n"));
- TALLOC_FREE(conn);
- return NULL;
+ if (!(conn->params = talloc(conn, struct share_params))) {
+ DEBUG(0, ("talloc failed\n"));
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
}
conn->params->service = -1;
set_conn_connectpath(conn, "/");
if (!smbd_vfs_init(conn)) {
- DEBUG(0,("get_nt_acl_no_snum: Unable to create a fake connection struct!\n"));
- conn_free(conn);
- return NULL;
- }
+ DEBUG(0,("smbd_vfs_init() failed!\n"));
+ TALLOC_FREE(frame);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ status = SMB_VFS_GET_NT_ACL(conn, fname, security_info_wanted, ctx, sd);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("set_nt_acl_no_snum: fset_nt_acl returned %s.\n",
+ nt_errstr(status)));
+ }
- ZERO_STRUCT( finfo );
- ZERO_STRUCT( fh );
+ conn_free(conn);
+ TALLOC_FREE(frame);
+
+ return status;
+}
+
+/* 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;
+ }
- finfo.fnum = -1;
- finfo.conn = conn;
- finfo.fh = &fh;
- finfo.fh->fd = -1;
+ *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;
+}
- status = create_synthetic_smb_fname(talloc_tos(), fname, NULL, NULL,
- &finfo.fsp_name);
+int posix_sys_acl_blob_get_file(vfs_handle_struct *handle,
+ const char *path_p,
+ TALLOC_CTX *mem_ctx,
+ char **blob_description,
+ DATA_BLOB *blob)
+{
+ int ret;
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct smb_acl_wrapper acl_wrapper = {};
+ struct smb_filename *smb_fname = NULL;
+ NTSTATUS status = create_synthetic_smb_fname_split(frame, path_p,
+ NULL,
+ &smb_fname);
if (!NT_STATUS_IS_OK(status)) {
- conn_free(conn);
- return NULL;
+ errno = map_errno_from_nt_status(status);
+ TALLOC_FREE(frame);
+ return -1;
}
- 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 NULL;
+ acl_wrapper.access_acl
+ = smb_vfs_call_sys_acl_get_file(handle,
+ path_p,
+ SMB_ACL_TYPE_ACCESS,
+ frame);
+
+ ret = smb_vfs_call_stat(handle, smb_fname);
+ if (ret == -1) {
+ TALLOC_FREE(frame);
+ return -1;
}
- ret_sd = dup_sec_desc( ctx, psd );
+ if (S_ISDIR(smb_fname->st.st_ex_mode)) {
+ acl_wrapper.default_acl
+ = smb_vfs_call_sys_acl_get_file(handle,
+ path_p,
+ SMB_ACL_TYPE_DEFAULT,
+ frame);
+ }
- TALLOC_FREE(finfo.fsp_name);
- conn_free(conn);
+ acl_wrapper.owner = smb_fname->st.st_ex_uid;
+ acl_wrapper.group = smb_fname->st.st_ex_gid;
+ acl_wrapper.mode = smb_fname->st.st_ex_mode;
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_struct_blob(blob, mem_ctx,
+ &acl_wrapper,
+ (ndr_push_flags_fn_t)ndr_push_smb_acl_wrapper))) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ *blob_description = talloc_strdup(mem_ctx, "posix_acl");
+ if (!*blob_description) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ TALLOC_FREE(frame);
+ return 0;
+}
+
+int posix_sys_acl_blob_get_fd(vfs_handle_struct *handle,
+ files_struct *fsp,
+ TALLOC_CTX *mem_ctx,
+ char **blob_description,
+ DATA_BLOB *blob)
+{
+ SMB_STRUCT_STAT sbuf;
+ TALLOC_CTX *frame;
+ struct smb_acl_wrapper acl_wrapper;
+ int ret;
+
+ /* This ensures that we also consider the default ACL */
+ if (fsp->is_directory || fsp->fh->fd == -1) {
+ return posix_sys_acl_blob_get_file(handle, fsp->fsp_name->base_name,
+ mem_ctx, blob_description, blob);
+ }
+ frame = talloc_stackframe();
+
+ acl_wrapper.default_acl = NULL;
+
+ acl_wrapper.access_acl = smb_vfs_call_sys_acl_get_file(handle, fsp->fsp_name->base_name,
+ SMB_ACL_TYPE_ACCESS, frame);
+
+ ret = smb_vfs_call_fstat(handle, fsp, &sbuf);
+ if (ret == -1) {
+ TALLOC_FREE(frame);
+ return -1;
+ }
- return ret_sd;
+ acl_wrapper.owner = sbuf.st_ex_uid;
+ acl_wrapper.group = sbuf.st_ex_gid;
+ acl_wrapper.mode = sbuf.st_ex_mode;
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_struct_blob(blob, mem_ctx,
+ &acl_wrapper,
+ (ndr_push_flags_fn_t)ndr_push_smb_acl_wrapper))) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ *blob_description = talloc_strdup(mem_ctx, "posix_acl");
+ if (!*blob_description) {
+ errno = EINVAL;
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ TALLOC_FREE(frame);
+ return 0;
}