mirror of
https://github.com/samba-team/samba.git
synced 2025-01-27 14:04:05 +03:00
First cut of new ACL mapping code from Andreas Gruenbacher <agruen@suse.de>.
This is not 100% the same as what SuSE shipped in their Samba, there is a crash bug fix, a race condition fix, and a few logic changes I'd like to discuss with Andreas. Added Andreas to (C) notices for posix_acls.c Jeremy.
This commit is contained in:
parent
6c7748b001
commit
a81d700ae9
@ -40,9 +40,9 @@ DOM_SID global_sid_NULL; /* NULL sid */
|
||||
DOM_SID global_sid_Authenticated_Users; /* All authenticated rids */
|
||||
DOM_SID global_sid_Network; /* Network rids */
|
||||
|
||||
static DOM_SID global_sid_Creator_Owner; /* Creator Owner */
|
||||
static DOM_SID global_sid_Creator_Group; /* Creator Group */
|
||||
static DOM_SID global_sid_Anonymous; /* Anonymous login */
|
||||
DOM_SID global_sid_Creator_Owner; /* Creator Owner */
|
||||
DOM_SID global_sid_Creator_Group; /* Creator Group */
|
||||
DOM_SID global_sid_Anonymous; /* Anonymous login */
|
||||
|
||||
DOM_SID global_sid_Builtin; /* Local well-known domain */
|
||||
DOM_SID global_sid_Builtin_Administrators; /* Builtin administrators */
|
||||
@ -166,6 +166,10 @@ void generate_wellknown_sids(void)
|
||||
initialised = True;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Create the SYSTEM token.
|
||||
***************************************************************************/
|
||||
|
||||
NT_USER_TOKEN *get_system_token(void)
|
||||
{
|
||||
generate_wellknown_sids(); /* The token is initialised here */
|
||||
@ -239,7 +243,10 @@ char *sid_to_string(fstring sidstr_out, const DOM_SID *sid)
|
||||
return sidstr_out;
|
||||
}
|
||||
|
||||
/* BIG NOTE: this function only does SIDS where the identauth is not >= 2^32 */
|
||||
/*
|
||||
* BIG NOTE: this function only does SIDS where the identauth is not >= 2^32
|
||||
* in a range of 2^48.
|
||||
*/
|
||||
ia = (sid->id_auth[5]) +
|
||||
(sid->id_auth[4] << 8 ) +
|
||||
(sid->id_auth[3] << 16) +
|
||||
@ -272,63 +279,63 @@ const char *sid_string_static(const DOM_SID *sid)
|
||||
|
||||
BOOL string_to_sid(DOM_SID *sidout, const char *sidstr)
|
||||
{
|
||||
pstring tok;
|
||||
char *p, *q;
|
||||
/* BIG NOTE: this function only does SIDS where the identauth is not >= 2^32 */
|
||||
uint32 ia;
|
||||
pstring tok;
|
||||
char *p, *q;
|
||||
/* BIG NOTE: this function only does SIDS where the identauth is not >= 2^32 */
|
||||
uint32 ia;
|
||||
|
||||
if (StrnCaseCmp( sidstr, "S-", 2)) {
|
||||
DEBUG(0,("string_to_sid: Sid %s does not start with 'S-'.\n", sidstr));
|
||||
return False;
|
||||
}
|
||||
if (StrnCaseCmp( sidstr, "S-", 2)) {
|
||||
DEBUG(0,("string_to_sid: Sid %s does not start with 'S-'.\n", sidstr));
|
||||
return False;
|
||||
}
|
||||
|
||||
memset((char *)sidout, '\0', sizeof(DOM_SID));
|
||||
memset((char *)sidout, '\0', sizeof(DOM_SID));
|
||||
|
||||
q = p = strdup(sidstr + 2);
|
||||
if (p == NULL) {
|
||||
DEBUG(0, ("string_to_sid: out of memory!\n"));
|
||||
return False;
|
||||
}
|
||||
q = p = strdup(sidstr + 2);
|
||||
if (p == NULL) {
|
||||
DEBUG(0, ("string_to_sid: out of memory!\n"));
|
||||
return False;
|
||||
}
|
||||
|
||||
if (!next_token(&p, tok, "-", sizeof(tok))) {
|
||||
DEBUG(0,("string_to_sid: Sid %s is not in a valid format.\n", sidstr));
|
||||
SAFE_FREE(q);
|
||||
return False;
|
||||
}
|
||||
if (!next_token(&p, tok, "-", sizeof(tok))) {
|
||||
DEBUG(0,("string_to_sid: Sid %s is not in a valid format.\n", sidstr));
|
||||
SAFE_FREE(q);
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Get the revision number. */
|
||||
sidout->sid_rev_num = (uint8)strtoul(tok, NULL, 10);
|
||||
/* Get the revision number. */
|
||||
sidout->sid_rev_num = (uint8)strtoul(tok, NULL, 10);
|
||||
|
||||
if (!next_token(&p, tok, "-", sizeof(tok))) {
|
||||
DEBUG(0,("string_to_sid: Sid %s is not in a valid format.\n", sidstr));
|
||||
SAFE_FREE(q);
|
||||
return False;
|
||||
}
|
||||
if (!next_token(&p, tok, "-", sizeof(tok))) {
|
||||
DEBUG(0,("string_to_sid: Sid %s is not in a valid format.\n", sidstr));
|
||||
SAFE_FREE(q);
|
||||
return False;
|
||||
}
|
||||
|
||||
/* identauth in decimal should be < 2^32 */
|
||||
ia = (uint32)strtoul(tok, NULL, 10);
|
||||
/* identauth in decimal should be < 2^32 */
|
||||
ia = (uint32)strtoul(tok, NULL, 10);
|
||||
|
||||
/* NOTE - the ia value is in big-endian format. */
|
||||
sidout->id_auth[0] = 0;
|
||||
sidout->id_auth[1] = 0;
|
||||
sidout->id_auth[2] = (ia & 0xff000000) >> 24;
|
||||
sidout->id_auth[3] = (ia & 0x00ff0000) >> 16;
|
||||
sidout->id_auth[4] = (ia & 0x0000ff00) >> 8;
|
||||
sidout->id_auth[5] = (ia & 0x000000ff);
|
||||
/* NOTE - the ia value is in big-endian format. */
|
||||
sidout->id_auth[0] = 0;
|
||||
sidout->id_auth[1] = 0;
|
||||
sidout->id_auth[2] = (ia & 0xff000000) >> 24;
|
||||
sidout->id_auth[3] = (ia & 0x00ff0000) >> 16;
|
||||
sidout->id_auth[4] = (ia & 0x0000ff00) >> 8;
|
||||
sidout->id_auth[5] = (ia & 0x000000ff);
|
||||
|
||||
sidout->num_auths = 0;
|
||||
sidout->num_auths = 0;
|
||||
|
||||
while(next_token(&p, tok, "-", sizeof(tok)) &&
|
||||
sidout->num_auths < MAXSUBAUTHS) {
|
||||
/*
|
||||
* NOTE - the subauths are in native machine-endian format. They
|
||||
* are converted to little-endian when linearized onto the wire.
|
||||
*/
|
||||
sid_append_rid(sidout, (uint32)strtoul(tok, NULL, 10));
|
||||
}
|
||||
while(next_token(&p, tok, "-", sizeof(tok)) &&
|
||||
sidout->num_auths < MAXSUBAUTHS) {
|
||||
/*
|
||||
* NOTE - the subauths are in native machine-endian format. They
|
||||
* are converted to little-endian when linearized onto the wire.
|
||||
*/
|
||||
sid_append_rid(sidout, (uint32)strtoul(tok, NULL, 10));
|
||||
}
|
||||
|
||||
SAFE_FREE(q);
|
||||
return True;
|
||||
SAFE_FREE(q);
|
||||
return True;
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
@ -412,10 +419,10 @@ void sid_copy(DOM_SID *dst, const DOM_SID *src)
|
||||
dst->sub_auths[i] = src->sub_auths[i];
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************
|
||||
Write a sid out into on-the-wire format.
|
||||
*****************************************************************/
|
||||
|
||||
BOOL sid_linearize(char *outbuf, size_t len, const DOM_SID *sid)
|
||||
{
|
||||
size_t i;
|
||||
@ -433,36 +440,41 @@ BOOL sid_linearize(char *outbuf, size_t len, const DOM_SID *sid)
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
parse a on-the-wire SID to a DOM_SID
|
||||
Parse a on-the-wire SID to a DOM_SID.
|
||||
*****************************************************************/
|
||||
|
||||
BOOL sid_parse(const char *inbuf, size_t len, DOM_SID *sid)
|
||||
{
|
||||
int i;
|
||||
if (len < 8) return False;
|
||||
if (len < 8)
|
||||
return False;
|
||||
|
||||
ZERO_STRUCTP(sid);
|
||||
|
||||
sid->sid_rev_num = CVAL(inbuf, 0);
|
||||
sid->num_auths = CVAL(inbuf, 1);
|
||||
memcpy(sid->id_auth, inbuf+2, 6);
|
||||
if (len < 8 + sid->num_auths*4) return False;
|
||||
for (i=0;i<sid->num_auths;i++) {
|
||||
if (len < 8 + sid->num_auths*4)
|
||||
return False;
|
||||
for (i=0;i<sid->num_auths;i++)
|
||||
sid->sub_auths[i] = IVAL(inbuf, 8+i*4);
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************
|
||||
Compare the auth portion of two sids.
|
||||
*****************************************************************/
|
||||
|
||||
static int sid_compare_auth(const DOM_SID *sid1, const DOM_SID *sid2)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (sid1 == sid2) return 0;
|
||||
if (!sid1) return -1;
|
||||
if (!sid2) return 1;
|
||||
if (sid1 == sid2)
|
||||
return 0;
|
||||
if (!sid1)
|
||||
return -1;
|
||||
if (!sid2)
|
||||
return 1;
|
||||
|
||||
if (sid1->sid_rev_num != sid2->sid_rev_num)
|
||||
return sid1->sid_rev_num - sid2->sid_rev_num;
|
||||
@ -477,15 +489,19 @@ static int sid_compare_auth(const DOM_SID *sid1, const DOM_SID *sid2)
|
||||
/*****************************************************************
|
||||
Compare two sids.
|
||||
*****************************************************************/
|
||||
|
||||
int sid_compare(const DOM_SID *sid1, const DOM_SID *sid2)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (sid1 == sid2) return 0;
|
||||
if (!sid1) return -1;
|
||||
if (!sid2) return 1;
|
||||
if (sid1 == sid2)
|
||||
return 0;
|
||||
if (!sid1)
|
||||
return -1;
|
||||
if (!sid2)
|
||||
return 1;
|
||||
|
||||
/* compare most likely different rids, first: i.e start at end */
|
||||
/* Compare most likely different rids, first: i.e start at end */
|
||||
if (sid1->num_auths != sid2->num_auths)
|
||||
return sid1->num_auths - sid2->num_auths;
|
||||
|
||||
@ -497,9 +513,10 @@ int sid_compare(const DOM_SID *sid1, const DOM_SID *sid2)
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
see if 2 SIDs are in the same domain
|
||||
this just compares the leading sub-auths
|
||||
See if 2 SIDs are in the same domain
|
||||
this just compares the leading sub-auths
|
||||
*****************************************************************/
|
||||
|
||||
int sid_compare_domain(const DOM_SID *sid1, const DOM_SID *sid2)
|
||||
{
|
||||
int n, i;
|
||||
@ -516,25 +533,25 @@ int sid_compare_domain(const DOM_SID *sid1, const DOM_SID *sid2)
|
||||
/*****************************************************************
|
||||
Compare two sids.
|
||||
*****************************************************************/
|
||||
|
||||
BOOL sid_equal(const DOM_SID *sid1, const DOM_SID *sid2)
|
||||
{
|
||||
return sid_compare(sid1, sid2) == 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************
|
||||
Check if the SID is the builtin SID (S-1-5-32).
|
||||
*****************************************************************/
|
||||
|
||||
BOOL sid_check_is_builtin(const DOM_SID *sid)
|
||||
{
|
||||
return sid_equal(sid, &global_sid_Builtin);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************
|
||||
Check if the SID is our domain SID (S-1-5-21-x-y-z).
|
||||
Check if the SID is one of the builtin SIDs (S-1-5-32-a).
|
||||
*****************************************************************/
|
||||
|
||||
BOOL sid_check_is_in_builtin(const DOM_SID *sid)
|
||||
{
|
||||
DOM_SID dom_sid;
|
||||
@ -546,7 +563,6 @@ BOOL sid_check_is_in_builtin(const DOM_SID *sid)
|
||||
return sid_equal(&dom_sid, &global_sid_Builtin);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************
|
||||
Calculates size of a sid.
|
||||
*****************************************************************/
|
||||
@ -574,25 +590,24 @@ BOOL non_mappable_sid(DOM_SID *sid)
|
||||
if (sid_equal(&dom, &global_sid_Builtin))
|
||||
return True;
|
||||
|
||||
if (sid_equal(&dom, &global_sid_Creator_Owner_Domain))
|
||||
return True;
|
||||
|
||||
if (sid_equal(&dom, &global_sid_NT_Authority))
|
||||
return True;
|
||||
|
||||
return False;
|
||||
}
|
||||
|
||||
/*
|
||||
return the binary string representation of a DOM_SID
|
||||
caller must free
|
||||
*/
|
||||
/*****************************************************************
|
||||
Return the binary string representation of a DOM_SID.
|
||||
Caller must free.
|
||||
*****************************************************************/
|
||||
|
||||
char *sid_binstring(const DOM_SID *sid)
|
||||
{
|
||||
char *buf, *s;
|
||||
int len = sid_size(sid);
|
||||
buf = malloc(len);
|
||||
if (!buf) return NULL;
|
||||
if (!buf)
|
||||
return NULL;
|
||||
sid_linearize(buf, len, sid);
|
||||
s = binary_string(buf, len);
|
||||
free(buf);
|
||||
@ -600,9 +615,10 @@ char *sid_binstring(const DOM_SID *sid)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
print a GUID structure for debugging
|
||||
*/
|
||||
/*****************************************************************
|
||||
Print a GUID structure for debugging.
|
||||
*****************************************************************/
|
||||
|
||||
void print_guid(GUID *guid)
|
||||
{
|
||||
int i;
|
||||
|
@ -216,6 +216,7 @@ typedef struct
|
||||
char *szLdapSuffix;
|
||||
char *szLdapFilter;
|
||||
char *szLdapAdminDn;
|
||||
char *szAclCompat;
|
||||
int ldap_passwd_sync;
|
||||
BOOL bMsAddPrinterWizard;
|
||||
BOOL bDNSproxy;
|
||||
@ -536,6 +537,8 @@ static BOOL handle_ldap_machine_suffix ( char *pszParmValue, char **ptr );
|
||||
static BOOL handle_ldap_user_suffix ( char *pszParmValue, char **ptr );
|
||||
static BOOL handle_ldap_suffix ( char *pszParmValue, char **ptr );
|
||||
|
||||
static BOOL handle_acl_compatibility(char *pszParmValue, char **ptr);
|
||||
|
||||
static void set_server_role(void);
|
||||
static void set_default_server_announce_type(void);
|
||||
|
||||
@ -820,8 +823,9 @@ static struct parm_struct parm_table[] = {
|
||||
{"write raw", P_BOOL, P_GLOBAL, &Globals.bWriteRaw, NULL, NULL, FLAG_DEVELOPER},
|
||||
{"disable netbios", P_BOOL, P_GLOBAL, &Globals.bDisableNetbios, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
|
||||
|
||||
{"acl compatibility", P_STRING, P_GLOBAL, &Globals.szAclCompat, handle_acl_compatibility, NULL, FLAG_SHARE | FLAG_GLOBAL | FLAG_ADVANCED},
|
||||
{"nt acl support", P_BOOL, P_LOCAL, &sDefault.bNTAclSupport, NULL, NULL, FLAG_GLOBAL | FLAG_SHARE | FLAG_ADVANCED | FLAG_WIZARD},
|
||||
{"nt pipe support", P_BOOL, P_GLOBAL, &Globals.bNTPipeSupport, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
|
||||
{"nt acl support", P_BOOL, P_LOCAL, &sDefault.bNTAclSupport, NULL, NULL, FLAG_GLOBAL | FLAG_SHARE | FLAG_ADVANCED | FLAG_WIZARD},
|
||||
{"nt status support", P_BOOL, P_GLOBAL, &Globals.bNTStatusSupport, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
|
||||
{"profile acls", P_BOOL, P_LOCAL, &sDefault.bProfileAcls, NULL, NULL, FLAG_GLOBAL | FLAG_SHARE | FLAG_ADVANCED | FLAG_WIZARD},
|
||||
|
||||
@ -1407,6 +1411,7 @@ static void init_globals(void)
|
||||
string_set(&Globals.szTemplateShell, "/bin/false");
|
||||
string_set(&Globals.szTemplateHomedir, "/home/%D/%U");
|
||||
string_set(&Globals.szWinbindSeparator, "\\");
|
||||
string_set(&Globals.szAclCompat, "");
|
||||
|
||||
Globals.winbind_cache_time = 15;
|
||||
Globals.bWinbindEnumUsers = True;
|
||||
@ -1579,6 +1584,7 @@ FN_GLOBAL_STRING(lp_wins_partners, &Globals.szWINSPartners)
|
||||
FN_GLOBAL_STRING(lp_template_homedir, &Globals.szTemplateHomedir)
|
||||
FN_GLOBAL_STRING(lp_template_shell, &Globals.szTemplateShell)
|
||||
FN_GLOBAL_STRING(lp_winbind_separator, &Globals.szWinbindSeparator)
|
||||
FN_GLOBAL_STRING(lp_acl_compatibility, &Globals.szAclCompat)
|
||||
FN_GLOBAL_BOOL(lp_winbind_enum_users, &Globals.bWinbindEnumUsers)
|
||||
FN_GLOBAL_BOOL(lp_winbind_enum_groups, &Globals.bWinbindEnumGroups)
|
||||
FN_GLOBAL_BOOL(lp_winbind_use_default_domain, &Globals.bWinbindUseDefaultDomain)
|
||||
@ -2771,6 +2777,19 @@ static BOOL handle_ldap_suffix( char *pszParmValue, char **ptr)
|
||||
return True;
|
||||
}
|
||||
|
||||
static BOOL handle_acl_compatibility(char *pszParmValue, char **ptr)
|
||||
{
|
||||
if (strequal(pszParmValue, "auto"))
|
||||
string_set(ptr, "");
|
||||
else if (strequal(pszParmValue, "winnt"))
|
||||
string_set(ptr, "winnt");
|
||||
else if (strequal(pszParmValue, "win2k"))
|
||||
string_set(ptr, "win2k");
|
||||
else
|
||||
return False;
|
||||
|
||||
return True;
|
||||
}
|
||||
/***************************************************************************
|
||||
initialise a copymap
|
||||
***************************************************************************/
|
||||
|
@ -884,7 +884,7 @@ static NTSTATUS get_group_alias_entries(TALLOC_CTX *ctx, DOMAIN_GRP **d_grp, DOM
|
||||
uint32 num_entries = 0;
|
||||
int i;
|
||||
GROUP_MAP smap;
|
||||
GROUP_MAP *map;
|
||||
GROUP_MAP *map = NULL;
|
||||
|
||||
sid_to_string(sid_str, sid);
|
||||
DEBUG(5, ("get_group_alias_entries: enumerating aliases on SID: %s\n", sid_str));
|
||||
|
@ -165,9 +165,13 @@ static BOOL open_file(files_struct *fsp,connection_struct *conn,
|
||||
local_flags |= O_NONBLOCK;
|
||||
#endif
|
||||
|
||||
/* actually do the open */
|
||||
/* Actually do the open */
|
||||
fsp->fd = fd_open(conn, fname, local_flags, mode);
|
||||
|
||||
/* Inherit the ACL if the file was created. */
|
||||
if ((local_flags & O_CREAT) && !VALID_STAT(*psbuf))
|
||||
inherit_access_acl(conn, fname, mode);
|
||||
|
||||
if (fsp->fd == -1) {
|
||||
DEBUG(3,("Error opening file %s (%s) (local_flags=%d) (flags=%d)\n",
|
||||
fname,strerror(errno),local_flags,flags));
|
||||
|
@ -1,7 +1,8 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
SMB NT Security Descriptor / Unix permission conversion.
|
||||
Copyright (C) Jeremy Allison 1994-2000
|
||||
Copyright (C) Jeremy Allison 1994-2000.
|
||||
Copyright (C) Andreas Gruenbacher 2002.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -329,6 +330,24 @@ static void merge_aces( canon_ace **pp_list_head )
|
||||
*pp_list_head = list_head;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Check if we need to return NT4.x compatible ACL entries.
|
||||
****************************************************************************/
|
||||
|
||||
static BOOL nt4_compatible_acls(void)
|
||||
{
|
||||
const char *compat = lp_acl_compatibility();
|
||||
|
||||
if (*compat == '\0') {
|
||||
enum remote_arch_types ra_type = get_remote_arch();
|
||||
|
||||
/* Automatically adapt to client */
|
||||
return (ra_type <= RA_WINNT);
|
||||
} else
|
||||
return (strequal(compat, "winnt"));
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
Map canon_ace perms to permission bits NT.
|
||||
The attr element is not used here - we only process deny entries on set,
|
||||
@ -345,7 +364,19 @@ static SEC_ACCESS map_canon_ace_perms(int *pacl_type, DOM_SID *powner_sid, canon
|
||||
if ((ace->perms & ALL_ACE_PERMS) == ALL_ACE_PERMS) {
|
||||
nt_mask = UNIX_ACCESS_RWX;
|
||||
} else if ((ace->perms & ALL_ACE_PERMS) == (mode_t)0) {
|
||||
nt_mask = UNIX_ACCESS_NONE;
|
||||
/*
|
||||
* Windows NT refuses to display ACEs with no permissions in them (but
|
||||
* they are perfectly legal with Windows 2000). If the ACE has empty
|
||||
* permissions we cannot use 0, so we use the otherwise unused
|
||||
* WRITE_OWNER permission, which we ignore when we set an ACL.
|
||||
* We abstract this into a #define of UNIX_ACCESS_NONE to allow this
|
||||
* to be changed in the future.
|
||||
*/
|
||||
|
||||
if (nt4_compatible_acls())
|
||||
nt_mask = UNIX_ACCESS_NONE;
|
||||
else
|
||||
nt_mask = 0;
|
||||
} else {
|
||||
nt_mask |= ((ace->perms & S_IRUSR) ? UNIX_ACCESS_R : 0 );
|
||||
nt_mask |= ((ace->perms & S_IWUSR) ? UNIX_ACCESS_W : 0 );
|
||||
@ -621,7 +652,7 @@ static BOOL ensure_canon_entry_valid(canon_ace **pp_ace,
|
||||
else if (got_grp && uid_entry_in_group(pace, pace_group))
|
||||
pace->perms = pace_group->perms;
|
||||
else
|
||||
pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRUSR, S_IWUSR, S_IXUSR);
|
||||
pace->perms = 0;
|
||||
apply_default_perms(fsp, pace, S_IRUSR);
|
||||
} else {
|
||||
pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRUSR, S_IWUSR, S_IXUSR);
|
||||
@ -668,7 +699,10 @@ static BOOL ensure_canon_entry_valid(canon_ace **pp_ace,
|
||||
pace->unix_ug.world = -1;
|
||||
pace->trustee = global_sid_World;
|
||||
pace->attr = ALLOW_ACE;
|
||||
pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IROTH, S_IWOTH, S_IXOTH);
|
||||
if (setting_acl)
|
||||
pace->perms = 0;
|
||||
else
|
||||
pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IROTH, S_IWOTH, S_IXOTH);
|
||||
apply_default_perms(fsp, pace, S_IROTH);
|
||||
|
||||
DLIST_ADD(*pp_ace, pace);
|
||||
@ -677,6 +711,51 @@ static BOOL ensure_canon_entry_valid(canon_ace **pp_ace,
|
||||
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.
|
||||
****************************************************************************/
|
||||
|
||||
static void check_owning_objs(canon_ace *ace, DOM_SID *pfile_owner_sid, DOM_SID *pfile_grp_sid)
|
||||
{
|
||||
BOOL got_user_obj, got_group_obj;
|
||||
canon_ace *current_ace;
|
||||
int i, entries;
|
||||
|
||||
entries = count_canon_ace_list(ace);
|
||||
got_user_obj = False;
|
||||
got_group_obj = False;
|
||||
|
||||
for (i=0, current_ace = ace; i < entries; i++, current_ace = current_ace->next) {
|
||||
if (current_ace->type == SMB_ACL_USER_OBJ)
|
||||
got_user_obj = True;
|
||||
else if (current_ace->type == SMB_ACL_GROUP_OBJ)
|
||||
got_group_obj = True;
|
||||
}
|
||||
if (got_user_obj && got_group_obj) {
|
||||
DEBUG(10,("check_owning_objs: ACL had owning user/group entries.\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
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)) {
|
||||
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)) {
|
||||
current_ace->type = SMB_ACL_GROUP_OBJ;
|
||||
got_group_obj = True;
|
||||
}
|
||||
}
|
||||
if (!got_user_obj)
|
||||
DEBUG(10,("check_owning_objs: ACL is missing an owner entry.\n"));
|
||||
if (!got_group_obj)
|
||||
DEBUG(10,("check_owning_objs: ACL is missing an owning group entry.\n"));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Unpack a SEC_DESC into two canonical ace lists.
|
||||
****************************************************************************/
|
||||
@ -687,6 +766,8 @@ static BOOL create_canon_ace_lists(files_struct *fsp,
|
||||
canon_ace **ppfile_ace, canon_ace **ppdir_ace,
|
||||
SEC_ACL *dacl)
|
||||
{
|
||||
extern DOM_SID global_sid_Creator_Owner;
|
||||
extern DOM_SID global_sid_Creator_Group;
|
||||
extern DOM_SID global_sid_World;
|
||||
extern struct generic_mapping file_generic_mapping;
|
||||
BOOL all_aces_are_inherit_only = (fsp->is_directory ? True : False);
|
||||
@ -713,23 +794,25 @@ static BOOL create_canon_ace_lists(files_struct *fsp,
|
||||
return False;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
/*
|
||||
* Convert GENERIC bits to specific bits.
|
||||
*/
|
||||
|
||||
se_map_generic(&psa->info.mask, &file_generic_mapping);
|
||||
se_map_generic(&psa->info.mask, &file_generic_mapping);
|
||||
|
||||
psa->info.mask &= (UNIX_ACCESS_NONE|FILE_ALL_ACCESS);
|
||||
psa->info.mask &= (UNIX_ACCESS_NONE|FILE_ALL_ACCESS);
|
||||
|
||||
if(psa->info.mask != UNIX_ACCESS_NONE)
|
||||
psa->info.mask &= ~UNIX_ACCESS_NONE;
|
||||
if(psa->info.mask != UNIX_ACCESS_NONE)
|
||||
psa->info.mask &= ~UNIX_ACCESS_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -804,15 +887,45 @@ static BOOL create_canon_ace_lists(files_struct *fsp,
|
||||
/*
|
||||
* Try and work out if the SID is a user or group
|
||||
* as we need to flag these differently for POSIX.
|
||||
* Note what kind of a POSIX ACL this should map to.
|
||||
*/
|
||||
|
||||
if( 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)) {
|
||||
current_ace->owner_type = UID_ACE;
|
||||
current_ace->unix_ug.world = -1;
|
||||
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.
|
||||
*/
|
||||
|
||||
if (nt4_compatible_acls())
|
||||
psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
|
||||
} else if (sid_equal(¤t_ace->trustee, &global_sid_Creator_Group)) {
|
||||
current_ace->owner_type = GID_ACE;
|
||||
current_ace->unix_ug.world = -1;
|
||||
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.
|
||||
*/
|
||||
if (nt4_compatible_acls())
|
||||
psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
|
||||
|
||||
} else if (sid_to_uid( ¤t_ace->trustee, ¤t_ace->unix_ug.uid, &sid_type)) {
|
||||
current_ace->owner_type = UID_ACE;
|
||||
current_ace->type = SMB_ACL_USER;
|
||||
} else if (sid_to_gid( ¤t_ace->trustee, ¤t_ace->unix_ug.gid, &sid_type)) {
|
||||
current_ace->owner_type = GID_ACE;
|
||||
current_ace->type = SMB_ACL_GROUP;
|
||||
} else {
|
||||
fstring str;
|
||||
|
||||
@ -832,31 +945,6 @@ static BOOL create_canon_ace_lists(files_struct *fsp,
|
||||
current_ace->perms |= map_nt_perms( psa->info, S_IRUSR);
|
||||
current_ace->attr = (psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED) ? ALLOW_ACE : DENY_ACE;
|
||||
|
||||
/*
|
||||
* Now note what kind of a POSIX ACL this should map to.
|
||||
*/
|
||||
|
||||
if(sid_equal(¤t_ace->trustee, pfile_owner_sid)) {
|
||||
|
||||
current_ace->type = SMB_ACL_USER_OBJ;
|
||||
|
||||
} else if( sid_equal(¤t_ace->trustee, pfile_grp_sid)) {
|
||||
|
||||
current_ace->type = SMB_ACL_GROUP_OBJ;
|
||||
|
||||
} else if( sid_equal(¤t_ace->trustee, &global_sid_World)) {
|
||||
|
||||
current_ace->type = SMB_ACL_OTHER;
|
||||
|
||||
} else {
|
||||
/*
|
||||
* Could be a SMB_ACL_USER or SMB_ACL_GROUP. Check by
|
||||
* looking at owner_type.
|
||||
*/
|
||||
|
||||
current_ace->type = (current_ace->owner_type == UID_ACE) ? SMB_ACL_USER : SMB_ACL_GROUP;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now add the created ace to either the file list, the directory
|
||||
* list, or both. We *MUST* preserve the order here (hence we use
|
||||
@ -970,6 +1058,15 @@ Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name ));
|
||||
free_canon_ace_list(dir_ace);
|
||||
file_ace = NULL;
|
||||
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_owning_objs(file_ace, pfile_owner_sid, pfile_grp_sid);
|
||||
check_owning_objs(dir_ace, pfile_owner_sid, pfile_grp_sid);
|
||||
}
|
||||
|
||||
*ppfile_ace = file_ace;
|
||||
@ -1375,7 +1472,7 @@ static BOOL unpack_canon_ace(files_struct *fsp,
|
||||
|
||||
pst->st_mode = create_default_mode(fsp, True);
|
||||
|
||||
if (!ensure_canon_entry_valid(&dir_ace, fsp, pfile_owner_sid, pfile_grp_sid, pst, True)) {
|
||||
if (dir_ace && !ensure_canon_entry_valid(&dir_ace, fsp, pfile_owner_sid, pfile_grp_sid, pst, True)) {
|
||||
free_canon_ace_list(file_ace);
|
||||
free_canon_ace_list(dir_ace);
|
||||
return False;
|
||||
@ -1398,14 +1495,13 @@ static BOOL unpack_canon_ace(files_struct *fsp,
|
||||
|
||||
Note that this doesn't exactly match the NT semantics for an ACL. As POSIX entries
|
||||
are not ordered, and match on the most specific entry rather than walking a list,
|
||||
then a simple POSIX permission of rw-r--r-- should really map to 6 entries,
|
||||
then a simple POSIX permission of rw-r--r-- should really map to 5 entries,
|
||||
|
||||
Entry 0: owner : deny all except read and write.
|
||||
Entry 1: group : deny all except read.
|
||||
Entry 2: Everyone : deny all except read.
|
||||
Entry 3: owner : allow read and write.
|
||||
Entry 4: group : allow read.
|
||||
Entry 5: Everyone : allow read.
|
||||
Entry 2: owner : allow read and write.
|
||||
Entry 3: group : allow read.
|
||||
Entry 4: Everyone : allow read.
|
||||
|
||||
But NT cannot display this in their ACL editor !
|
||||
********************************************************************************/
|
||||
@ -1455,7 +1551,7 @@ static void arrange_posix_perms( char *filename, canon_ace **pp_list_head)
|
||||
****************************************************************************/
|
||||
|
||||
static canon_ace *canonicalise_acl( files_struct *fsp, SMB_ACL_T posix_acl, SMB_STRUCT_STAT *psbuf,
|
||||
DOM_SID *powner, DOM_SID *pgroup)
|
||||
DOM_SID *powner, DOM_SID *pgroup, SMB_ACL_TYPE_T acl_type)
|
||||
{
|
||||
extern DOM_SID global_sid_World;
|
||||
connection_struct *conn = fsp->conn;
|
||||
@ -1489,7 +1585,7 @@ static canon_ace *canonicalise_acl( files_struct *fsp, SMB_ACL_T posix_acl, SMB_
|
||||
switch(tagtype) {
|
||||
case SMB_ACL_USER_OBJ:
|
||||
/* Get the SID from the owner. */
|
||||
uid_to_sid( &sid, psbuf->st_uid );
|
||||
sid_copy(&sid, powner);
|
||||
unix_ug.uid = psbuf->st_uid;
|
||||
owner_type = UID_ACE;
|
||||
break;
|
||||
@ -1500,6 +1596,15 @@ static canon_ace *canonicalise_acl( files_struct *fsp, SMB_ACL_T posix_acl, SMB_
|
||||
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 (acl_type == SMB_ACL_TYPE_ACCESS && *puid == psbuf->st_uid)
|
||||
continue;
|
||||
uid_to_sid( &sid, *puid);
|
||||
unix_ug.uid = *puid;
|
||||
owner_type = UID_ACE;
|
||||
@ -1508,7 +1613,7 @@ static canon_ace *canonicalise_acl( files_struct *fsp, SMB_ACL_T posix_acl, SMB_
|
||||
}
|
||||
case SMB_ACL_GROUP_OBJ:
|
||||
/* Get the SID from the owning group. */
|
||||
gid_to_sid( &sid, psbuf->st_gid );
|
||||
sid_copy(&sid, pgroup);
|
||||
unix_ug.gid = psbuf->st_gid;
|
||||
owner_type = GID_ACE;
|
||||
break;
|
||||
@ -1611,8 +1716,11 @@ static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL defau
|
||||
canon_ace *p_ace;
|
||||
int i;
|
||||
SMB_ACL_ENTRY_T mask_entry;
|
||||
BOOL got_mask_entry = False;
|
||||
SMB_ACL_PERMSET_T mask_permset;
|
||||
SMB_ACL_TYPE_T the_acl_type = (default_ace ? SMB_ACL_TYPE_DEFAULT : SMB_ACL_TYPE_ACCESS);
|
||||
BOOL needs_mask = False;
|
||||
mode_t mask_perms = 0;
|
||||
|
||||
if (the_acl == NULL) {
|
||||
|
||||
@ -1632,6 +1740,20 @@ static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL defau
|
||||
SMB_ACL_ENTRY_T the_entry;
|
||||
SMB_ACL_PERMSET_T the_permset;
|
||||
|
||||
/*
|
||||
* ACLs only "need" an ACL_MASK entry if there are any named user or
|
||||
* named group entries. But if there is an ACL_MASK entry, it applies
|
||||
* to ACL_USER, ACL_GROUP, and ACL_GROUP_OBJ entries. Set the mask
|
||||
* so that it doesn't deny (i.e., mask off) any permissions.
|
||||
*/
|
||||
|
||||
if (p_ace->type == SMB_ACL_USER || p_ace->type == SMB_ACL_GROUP) {
|
||||
needs_mask = True;
|
||||
mask_perms |= p_ace->perms;
|
||||
} else if (p_ace->type == SMB_ACL_GROUP_OBJ) {
|
||||
mask_perms |= p_ace->perms;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the entry for this ACE.
|
||||
*/
|
||||
@ -1642,6 +1764,11 @@ static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL defau
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (p_ace->type == SMB_ACL_MASK) {
|
||||
mask_entry = the_entry;
|
||||
got_mask_entry = True;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ok - we now know the ACL calls should be working, don't
|
||||
* allow fallback to chmod.
|
||||
@ -1706,33 +1833,31 @@ static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL defau
|
||||
print_canon_ace( p_ace, i);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add in a mask of rwx.
|
||||
*/
|
||||
if (needs_mask && !got_mask_entry) {
|
||||
if (conn->vfs_ops.sys_acl_create_entry(conn, &the_acl, &mask_entry) == -1) {
|
||||
DEBUG(0,("set_canon_ace_list: Failed to create mask entry. (%s)\n", strerror(errno) ));
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (conn->vfs_ops.sys_acl_create_entry( conn, &the_acl, &mask_entry) == -1) {
|
||||
DEBUG(0,("set_canon_ace_list: Failed to create mask entry. (%s)\n", strerror(errno) ));
|
||||
goto done;
|
||||
}
|
||||
if (conn->vfs_ops.sys_acl_set_tag_type(conn, 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 done;
|
||||
}
|
||||
|
||||
if (conn->vfs_ops.sys_acl_set_tag_type(conn, 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 done;
|
||||
}
|
||||
if (conn->vfs_ops.sys_acl_get_permset(conn, mask_entry, &mask_permset) == -1) {
|
||||
DEBUG(0,("set_canon_ace_list: Failed to get mask permset. (%s)\n", strerror(errno) ));
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (conn->vfs_ops.sys_acl_get_permset(conn, mask_entry, &mask_permset) == -1) {
|
||||
DEBUG(0,("set_canon_ace_list: Failed to get mask permset. (%s)\n", strerror(errno) ));
|
||||
goto done;
|
||||
}
|
||||
if (map_acl_perms_to_permset(conn, S_IRUSR|S_IWUSR|S_IXUSR, &mask_permset) == -1) {
|
||||
DEBUG(0,("set_canon_ace_list: Failed to create mask permset. (%s)\n", strerror(errno) ));
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (map_acl_perms_to_permset(conn, S_IRUSR|S_IWUSR|S_IXUSR, &mask_permset) == -1) {
|
||||
DEBUG(0,("set_canon_ace_list: Failed to create mask permset. (%s)\n", strerror(errno) ));
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (conn->vfs_ops.sys_acl_set_permset(conn, mask_entry, mask_permset) == -1) {
|
||||
DEBUG(0,("set_canon_ace_list: Failed to add mask permset. (%s)\n", strerror(errno) ));
|
||||
goto done;
|
||||
if (conn->vfs_ops.sys_acl_set_permset(conn, mask_entry, mask_permset) == -1) {
|
||||
DEBUG(0,("set_canon_ace_list: Failed to add mask permset. (%s)\n", strerror(errno) ));
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1758,6 +1883,12 @@ static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL defau
|
||||
*/
|
||||
if (errno == ENOSYS)
|
||||
*pacl_set_support = False;
|
||||
|
||||
#ifdef ENOTSUP
|
||||
if (errno == ENOTSUP)
|
||||
*pacl_set_support = False;
|
||||
#endif
|
||||
|
||||
DEBUG(2,("set_canon_ace_list: sys_acl_set_file type %s failed for file %s (%s).\n",
|
||||
the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file",
|
||||
fsp->fsp_name, strerror(errno) ));
|
||||
@ -1771,6 +1902,12 @@ static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL defau
|
||||
*/
|
||||
if (errno == ENOSYS)
|
||||
*pacl_set_support = False;
|
||||
|
||||
#ifdef ENOTSUP
|
||||
if (errno == ENOTSUP)
|
||||
*pacl_set_support = False;
|
||||
#endif
|
||||
|
||||
DEBUG(2,("set_canon_ace_list: sys_acl_set_file failed for file %s (%s).\n",
|
||||
fsp->fsp_name, strerror(errno) ));
|
||||
goto done;
|
||||
@ -1787,6 +1924,39 @@ static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL defau
|
||||
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;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
SMB_ACL_T free_empty_sys_acl(connection_struct *conn, SMB_ACL_T acl)
|
||||
{
|
||||
SMB_ACL_ENTRY_T entry;
|
||||
|
||||
if (!acl)
|
||||
return NULL;
|
||||
if (conn->vfs_ops.sys_acl_get_entry(conn, acl, SMB_ACL_FIRST_ENTRY, &entry) != 1) {
|
||||
conn->vfs_ops.sys_acl_free_acl(conn, acl);
|
||||
return NULL;
|
||||
}
|
||||
return acl;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Convert a canon_ace to a generic 3 element permission - if possible.
|
||||
****************************************************************************/
|
||||
@ -1922,6 +2092,8 @@ size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc)
|
||||
{
|
||||
extern DOM_SID global_sid_Builtin_Administrators;
|
||||
extern DOM_SID global_sid_Builtin_Users;
|
||||
extern DOM_SID global_sid_Creator_Owner;
|
||||
extern DOM_SID global_sid_Creator_Group;
|
||||
connection_struct *conn = fsp->conn;
|
||||
SMB_STRUCT_STAT sbuf;
|
||||
SEC_ACE *nt_ace_list = NULL;
|
||||
@ -1958,8 +2130,10 @@ size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc)
|
||||
* If it's a directory get the default POSIX ACL.
|
||||
*/
|
||||
|
||||
if(fsp->is_directory)
|
||||
if(fsp->is_directory) {
|
||||
dir_acl = conn->vfs_ops.sys_acl_get_file(conn, fsp->fsp_name, SMB_ACL_TYPE_DEFAULT);
|
||||
dir_acl = free_empty_sys_acl(conn, dir_acl);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
@ -1990,35 +2164,31 @@ size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc)
|
||||
create_file_sids(&sbuf, &owner_sid, &group_sid);
|
||||
}
|
||||
|
||||
/*
|
||||
* In the optimum case Creator Owner and Creator Group would be used for
|
||||
* the ACL_USER_OBJ and ACL_GROUP_OBJ entries, respectively, but this
|
||||
* would lead to usability problems under Windows: The Creator entries
|
||||
* are only available in browse lists of directories and not for files;
|
||||
* additionally the identity of the owning group couldn't be determined.
|
||||
* We therefore use those identities only for Default ACLs.
|
||||
*/
|
||||
|
||||
/* Create the canon_ace lists. */
|
||||
file_ace = canonicalise_acl( fsp, posix_acl, &sbuf, &owner_sid, &group_sid);
|
||||
num_acls = count_canon_ace_list(file_ace);
|
||||
file_ace = canonicalise_acl( fsp, posix_acl, &sbuf, &owner_sid, &group_sid, SMB_ACL_TYPE_ACCESS );
|
||||
|
||||
/* We must have *some* ACLS. */
|
||||
|
||||
if (num_acls == 0) {
|
||||
if (count_canon_ace_list(file_ace) == 0) {
|
||||
DEBUG(0,("get_nt_acl : No ACLs on file (%s) !\n", fsp->fsp_name ));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (fsp->is_directory) {
|
||||
/*
|
||||
* If we have to fake a default ACL then this is the mode to use.
|
||||
*/
|
||||
sbuf.st_mode = unix_mode( fsp->conn, FILE_ATTRIBUTE_ARCHIVE, fsp->fsp_name);
|
||||
|
||||
dir_ace = canonicalise_acl(fsp, dir_acl, &sbuf, &owner_sid, &group_sid);
|
||||
num_dir_acls = count_canon_ace_list(dir_ace);
|
||||
if (fsp->is_directory && dir_acl) {
|
||||
dir_ace = canonicalise_acl(fsp, dir_acl, &sbuf,
|
||||
&global_sid_Creator_Owner,
|
||||
&global_sid_Creator_Group, SMB_ACL_TYPE_DEFAULT );
|
||||
}
|
||||
|
||||
/* Allocate the ace list. */
|
||||
if ((nt_ace_list = (SEC_ACE *)malloc((num_acls + num_profile_acls + num_dir_acls)* sizeof(SEC_ACE))) == 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_profile_acls + num_dir_acls) * sizeof(SEC_ACE) );
|
||||
|
||||
/*
|
||||
* Create the NT ACE list from the canonical ace lists.
|
||||
*/
|
||||
@ -2028,16 +2198,112 @@ size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc)
|
||||
int nt_acl_type;
|
||||
int i;
|
||||
|
||||
if (nt4_compatible_acls()) {
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
if (!dir_ace)
|
||||
goto simplify_file_ace_only;
|
||||
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
|
||||
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(dir_ace, SMB_ACL_GROUP_OBJ, NULL);
|
||||
if (ace && !ace->perms) {
|
||||
DLIST_REMOVE(dir_ace, ace);
|
||||
SAFE_FREE(ace);
|
||||
}
|
||||
|
||||
simplify_file_ace_only:
|
||||
|
||||
ace = canon_ace_entry_for(file_ace, SMB_ACL_OTHER, NULL);
|
||||
if (ace && !ace->perms) {
|
||||
DLIST_REMOVE(file_ace, ace);
|
||||
SAFE_FREE(ace);
|
||||
}
|
||||
|
||||
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_dir_acls = count_canon_ace_list(dir_ace);
|
||||
|
||||
/* Allocate the ace list. */
|
||||
if ((nt_ace_list = (SEC_ACE *)malloc((num_acls + num_profile_acls + num_dir_acls)* sizeof(SEC_ACE))) == 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_dir_acls) * sizeof(SEC_ACE) );
|
||||
|
||||
/*
|
||||
* Create the NT ACE list from the canonical ace lists.
|
||||
*/
|
||||
|
||||
ace = file_ace;
|
||||
|
||||
for (i = 0; i < num_acls; i++, ace = ace->next) {
|
||||
SEC_ACCESS acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
|
||||
SEC_ACCESS acc;
|
||||
|
||||
acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
|
||||
init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc, 0);
|
||||
}
|
||||
|
||||
/* The User must have access to a profile share - even if we can't map the SID. */
|
||||
if (lp_profile_acls(SNUM(fsp->conn))) {
|
||||
SEC_ACCESS acc;
|
||||
|
||||
init_sec_access(&acc,FILE_GENERIC_ALL);
|
||||
init_sec_ace(&nt_ace_list[num_aces++], &global_sid_Builtin_Users, SEC_ACE_TYPE_ACCESS_ALLOWED, acc, 0);
|
||||
}
|
||||
@ -2045,14 +2311,17 @@ size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc)
|
||||
ace = dir_ace;
|
||||
|
||||
for (i = 0; i < num_dir_acls; i++, ace = ace->next) {
|
||||
SEC_ACCESS acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
|
||||
init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc,
|
||||
SEC_ACCESS acc;
|
||||
|
||||
acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
|
||||
init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc,
|
||||
SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_INHERIT_ONLY);
|
||||
}
|
||||
|
||||
/* The User must have access to a profile share - even if we can't map the SID. */
|
||||
if (lp_profile_acls(SNUM(fsp->conn))) {
|
||||
SEC_ACCESS acc;
|
||||
|
||||
init_sec_access(&acc,FILE_GENERIC_ALL);
|
||||
init_sec_ace(&nt_ace_list[num_aces++], &global_sid_Builtin_Users, SEC_ACE_TYPE_ACCESS_ALLOWED, acc,
|
||||
SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
|
||||
@ -2087,11 +2356,22 @@ size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc)
|
||||
if(!*ppdesc) {
|
||||
DEBUG(0,("get_nt_acl: Unable to malloc space for security descriptor.\n"));
|
||||
sd_size = 0;
|
||||
} else {
|
||||
/*
|
||||
* Windows 2000: The DACL_PROTECTED flag in the security
|
||||
* descriptor marks the ACL as non-inheriting, i.e., no
|
||||
* ACEs from higher level directories propagate to this
|
||||
* ACL. In the POSIX ACL model permissions are only
|
||||
* inherited at file create time, so ACLs never contain
|
||||
* any ACEs that are inherited dynamically. The DACL_PROTECTED
|
||||
* flag doesn't seem to bother Windows NT.
|
||||
*/
|
||||
(*ppdesc)->type |= SE_DESC_DACL_PROTECTED;
|
||||
}
|
||||
|
||||
done:
|
||||
done:
|
||||
|
||||
if (posix_acl)
|
||||
if (posix_acl)
|
||||
conn->vfs_ops.sys_acl_free_acl(conn, posix_acl);
|
||||
if (dir_acl)
|
||||
conn->vfs_ops.sys_acl_free_acl(conn, dir_acl);
|
||||
@ -2379,6 +2659,12 @@ static int chmod_acl_internals( connection_struct *conn, SMB_ACL_T posix_acl, mo
|
||||
perms = unix_perms_to_acl_perms(mode, S_IRGRP, S_IWGRP, S_IXGRP);
|
||||
break;
|
||||
case SMB_ACL_MASK:
|
||||
/*
|
||||
* FIXME: The ACL_MASK entry permissions should really be set to
|
||||
* the union of the permissions of all ACL_USER,
|
||||
* ACL_GROUP_OBJ, and ACL_GROUP entries. That's what
|
||||
* acl_calc_mask() does, but Samba ACLs doesn't provide it.
|
||||
*/
|
||||
perms = S_IRUSR|S_IWUSR|S_IXUSR;
|
||||
break;
|
||||
case SMB_ACL_OTHER:
|
||||
@ -2406,6 +2692,31 @@ static int chmod_acl_internals( connection_struct *conn, SMB_ACL_T posix_acl, mo
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Get the access ACL of FROM, do a chmod by setting the ACL USER_OBJ,
|
||||
GROUP_OBJ and OTHER bits in an ACL and set the mask to rwx. Set the
|
||||
resulting ACL on TO. Note that name is in UNIX character set.
|
||||
****************************************************************************/
|
||||
|
||||
static int copy_access_acl(connection_struct *conn, const char *from, const char *to, mode_t mode)
|
||||
{
|
||||
SMB_ACL_T posix_acl = NULL;
|
||||
int ret = -1;
|
||||
|
||||
if ((posix_acl = conn->vfs_ops.sys_acl_get_file(conn, from, SMB_ACL_TYPE_ACCESS)) == NULL)
|
||||
return -1;
|
||||
|
||||
if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1)
|
||||
goto done;
|
||||
|
||||
ret = conn->vfs_ops.sys_acl_set_file(conn, to, SMB_ACL_TYPE_ACCESS, posix_acl);
|
||||
|
||||
done:
|
||||
|
||||
conn->vfs_ops.sys_acl_free_acl(conn, posix_acl);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
|
||||
and set the mask to rwx. Needed to preserve complex ACLs set by NT.
|
||||
@ -2414,21 +2725,23 @@ static int chmod_acl_internals( connection_struct *conn, SMB_ACL_T posix_acl, mo
|
||||
|
||||
int chmod_acl(connection_struct *conn, const char *name, mode_t mode)
|
||||
{
|
||||
SMB_ACL_T posix_acl = NULL;
|
||||
int ret = -1;
|
||||
return copy_access_acl(conn, name, name, mode);
|
||||
}
|
||||
|
||||
if ((posix_acl = conn->vfs_ops.sys_acl_get_file(conn, name, SMB_ACL_TYPE_ACCESS)) == NULL)
|
||||
return -1;
|
||||
/****************************************************************************
|
||||
If "inherit permissions" is set and the parent directory has no default
|
||||
ACL but it does have an Access ACL, inherit this Access ACL to file name.
|
||||
****************************************************************************/
|
||||
|
||||
if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1)
|
||||
goto done;
|
||||
int inherit_access_acl(connection_struct *conn, const char *name, mode_t mode)
|
||||
{
|
||||
pstring dirname;
|
||||
pstrcpy(dirname, parent_dirname(name));
|
||||
|
||||
ret = conn->vfs_ops.sys_acl_set_file(conn, name, SMB_ACL_TYPE_ACCESS, posix_acl);
|
||||
if (!lp_inherit_perms(SNUM(conn)) || directory_has_default_acl(conn, dirname))
|
||||
return 0;
|
||||
|
||||
done:
|
||||
|
||||
conn->vfs_ops.sys_acl_free_acl(conn, posix_acl);
|
||||
return ret;
|
||||
return copy_access_acl(conn, dirname, name, mode);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -2622,6 +2622,8 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
|
||||
if (conn->vfs_ops.mknod(conn,dos_to_unix_static(fname), unixmode, dev) != 0)
|
||||
return(UNIXERROR(ERRDOS,ERRnoaccess));
|
||||
|
||||
inherit_access_acl(conn, fname, unixmode);
|
||||
|
||||
SSVAL(params,0,0);
|
||||
send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
|
||||
return(-1);
|
||||
|
@ -456,7 +456,7 @@ BOOL lookup_name(const char *domain, const char *name, DOM_SID *psid, enum SID_N
|
||||
if (strequal(global_myname, domain)) {
|
||||
local_lookup = True;
|
||||
} else if (lp_server_role() == ROLE_DOMAIN_PDC ||
|
||||
lp_server_role() == ROLE_DOMAIN_PDC) {
|
||||
lp_server_role() == ROLE_DOMAIN_BDC) {
|
||||
if (strequal(domain, global_myworkgroup)) {
|
||||
local_lookup = True;
|
||||
}
|
||||
|
@ -319,6 +319,9 @@ int vfs_mkdir(connection_struct *conn, const char *name, mode_t mode)
|
||||
SMB_STRUCT_STAT sbuf;
|
||||
|
||||
if(!(ret=conn->vfs_ops.mkdir(conn,name,mode))) {
|
||||
|
||||
inherit_access_acl(conn, name, mode);
|
||||
|
||||
/*
|
||||
* Check if high bits should have been set,
|
||||
* then (if bits are missing): add them.
|
||||
|
Loading…
x
Reference in New Issue
Block a user