diff options
Diffstat (limited to 'source3/smbd/posix_acls.c')
-rw-r--r-- | source3/smbd/posix_acls.c | 180 |
1 files changed, 50 insertions, 130 deletions
diff --git a/source3/smbd/posix_acls.c b/source3/smbd/posix_acls.c index 85818d524a3..9c8835214fb 100644 --- a/source3/smbd/posix_acls.c +++ b/source3/smbd/posix_acls.c @@ -104,7 +104,7 @@ static void print_canon_ace(canon_ace *pace, int num) dbgtext( "canon_ace index %d. Type = %s ", num, pace->attr == ALLOW_ACE ? "allow" : "deny" ); dbgtext( "SID = %s ", sid_to_string( str, &pace->trustee)); if (pace->owner_type == UID_ACE) { - const char *u_name = uidtoname(pace->unix_ug.uid); + char *u_name = uidtoname(pace->unix_ug.uid); dbgtext( "uid %u (%s) ", (unsigned int)pace->unix_ug.uid, u_name); } else if (pace->owner_type == GID_ACE) { char *g_name = gidtoname(pace->unix_ug.gid); @@ -439,15 +439,9 @@ static BOOL unpack_nt_owners(SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *pgrp, if (security_info_sent & OWNER_SECURITY_INFORMATION) { sid_copy(&owner_sid, psd->owner_sid); if (!sid_to_uid( &owner_sid, puser, &sid_type)) { -#if ACL_FORCE_UNMAPPABLE - /* this allows take ownership to work reasonably */ - extern struct current_user current_user; - *puser = current_user.uid; -#else DEBUG(3,("unpack_nt_owners: unable to validate owner sid for %s\n", sid_string_static(&owner_sid))); return False; -#endif } } @@ -459,14 +453,8 @@ static BOOL unpack_nt_owners(SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *pgrp, if (security_info_sent & GROUP_SECURITY_INFORMATION) { sid_copy(&grp_sid, psd->grp_sid); if (!sid_to_gid( &grp_sid, pgrp, &sid_type)) { -#if ACL_FORCE_UNMAPPABLE - /* this allows take group ownership to work reasonably */ - extern struct current_user current_user; - *pgrp = current_user.gid; -#else DEBUG(3,("unpack_nt_owners: unable to validate group sid.\n")); return False; -#endif } } @@ -479,7 +467,7 @@ static BOOL unpack_nt_owners(SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *pgrp, Ensure the enforced permissions for this share apply. ****************************************************************************/ -static void apply_default_perms(files_struct *fsp, canon_ace *pace, mode_t type) +static mode_t apply_default_perms(files_struct *fsp, mode_t perms, mode_t type) { int snum = SNUM(fsp->conn); mode_t and_bits = (mode_t)0; @@ -498,10 +486,6 @@ static void apply_default_perms(files_struct *fsp, canon_ace *pace, mode_t type) /* Now bounce them into the S_USR space. */ switch(type) { case S_IRUSR: - /* Ensure owner has read access. */ - pace->perms |= S_IRUSR; - if (fsp->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); break; @@ -515,34 +499,7 @@ static void apply_default_perms(files_struct *fsp, canon_ace *pace, mode_t type) break; } - pace->perms = ((pace->perms & and_bits)|or_bits); -} - -/**************************************************************************** - Check if a given uid/SID is in a group gid/SID. This is probably very - expensive and will need optimisation. A *lot* of optimisation :-). JRA. -****************************************************************************/ - -static BOOL uid_entry_in_group( canon_ace *uid_ace, canon_ace *group_ace ) -{ - extern DOM_SID global_sid_World; - fstring u_name; - fstring g_name; - - /* "Everyone" always matches every uid. */ - - if (sid_equal(&group_ace->trustee, &global_sid_World)) - return True; - - fstrcpy(u_name, uidtoname(uid_ace->unix_ug.uid)); - fstrcpy(g_name, gidtoname(group_ace->unix_ug.gid)); - - /* - * Due to the winbind interfaces we need to do this via names, - * not uids/gids. - */ - - return user_in_group_list(u_name, g_name ); + return ((perms & and_bits)|or_bits); } /**************************************************************************** @@ -567,16 +524,24 @@ static BOOL ensure_canon_entry_valid(canon_ace **pp_ace, BOOL got_user = False; BOOL got_grp = False; BOOL got_other = False; - canon_ace *pace_other = NULL; - canon_ace *pace_group = NULL; for (pace = *pp_ace; pace; pace = pace->next) { if (pace->type == SMB_ACL_USER_OBJ) { - if (setting_acl) - apply_default_perms(fsp, pace, S_IRUSR); - got_user = True; + if (setting_acl) { + /* Ensure owner has read access. */ + pace->perms |= S_IRUSR; + if (fsp->is_directory) + pace->perms |= (S_IWUSR|S_IXUSR); + /* + * Ensure create mask/force create mode is respected on set. + */ + + pace->perms = apply_default_perms(fsp, pace->perms, S_IRUSR); + } + + got_user = True; } else if (pace->type == SMB_ACL_GROUP_OBJ) { /* @@ -584,10 +549,8 @@ static BOOL ensure_canon_entry_valid(canon_ace **pp_ace, */ if (setting_acl) - apply_default_perms(fsp, pace, S_IRGRP); + pace->perms = apply_default_perms(fsp, pace->perms, S_IRGRP); got_grp = True; - pace_group = pace; - } else if (pace->type == SMB_ACL_OTHER) { /* @@ -595,9 +558,8 @@ static BOOL ensure_canon_entry_valid(canon_ace **pp_ace, */ if (setting_acl) - apply_default_perms(fsp, pace, S_IROTH); + pace->perms = apply_default_perms(fsp, pace->perms, S_IROTH); got_other = True; - pace_other = pace; } } @@ -612,21 +574,9 @@ static BOOL ensure_canon_entry_valid(canon_ace **pp_ace, pace->owner_type = UID_ACE; pace->unix_ug.uid = pst->st_uid; pace->trustee = *pfile_owner_sid; + pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRUSR, S_IWUSR, S_IXUSR); pace->attr = ALLOW_ACE; - if (setting_acl) { - /* If we only got an "everyone" perm, just use that. */ - if (!got_grp && got_other) - pace->perms = pace_other->perms; - 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); - apply_default_perms(fsp, pace, S_IRUSR); - } else { - pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRUSR, S_IWUSR, S_IXUSR); - } - DLIST_ADD(*pp_ace, pace); } @@ -641,17 +591,8 @@ static BOOL ensure_canon_entry_valid(canon_ace **pp_ace, pace->owner_type = GID_ACE; pace->unix_ug.uid = pst->st_gid; pace->trustee = *pfile_grp_sid; + pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRGRP, S_IWGRP, S_IXGRP); pace->attr = ALLOW_ACE; - if (setting_acl) { - /* If we only got an "everyone" perm, just use that. */ - if (got_other) - pace->perms = pace_other->perms; - else - pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRGRP, S_IWGRP, S_IXGRP); - apply_default_perms(fsp, pace, S_IRGRP); - } else { - pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRGRP, S_IWGRP, S_IXGRP); - } DLIST_ADD(*pp_ace, pace); } @@ -667,9 +608,8 @@ static BOOL ensure_canon_entry_valid(canon_ace **pp_ace, pace->owner_type = WORLD_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); - apply_default_perms(fsp, pace, S_IROTH); + pace->attr = ALLOW_ACE; DLIST_ADD(*pp_ace, pace); } @@ -979,6 +919,33 @@ Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name )); } /**************************************************************************** + Check if a given uid/SID is in a group gid/SID. This is probably very + expensive and will need optimisation. A *lot* of optimisation :-). JRA. +****************************************************************************/ + +static BOOL uid_entry_in_group( canon_ace *uid_ace, canon_ace *group_ace ) +{ + extern DOM_SID global_sid_World; + fstring u_name; + fstring g_name; + + /* "Everyone" always matches every uid. */ + + if (sid_equal(&group_ace->trustee, &global_sid_World)) + return True; + + fstrcpy(u_name, uidtoname(uid_ace->unix_ug.uid)); + fstrcpy(g_name, gidtoname(group_ace->unix_ug.gid)); + + /* + * Due to the winbind interfaces we need to do this via names, + * not uids/gids. + */ + + return user_in_group_list(u_name, g_name ); +} + +/**************************************************************************** ASCII art time again... JRA :-). We have 3 cases to process when moving from an NT ACL to a POSIX ACL. Firstly, @@ -2029,52 +1996,6 @@ size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc) return sd_size; } -/* - try to chown a file. We will be able to chown it under the following conditions - - 1) if we have root privileges, then it will just work - 2) if we have write permission to the file and dos_filemodes is set - then allow chown to the currently authenticated user. - - */ -static int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_t gid) -{ - int ret; - extern struct current_user current_user; - files_struct *fsp; - SMB_STRUCT_STAT st; - - /* try the direct way first */ - ret = vfs_chown(conn, fname, uid, gid); - if (ret == 0) - return 0; - - if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn))) - return -1; - - if (vfs_stat(conn,fname,&st)) - return -1; - - fsp = open_file_fchmod(conn,fname,&st); - if (!fsp) - return -1; - - /* only allow chown to the current user. This is more secure, - and also copes with the case where the SID in a take ownership ACL is - a local SID on the users workstation - */ - uid = current_user.uid; - - become_root(); - /* Keep the current file gid the same. */ - ret = vfswrap_fchown(fsp, fsp->fd, uid, (gid_t)-1); - unbecome_root(); - - close_file_fchmod(fsp); - - return ret; -} - /**************************************************************************** Reply to set a security descriptor on an fsp. security_info_sent is the description of the following NT ACL. @@ -2131,7 +2052,7 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) 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) { + if(vfs_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; @@ -2387,7 +2308,6 @@ BOOL directory_has_default_acl(connection_struct *conn, const char *fname) if (dir_acl != NULL && (conn->vfs_ops.sys_acl_get_entry(conn, dir_acl, SMB_ACL_FIRST_ENTRY, &entry) == 1)) has_acl = True; - if (dir_acl) - conn->vfs_ops.sys_acl_free_acl(conn, dir_acl); + conn->vfs_ops.sys_acl_free_acl(conn, dir_acl); return has_acl; } |