diff options
author | Andrew Tridgell <tridge@samba.org> | 2002-07-15 10:35:28 +0000 |
---|---|---|
committer | Andrew Tridgell <tridge@samba.org> | 2002-07-15 10:35:28 +0000 |
commit | 03ac082dcb375b6f3ca3d810a6a6367542bc23ce (patch) | |
tree | f13f085fad5de50ebe4b066eb7e2629d55032a2d /source/smbd/posix_acls.c | |
parent | b8d39651fb90ef170055735412417239a63afc5d (diff) | |
download | samba-03ac082dcb375b6f3ca3d810a6a6367542bc23ce.tar.gz samba-03ac082dcb375b6f3ca3d810a6a6367542bc23ce.tar.xz samba-03ac082dcb375b6f3ca3d810a6a6367542bc23ce.zip |
updated the 3.0 branch from the head branch - ready for alpha18
Diffstat (limited to 'source/smbd/posix_acls.c')
-rw-r--r-- | source/smbd/posix_acls.c | 180 |
1 files changed, 130 insertions, 50 deletions
diff --git a/source/smbd/posix_acls.c b/source/smbd/posix_acls.c index 9c8835214fb..85818d524a3 100644 --- a/source/smbd/posix_acls.c +++ b/source/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) { - char *u_name = uidtoname(pace->unix_ug.uid); + const 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,9 +439,15 @@ 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 } } @@ -453,8 +459,14 @@ 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 } } @@ -467,7 +479,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 mode_t apply_default_perms(files_struct *fsp, mode_t perms, mode_t type) +static void apply_default_perms(files_struct *fsp, canon_ace *pace, mode_t type) { int snum = SNUM(fsp->conn); mode_t and_bits = (mode_t)0; @@ -486,6 +498,10 @@ static mode_t apply_default_perms(files_struct *fsp, mode_t perms, 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; @@ -499,7 +515,34 @@ static mode_t apply_default_perms(files_struct *fsp, mode_t perms, mode_t type) break; } - return ((perms & and_bits)|or_bits); + 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 ); } /**************************************************************************** @@ -524,24 +567,16 @@ 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) { - /* 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); - } - + if (setting_acl) + apply_default_perms(fsp, pace, S_IRUSR); got_user = True; + } else if (pace->type == SMB_ACL_GROUP_OBJ) { /* @@ -549,8 +584,10 @@ static BOOL ensure_canon_entry_valid(canon_ace **pp_ace, */ if (setting_acl) - pace->perms = apply_default_perms(fsp, pace->perms, S_IRGRP); + apply_default_perms(fsp, pace, S_IRGRP); got_grp = True; + pace_group = pace; + } else if (pace->type == SMB_ACL_OTHER) { /* @@ -558,8 +595,9 @@ static BOOL ensure_canon_entry_valid(canon_ace **pp_ace, */ if (setting_acl) - pace->perms = apply_default_perms(fsp, pace->perms, S_IROTH); + apply_default_perms(fsp, pace, S_IROTH); got_other = True; + pace_other = pace; } } @@ -574,9 +612,21 @@ 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); } @@ -591,8 +641,17 @@ 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); } @@ -608,8 +667,9 @@ 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->perms = unix_perms_to_acl_perms(pst->st_mode, S_IROTH, S_IWOTH, S_IXOTH); 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); DLIST_ADD(*pp_ace, pace); } @@ -919,33 +979,6 @@ 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, @@ -1996,6 +2029,52 @@ 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. @@ -2052,7 +2131,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(vfs_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) { + 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; @@ -2308,6 +2387,7 @@ 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; - conn->vfs_ops.sys_acl_free_acl(conn, dir_acl); + if (dir_acl) + conn->vfs_ops.sys_acl_free_acl(conn, dir_acl); return has_acl; } |