diff options
author | Simo Sorce <idra@samba.org> | 2008-02-01 14:24:31 -0500 |
---|---|---|
committer | Simo Sorce <idra@samba.org> | 2008-02-01 14:24:31 -0500 |
commit | 2fffc9a1b1fe2a1490e867bb38462e50c282d2b3 (patch) | |
tree | 428e09c9b35138db8b7ca7161c659a71aa129d29 /source3/smbd/posix_acls.c | |
parent | 93a3c5b3f9927973b4ad1496f593ea147052d1e1 (diff) | |
parent | b708005a7106db26d7df689b887b419c9f2ea41c (diff) | |
download | samba-2fffc9a1b1fe2a1490e867bb38462e50c282d2b3.tar.gz samba-2fffc9a1b1fe2a1490e867bb38462e50c282d2b3.tar.bz2 samba-2fffc9a1b1fe2a1490e867bb38462e50c282d2b3.zip |
Merge branch 'v3-2-test' of ssh://git.samba.org/data/git/samba into v3-2-test
(This used to be commit 7dbfc7bdc65314466a83e8121b35c9bcb24b2631)
Diffstat (limited to 'source3/smbd/posix_acls.c')
-rw-r--r-- | source3/smbd/posix_acls.c | 521 |
1 files changed, 326 insertions, 195 deletions
diff --git a/source3/smbd/posix_acls.c b/source3/smbd/posix_acls.c index ccfed69721..f60329a039 100644 --- a/source3/smbd/posix_acls.c +++ b/source3/smbd/posix_acls.c @@ -229,7 +229,7 @@ static void store_inheritance_attributes(files_struct *fsp, canon_ace *file_ace_ if (!pai_protected && num_inherited_entries(file_ace_list) == 0 && num_inherited_entries(dir_ace_list) == 0) { /* Instead just remove the attribute if it exists. */ if (fsp->fh->fd != -1) - SMB_VFS_FREMOVEXATTR(fsp, fsp->fh->fd, SAMBA_POSIX_INHERITANCE_EA_NAME); + SMB_VFS_FREMOVEXATTR(fsp, SAMBA_POSIX_INHERITANCE_EA_NAME); else SMB_VFS_REMOVEXATTR(fsp->conn, fsp->fsp_name, SAMBA_POSIX_INHERITANCE_EA_NAME); return; @@ -238,7 +238,7 @@ static void store_inheritance_attributes(files_struct *fsp, canon_ace *file_ace_ pai_buf = create_pai_buf(file_ace_list, dir_ace_list, pai_protected, &store_size); if (fsp->fh->fd != -1) - ret = SMB_VFS_FSETXATTR(fsp, fsp->fh->fd, SAMBA_POSIX_INHERITANCE_EA_NAME, + ret = SMB_VFS_FSETXATTR(fsp, SAMBA_POSIX_INHERITANCE_EA_NAME, pai_buf, store_size, 0); else ret = SMB_VFS_SETXATTR(fsp->conn,fsp->fsp_name, SAMBA_POSIX_INHERITANCE_EA_NAME, @@ -430,7 +430,7 @@ static struct pai_val *create_pai_val(char *buf, size_t size) Load the user.SAMBA_PAI attribute. ************************************************************************/ -static struct pai_val *load_inherited_info(files_struct *fsp) +static struct pai_val *fload_inherited_info(files_struct *fsp) { char *pai_buf; size_t pai_buf_size = 1024; @@ -445,7 +445,7 @@ static struct pai_val *load_inherited_info(files_struct *fsp) do { if (fsp->fh->fd != -1) - ret = SMB_VFS_FGETXATTR(fsp, fsp->fh->fd, SAMBA_POSIX_INHERITANCE_EA_NAME, + ret = SMB_VFS_FGETXATTR(fsp, SAMBA_POSIX_INHERITANCE_EA_NAME, pai_buf, pai_buf_size); else ret = SMB_VFS_GETXATTR(fsp->conn,fsp->fsp_name,SAMBA_POSIX_INHERITANCE_EA_NAME, @@ -490,6 +490,71 @@ static struct pai_val *load_inherited_info(files_struct *fsp) return paiv; } +/************************************************************************ + Load the user.SAMBA_PAI attribute. +************************************************************************/ + +static struct pai_val *load_inherited_info(const struct connection_struct *conn, + const char *fname) +{ + char *pai_buf; + size_t pai_buf_size = 1024; + struct pai_val *paiv = NULL; + ssize_t ret; + + if (!lp_map_acl_inherit(SNUM(conn))) { + return NULL; + } + + if ((pai_buf = (char *)SMB_MALLOC(pai_buf_size)) == NULL) { + return NULL; + } + + do { + ret = SMB_VFS_GETXATTR(conn, fname, + SAMBA_POSIX_INHERITANCE_EA_NAME, + pai_buf, pai_buf_size); + + if (ret == -1) { + if (errno != ERANGE) { + break; + } + /* Buffer too small - enlarge it. */ + pai_buf_size *= 2; + SAFE_FREE(pai_buf); + if (pai_buf_size > 1024*1024) { + return NULL; /* Limit malloc to 1mb. */ + } + if ((pai_buf = (char *)SMB_MALLOC(pai_buf_size)) == NULL) + return NULL; + } + } while (ret == -1); + + DEBUG(10,("load_inherited_info: ret = %lu for file %s\n", (unsigned long)ret, fname)); + + if (ret == -1) { + /* No attribute or not supported. */ +#if defined(ENOATTR) + if (errno != ENOATTR) + DEBUG(10,("load_inherited_info: Error %s\n", strerror(errno) )); +#else + if (errno != ENOSYS) + DEBUG(10,("load_inherited_info: Error %s\n", strerror(errno) )); +#endif + SAFE_FREE(pai_buf); + return NULL; + } + + paiv = create_pai_val(pai_buf, ret); + + if (paiv && paiv->pai_protected) { + DEBUG(10,("load_inherited_info: ACL is protected for file %s\n", fname)); + } + + SAFE_FREE(pai_buf); + return paiv; +} + /**************************************************************************** Functions to manipulate the internal ACE format. ****************************************************************************/ @@ -826,7 +891,7 @@ static bool nt4_compatible_acls(void) ****************************************************************************/ static SEC_ACCESS map_canon_ace_perms(int snum, - int *pacl_type, + enum security_ace_type *pacl_type, mode_t perms, bool directory_ace) { @@ -999,20 +1064,21 @@ NTSTATUS unpack_nt_owners(int snum, uid_t *puser, gid_t *pgrp, uint32 security_i Ensure the enforced permissions for this share apply. ****************************************************************************/ -static void apply_default_perms(const files_struct *fsp, canon_ace *pace, mode_t type) +static void apply_default_perms(const struct share_params *params, + const bool is_directory, canon_ace *pace, + mode_t type) { - int snum = SNUM(fsp->conn); mode_t and_bits = (mode_t)0; mode_t or_bits = (mode_t)0; /* Get the initial bits to apply. */ - if (fsp->is_directory) { - and_bits = lp_dir_security_mask(snum); - or_bits = lp_force_dir_security_mode(snum); + if (is_directory) { + and_bits = lp_dir_security_mask(params->service); + or_bits = lp_force_dir_security_mode(params->service); } else { - and_bits = lp_security_mask(snum); - or_bits = lp_force_security_mode(snum); + and_bits = lp_security_mask(params->service); + or_bits = lp_force_security_mode(params->service); } /* Now bounce them into the S_USR space. */ @@ -1020,7 +1086,7 @@ static void apply_default_perms(const files_struct *fsp, canon_ace *pace, mode_t case S_IRUSR: /* Ensure owner has read access. */ pace->perms |= S_IRUSR; - if (fsp->is_directory) + if (is_directory) pace->perms |= (S_IWUSR|S_IXUSR); and_bits = unix_perms_to_acl_perms(and_bits, S_IRUSR, S_IWUSR, S_IXUSR); or_bits = unix_perms_to_acl_perms(or_bits, S_IRUSR, S_IWUSR, S_IXUSR); @@ -1076,7 +1142,8 @@ static bool uid_entry_in_group( canon_ace *uid_ace, canon_ace *group_ace ) ****************************************************************************/ static bool ensure_canon_entry_valid(canon_ace **pp_ace, - const files_struct *fsp, + const struct share_params *params, + const bool is_directory, const DOM_SID *pfile_owner_sid, const DOM_SID *pfile_grp_sid, const SMB_STRUCT_STAT *pst, @@ -1092,7 +1159,7 @@ static bool ensure_canon_entry_valid(canon_ace **pp_ace, if (pace->type == SMB_ACL_USER_OBJ) { if (setting_acl) - apply_default_perms(fsp, pace, S_IRUSR); + apply_default_perms(params, is_directory, pace, S_IRUSR); got_user = True; } else if (pace->type == SMB_ACL_GROUP_OBJ) { @@ -1102,7 +1169,7 @@ static bool ensure_canon_entry_valid(canon_ace **pp_ace, */ if (setting_acl) - apply_default_perms(fsp, pace, S_IRGRP); + apply_default_perms(params, is_directory, pace, S_IRGRP); got_grp = True; } else if (pace->type == SMB_ACL_OTHER) { @@ -1112,7 +1179,7 @@ static bool ensure_canon_entry_valid(canon_ace **pp_ace, */ if (setting_acl) - apply_default_perms(fsp, pace, S_IROTH); + apply_default_perms(params, is_directory, pace, S_IROTH); got_other = True; pace_other = pace; } @@ -1155,7 +1222,7 @@ static bool ensure_canon_entry_valid(canon_ace **pp_ace, pace->perms = 0; } - apply_default_perms(fsp, pace, S_IRUSR); + apply_default_perms(params, is_directory, pace, S_IRUSR); } else { pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRUSR, S_IWUSR, S_IXUSR); } @@ -1181,7 +1248,7 @@ static bool ensure_canon_entry_valid(canon_ace **pp_ace, pace->perms = pace_other->perms; else pace->perms = 0; - apply_default_perms(fsp, pace, S_IRGRP); + apply_default_perms(params, is_directory, pace, S_IRGRP); } else { pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRGRP, S_IWGRP, S_IXGRP); } @@ -1203,7 +1270,7 @@ static bool ensure_canon_entry_valid(canon_ace **pp_ace, pace->attr = ALLOW_ACE; if (setting_acl) { pace->perms = 0; - apply_default_perms(fsp, pace, S_IROTH); + apply_default_perms(params, is_directory, pace, S_IROTH); } else pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IROTH, S_IWOTH, S_IXOTH); @@ -1341,12 +1408,12 @@ static bool create_canon_ace_lists(files_struct *fsp, SMB_STRUCT_STAT *pst, psa1->flags |= (psa2->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT)); psa2->flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT); - + } else if (psa2->flags & SEC_ACE_FLAG_INHERIT_ONLY) { psa2->flags |= (psa1->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT)); psa1->flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT); - + } } } @@ -1407,10 +1474,22 @@ static bool create_canon_ace_lists(files_struct *fsp, SMB_STRUCT_STAT *pst, } else if (sid_to_uid( ¤t_ace->trustee, ¤t_ace->unix_ug.uid)) { current_ace->owner_type = UID_ACE; - current_ace->type = SMB_ACL_USER; + /* If it's the owning user, this is a user_obj, not + * a user. */ + if (current_ace->unix_ug.uid == pst->st_uid) { + current_ace->type = SMB_ACL_USER_OBJ; + } else { + current_ace->type = SMB_ACL_USER; + } } else if (sid_to_gid( ¤t_ace->trustee, ¤t_ace->unix_ug.gid)) { current_ace->owner_type = GID_ACE; - current_ace->type = SMB_ACL_GROUP; + /* If it's the primary group, this is a group_obj, not + * a group. */ + if (current_ace->unix_ug.gid == pst->st_gid) { + current_ace->type = SMB_ACL_GROUP_OBJ; + } else { + current_ace->type = SMB_ACL_GROUP; + } } else { /* * Silently ignore map failures in non-mappable SIDs (NT Authority, BUILTIN etc). @@ -2014,7 +2093,7 @@ static bool unpack_canon_ace(files_struct *fsp, pst->st_mode = create_default_mode(fsp, False); - if (!ensure_canon_entry_valid(&file_ace, fsp, pfile_owner_sid, pfile_grp_sid, pst, True)) { + if (!ensure_canon_entry_valid(&file_ace, fsp->conn->params, fsp->is_directory, pfile_owner_sid, pfile_grp_sid, pst, True)) { free_canon_ace_list(file_ace); free_canon_ace_list(dir_ace); return False; @@ -2030,7 +2109,7 @@ static bool unpack_canon_ace(files_struct *fsp, pst->st_mode = create_default_mode(fsp, True); - if (dir_ace && !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->conn->params, fsp->is_directory, pfile_owner_sid, pfile_grp_sid, pst, True)) { free_canon_ace_list(file_ace); free_canon_ace_list(dir_ace); return False; @@ -2108,10 +2187,11 @@ static void arrange_posix_perms(const char *filename, canon_ace **pp_list_head) Create a linked list of canonical ACE entries. ****************************************************************************/ -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) +static canon_ace *canonicalise_acl(struct connection_struct *conn, + const char *fname, SMB_ACL_T posix_acl, + const SMB_STRUCT_STAT *psbuf, + const DOM_SID *powner, const DOM_SID *pgroup, struct pai_val *pal, SMB_ACL_TYPE_T the_acl_type) { - connection_struct *conn = fsp->conn; mode_t acl_mask = (S_IRUSR|S_IWUSR|S_IXUSR); canon_ace *list_head = NULL; canon_ace *ace = NULL; @@ -2226,7 +2306,9 @@ static canon_ace *canonicalise_acl( const files_struct *fsp, SMB_ACL_T posix_acl * This next call will ensure we have at least a user/group/world set. */ - if (!ensure_canon_entry_valid(&list_head, fsp, powner, pgroup, psbuf, False)) + if (!ensure_canon_entry_valid(&list_head, conn->params, + S_ISDIR(psbuf->st_mode), powner, pgroup, + psbuf, False)) goto fail; /* @@ -2252,7 +2334,7 @@ static canon_ace *canonicalise_acl( const files_struct *fsp, SMB_ACL_T posix_acl } } - arrange_posix_perms(fsp->fsp_name,&list_head ); + arrange_posix_perms(fname,&list_head ); print_canon_ace_list( "canonicalise_acl: ace entries after arrange", list_head ); @@ -2503,7 +2585,7 @@ static bool set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, bool defau } } } else { - if (SMB_VFS_SYS_ACL_SET_FD(fsp, fsp->fh->fd, the_acl) == -1) { + if (SMB_VFS_SYS_ACL_SET_FD(fsp, the_acl) == -1) { /* * Some systems allow all the above calls and only fail with no ACL support * when attempting to apply the acl. HPUX with HFS is an example of this. JRA. @@ -2519,7 +2601,7 @@ static bool set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, bool defau fsp->fsp_name )); become_root(); - sret = SMB_VFS_SYS_ACL_SET_FD(fsp, fsp->fh->fd, the_acl); + sret = SMB_VFS_SYS_ACL_SET_FD(fsp, the_acl); unbecome_root(); if (sret == 0) { ret = True; @@ -2719,6 +2801,7 @@ static size_t merge_default_aces( SEC_ACE *nt_ace_list, size_t num_aces) return num_aces; } + /**************************************************************************** Reply to query a security descriptor from an fsp. If it succeeds it allocates the space for the return elements and returns the size needed to return the @@ -2726,11 +2809,15 @@ static size_t merge_default_aces( SEC_ACE *nt_ace_list, size_t num_aces) the UNIX style get ACL. ****************************************************************************/ -NTSTATUS get_nt_acl(files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc) +static NTSTATUS posix_get_nt_acl_common(struct connection_struct *conn, + const char *name, + const SMB_STRUCT_STAT *sbuf, + struct pai_val *pal, + SMB_ACL_T posix_acl, + SMB_ACL_T def_acl, + uint32_t security_info, + SEC_DESC **ppdesc) { - connection_struct *conn = fsp->conn; - SMB_STRUCT_STAT sbuf; - SEC_ACE *nt_ace_list = NULL; DOM_SID owner_sid; DOM_SID group_sid; size_t sd_size = 0; @@ -2738,57 +2825,12 @@ NTSTATUS get_nt_acl(files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc) size_t num_acls = 0; size_t num_def_acls = 0; size_t num_aces = 0; - SMB_ACL_T posix_acl = NULL; - SMB_ACL_T def_acl = NULL; canon_ace *file_ace = NULL; canon_ace *dir_ace = NULL; + SEC_ACE *nt_ace_list = NULL; size_t num_profile_acls = 0; - struct pai_val *pal = NULL; SEC_DESC *psd = NULL; - *ppdesc = NULL; - - DEBUG(10,("get_nt_acl: called for file %s\n", fsp->fsp_name )); - - if(fsp->is_directory || fsp->fh->fd == -1) { - - /* Get the stat struct for the owner info. */ - if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0) { - return map_nt_error_from_unix(errno); - } - /* - * Get the ACL from the path. - */ - - posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_ACCESS); - - /* - * If it's a directory get the default POSIX ACL. - */ - - if(fsp->is_directory) { - def_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_DEFAULT); - def_acl = free_empty_sys_acl(conn, def_acl); - } - - } else { - - /* Get the stat struct for the owner info. */ - if(SMB_VFS_FSTAT(fsp,fsp->fh->fd,&sbuf) != 0) { - return map_nt_error_from_unix(errno); - } - /* - * Get the ACL from the fd. - */ - posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fsp->fh->fd); - } - - DEBUG(5,("get_nt_acl : file ACL %s, directory ACL %s\n", - posix_acl ? "present" : "absent", - def_acl ? "present" : "absent" )); - - pal = load_inherited_info(fsp); - /* * Get the owner, group and world SIDs. */ @@ -2799,7 +2841,7 @@ NTSTATUS get_nt_acl(files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc) sid_copy(&group_sid, &global_sid_Builtin_Users); num_profile_acls = 2; } else { - create_file_sids(&sbuf, &owner_sid, &group_sid); + create_file_sids(sbuf, &owner_sid, &group_sid); } if ((security_info & DACL_SECURITY_INFORMATION) && !(security_info & PROTECTED_DACL_SECURITY_INFORMATION)) { @@ -2814,19 +2856,23 @@ NTSTATUS get_nt_acl(files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc) */ /* Create the canon_ace lists. */ - file_ace = canonicalise_acl( fsp, posix_acl, &sbuf, &owner_sid, &group_sid, pal, SMB_ACL_TYPE_ACCESS ); + file_ace = canonicalise_acl(conn, name, posix_acl, sbuf, + &owner_sid, &group_sid, pal, + SMB_ACL_TYPE_ACCESS); /* We must have *some* ACLS. */ if (count_canon_ace_list(file_ace) == 0) { - DEBUG(0,("get_nt_acl : No ACLs on file (%s) !\n", fsp->fsp_name )); + DEBUG(0,("get_nt_acl : No ACLs on file (%s) !\n", name)); goto done; } - if (fsp->is_directory && def_acl) { - dir_ace = canonicalise_acl(fsp, def_acl, &sbuf, - &global_sid_Creator_Owner, - &global_sid_Creator_Group, pal, SMB_ACL_TYPE_DEFAULT ); + if (S_ISDIR(sbuf->st_mode) && def_acl) { + dir_ace = canonicalise_acl(conn, name, def_acl, + sbuf, + &global_sid_Creator_Owner, + &global_sid_Creator_Group, + pal, SMB_ACL_TYPE_DEFAULT); } /* @@ -2835,7 +2881,7 @@ NTSTATUS get_nt_acl(files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc) { canon_ace *ace; - int nt_acl_type; + enum security_ace_type nt_acl_type; int i; if (nt4_compatible_acls() && dir_ace) { @@ -2910,7 +2956,7 @@ NTSTATUS get_nt_acl(files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc) acc = map_canon_ace_perms(SNUM(conn), &nt_acl_type, ace->perms, - fsp->is_directory); + S_ISDIR(sbuf->st_mode)); init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, @@ -2939,7 +2985,7 @@ NTSTATUS get_nt_acl(files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc) acc = map_canon_ace_perms(SNUM(conn), &nt_acl_type, ace->perms, - fsp->is_directory); + S_ISDIR(sbuf->st_mode)); init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, @@ -3028,6 +3074,69 @@ NTSTATUS get_nt_acl(files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc) return NT_STATUS_OK; } +NTSTATUS posix_fget_nt_acl(struct files_struct *fsp, uint32_t security_info, + SEC_DESC **ppdesc) +{ + SMB_STRUCT_STAT sbuf; + SMB_ACL_T posix_acl = NULL; + struct pai_val *pal; + + *ppdesc = NULL; + + DEBUG(10,("posix_fget_nt_acl: called for file %s\n", fsp->fsp_name )); + + /* can it happen that fsp_name == NULL ? */ + if (fsp->is_directory || fsp->fh->fd == -1) { + return posix_get_nt_acl(fsp->conn, fsp->fsp_name, + security_info, ppdesc); + } + + /* Get the stat struct for the owner info. */ + if(SMB_VFS_FSTAT(fsp, &sbuf) != 0) { + return map_nt_error_from_unix(errno); + } + + /* Get the ACL from the fd. */ + posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp); + + pal = fload_inherited_info(fsp); + + return posix_get_nt_acl_common(fsp->conn, fsp->fsp_name, &sbuf, pal, + posix_acl, NULL, security_info, ppdesc); +} + +NTSTATUS posix_get_nt_acl(struct connection_struct *conn, const char *name, + uint32_t security_info, SEC_DESC **ppdesc) +{ + SMB_STRUCT_STAT sbuf; + SMB_ACL_T posix_acl = NULL; + SMB_ACL_T def_acl = NULL; + struct pai_val *pal; + + *ppdesc = NULL; + + DEBUG(10,("posix_get_nt_acl: called for file %s\n", name )); + + /* Get the stat struct for the owner info. */ + if(SMB_VFS_STAT(conn, name, &sbuf) != 0) { + return map_nt_error_from_unix(errno); + } + + /* Get the ACL from the path. */ + posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, name, SMB_ACL_TYPE_ACCESS); + + /* If it's a directory get the default POSIX ACL. */ + if(S_ISDIR(sbuf.st_mode)) { + def_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, name, SMB_ACL_TYPE_DEFAULT); + def_acl = free_empty_sys_acl(conn, def_acl); + } + + pal = load_inherited_info(conn, name); + + return posix_get_nt_acl_common(conn, name, &sbuf, pal, posix_acl, + def_acl, security_info, ppdesc); +} + /**************************************************************************** Try to chown a file. We will be able to chown it under the following conditions. @@ -3097,7 +3206,7 @@ int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_t gid) become_root(); /* Keep the current file gid the same. */ - ret = SMB_VFS_FCHOWN(fsp, fsp->fh->fd, uid, (gid_t)-1); + ret = SMB_VFS_FCHOWN(fsp, uid, (gid_t)-1); unbecome_root(); close_file_fchmod(fsp); @@ -3105,57 +3214,8 @@ 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 + Take care of parent ACL inheritance. ****************************************************************************/ static NTSTATUS append_parent_acl(files_struct *fsp, @@ -3173,7 +3233,7 @@ static NTSTATUS append_parent_acl(files_struct *fsp, NTSTATUS status; int info; unsigned int i, j; - mode_t unx_mode; + bool is_dacl_protected = (psd->type & SE_DESC_DACL_PROTECTED); ZERO_STRUCT(sbuf); @@ -3188,12 +3248,6 @@ static NTSTATUS append_parent_acl(files_struct *fsp, 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, @@ -3210,7 +3264,7 @@ static NTSTATUS append_parent_acl(files_struct *fsp, return status; } - status = SMB_VFS_GET_NT_ACL(parent_fsp, parent_fsp->fsp_name, + status = SMB_VFS_GET_NT_ACL(parent_fsp->conn, parent_fsp->fsp_name, DACL_SECURITY_INFORMATION, &parent_sd ); close_file(parent_fsp, NORMAL_CLOSE); @@ -3221,20 +3275,23 @@ static NTSTATUS append_parent_acl(files_struct *fsp, /* * Make room for potentially all the ACLs from - * the parent, plus the user/group/other triple. + * the parent. We used to add the ugw triple here, + * as we knew we were dealing with POSIX ACLs. + * We no longer need to do so as we can guarentee + * that a default ACL from the parent directory will + * be well formed for POSIX ACLs if it came from a + * POSIX ACL source, and if we're not writing to a + * POSIX ACL sink then we don't care if it's not well + * formed. JRA. */ - num_aces += parent_sd->dacl->num_aces + 3; + num_aces += parent_sd->dacl->num_aces; 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]); @@ -3245,49 +3302,95 @@ static NTSTATUS append_parent_acl(files_struct *fsp, * 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. */ + if (!(se->flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) { + /* Doesn't apply to a directory - ignore. */ + DEBUG(10,("append_parent_acl: directory %s " + "ignoring non container " + "inherit flags %u on ACE with sid %s " + "from parent %s\n", + fsp->fsp_name, + (unsigned int)se->flags, + sid_string_dbg(&se->trustee), + parent_name)); 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. */ + if (!(se->flags & SEC_ACE_FLAG_OBJECT_INHERIT)) { + /* Doesn't apply to a file - ignore. */ + DEBUG(10,("append_parent_acl: file %s " + "ignoring non object " + "inherit flags %u on ACE with sid %s " + "from parent %s\n", + fsp->fsp_name, + (unsigned int)se->flags, + sid_string_dbg(&se->trustee), + parent_name)); + continue; + } + } + + if (is_dacl_protected) { + /* If the DACL is protected it means we must + * not overwrite an existing ACE entry with the + * same SID. This is order N^2. Ouch :-(. JRA. */ + unsigned int k; + for (k = 0; k < psd->dacl->num_aces; k++) { + if (sid_equal(&psd->dacl->aces[k].trustee, + &se->trustee)) { + break; + } + } + if (k < psd->dacl->num_aces) { + /* SID matched. Ignore. */ + DEBUG(10,("append_parent_acl: path %s " + "ignoring ACE with protected sid %s " + "from parent %s\n", + fsp->fsp_name, + sid_string_dbg(&se->trustee), + parent_name)); 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; + + if (fsp->is_directory) { + /* + * Strip off any inherit only. It's applied. + */ + new_ace[i].flags &= ~(SEC_ACE_FLAG_INHERIT_ONLY); + if (se->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) { + /* No further inheritance. */ + new_ace[i].flags &= + ~(SEC_ACE_FLAG_CONTAINER_INHERIT| + SEC_ACE_FLAG_OBJECT_INHERIT); + } + } else { + /* + * Strip off any container or inherit + * flags, they can't apply to objects. + */ + new_ace[i].flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT| + SEC_ACE_FLAG_INHERIT_ONLY| + SEC_ACE_FLAG_NO_PROPAGATE_INHERIT); + } i++; + + DEBUG(10,("append_parent_acl: path %s " + "inheriting ACE with sid %s " + "from parent %s\n", + fsp->fsp_name, + sid_string_dbg(&se->trustee), + parent_name)); } parent_sd->dacl->aces = new_ace; @@ -3316,6 +3419,9 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) bool acl_perms = False; mode_t orig_mode = (mode_t)0; NTSTATUS status; + uid_t orig_uid; + gid_t orig_gid; + bool need_chown = False; DEBUG(10,("set_nt_acl: called for file %s\n", fsp->fsp_name )); @@ -3332,12 +3438,14 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0) return map_nt_error_from_unix(errno); } else { - if(SMB_VFS_FSTAT(fsp,fsp->fh->fd,&sbuf) != 0) + if(SMB_VFS_FSTAT(fsp, &sbuf) != 0) 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. @@ -3352,7 +3460,11 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) * Do we need to chown ? */ - if (((user != (uid_t)-1) && (sbuf.st_uid != user)) || (( grp != (gid_t)-1) && (sbuf.st_gid != grp))) { + if (((user != (uid_t)-1) && (orig_uid != user)) || (( grp != (gid_t)-1) && (orig_gid != grp))) { + need_chown = True; + } + + if (need_chown && (user == (uid_t)-1 || user == current_user.ut.uid)) { DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n", fsp->fsp_name, (unsigned int)user, (unsigned int)grp )); @@ -3382,7 +3494,7 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) 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); + ret = SMB_VFS_FSTAT(fsp, &sbuf); if(ret != 0) return map_nt_error_from_unix(errno); @@ -3390,6 +3502,11 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) /* Save the original elements we check against. */ orig_mode = sbuf.st_mode; + orig_uid = sbuf.st_uid; + orig_gid = sbuf.st_gid; + + /* We did chown already, drop the flag */ + need_chown = False; } create_file_sids(&sbuf, &file_owner_sid, &file_grp_sid); @@ -3533,6 +3650,21 @@ NTSTATUS 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) )); + if (errno == EPERM) { + return NT_STATUS_INVALID_OWNER; + } + return map_nt_error_from_unix(errno); + } + } + return NT_STATUS_OK; } @@ -3705,19 +3837,19 @@ int inherit_access_acl(connection_struct *conn, const char *inherit_from_dir, and set the mask to rwx. Needed to preserve complex ACLs set by NT. ****************************************************************************/ -int fchmod_acl(files_struct *fsp, int fd, mode_t mode) +int fchmod_acl(files_struct *fsp, mode_t mode) { connection_struct *conn = fsp->conn; SMB_ACL_T posix_acl = NULL; int ret = -1; - if ((posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fd)) == NULL) + if ((posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp)) == NULL) return -1; if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1) goto done; - ret = SMB_VFS_SYS_ACL_SET_FD(fsp, fd, posix_acl); + ret = SMB_VFS_SYS_ACL_SET_FD(fsp, posix_acl); done: @@ -4002,7 +4134,7 @@ static bool remove_posix_acl(connection_struct *conn, files_struct *fsp, const c /* Get the current file ACL. */ if (fsp && fsp->fh->fd != -1) { - file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fsp->fh->fd); + file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp); } else { file_acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, SMB_ACL_TYPE_ACCESS); } @@ -4055,7 +4187,7 @@ static bool remove_posix_acl(connection_struct *conn, files_struct *fsp, const c /* Set the new empty file ACL. */ if (fsp && fsp->fh->fd != -1) { - if (SMB_VFS_SYS_ACL_SET_FD(fsp, fsp->fh->fd, new_file_acl) == -1) { + if (SMB_VFS_SYS_ACL_SET_FD(fsp, new_file_acl) == -1) { DEBUG(5,("remove_posix_acl: acl_set_file failed on %s (%s)\n", fname, strerror(errno) )); goto done; @@ -4102,7 +4234,7 @@ bool set_unix_posix_acl(connection_struct *conn, files_struct *fsp, const char * if (fsp && fsp->fh->fd != -1) { /* The preferred way - use an open fd. */ - if (SMB_VFS_SYS_ACL_SET_FD(fsp, fsp->fh->fd, file_acl) == -1) { + if (SMB_VFS_SYS_ACL_SET_FD(fsp, file_acl) == -1) { DEBUG(5,("set_unix_posix_acl: acl_set_file failed on %s (%s)\n", fname, strerror(errno) )); SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl); @@ -4171,8 +4303,7 @@ SEC_DESC *get_nt_acl_no_snum( TALLOC_CTX *ctx, const char *fname) finfo.fh->fd = -1; finfo.fsp_name = CONST_DISCARD(char *,fname); - if (!NT_STATUS_IS_OK(get_nt_acl( &finfo, DACL_SECURITY_INFORMATION, - &psd ))) { + if (!NT_STATUS_IS_OK(posix_fget_nt_acl( &finfo, DACL_SECURITY_INFORMATION, &psd))) { DEBUG(0,("get_nt_acl_no_snum: get_nt_acl returned zero.\n")); conn_free_internal( &conn ); return NULL; |