X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=source%2Fsmbd%2Fposix_acls.c;h=aa1629e598bd6ca6e6cc4a7c043cb9faa47ba06f;hb=785c4d7d821d5302ed72c10b85366cb34915bcb9;hp=7eda998547e650afad450ab250828a256fe81ac1;hpb=10649540ac11e679997f414d4a6b12d057bd7913;p=obnox%2Fsamba%2Fsamba-obnox.git diff --git a/source/smbd/posix_acls.c b/source/smbd/posix_acls.c index 7eda998547e..aa1629e598b 100644 --- a/source/smbd/posix_acls.c +++ b/source/smbd/posix_acls.c @@ -6,7 +6,7 @@ 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 - the Free Software Foundation; either version 2 of the License, or + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -15,14 +15,13 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + along with this program. If not, see . */ #include "includes.h" extern struct current_user current_user; -extern struct generic_mapping file_generic_mapping; +extern const struct generic_mapping file_generic_mapping; #undef DBGC_CLASS #define DBGC_CLASS DBGC_ACLS @@ -47,8 +46,8 @@ typedef struct canon_ace { DOM_SID trustee; enum ace_owner owner_type; enum ace_attribute attr; - posix_id unix_ug; - BOOL inherited; + posix_id unix_ug; + bool inherited; } canon_ace; #define ALL_ACE_PERMS (S_IRUSR|S_IWUSR|S_IXUSR) @@ -80,11 +79,11 @@ typedef struct canon_ace { struct pai_entry { struct pai_entry *next, *prev; enum ace_owner owner_type; - posix_id unix_ug; + posix_id unix_ug; }; - + struct pai_val { - BOOL pai_protected; + bool pai_protected; unsigned int num_entries; struct pai_entry *entry_list; unsigned int num_def_entries; @@ -149,7 +148,7 @@ static unsigned int num_inherited_entries(canon_ace *ace_list) Create the on-disk format. Caller must free. ************************************************************************/ -static char *create_pai_buf(canon_ace *file_ace_list, canon_ace *dir_ace_list, BOOL pai_protected, size_t *store_size) +static char *create_pai_buf(canon_ace *file_ace_list, canon_ace *dir_ace_list, bool pai_protected, size_t *store_size) { char *pai_buf = NULL; canon_ace *ace_list = NULL; @@ -213,7 +212,7 @@ static char *create_pai_buf(canon_ace *file_ace_list, canon_ace *dir_ace_list, B ************************************************************************/ static void store_inheritance_attributes(files_struct *fsp, canon_ace *file_ace_list, - canon_ace *dir_ace_list, BOOL pai_protected) + canon_ace *dir_ace_list, bool pai_protected) { int ret; size_t store_size; @@ -276,7 +275,7 @@ static void free_inherited_info(struct pai_val *pal) Was this ACL protected ? ************************************************************************/ -static BOOL get_protected_flag(struct pai_val *pal) +static bool get_protected_flag(struct pai_val *pal) { if (!pal) return False; @@ -287,7 +286,7 @@ static BOOL get_protected_flag(struct pai_val *pal) Was this ACE inherited ? ************************************************************************/ -static BOOL get_inherited_flag(struct pai_val *pal, canon_ace *ace_entry, BOOL default_ace) +static bool get_inherited_flag(struct pai_val *pal, canon_ace *ace_entry, bool default_ace) { struct pai_entry *paie; @@ -307,7 +306,7 @@ static BOOL get_inherited_flag(struct pai_val *pal, canon_ace *ace_entry, BOOL d Ensure an attribute just read is valid. ************************************************************************/ -static BOOL check_pai_ok(char *pai_buf, size_t pai_buf_data_size) +static bool check_pai_ok(char *pai_buf, size_t pai_buf_data_size) { uint16 num_entries; uint16 num_def_entries; @@ -673,7 +672,7 @@ static void create_file_sids(SMB_STRUCT_STAT *psbuf, DOM_SID *powner_sid, DOM_SI Is the identity in two ACEs equal ? Check both SID and uid/gid. ****************************************************************************/ -static BOOL identity_in_ace_equal(canon_ace *ace1, canon_ace *ace2) +static bool identity_in_ace_equal(canon_ace *ace1, canon_ace *ace2) { if (sid_equal(&ace1->trustee, &ace2->trustee)) { return True; @@ -808,7 +807,7 @@ static void merge_aces( canon_ace **pp_list_head ) Check if we need to return NT4.x compatible ACL entries. ****************************************************************************/ -static BOOL nt4_compatible_acls(void) +static bool nt4_compatible_acls(void) { int compat = lp_acl_compatibility(); @@ -828,20 +827,23 @@ static BOOL nt4_compatible_acls(void) not get. Deny entries are implicit on get with ace->perms = 0. ****************************************************************************/ -static SEC_ACCESS map_canon_ace_perms(int snum, int *pacl_type, DOM_SID *powner_sid, canon_ace *ace, BOOL directory_ace) +static SEC_ACCESS map_canon_ace_perms(int snum, + int *pacl_type, + mode_t perms, + bool directory_ace) { SEC_ACCESS sa; uint32 nt_mask = 0; *pacl_type = SEC_ACE_TYPE_ACCESS_ALLOWED; - if (lp_acl_map_full_control(snum) && ((ace->perms & ALL_ACE_PERMS) == ALL_ACE_PERMS)) { + if (lp_acl_map_full_control(snum) && ((perms & ALL_ACE_PERMS) == ALL_ACE_PERMS)) { if (directory_ace) { nt_mask = UNIX_DIRECTORY_ACCESS_RWX; } else { nt_mask = UNIX_ACCESS_RWX; } - } else if ((ace->perms & ALL_ACE_PERMS) == (mode_t)0) { + } else if ((perms & ALL_ACE_PERMS) == (mode_t)0) { /* * Windows NT refuses to display ACEs with no permissions in them (but * they are perfectly legal with Windows 2000). If the ACE has empty @@ -857,18 +859,18 @@ static SEC_ACCESS map_canon_ace_perms(int snum, int *pacl_type, DOM_SID *powner_ nt_mask = 0; } else { if (directory_ace) { - nt_mask |= ((ace->perms & S_IRUSR) ? UNIX_DIRECTORY_ACCESS_R : 0 ); - nt_mask |= ((ace->perms & S_IWUSR) ? UNIX_DIRECTORY_ACCESS_W : 0 ); - nt_mask |= ((ace->perms & S_IXUSR) ? UNIX_DIRECTORY_ACCESS_X : 0 ); + nt_mask |= ((perms & S_IRUSR) ? UNIX_DIRECTORY_ACCESS_R : 0 ); + nt_mask |= ((perms & S_IWUSR) ? UNIX_DIRECTORY_ACCESS_W : 0 ); + nt_mask |= ((perms & S_IXUSR) ? UNIX_DIRECTORY_ACCESS_X : 0 ); } else { - nt_mask |= ((ace->perms & S_IRUSR) ? UNIX_ACCESS_R : 0 ); - nt_mask |= ((ace->perms & S_IWUSR) ? UNIX_ACCESS_W : 0 ); - nt_mask |= ((ace->perms & S_IXUSR) ? UNIX_ACCESS_X : 0 ); + nt_mask |= ((perms & S_IRUSR) ? UNIX_ACCESS_R : 0 ); + nt_mask |= ((perms & S_IWUSR) ? UNIX_ACCESS_W : 0 ); + nt_mask |= ((perms & S_IXUSR) ? UNIX_ACCESS_X : 0 ); } } DEBUG(10,("map_canon_ace_perms: Mapped (UNIX) %x to (NT) %x\n", - (unsigned int)ace->perms, (unsigned int)nt_mask )); + (unsigned int)perms, (unsigned int)nt_mask )); init_sec_access(&sa,nt_mask); return sa; @@ -923,7 +925,7 @@ static mode_t map_nt_perms( uint32 *mask, int type) Unpack a SEC_DESC into a UNIX owner and group. ****************************************************************************/ -BOOL unpack_nt_owners(int snum, uid_t *puser, gid_t *pgrp, uint32 security_info_sent, SEC_DESC *psd) +NTSTATUS unpack_nt_owners(int snum, uid_t *puser, gid_t *pgrp, uint32 security_info_sent, SEC_DESC *psd) { DOM_SID owner_sid; DOM_SID grp_sid; @@ -933,7 +935,7 @@ BOOL unpack_nt_owners(int snum, uid_t *puser, gid_t *pgrp, uint32 security_info_ if(security_info_sent == 0) { DEBUG(0,("unpack_nt_owners: no security info sent !\n")); - return True; + return NT_STATUS_OK; } /* @@ -961,9 +963,11 @@ BOOL unpack_nt_owners(int snum, uid_t *puser, gid_t *pgrp, uint32 security_info_ DEBUG(3,("unpack_nt_owners: unable to validate" " owner sid for %s\n", sid_string_static(&owner_sid))); - return False; + return NT_STATUS_INVALID_OWNER; } } + DEBUG(3,("unpack_nt_owners: owner sid mapped to uid %u\n", + (unsigned int)*puser )); } /* @@ -981,21 +985,23 @@ BOOL unpack_nt_owners(int snum, uid_t *puser, gid_t *pgrp, uint32 security_info_ } else { DEBUG(3,("unpack_nt_owners: unable to validate" " group sid.\n")); - return False; + return NT_STATUS_INVALID_OWNER; } } - } + DEBUG(3,("unpack_nt_owners: group sid mapped to gid %u\n", + (unsigned int)*pgrp)); + } DEBUG(5,("unpack_nt_owners: owner_sids validated.\n")); - return True; + return NT_STATUS_OK; } /**************************************************************************** Ensure the enforced permissions for this share apply. ****************************************************************************/ -static void apply_default_perms(files_struct *fsp, canon_ace *pace, mode_t type) +static void apply_default_perms(const files_struct *fsp, canon_ace *pace, mode_t type) { int snum = SNUM(fsp->conn); mode_t and_bits = (mode_t)0; @@ -1039,9 +1045,9 @@ static void apply_default_perms(files_struct *fsp, canon_ace *pace, mode_t type) expensive and will need optimisation. A *lot* of optimisation :-). JRA. ****************************************************************************/ -static BOOL uid_entry_in_group( canon_ace *uid_ace, canon_ace *group_ace ) +static bool uid_entry_in_group( canon_ace *uid_ace, canon_ace *group_ace ) { - fstring u_name; + const char *u_name = NULL; /* "Everyone" always matches every uid. */ @@ -1053,7 +1059,11 @@ static BOOL uid_entry_in_group( canon_ace *uid_ace, canon_ace *group_ace ) if (uid_ace->unix_ug.uid == current_user.ut.uid && group_ace->unix_ug.gid == current_user.ut.gid) return True; - fstrcpy(u_name, uidtoname(uid_ace->unix_ug.uid)); + /* u_name talloc'ed off tos. */ + u_name = uidtoname(uid_ace->unix_ug.uid); + if (!u_name) { + return False; + } return user_in_group_sid(u_name, &group_ace->trustee); } @@ -1067,17 +1077,17 @@ static BOOL uid_entry_in_group( canon_ace *uid_ace, canon_ace *group_ace ) type. ****************************************************************************/ -static BOOL ensure_canon_entry_valid(canon_ace **pp_ace, - files_struct *fsp, +static bool ensure_canon_entry_valid(canon_ace **pp_ace, + const files_struct *fsp, const DOM_SID *pfile_owner_sid, const DOM_SID *pfile_grp_sid, SMB_STRUCT_STAT *pst, - BOOL setting_acl) + bool setting_acl) { canon_ace *pace; - BOOL got_user = False; - BOOL got_grp = False; - BOOL got_other = False; + bool got_user = False; + bool got_grp = False; + bool got_other = False; canon_ace *pace_other = NULL; for (pace = *pp_ace; pace; pace = pace->next) { @@ -1127,7 +1137,7 @@ static BOOL ensure_canon_entry_valid(canon_ace **pp_ace, /* 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; + bool group_matched = False; canon_ace *pace_iter; for (pace_iter = *pp_ace; pace_iter; pace_iter = pace_iter->next) { @@ -1213,7 +1223,7 @@ static BOOL ensure_canon_entry_valid(canon_ace **pp_ace, 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; + bool got_user_obj, got_group_obj; canon_ace *current_ace; int i, entries; @@ -1254,18 +1264,18 @@ static void check_owning_objs(canon_ace *ace, DOM_SID *pfile_owner_sid, DOM_SID Unpack a SEC_DESC into two canonical ace lists. ****************************************************************************/ -static BOOL create_canon_ace_lists(files_struct *fsp, SMB_STRUCT_STAT *pst, +static bool create_canon_ace_lists(files_struct *fsp, SMB_STRUCT_STAT *pst, DOM_SID *pfile_owner_sid, DOM_SID *pfile_grp_sid, canon_ace **ppfile_ace, canon_ace **ppdir_ace, SEC_ACL *dacl) { - BOOL all_aces_are_inherit_only = (fsp->is_directory ? True : False); + bool all_aces_are_inherit_only = (fsp->is_directory ? True : False); canon_ace *file_ace = NULL; canon_ace *dir_ace = NULL; canon_ace *current_ace = NULL; - BOOL got_dir_allow = False; - BOOL got_file_allow = False; + bool got_dir_allow = False; + bool got_file_allow = False; int i, j; *ppfile_ace = NULL; @@ -1895,7 +1905,7 @@ static void process_deny_list( canon_ace **pp_ace_list ) no user/group/world entries. ****************************************************************************/ -static mode_t create_default_mode(files_struct *fsp, BOOL interitable_mode) +static mode_t create_default_mode(files_struct *fsp, bool interitable_mode) { int snum = SNUM(fsp->conn); mode_t and_bits = (mode_t)0; @@ -1929,7 +1939,7 @@ static mode_t create_default_mode(files_struct *fsp, BOOL interitable_mode) succeeding. ****************************************************************************/ -static BOOL unpack_canon_ace(files_struct *fsp, +static bool unpack_canon_ace(files_struct *fsp, SMB_STRUCT_STAT *pst, DOM_SID *pfile_owner_sid, DOM_SID *pfile_grp_sid, @@ -2100,7 +2110,7 @@ static void arrange_posix_perms( char *filename, canon_ace **pp_list_head) Create a linked list of canonical ACE entries. ****************************************************************************/ -static canon_ace *canonicalise_acl( files_struct *fsp, SMB_ACL_T posix_acl, SMB_STRUCT_STAT *psbuf, +static canon_ace *canonicalise_acl( const files_struct *fsp, SMB_ACL_T posix_acl, SMB_STRUCT_STAT *psbuf, const DOM_SID *powner, const DOM_SID *pgroup, struct pai_val *pal, SMB_ACL_TYPE_T the_acl_type) { connection_struct *conn = fsp->conn; @@ -2260,7 +2270,7 @@ static canon_ace *canonicalise_acl( files_struct *fsp, SMB_ACL_T posix_acl, SMB_ Check if the current user group list contains a given group. ****************************************************************************/ -static BOOL current_user_in_group(gid_t gid) +static bool current_user_in_group(gid_t gid) { int i; @@ -2278,7 +2288,7 @@ static BOOL current_user_in_group(gid_t gid) and 'dos filemode' ****************************************************************************/ -static BOOL acl_group_override(connection_struct *conn, gid_t prim_gid) +static bool acl_group_override(connection_struct *conn, gid_t prim_gid) { if ( (errno == EACCES || errno == EPERM) && (lp_acl_group_control(SNUM(conn)) || lp_dos_filemode(SNUM(conn))) @@ -2294,18 +2304,18 @@ static BOOL acl_group_override(connection_struct *conn, gid_t prim_gid) Attempt to apply an ACL to a file or directory. ****************************************************************************/ -static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL default_ace, gid_t prim_gid, BOOL *pacl_set_support) +static bool set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, bool default_ace, gid_t prim_gid, bool *pacl_set_support) { connection_struct *conn = fsp->conn; - BOOL ret = False; + bool ret = False; SMB_ACL_T the_acl = SMB_VFS_SYS_ACL_INIT(conn, (int)count_canon_ace_list(the_ace) + 1); canon_ace *p_ace; int i; SMB_ACL_ENTRY_T mask_entry; - BOOL got_mask_entry = False; + 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; + bool needs_mask = False; mode_t mask_perms = 0; #if defined(POSIX_ACL_NEEDS_MASK) @@ -2576,7 +2586,7 @@ SMB_ACL_T free_empty_sys_acl(connection_struct *conn, SMB_ACL_T the_acl) #define MAP_PERM(p,mask,result) (((p) & (mask)) ? (result) : 0 ) -static BOOL convert_canon_ace_to_posix_perms( files_struct *fsp, canon_ace *file_ace_list, mode_t *posix_perms) +static bool convert_canon_ace_to_posix_perms( files_struct *fsp, canon_ace *file_ace_list, mode_t *posix_perms) { int snum = SNUM(fsp->conn); size_t ace_count = count_canon_ace_list(file_ace_list); @@ -2660,8 +2670,8 @@ static size_t merge_default_aces( SEC_ACE *nt_ace_list, size_t num_aces) for (j = i+1; j < num_aces; j++) { uint32 i_flags_ni = (nt_ace_list[i].flags & ~SEC_ACE_FLAG_INHERITED_ACE); uint32 j_flags_ni = (nt_ace_list[j].flags & ~SEC_ACE_FLAG_INHERITED_ACE); - BOOL i_inh = (nt_ace_list[i].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False; - BOOL j_inh = (nt_ace_list[j].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False; + bool i_inh = (nt_ace_list[i].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False; + bool j_inh = (nt_ace_list[j].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False; /* We know the lower number ACE's are file entries. */ if ((nt_ace_list[i].type == nt_ace_list[j].type) && @@ -2889,26 +2899,37 @@ size_t get_nt_acl(files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc) } memset(nt_ace_list, '\0', (num_acls + num_def_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; - acc = map_canon_ace_perms(SNUM(conn), &nt_acl_type, &owner_sid, ace, fsp->is_directory); - init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc, ace->inherited ? SEC_ACE_FLAG_INHERITED_ACE : 0); + acc = map_canon_ace_perms(SNUM(conn), + &nt_acl_type, + ace->perms, + fsp->is_directory); + init_sec_ace(&nt_ace_list[num_aces++], + &ace->trustee, + nt_acl_type, + acc, + ace->inherited ? + SEC_ACE_FLAG_INHERITED_ACE : 0); } - /* The User must have access to a profile share - even if we can't map the SID. */ + /* The User must have access to a profile share - even + * if we can't map the SID. */ if (lp_profile_acls(SNUM(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, + init_sec_ace(&nt_ace_list[num_aces++], + &global_sid_Builtin_Users, + SEC_ACE_TYPE_ACCESS_ALLOWED, acc, 0); } @@ -2916,18 +2937,27 @@ size_t get_nt_acl(files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc) for (i = 0; i < num_def_acls; i++, ace = ace->next) { SEC_ACCESS acc; - - acc = map_canon_ace_perms(SNUM(conn), &nt_acl_type, &owner_sid, ace, fsp->is_directory); - 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| - (ace->inherited ? SEC_ACE_FLAG_INHERITED_ACE : 0)); + + acc = map_canon_ace_perms(SNUM(conn), + &nt_acl_type, + ace->perms, + fsp->is_directory); + 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| + (ace->inherited ? + SEC_ACE_FLAG_INHERITED_ACE : 0)); } - /* The User must have access to a profile share - even if we can't map the SID. */ + /* The User must have access to a profile share - even + * if we can't map the SID. */ if (lp_profile_acls(SNUM(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| @@ -2945,14 +2975,14 @@ size_t get_nt_acl(files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc) } if (num_aces) { - if((psa = make_sec_acl( main_loop_talloc_get(), NT4_ACL_REVISION, num_aces, nt_ace_list)) == NULL) { + if((psa = make_sec_acl( talloc_tos(), NT4_ACL_REVISION, num_aces, nt_ace_list)) == NULL) { DEBUG(0,("get_nt_acl: Unable to malloc space for acl.\n")); goto done; } } } /* security_info & DACL_SECURITY_INFORMATION */ - psd = make_standard_sec_desc( main_loop_talloc_get(), + psd = make_standard_sec_desc( talloc_tos(), (security_info & OWNER_SECURITY_INFORMATION) ? &owner_sid : NULL, (security_info & GROUP_SECURITY_INFORMATION) ? &group_sid : NULL, psa, @@ -3029,9 +3059,9 @@ int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_t gid) /* Case (2) / (3) */ if (lp_enable_privileges()) { - BOOL has_take_ownership_priv = user_has_privileges(current_user.nt_user_token, + bool has_take_ownership_priv = user_has_privileges(current_user.nt_user_token, &se_take_ownership); - BOOL has_restore_priv = user_has_privileges(current_user.nt_user_token, + bool has_restore_priv = user_has_privileges(current_user.nt_user_token, &se_restore); /* Case (2) */ @@ -3049,6 +3079,7 @@ int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_t gid) /* Case (4). */ if (!lp_dos_filemode(SNUM(conn))) { + errno = EPERM; return -1; } @@ -3076,33 +3107,224 @@ int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_t gid) return ret; } +static NTSTATUS append_ugw_ace(files_struct *fsp, + SMB_STRUCT_STAT *psbuf, + mode_t unx_mode, + int ugw, + SEC_ACE *se) +{ + mode_t perms; + SEC_ACCESS acc; + int nt_acl_type; + DOM_SID trustee; + + switch (ugw) { + case S_IRUSR: + perms = unix_perms_to_acl_perms(unx_mode, + S_IRUSR, + S_IWUSR, + S_IXUSR); + uid_to_sid(&trustee, psbuf->st_uid ); + break; + case S_IRGRP: + perms = unix_perms_to_acl_perms(unx_mode, + S_IRGRP, + S_IWGRP, + S_IXGRP); + gid_to_sid(&trustee, psbuf->st_gid ); + break; + case S_IROTH: + perms = unix_perms_to_acl_perms(unx_mode, + S_IROTH, + S_IWOTH, + S_IXOTH); + sid_copy(&trustee, &global_sid_World); + break; + default: + return NT_STATUS_INVALID_PARAMETER; + } + acc = map_canon_ace_perms(SNUM(fsp->conn), + &nt_acl_type, + perms, + fsp->is_directory); + + init_sec_ace(se, + &trustee, + nt_acl_type, + acc, + 0); + return NT_STATUS_OK; +} + +/**************************************************************************** + If this is an +****************************************************************************/ + +static NTSTATUS append_parent_acl(files_struct *fsp, + SMB_STRUCT_STAT *psbuf, + SEC_DESC *psd, + SEC_DESC **pp_new_sd) +{ + SEC_DESC *parent_sd = NULL; + files_struct *parent_fsp = NULL; + TALLOC_CTX *mem_ctx = talloc_parent(psd); + char *parent_name = NULL; + SEC_ACE *new_ace = NULL; + unsigned int num_aces = psd->dacl->num_aces; + SMB_STRUCT_STAT sbuf; + NTSTATUS status; + int info; + size_t sd_size; + unsigned int i, j; + mode_t unx_mode; + + ZERO_STRUCT(sbuf); + + if (mem_ctx == NULL) { + return NT_STATUS_NO_MEMORY; + } + + if (!parent_dirname_talloc(mem_ctx, + fsp->fsp_name, + &parent_name, + NULL)) { + return NT_STATUS_NO_MEMORY; + } + + /* Create a default mode for u/g/w. */ + unx_mode = unix_mode(fsp->conn, + aARCH | (fsp->is_directory ? aDIR : 0), + fsp->fsp_name, + parent_name); + + status = open_directory(fsp->conn, + NULL, + parent_name, + &sbuf, + FILE_READ_ATTRIBUTES, /* Just a stat open */ + FILE_SHARE_NONE, /* Ignored for stat opens */ + FILE_OPEN, + 0, + INTERNAL_OPEN_ONLY, + &info, + &parent_fsp); + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + sd_size = SMB_VFS_GET_NT_ACL(parent_fsp, parent_fsp->fsp_name, + DACL_SECURITY_INFORMATION, &parent_sd ); + + close_file(parent_fsp, NORMAL_CLOSE); + + if (!sd_size) { + return NT_STATUS_ACCESS_DENIED; + } + + /* + * Make room for potentially all the ACLs from + * the parent, plus the user/group/other triple. + */ + + num_aces += parent_sd->dacl->num_aces + 3; + + if((new_ace = TALLOC_ZERO_ARRAY(mem_ctx, SEC_ACE, + num_aces)) == NULL) { + return NT_STATUS_NO_MEMORY; + } + + DEBUG(10,("append_parent_acl: parent ACL has %u entries. New " + "ACL has %u entries\n", + parent_sd->dacl->num_aces, num_aces )); + + /* Start by copying in all the given ACE entries. */ + for (i = 0; i < psd->dacl->num_aces; i++) { + sec_ace_copy(&new_ace[i], &psd->dacl->aces[i]); + } + + /* + * Note that we're ignoring "inherit permissions" here + * as that really only applies to newly created files. JRA. + */ + + /* + * Append u/g/w. + */ + + status = append_ugw_ace(fsp, psbuf, unx_mode, S_IRUSR, &new_ace[i++]); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + status = append_ugw_ace(fsp, psbuf, unx_mode, S_IRGRP, &new_ace[i++]); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + status = append_ugw_ace(fsp, psbuf, unx_mode, S_IROTH, &new_ace[i++]); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* Finally append any inherited ACEs. */ + for (j = 0; j < parent_sd->dacl->num_aces; j++) { + SEC_ACE *se = &parent_sd->dacl->aces[j]; + uint32 i_flags = se->flags & (SEC_ACE_FLAG_OBJECT_INHERIT| + SEC_ACE_FLAG_CONTAINER_INHERIT| + SEC_ACE_FLAG_INHERIT_ONLY); + + if (fsp->is_directory) { + if (i_flags == SEC_ACE_FLAG_OBJECT_INHERIT) { + /* Should only apply to a file - ignore. */ + continue; + } + } else { + if ((i_flags & (SEC_ACE_FLAG_OBJECT_INHERIT| + SEC_ACE_FLAG_INHERIT_ONLY)) != + SEC_ACE_FLAG_OBJECT_INHERIT) { + /* Should not apply to a file - ignore. */ + continue; + } + } + sec_ace_copy(&new_ace[i], se); + if (se->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) { + new_ace[i].flags &= ~(SEC_ACE_FLAG_VALID_INHERIT); + } + new_ace[i].flags |= SEC_ACE_FLAG_INHERITED_ACE; + i++; + } + + parent_sd->dacl->aces = new_ace; + parent_sd->dacl->num_aces = i; + + *pp_new_sd = parent_sd; + return status; +} + /**************************************************************************** Reply to set a security descriptor on an fsp. security_info_sent is the description of the following NT ACL. This should be the only external function needed for the UNIX style set ACL. ****************************************************************************/ -BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) +NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) { connection_struct *conn = fsp->conn; uid_t user = (uid_t)-1; gid_t grp = (gid_t)-1; - SMB_STRUCT_STAT sbuf; + SMB_STRUCT_STAT sbuf; DOM_SID file_owner_sid; DOM_SID file_grp_sid; canon_ace *file_ace_list = NULL; canon_ace *dir_ace_list = NULL; - BOOL acl_perms = False; + bool acl_perms = False; mode_t orig_mode = (mode_t)0; - uid_t orig_uid; - gid_t orig_gid; - BOOL need_chown = False; + NTSTATUS status; DEBUG(10,("set_nt_acl: called for file %s\n", fsp->fsp_name )); if (!CAN_WRITE(conn)) { DEBUG(10,("set acl rejected on read-only share\n")); - return False; + return NT_STATUS_MEDIA_WRITE_PROTECTED; } /* @@ -3111,40 +3333,29 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) if(fsp->is_directory || fsp->fh->fd == -1) { if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0) - return False; + return map_nt_error_from_unix(errno); } else { if(SMB_VFS_FSTAT(fsp,fsp->fh->fd,&sbuf) != 0) - return False; + return map_nt_error_from_unix(errno); } /* Save the original elements we check against. */ orig_mode = sbuf.st_mode; - orig_uid = sbuf.st_uid; - orig_gid = sbuf.st_gid; /* * Unpack the user/group/world id's. */ - if (!unpack_nt_owners( SNUM(conn), &user, &grp, security_info_sent, psd)) { - return False; + status = unpack_nt_owners( SNUM(conn), &user, &grp, security_info_sent, psd); + if (!NT_STATUS_IS_OK(status)) { + return status; } /* * Do we need to chown ? */ - if (((user != (uid_t)-1) && (orig_uid != user)) || (( grp != (gid_t)-1) && (orig_gid != grp))) { - need_chown = True; - } - - /* - * Chown before setting ACL only if we don't change the user, or - * if we change to the current user, but not if we want to give away - * the file. - */ - - if (need_chown && (user == (uid_t)-1 || user == current_user.ut.uid)) { + if (((user != (uid_t)-1) && (sbuf.st_uid != user)) || (( grp != (gid_t)-1) && (sbuf.st_gid != grp))) { DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n", fsp->fsp_name, (unsigned int)user, (unsigned int)grp )); @@ -3152,7 +3363,10 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) if(try_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) { DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n", fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) )); - return False; + if (errno == EPERM) { + return NT_STATUS_INVALID_OWNER; + } + return map_nt_error_from_unix(errno); } /* @@ -3162,32 +3376,39 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) if(fsp->is_directory) { if(SMB_VFS_STAT(fsp->conn, fsp->fsp_name, &sbuf) != 0) { - return False; + return map_nt_error_from_unix(errno); } } else { int ret; - + if(fsp->fh->fd == -1) ret = SMB_VFS_STAT(fsp->conn, fsp->fsp_name, &sbuf); else ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&sbuf); - + if(ret != 0) - return False; + return map_nt_error_from_unix(errno); } /* Save the original elements we check against. */ orig_mode = sbuf.st_mode; - orig_uid = sbuf.st_uid; - orig_gid = sbuf.st_gid; - - /* We did it, don't try again */ - need_chown = False; } create_file_sids(&sbuf, &file_owner_sid, &file_grp_sid); + if ((security_info_sent & DACL_SECURITY_INFORMATION) && + psd->dacl != NULL && + (psd->type & (SE_DESC_DACL_AUTO_INHERITED| + SE_DESC_DACL_AUTO_INHERIT_REQ))== + (SE_DESC_DACL_AUTO_INHERITED| + SE_DESC_DACL_AUTO_INHERIT_REQ) ) { + status = append_parent_acl(fsp, &sbuf, psd, &psd); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + } + acl_perms = unpack_canon_ace( fsp, &sbuf, &file_owner_sid, &file_grp_sid, &file_ace_list, &dir_ace_list, security_info_sent, psd); @@ -3198,7 +3419,7 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) DEBUG(3,("set_nt_acl: cannot set permissions\n")); free_canon_ace_list(file_ace_list); free_canon_ace_list(dir_ace_list); - return False; + return NT_STATUS_ACCESS_DENIED; } /* @@ -3207,8 +3428,8 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) if((security_info_sent & DACL_SECURITY_INFORMATION) && (psd->dacl != NULL)) { - BOOL acl_set_support = False; - BOOL ret = False; + bool acl_set_support = False; + bool ret = False; /* * Try using the POSIX ACL set first. Fall back to chmod if @@ -3221,7 +3442,7 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) DEBUG(3,("set_nt_acl: failed to set file acl on file %s (%s).\n", fsp->fsp_name, strerror(errno) )); free_canon_ace_list(file_ace_list); free_canon_ace_list(dir_ace_list); - return False; + return map_nt_error_from_unix(errno); } } @@ -3231,7 +3452,7 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) DEBUG(3,("set_nt_acl: failed to set default acl on directory %s (%s).\n", fsp->fsp_name, strerror(errno) )); free_canon_ace_list(file_ace_list); free_canon_ace_list(dir_ace_list); - return False; + return map_nt_error_from_unix(errno); } } else { @@ -3256,7 +3477,7 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) DEBUG(3,("set_nt_acl: sys_acl_delete_def_file failed (%s)\n", strerror(errno))); free_canon_ace_list(file_ace_list); free_canon_ace_list(dir_ace_list); - return False; + return map_nt_error_from_unix(errno); } } } @@ -3279,7 +3500,7 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) free_canon_ace_list(dir_ace_list); DEBUG(3,("set_nt_acl: failed to convert file acl to posix permissions for file %s.\n", fsp->fsp_name )); - return False; + return NT_STATUS_ACCESS_DENIED; } if (orig_mode != posix_perms) { @@ -3304,7 +3525,7 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) fsp->fsp_name, (unsigned int)posix_perms, strerror(errno) )); free_canon_ace_list(file_ace_list); free_canon_ace_list(dir_ace_list); - return False; + return map_nt_error_from_unix(errno); } } } @@ -3315,20 +3536,7 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) free_canon_ace_list(dir_ace_list); } - /* Any chown pending? */ - if (need_chown) { - - DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n", - fsp->fsp_name, (unsigned int)user, (unsigned int)grp )); - - if(try_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) { - DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n", - fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) )); - return False; - } - } - - return True; + return NT_STATUS_OK; } /**************************************************************************** @@ -3524,10 +3732,10 @@ int fchmod_acl(files_struct *fsp, int fd, mode_t mode) Check for an existing default POSIX ACL on a directory. ****************************************************************************/ -BOOL directory_has_default_acl(connection_struct *conn, const char *fname) +bool directory_has_default_acl(connection_struct *conn, const char *fname) { SMB_ACL_T def_acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, SMB_ACL_TYPE_DEFAULT); - BOOL has_acl = False; + 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)) { @@ -3544,7 +3752,7 @@ BOOL directory_has_default_acl(connection_struct *conn, const char *fname) Map from wire type to permset. ****************************************************************************/ -static BOOL unix_ex_wire_to_permset(connection_struct *conn, unsigned char wire_perm, SMB_ACL_PERMSET_T *p_permset) +static bool unix_ex_wire_to_permset(connection_struct *conn, unsigned char wire_perm, SMB_ACL_PERMSET_T *p_permset) { if (wire_perm & ~(SMB_POSIX_ACL_READ|SMB_POSIX_ACL_WRITE|SMB_POSIX_ACL_EXECUTE)) { return False; @@ -3576,7 +3784,7 @@ static BOOL unix_ex_wire_to_permset(connection_struct *conn, unsigned char wire_ Map from wire type to tagtype. ****************************************************************************/ -static BOOL unix_ex_wire_to_tagtype(unsigned char wire_tt, SMB_ACL_TAG_T *p_tt) +static bool unix_ex_wire_to_tagtype(unsigned char wire_tt, SMB_ACL_TAG_T *p_tt) { switch (wire_tt) { case SMB_POSIX_ACL_USER_OBJ: @@ -3699,7 +3907,7 @@ static SMB_ACL_T create_posix_acl_from_wire(connection_struct *conn, uint16 num_ on the directory. ****************************************************************************/ -BOOL set_unix_posix_default_acl(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf, +bool set_unix_posix_default_acl(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf, uint16 num_def_acls, const char *pdata) { SMB_ACL_T def_acl = NULL; @@ -3744,12 +3952,12 @@ BOOL set_unix_posix_default_acl(connection_struct *conn, const char *fname, SMB_ FIXME ! How does the share mask/mode fit into this.... ? ****************************************************************************/ -static BOOL remove_posix_acl(connection_struct *conn, files_struct *fsp, const char *fname) +static bool remove_posix_acl(connection_struct *conn, files_struct *fsp, const char *fname) { SMB_ACL_T file_acl = NULL; int entry_id = SMB_ACL_FIRST_ENTRY; SMB_ACL_ENTRY_T entry; - BOOL ret = False; + 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_ENTRY_T user_ent = NULL; @@ -3882,7 +4090,7 @@ static BOOL remove_posix_acl(connection_struct *conn, files_struct *fsp, const c except SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER. ****************************************************************************/ -BOOL set_unix_posix_acl(connection_struct *conn, files_struct *fsp, const char *fname, uint16 num_acls, const char *pdata) +bool set_unix_posix_acl(connection_struct *conn, files_struct *fsp, const char *fname, uint16 num_acls, const char *pdata) { SMB_ACL_T file_acl = NULL; @@ -3917,463 +4125,25 @@ BOOL set_unix_posix_acl(connection_struct *conn, files_struct *fsp, const char * return True; } -/**************************************************************************** - Check for POSIX group ACLs. If none use stat entry. - Return -1 if no match, 0 if match and denied, 1 if match and allowed. -****************************************************************************/ - -static int check_posix_acl_group_access(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf, uint32 access_mask) -{ - SMB_ACL_T posix_acl = NULL; - int entry_id = SMB_ACL_FIRST_ENTRY; - SMB_ACL_ENTRY_T entry; - int i; - BOOL seen_mask = False; - BOOL seen_owning_group = False; - int ret = -1; - gid_t cu_gid; - - DEBUG(10,("check_posix_acl_group_access: requesting 0x%x on file %s\n", - (unsigned int)access_mask, fname )); - - if ((posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS)) == NULL) { - goto check_stat; - } - - /* First ensure the group mask allows group access. */ - /* Also check any user entries (these take preference over group). */ - - while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) { - SMB_ACL_TAG_T tagtype; - SMB_ACL_PERMSET_T permset; - int have_write = -1; - int have_read = -1; - - /* get_next... */ - if (entry_id == SMB_ACL_FIRST_ENTRY) - entry_id = SMB_ACL_NEXT_ENTRY; - - if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) { - goto check_stat; - } - - if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) { - goto check_stat; - } - - have_read = SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ); - if (have_read == -1) { - goto check_stat; - } - - have_write = SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE); - if (have_write == -1) { - goto check_stat; - } - - /* - * Solaris returns 2 for this if write is available. - * canonicalize to 0 or 1. - */ - have_write = (have_write ? 1 : 0); - have_read = (have_read ? 1 : 0); - - switch(tagtype) { - case SMB_ACL_MASK: - seen_mask = True; - switch (access_mask) { - case FILE_READ_DATA: - if (!have_read) { - ret = -1; - DEBUG(10,("check_posix_acl_group_access: file %s " - "refusing read due to mask.\n", fname)); - goto done; - } - break; - case FILE_WRITE_DATA: - if (!have_write) { - ret = -1; - DEBUG(10,("check_posix_acl_group_access: file %s " - "refusing write due to mask.\n", fname)); - goto done; - } - break; - default: /* FILE_READ_DATA|FILE_WRITE_DATA */ - if (!have_write || !have_read) { - ret = -1; - DEBUG(10,("check_posix_acl_group_access: file %s " - "refusing read/write due to mask.\n", fname)); - goto done; - } - break; - } - break; - case SMB_ACL_USER: - { - /* Check against current_user.ut.uid. */ - uid_t *puid = (uid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry); - if (puid == NULL) { - goto check_stat; - } - if (current_user.ut.uid == *puid) { - /* We have a uid match but we must ensure we have seen the acl mask. */ - switch (access_mask) { - case FILE_READ_DATA: - ret = have_read; - break; - case FILE_WRITE_DATA: - ret = have_write; - break; - default: /* FILE_READ_DATA|FILE_WRITE_DATA */ - ret = (have_write & have_read); - break; - } - DEBUG(10,("check_posix_acl_group_access: file %s " - "match on user %u -> %s.\n", - fname, (unsigned int)*puid, - ret ? "can access" : "cannot access")); - if (seen_mask) { - goto done; - } - } - break; - } - default: - continue; - } - } - - /* If ret is anything other than -1 we matched on a user entry. */ - if (ret != -1) { - goto done; - } - - /* Next check all group entries. */ - entry_id = SMB_ACL_FIRST_ENTRY; - while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) { - SMB_ACL_TAG_T tagtype; - SMB_ACL_PERMSET_T permset; - int have_write = -1; - int have_read = -1; - - /* get_next... */ - if (entry_id == SMB_ACL_FIRST_ENTRY) - entry_id = SMB_ACL_NEXT_ENTRY; - - if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) { - goto check_stat; - } - - if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) { - goto check_stat; - } - - have_read = SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ); - if (have_read == -1) { - goto check_stat; - } - - have_write = SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE); - if (have_write == -1) { - goto check_stat; - } - - /* - * Solaris returns 2 for this if write is available. - * canonicalize to 0 or 1. - */ - have_write = (have_write ? 1 : 0); - have_read = (have_read ? 1 : 0); - - switch(tagtype) { - case SMB_ACL_GROUP: - case SMB_ACL_GROUP_OBJ: - { - gid_t *pgid = NULL; - - if (tagtype == SMB_ACL_GROUP) { - pgid = (gid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry); - } else { - seen_owning_group = True; - pgid = &psbuf->st_gid; - } - if (pgid == NULL) { - goto check_stat; - } - - /* - * Does it match the current effective group - * or supplementary groups ? - */ - for (cu_gid = get_current_user_gid_first(&i); cu_gid != (gid_t)-1; - cu_gid = get_current_user_gid_next(&i)) { - if (cu_gid == *pgid) { - switch (access_mask) { - case FILE_READ_DATA: - ret = have_read; - break; - case FILE_WRITE_DATA: - ret = have_write; - break; - default: /* FILE_READ_DATA|FILE_WRITE_DATA */ - ret = (have_write & have_read); - break; - } - - DEBUG(10,("check_posix_acl_group_access: file %s " - "match on group %u -> can access.\n", - fname, (unsigned int)cu_gid )); - - /* If we don't have access permission this entry doesn't - terminate the enumeration of the entries. */ - if (ret) { - goto done; - } - /* But does terminate the group iteration. */ - break; - } - } - break; - } - default: - continue; - } - } - - /* If ret is -1 here we didn't match on the user entry or - supplemental group entries. */ - - DEBUG(10,("check_posix_acl_group_access: ret = %d before check_stat:\n", ret)); - - check_stat: - - /* - * We only check the S_I[RW]GRP permissions if we haven't already - * seen an owning group SMB_ACL_GROUP_OBJ ace entry. If there is an - * SMB_ACL_GROUP_OBJ ace entry then the group bits in st_gid are - * the same as the SMB_ACL_MASK bits, not the SMB_ACL_GROUP_OBJ - * bits. Thanks to Marc Cousin for pointing - * this out. JRA. - */ - - if (!seen_owning_group) { - /* Do we match on the owning group entry ? */ - /* - * Does it match the current effective group - * or supplementary groups ? - */ - for (cu_gid = get_current_user_gid_first(&i); cu_gid != (gid_t)-1; - cu_gid = get_current_user_gid_next(&i)) { - if (cu_gid == psbuf->st_gid) { - switch (access_mask) { - case FILE_READ_DATA: - ret = (psbuf->st_mode & S_IRGRP) ? 1 : 0; - break; - case FILE_WRITE_DATA: - ret = (psbuf->st_mode & S_IWGRP) ? 1 : 0; - break; - default: /* FILE_READ_DATA|FILE_WRITE_DATA */ - if ((psbuf->st_mode & (S_IWGRP|S_IRGRP)) == (S_IWGRP|S_IRGRP)) { - ret = 1; - } else { - ret = 0; - } - break; - } - DEBUG(10,("check_posix_acl_group_access: file %s " - "match on owning group %u -> %s.\n", - fname, (unsigned int)psbuf->st_gid, - ret ? "can access" : "cannot access")); - break; - } - } - - if (cu_gid == (gid_t)-1) { - DEBUG(10,("check_posix_acl_group_access: file %s " - "failed to match on user or group in token (ret = %d).\n", - fname, ret )); - } - } - - done: - - if (posix_acl) { - SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl); - } - - DEBUG(10,("check_posix_acl_group_access: file %s returning (ret = %d).\n", fname, ret )); - return ret; -} - -/**************************************************************************** - Actually emulate the in-kernel access checking for delete access. We need - this to successfully return ACCESS_DENIED on a file open for delete access. -****************************************************************************/ - -BOOL can_delete_file_in_directory(connection_struct *conn, const char *fname) -{ - SMB_STRUCT_STAT sbuf; - pstring dname; - int ret; - - if (!CAN_WRITE(conn)) { - return False; - } - - /* Get the parent directory permission mask and owners. */ - pstrcpy(dname, parent_dirname(fname)); - if(SMB_VFS_STAT(conn, dname, &sbuf) != 0) { - return False; - } - if (!S_ISDIR(sbuf.st_mode)) { - return False; - } - if (current_user.ut.uid == 0 || conn->admin_user) { - /* I'm sorry sir, I didn't know you were root... */ - return True; - } - - /* Check primary owner write access. */ - if (current_user.ut.uid == sbuf.st_uid) { - return (sbuf.st_mode & S_IWUSR) ? True : False; - } - -#ifdef S_ISVTX - /* sticky bit means delete only by owner or root. */ - if (sbuf.st_mode & S_ISVTX) { - SMB_STRUCT_STAT sbuf_file; - if(SMB_VFS_STAT(conn, fname, &sbuf_file) != 0) { - if (errno == ENOENT) { - /* If the file doesn't already exist then - * yes we'll be able to delete it. */ - return True; - } - return False; - } - /* - * Patch from SATOH Fumiyasu - * for bug #3348. Don't assume owning sticky bit - * directory means write access allowed. - */ - if (current_user.ut.uid != sbuf_file.st_uid) { - return False; - } - } -#endif - - /* Check group or explicit user acl entry write access. */ - ret = check_posix_acl_group_access(conn, dname, &sbuf, FILE_WRITE_DATA); - if (ret == 0 || ret == 1) { - return ret ? True : False; - } - - /* Finally check other write access. */ - return (sbuf.st_mode & S_IWOTH) ? True : False; -} - -/**************************************************************************** - Actually emulate the in-kernel access checking for read/write access. We need - this to successfully check for ability to write for dos filetimes. - Note this doesn't take into account share write permissions. -****************************************************************************/ - -BOOL can_access_file(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf, uint32 access_mask) -{ - int ret; - - if (!(access_mask & (FILE_READ_DATA|FILE_WRITE_DATA))) { - return False; - } - access_mask &= (FILE_READ_DATA|FILE_WRITE_DATA); - - DEBUG(10,("can_access_file: requesting 0x%x on file %s\n", - (unsigned int)access_mask, fname )); - - if (current_user.ut.uid == 0 || conn->admin_user) { - /* I'm sorry sir, I didn't know you were root... */ - return True; - } - - if (!VALID_STAT(*psbuf)) { - /* Get the file permission mask and owners. */ - if(SMB_VFS_STAT(conn, fname, psbuf) != 0) { - return False; - } - } - - /* Check primary owner access. */ - if (current_user.ut.uid == psbuf->st_uid) { - switch (access_mask) { - case FILE_READ_DATA: - return (psbuf->st_mode & S_IRUSR) ? True : False; - - case FILE_WRITE_DATA: - return (psbuf->st_mode & S_IWUSR) ? True : False; - - default: /* FILE_READ_DATA|FILE_WRITE_DATA */ - - if ((psbuf->st_mode & (S_IWUSR|S_IRUSR)) == (S_IWUSR|S_IRUSR)) { - return True; - } else { - return False; - } - } - } - - /* Check group or explicit user acl entry access. */ - ret = check_posix_acl_group_access(conn, fname, psbuf, access_mask); - if (ret == 0 || ret == 1) { - return ret ? True : False; - } - - /* Finally check other access. */ - switch (access_mask) { - case FILE_READ_DATA: - return (psbuf->st_mode & S_IROTH) ? True : False; - - case FILE_WRITE_DATA: - return (psbuf->st_mode & S_IWOTH) ? True : False; - - default: /* FILE_READ_DATA|FILE_WRITE_DATA */ - - if ((psbuf->st_mode & (S_IWOTH|S_IROTH)) == (S_IWOTH|S_IROTH)) { - return True; - } - } - return False; -} - -/**************************************************************************** - Userspace check for write access. - Note this doesn't take into account share write permissions. -****************************************************************************/ - -BOOL can_write_to_file(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf) -{ - return can_access_file(conn, fname, psbuf, FILE_WRITE_DATA); -} - /******************************************************************** Pull the NT ACL from a file on disk or the OpenEventlog() access 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(). - + Assume we are dealing with files (for now) ********************************************************************/ -SEC_DESC* get_nt_acl_no_snum( TALLOC_CTX *ctx, const char *fname) +SEC_DESC *get_nt_acl_no_snum( TALLOC_CTX *ctx, const char *fname) { SEC_DESC *psd, *ret_sd; connection_struct conn; files_struct finfo; struct fd_handle fh; - pstring path; - pstring filename; - + ZERO_STRUCT( conn ); - + if ( !(conn.mem_ctx = talloc_init( "novfs_get_nt_acl" )) ) { DEBUG(0,("get_nt_acl_no_snum: talloc() failed!\n")); return NULL; @@ -4386,35 +4156,33 @@ SEC_DESC* get_nt_acl_no_snum( TALLOC_CTX *ctx, const char *fname) } conn.params->service = -1; - - pstrcpy( path, "/" ); - set_conn_connectpath(&conn, path); - + + 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_internal( &conn ); return NULL; } - + ZERO_STRUCT( finfo ); ZERO_STRUCT( fh ); - + finfo.fnum = -1; finfo.conn = &conn; finfo.fh = &fh; finfo.fh->fd = -1; - pstrcpy( filename, fname ); - finfo.fsp_name = filename; - + finfo.fsp_name = CONST_DISCARD(char *,fname); + if (get_nt_acl( &finfo, DACL_SECURITY_INFORMATION, &psd ) == 0) { DEBUG(0,("get_nt_acl_no_snum: get_nt_acl returned zero.\n")); conn_free_internal( &conn ); return NULL; } - + ret_sd = dup_sec_desc( ctx, psd ); - + conn_free_internal( &conn ); - + return ret_sd; }