From 2f7c1db093504a9798cdfd9c5d08a259cb4abc46 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 23 Jan 2001 01:52:30 +0000 Subject: include/vfs.h: smbd/vfs-wrap.c: smbd/vfs.c: Added fchmod_acl and chmod_acl. lib/substitute.c: smbd/lanman.c: smbd/open.c: smbd/process.c: smbd/reply.c: smbd/service.c: Removed sessetup_user variable. Added current_user_info struct which conatins domain info etc. Added '%D' for client domain parameter. Jeremy. (This used to be commit 2844ec3d511680609d6794b8718001a1bda9e89f) --- source3/smbd/lanman.c | 4 +- source3/smbd/open.c | 4 +- source3/smbd/posix_acls.c | 319 +++++++++++++++++++++++++++++++++++++++++++--- source3/smbd/process.c | 6 +- source3/smbd/reply.c | 6 +- source3/smbd/service.c | 32 ++++- source3/smbd/vfs-wrap.c | 38 ++++++ source3/smbd/vfs.c | 12 +- 8 files changed, 389 insertions(+), 32 deletions(-) (limited to 'source3/smbd') diff --git a/source3/smbd/lanman.c b/source3/smbd/lanman.c index fd59f4603a..33da479361 100644 --- a/source3/smbd/lanman.c +++ b/source3/smbd/lanman.c @@ -2187,7 +2187,7 @@ static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid, char *param char *str2 = skip_string(str1,1); char *p = skip_string(str2,1); char *p2; - extern pstring sesssetup_user; + extern userdom_struct current_user_info; int level = SVAL(p,0); DEBUG(4,("NetWkstaGetInfo level %d\n",level)); @@ -2216,7 +2216,7 @@ static BOOL api_NetWkstaGetInfo(connection_struct *conn,uint16 vuid, char *param p += 4; SIVAL(p,0,PTR_DIFF(p2,*rdata)); - pstrcpy(p2,sesssetup_user); + pstrcpy(p2,current_user_info.smb_name); p2 = skip_string(p2,1); p += 4; diff --git a/source3/smbd/open.c b/source3/smbd/open.c index b23da55542..77962562e3 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -25,7 +25,7 @@ extern int DEBUGLEVEL; -extern pstring sesssetup_user; +extern userdom_struct current_user_info; extern uint16 global_oplock_port; extern BOOL global_client_failed_oplock_break; @@ -188,7 +188,7 @@ static BOOL open_file(files_struct *fsp,connection_struct *conn, fsp->wcp = NULL; /* Write cache pointer. */ DEBUG(2,("%s opened file %s read=%s write=%s (numopen=%d)\n", - *sesssetup_user ? sesssetup_user : conn->user,fsp->fsp_name, + *current_user_info.smb_name ? current_user_info.smb_name : conn->user,fsp->fsp_name, BOOLSTR(fsp->can_read), BOOLSTR(fsp->can_write), conn->num_files_open + 1)); diff --git a/source3/smbd/posix_acls.c b/source3/smbd/posix_acls.c index 0071f8786d..2bd0065d58 100644 --- a/source3/smbd/posix_acls.c +++ b/source3/smbd/posix_acls.c @@ -41,6 +41,22 @@ typedef struct canon_ace { static void free_canon_ace_list( canon_ace *list_head ); +/**************************************************************************** + Function to duplicate a canon_ace entry. +****************************************************************************/ + +static canon_ace *dup_canon_ace( canon_ace *src_ace) +{ + canon_ace *dst_ace = (canon_ace *)malloc(sizeof(canon_ace)); + + if (dst_ace == NULL) + return NULL; + + *dst_ace = *src_ace; + dst_ace->prev = dst_ace->next = NULL; + return dst_ace; +} + /**************************************************************************** Function to create owner and group SIDs from a SMB_STRUCT_STAT. ****************************************************************************/ @@ -253,12 +269,121 @@ static BOOL merge_aces( canon_ace *list_head, canon_ace *p_ace) return False; } +/**************************************************************************** + Create a default mode for a directory default ACE. +****************************************************************************/ + +static mode_t get_default_ace_mode(files_struct *fsp, int type) +{ + mode_t force_mode = lp_force_dir_security_mode(SNUM(fsp->conn)); + mode_t mode = 0; + + switch(type) { + case S_IRUSR: + mode |= (force_mode & S_IRUSR) ? S_IRUSR : 0; + mode |= (force_mode & S_IWUSR) ? S_IWUSR : 0; + mode |= (force_mode & S_IXUSR) ? S_IXUSR : 0; + break; + case S_IRGRP: + mode |= (force_mode & S_IRGRP) ? S_IRUSR : 0; + mode |= (force_mode & S_IWGRP) ? S_IWUSR : 0; + mode |= (force_mode & S_IXGRP) ? S_IXUSR : 0; + break; + case S_IROTH: + mode |= (force_mode & S_IROTH) ? S_IRUSR : 0; + mode |= (force_mode & S_IWOTH) ? S_IWUSR : 0; + mode |= (force_mode & S_IXOTH) ? S_IXUSR : 0; + break; + } + + return mode; +} + +/**************************************************************************** + A well formed POSIX file or default ACL has at least 3 entries, a + SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ. +****************************************************************************/ + +static BOOL ensure_canon_entry_valid(canon_ace **pp_ace, + files_struct *fsp, + DOM_SID *pfile_owner_sid, + DOM_SID *pfile_grp_sid, + SMB_STRUCT_STAT *pst, + BOOL default_acl) +{ + extern DOM_SID global_sid_World; + canon_ace *pace; + BOOL got_user = False; + BOOL got_grp = False; + BOOL got_other = False; + + for (pace = *pp_ace; pace; pace = pace->next) { + if (pace->type == SMB_ACL_USER_OBJ) + got_user = True; + else if (pace->type == SMB_ACL_GROUP_OBJ) + got_grp = True; + else if (pace->type == SMB_ACL_OTHER) + got_other = True; + } + + if (!got_user) { + if ((pace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) { + DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n")); + return False; + } + + ZERO_STRUCTP(pace); + pace->type = SMB_ACL_USER_OBJ; + pace->owner_type = UID_ACE; + pace->unix_ug.uid = pst->st_uid; + pace->sid = *pfile_owner_sid; + pace->perms = default_acl ? get_default_ace_mode(fsp, S_IRUSR): 0; + + DLIST_ADD(*pp_ace, pace); + } + + if (!got_grp) { + if ((pace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) { + DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n")); + return False; + } + + ZERO_STRUCTP(pace); + pace->type = SMB_ACL_GROUP_OBJ; + pace->owner_type = GID_ACE; + pace->unix_ug.uid = pst->st_gid; + pace->sid = *pfile_grp_sid; + pace->perms = default_acl ? get_default_ace_mode(fsp, S_IRGRP): 0; + + DLIST_ADD(*pp_ace, pace); + } + + if (!got_other) { + if ((pace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) { + DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n")); + return False; + } + + ZERO_STRUCTP(pace); + pace->type = SMB_ACL_OTHER; + pace->owner_type = WORLD_ACE; + pace->unix_ug.world = -1; + pace->sid = global_sid_World; + pace->perms = default_acl ? get_default_ace_mode(fsp, S_IROTH): 0; + + DLIST_ADD(*pp_ace, pace); + } + + return True; +} + /**************************************************************************** Unpack a SEC_DESC into two canonical ace lists. We don't depend on this succeeding. ****************************************************************************/ static BOOL unpack_canon_ace(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, @@ -383,7 +508,8 @@ static BOOL unpack_canon_ace(files_struct *fsp, current_ace->type = (current_ace->owner_type == UID_ACE) ? SMB_ACL_USER : SMB_ACL_GROUP; } - if (fsp->is_directory && (psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) { + if (fsp->is_directory) { + /* * We can only add to the default POSIX ACE list if the ACE is * designed to be inherited by both files and directories. @@ -391,14 +517,45 @@ static BOOL unpack_canon_ace(files_struct *fsp, if ((psa->flags & (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) == (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) { DLIST_ADD(dir_ace, current_ace); - } else { - DEBUG(0,("unpack_canon_ace: unable to use a non-generic default ACE.\n")); - free(current_ace); + + /* + * If this is not an inherit only ACE we need to add a duplicate + * to the file acl. + */ + + if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) { + canon_ace *dup_ace = dup_canon_ace(current_ace); + + if (!dup_ace) { + DEBUG(0,("unpack_canon_ace: malloc fail !\n")); + free_canon_ace_list(file_ace); + free_canon_ace_list(dir_ace); + return False; + } + + current_ace = dup_ace; + } else { + current_ace = NULL; + } } - } else { + } + + /* + * Only add to the file ACL if not inherit only. + */ + + if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) { DLIST_ADD(file_ace, current_ace); all_aces_are_inherit_only = False; + current_ace = NULL; } + + /* + * Free if ACE was not addedd. + */ + + if (current_ace) + free(current_ace); } if (fsp->is_directory && all_aces_are_inherit_only) { @@ -431,6 +588,36 @@ static BOOL unpack_canon_ace(files_struct *fsp, goto again_dir; } + /* + * A well formed POSIX file or default ACL has at least 3 entries, a + * SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ + * and optionally a mask entry. Ensure this is the case. + */ + + if (!ensure_canon_entry_valid(&file_ace, fsp, pfile_owner_sid, pfile_grp_sid, pst, False)) { + free_canon_ace_list(file_ace); + free_canon_ace_list(dir_ace); + return False; + } + + if (!ensure_canon_entry_valid(&dir_ace, fsp, pfile_owner_sid, pfile_grp_sid, pst, True)) { + free_canon_ace_list(file_ace); + free_canon_ace_list(dir_ace); + return False; + } + + if( DEBUGLVL( 10 )) { + dbgtext("unpack_canon_ace: File ACL:\n"); + for (i = 0, current_ace = file_ace; current_ace; current_ace = current_ace->next, i++ ) { + print_canon_ace( current_ace, i); + } + + dbgtext("unpack_canon_ace: Directory ACL:\n"); + for (i = 0, current_ace = dir_ace; current_ace; current_ace = current_ace->next, i++ ) { + print_canon_ace( current_ace, i); + } + } + *ppfile_ace = file_ace; *ppdir_ace = dir_ace; return True; @@ -914,7 +1101,7 @@ static canon_ace *canonicalise_acl( SMB_ACL_T posix_acl, SMB_STRUCT_STAT *psbuf) 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) +static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL default_ace, BOOL *pacl_set_support) { BOOL ret = False; SMB_ACL_T the_acl = sys_acl_init((int)count_canon_ace_list(the_ace) + 1); @@ -933,6 +1120,7 @@ static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL defau DEBUG(0,("set_canon_ace_list: Unable to init %s ACL. (%s)\n", default_ace ? "default" : "file", strerror(errno) )); #endif + *pacl_set_support = False; return False; } @@ -950,6 +1138,13 @@ static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL defau goto done; } + /* + * Ok - we now know the ACL calls should be working, don't + * allow fallback to chmod. + */ + + *pacl_set_support = True; + /* * Initialise the entry from the canon_ace. */ @@ -1041,7 +1236,9 @@ static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL defau */ if (sys_acl_valid(the_acl) == -1) { - DEBUG(0,("set_canon_ace_list: ACL is invalid for set (%s).\n", strerror(errno) )); + DEBUG(0,("set_canon_ace_list: ACL type (%s) is invalid for set (%s).\n", + the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file", + strerror(errno) )); goto done; } @@ -1051,7 +1248,8 @@ static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL defau if(default_ace || fsp->is_directory || fsp->fd == -1) { if (sys_acl_set_file(fsp->fsp_name, the_acl_type, the_acl) == -1) { - DEBUG(0,("set_canon_ace_list: sys_acl_set_file failed for file %s (%s).\n", + DEBUG(0,("set_canon_ace_list: sys_acl_set_file type %s failed for file %s (%s).\n", + the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file", fsp->fsp_name, strerror(errno) )); goto done; } @@ -1150,7 +1348,7 @@ size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc) num_acls = count_canon_ace_list(file_ace); if (fsp->is_directory) { - if (dir_ace) + if (dir_acl) dir_ace = canonicalise_acl( dir_acl, &sbuf); else dir_ace = unix_canonicalise_acl(fsp, &sbuf, &owner_sid, &group_sid); @@ -1302,7 +1500,7 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) create_file_sids(&sbuf, &file_owner_sid, &file_grp_sid); - acl_perms = unpack_canon_ace( fsp, &file_owner_sid, &file_grp_sid, + acl_perms = unpack_canon_ace( fsp, &sbuf, &file_owner_sid, &file_grp_sid, &file_ace_list, &dir_ace_list, security_info_sent, psd); posix_perms = unpack_posix_permissions( fsp, &sbuf, &perms, security_info_sent, psd, acl_perms); @@ -1324,17 +1522,31 @@ 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; /* * Try using the POSIX ACL set first. All back to chmod if * we have no ACL support on this filesystem. */ - if (acl_perms && file_ace_list && set_canon_ace_list(fsp, file_ace_list, False)) - acl_set_support = True; + if (acl_perms && file_ace_list) { + ret = set_canon_ace_list(fsp, file_ace_list, False, &acl_set_support); + if (acl_set_support && ret == False) { + 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; + } + } - if (acl_perms && acl_set_support && fsp->is_directory && dir_ace_list) - set_canon_ace_list(fsp, dir_ace_list, True); + if (acl_perms && acl_set_support && fsp->is_directory && dir_ace_list) { + if (!set_canon_ace_list(fsp, dir_ace_list, True, &acl_set_support)) { + 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; + } + } /* * If we cannot set using POSIX ACLs we fall back to checking if we need to chmod. @@ -1347,7 +1559,7 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) file_ace_list = NULL; dir_ace_list = NULL; - DEBUG(3,("call_nt_transact_set_security_desc: chmod %s. perms = 0%o.\n", + DEBUG(3,("set_nt_acl: chmod %s. perms = 0%o.\n", fsp->fsp_name, (unsigned int)perms )); if(conn->vfs_ops.chmod(conn,dos_to_unix(fsp->fsp_name, False), perms) == -1) { @@ -1363,4 +1575,81 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) return True; } + +/**************************************************************************** + Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL + and set the mask to rwx. Needed to preserve complex ACLs set by NT. +****************************************************************************/ + +static int chmod_acl_internals( SMB_ACL_T posix_acl, mode_t mode) +{ + int entry_id = SMB_ACL_FIRST_ENTRY; + SMB_ACL_ENTRY_T entry; + int num_entries = 0; + +#if 1 + return -1; +#else + while ( sys_acl_get_entry(posix_acl, entry_id, &entry) == 1) { + SMB_ACL_TAG_T tagtype; + SMB_ACL_PERMSET_T permset; + + if (sys_acl_get_tag_type(entry, &tagtype) == -1) + return -1; + + if (sys_acl_get_permset(entry, &permset) == -1) + return -1; + + num_entries++; + + switch(tagtype) { + case SMB_ACL_USER_OBJ: + break; + case SMB_ACL_USER: + break; + case SMB_ACL_GROUP_OBJ: + break; + case SMB_ACL_GROUP: + break; + case SMB_ACL_MASK: + break; + case SMB_ACL_OTHER: + break; + } + + } +#endif +} + +/**************************************************************************** + Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL + and set the mask to rwx. Needed to preserve complex ACLs set by NT. + Note that name is in UNIX character set. +****************************************************************************/ + +int chmod_acl(char *name, mode_t mode) +{ + SMB_ACL_T posix_acl = NULL; + + if ((posix_acl = sys_acl_get_file(name, SMB_ACL_TYPE_ACCESS)) == NULL) + return -1; + + return chmod_acl_internals(posix_acl, mode); +} + +/**************************************************************************** + Do an fchmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL + and set the mask to rwx. Needed to preserve complex ACLs set by NT. +****************************************************************************/ + +int fchmod_acl(int fd, mode_t mode) +{ + SMB_ACL_T posix_acl = NULL; + + if ((posix_acl = sys_acl_get_fd(fd)) == NULL) + return -1; + + return chmod_acl_internals(posix_acl, mode); +} + #undef OLD_NTDOMAIN diff --git a/source3/smbd/process.c b/source3/smbd/process.c index ea0309599f..0916dc5b7e 100644 --- a/source3/smbd/process.c +++ b/source3/smbd/process.c @@ -44,7 +44,7 @@ int max_recv = BUFFER_SIZE; extern int last_message; extern int global_oplock_break; -extern pstring sesssetup_user; +extern userdom_struct current_user_info; extern char *last_inbuf; extern char *InBuffer; extern char *OutBuffer; @@ -524,7 +524,7 @@ static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize SSVAL(inbuf,smb_uid,session_tag); /* - * Ensure the correct username is in sesssetup_user. + * Ensure the correct username is in current_user_info. * This is a really ugly bugfix for problems with * multiple session_setup_and_X's being done and * allowing %U and %G substitutions to work correctly. @@ -539,7 +539,7 @@ static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize if(session_tag != UID_FIELD_INVALID) vuser = get_valid_user_struct(session_tag); if(vuser != NULL) - pstrcpy( sesssetup_user, vuser->user.smb_name); + current_user_info = vuser->user; } /* does this protocol need to be run as root? */ diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index 7738f2594f..624dc59084 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -36,7 +36,7 @@ extern char magic_char; extern BOOL case_sensitive; extern BOOL case_preserve; extern BOOL short_case_preserve; -extern pstring sesssetup_user; +extern userdom_struct current_user_info; extern pstring global_myname; extern fstring global_myworkgroup; extern int global_oplock_break; @@ -879,7 +879,7 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int guest = True; } - pstrcpy(sesssetup_user,user); + pstrcpy(current_user_info.smb_name,user); reload_services(True); @@ -1042,7 +1042,7 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int /* register the name and uid as being validated, so further connections to a uid can get through without a password, on the same VC */ - sess_vuid = register_vuid(uid,gid,user,sesssetup_user,domain,guest); + sess_vuid = register_vuid(uid,gid,user,current_user_info.smb_name,domain,guest); SSVAL(outbuf,smb_uid,sess_vuid); SSVAL(inbuf,smb_uid,sess_vuid); diff --git a/source3/smbd/service.c b/source3/smbd/service.c index 1db5dc4a5f..a6e66965c3 100644 --- a/source3/smbd/service.c +++ b/source3/smbd/service.c @@ -33,7 +33,7 @@ extern BOOL case_mangle; extern BOOL case_sensitive; extern BOOL use_mangled_map; extern fstring remote_machine; -extern pstring sesssetup_user; +extern userdom_struct current_user_info; extern fstring remote_machine; @@ -113,8 +113,28 @@ int find_service(char *service) int iHomeService; if ((iHomeService = lp_servicenumber(HOMES_NAME)) >= 0) { - lp_add_home(service,iHomeService,phome_dir); - iService = lp_servicenumber(service); + /* + * If this is a winbindd provided username, remove + * the domain component before adding the service. + * Log a warning if the "path=" parameter does not + * include any macros. + */ + + fstring new_service; + char *usr_p = NULL; + + fstrcpy(new_service, service); + + if ((usr_p = strchr(service,*lp_winbind_separator())) != NULL) + fstrcpy(new_service, usr_p+1); + + lp_add_home(new_service,iHomeService,phome_dir); + iService = lp_servicenumber(new_service); + + if (usr_p && (strchr(lp_pathname(iService),'%') == NULL)) + DEBUG(0,("find_service: Service %s added for user %s - contains non-local (Domain) user \ +with non parameterised path (%s). This may be cause the wrong directory to be seen.\n", + new_service, service, lp_pathname(iService) )); } } } @@ -234,11 +254,11 @@ connection_struct *make_connection(char *service,char *user,char *password, int return(make_connection(dos_username,user,password,pwlen,dev,vuid,ecode)); } } else { - /* Security = share. Try with sesssetup_user + /* Security = share. Try with current_user_info.smb_name * as the username. */ - if(*sesssetup_user) { + if(*current_user_info.smb_name) { fstring dos_username; - fstrcpy(user,sesssetup_user); + fstrcpy(user,current_user_info.smb_name); fstrcpy(dos_username, user); unix_to_dos(dos_username, True); return(make_connection(dos_username,user,password,pwlen,dev,vuid,ecode)); diff --git a/source3/smbd/vfs-wrap.c b/source3/smbd/vfs-wrap.c index a9d8a32430..ad4d4ddbef 100644 --- a/source3/smbd/vfs-wrap.c +++ b/source3/smbd/vfs-wrap.c @@ -107,6 +107,20 @@ int vfswrap_mkdir(connection_struct *conn, char *path, mode_t mode) #endif result = mkdir(path, mode); + + if (result == 0) { + /* + * We need to do this as the default behavior of POSIX ACLs + * is to set the mask to be the requested group permission + * bits, not the group permission bits to be the requested + * group permission bits. This is not what we want, as it will + * mess up any inherited ACL bits that were set. JRA. + */ + if (conn->vfs_ops.chmod_acl != NULL) { + conn->vfs_ops.chmod_acl(conn, path, mode); + } + } + END_PROFILE(syscall_mkdir); return result; } @@ -332,6 +346,19 @@ int vfswrap_chmod(connection_struct *conn, char *path, mode_t mode) } #endif + /* + * We need to do this due to the fact that the default POSIX ACL + * chmod modifies the ACL *mask* for the group owner, not the + * group owner bits directly. JRA. + */ + + if (conn->vfs_ops.chmod_acl != NULL) { + if ((result = conn->vfs_ops.chmod_acl(conn, path, mode)) == 0) { + END_PROFILE(syscall_chmod); + return result; + } + } + result = chmod(path, mode); END_PROFILE(syscall_chmod); return result; @@ -506,4 +533,15 @@ BOOL vfswrap_set_nt_acl(files_struct *fsp, char *name, uint32 security_info_sent { return set_nt_acl(fsp, security_info_sent, psd); } + +int vfswrap_chmod_acl(connection_struct *conn, char *name, mode_t mode) +{ + return chmod_acl(name, mode); +} + +int vfswrap_fchmod_acl(files_struct *fsp, int fd, mode_t mode) +{ + return fchmod_acl(fd, mode); +} + #undef OLD_NTDOMAIN diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c index cbd1fd6825..2cd83c37f3 100644 --- a/source3/smbd/vfs.c +++ b/source3/smbd/vfs.c @@ -74,7 +74,10 @@ struct vfs_ops default_vfs_ops = { vfswrap_fget_nt_acl, vfswrap_get_nt_acl, vfswrap_fset_nt_acl, - vfswrap_set_nt_acl + vfswrap_set_nt_acl, + + vfswrap_chmod_acl, + vfswrap_fchmod_acl }; /**************************************************************************** @@ -257,6 +260,13 @@ BOOL vfs_init_custom(connection_struct *conn) conn->vfs_ops.set_nt_acl = default_vfs_ops.set_nt_acl; } + if (conn->vfs_ops.chmod_acl == NULL) { + conn->vfs_ops.chmod_acl = default_vfs_ops.chmod_acl; + } + + if (conn->vfs_ops.fchmod_acl == NULL) { + conn->vfs_ops.fchmod_acl = default_vfs_ops.fchmod_acl; + } return True; } #endif -- cgit