4 Unix SMB/Netbios implementation.
6 SMB NT Security Descriptor / Unix permission conversion.
7 Copyright (C) Jeremy Allison 1994-2000
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 typedef struct canon_ace {
27 struct canon_ace *next, *prev;
29 SMB_ACL_PERMSET_T perms;
33 /****************************************************************************
34 Function to create owner and group SIDs from a SMB_STRUCT_STAT.
35 ****************************************************************************/
37 static void create_file_sids(SMB_STRUCT_STAT *psbuf, DOM_SID *powner_sid, DOM_SID *pgroup_sid)
39 uid_to_sid( powner_sid, psbuf->st_uid );
40 gid_to_sid( pgroup_sid, psbuf->st_gid );
43 /****************************************************************************
44 Map canon_ace perms to NT.
45 ****************************************************************************/
47 static SEC_ACCESS map_canon_ace_perms(int *pacl_type, DOM_SID *powner_sid, canon_ace *ace)
52 *pacl_type = SEC_ACE_TYPE_ACCESS_ALLOWED;
54 if((ace->perms & (SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE)) == (SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE)) {
55 nt_mask = UNIX_ACCESS_RWX;
56 } else if((ace->perms & (SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE)) == 0) {
58 * Here we differentiate between the owner and any other user.
60 if (sid_equal(powner_sid, &ace->sid)
61 nt_mask = UNIX_ACCESS_NONE;
63 /* Not owner, this is an access denied ACE. */
64 nt_mask = UNIX_ACCESS_RWX;
65 *pacl_type = SEC_ACE_TYPE_ACCESS_DENIED;
68 nt_mask |= (perm & SMB_ACL_READ) ? UNIX_ACCESS_R : 0;
69 nt_mask |= (perm & SMB_ACL_WRITE) ? UNIX_ACCESS_W : 0;
70 nt_mask |= (perm & SMB_ACL_EXECUTE) ? UNIX_ACCESS_X : 0;
72 init_sec_access(&sa,nt_mask);
76 /****************************************************************************
78 ****************************************************************************/
80 #define FILE_SPECIFIC_READ_BITS (FILE_READ_DATA|FILE_READ_EA|FILE_READ_ATTRIBUTES)
81 #define FILE_SPECIFIC_WRITE_BITS (FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_WRITE_EA|FILE_WRITE_ATTRIBUTES)
82 #define FILE_SPECIFIC_EXECUTE_BITS (FILE_EXECUTE)
84 static mode_t map_nt_perms( SEC_ACCESS sec_access, int type)
90 if(sec_access.mask & GENERIC_ALL_ACCESS)
91 mode = S_IRUSR|S_IWUSR|S_IXUSR;
93 mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRUSR : 0;
94 mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWUSR : 0;
95 mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXUSR : 0;
99 if(sec_access.mask & GENERIC_ALL_ACCESS)
100 mode = S_IRGRP|S_IWGRP|S_IXGRP;
102 mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRGRP : 0;
103 mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWGRP : 0;
104 mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXGRP : 0;
108 if(sec_access.mask & GENERIC_ALL_ACCESS)
109 mode = S_IROTH|S_IWOTH|S_IXOTH;
111 mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IROTH : 0;
112 mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWOTH : 0;
113 mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXOTH : 0;
121 /****************************************************************************
122 Unpack a SEC_DESC into a owner, group and set of UNIX permissions.
123 ****************************************************************************/
125 static BOOL unpack_nt_permissions(SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *pgrp, mode_t *pmode,
126 uint32 security_info_sent, SEC_DESC *psd, BOOL is_directory)
128 extern DOM_SID global_sid_World;
131 DOM_SID file_owner_sid;
132 DOM_SID file_grp_sid;
135 SEC_ACL *dacl = psd->dacl;
136 BOOL all_aces_are_inherit_only = (is_directory ? True : False);
138 enum SID_NAME_USE sid_type;
144 if(security_info_sent == 0) {
145 DEBUG(0,("unpack_nt_permissions: no security info sent !\n"));
150 * Windows 2000 sends the owner and group SIDs as the logged in
151 * user, not the connected user. But it still sends the file
152 * owner SIDs on an ACL set. So we need to check for the file
153 * owner and group SIDs as well as the owner SIDs. JRA.
156 create_file_sids(psbuf, &file_owner_sid, &file_grp_sid);
159 * Validate the owner and group SID's.
162 memset(&owner_sid, '\0', sizeof(owner_sid));
163 memset(&grp_sid, '\0', sizeof(grp_sid));
165 DEBUG(5,("unpack_nt_permissions: validating owner_sid.\n"));
168 * Don't immediately fail if the owner sid cannot be validated.
169 * This may be a group chown only set.
172 if (security_info_sent & OWNER_SECURITY_INFORMATION) {
173 if (!sid_to_uid( &owner_sid, puser, &sid_type))
174 DEBUG(3,("unpack_nt_permissions: unable to validate owner sid.\n"));
178 * Don't immediately fail if the group sid cannot be validated.
179 * This may be an owner chown only set.
182 if (security_info_sent & GROUP_SECURITY_INFORMATION) {
183 if (!sid_to_gid( &grp_sid, pgrp, &sid_type))
184 DEBUG(3,("unpack_nt_permissions: unable to validate group sid.\n"));
188 * If no DACL then this is a chown only security descriptor.
191 if(!(security_info_sent & DACL_SECURITY_INFORMATION) || !dacl) {
197 * Now go through the DACL and ensure that
198 * any owner/group sids match.
201 for(i = 0; i < dacl->num_aces; i++) {
203 SEC_ACE *psa = &dacl->ace[i];
205 if((psa->type != SEC_ACE_TYPE_ACCESS_ALLOWED) &&
206 (psa->type != SEC_ACE_TYPE_ACCESS_DENIED)) {
207 DEBUG(3,("unpack_nt_permissions: unable to set anything but an ALLOW or DENY ACE.\n"));
212 * Ignore or remove bits we don't care about on a directory ACE.
216 if(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
217 DEBUG(3,("unpack_nt_permissions: ignoring inherit only ACE.\n"));
222 * At least one of the ACE entries wasn't inherit only.
223 * Flag this so we know the returned mode is valid.
226 all_aces_are_inherit_only = False;
230 * Windows 2000 sets these flags even on *file* ACE's. This is wrong
231 * but we can ignore them for now. Revisit this when we go to POSIX
232 * ACLs on directories.
235 psa->flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT);
237 if(psa->flags != 0) {
238 DEBUG(1,("unpack_nt_permissions: unable to set ACE flags (%x).\n",
239 (unsigned int)psa->flags));
244 * The security mask may be UNIX_ACCESS_NONE which should map into
245 * no permissions (we overload the WRITE_OWNER bit for this) or it
246 * should be one of the ALL/EXECUTE/READ/WRITE bits. Arrange for this
247 * to be so. Any other bits override the UNIX_ACCESS_NONE bit.
250 psa->info.mask &= (GENERIC_ALL_ACCESS|GENERIC_EXECUTE_ACCESS|GENERIC_WRITE_ACCESS|
251 GENERIC_READ_ACCESS|UNIX_ACCESS_NONE|FILE_ALL_ATTRIBUTES);
253 if(psa->info.mask != UNIX_ACCESS_NONE)
254 psa->info.mask &= ~UNIX_ACCESS_NONE;
256 sid_copy(&ace_sid, &psa->sid);
258 if(sid_equal(&ace_sid, &file_owner_sid)) {
260 * Map the desired permissions into owner perms.
263 if(psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED)
264 *pmode |= map_nt_perms( psa->info, S_IRUSR);
266 *pmode &= ~(map_nt_perms( psa->info, S_IRUSR));
268 } else if( sid_equal(&ace_sid, &file_grp_sid)) {
270 * Map the desired permissions into group perms.
273 if(psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED)
274 *pmode |= map_nt_perms( psa->info, S_IRGRP);
276 *pmode &= ~(map_nt_perms( psa->info, S_IRGRP));
278 } else if( sid_equal(&ace_sid, &global_sid_World)) {
280 * Map the desired permissions into other perms.
283 if(psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED)
284 *pmode |= map_nt_perms( psa->info, S_IROTH);
286 *pmode &= ~(map_nt_perms( psa->info, S_IROTH));
289 DEBUG(0,("unpack_nt_permissions: unknown SID used in ACL.\n"));
294 if (is_directory && all_aces_are_inherit_only) {
296 * Windows 2000 is doing one of these weird 'inherit acl'
297 * traverses to conserve NTFS ACL resources. Just pretend
298 * there was no DACL sent. JRA.
301 DEBUG(10,("unpack_nt_permissions: Win2k inherit acl traverse. Ignoring DACL.\n"));
302 free_sec_acl(&psd->dacl);
308 /****************************************************************************
309 Map generic UNIX permissions to POSIX ACL perms.
310 ****************************************************************************/
312 static SMB_ACL_PERMSET_T unix_perms_to_acl_perms(mode_t mode, int r_mask, int w_mask, int x_mask)
314 SMB_ACL_PERMSET_T ret = 0;
316 ret |= (mode & r_mask) ? SMB_ACL_READ : 0;
317 ret |= (mode & w_mask) ? SMB_ACL_WRITE : 0;
318 ret |= (mode & x_mask) ? SMB_ACL_EXECUTE : 0;
323 /****************************************************************************
324 Count a linked list of canonical ACE entries.
325 ****************************************************************************/
327 static size_t count_canon_ace_list( canon_ace *list_head )
332 for (ace = list_head; ace; ace = ace->next)
338 /****************************************************************************
339 Free a linked list of canonical ACE entries.
340 ****************************************************************************/
342 static void free_canon_ace_list( canon_ace *list_head )
345 canon_ace *old_head = list_head;
346 DLIST_REMOVE(list_head, list_head);
351 /******************************************************************************
352 Fall back to the generic 3 element UNIX permissions.
353 ********************************************************************************/
355 static canon_ace *unix_canonicalise_acl(files_struct *fsp, SMB_STRUCT_STAT *psbuf,
356 DOM_SID *powner, DOM_SID *pgroup)
358 extern DOM_SID global_sid_World;
359 canon_ace *list_head = NULL;
360 canon_ace *owner_ace = NULL;
361 canon_ace *group_ace = NULL;
362 canon_ace *other_ace = NULL;
364 SMB_ACL_PERMSET_T perms;
368 * Create 3 linked list entries.
371 if ((owner_ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL)
374 if ((gtoup_ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL)
377 if ((other_ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL)
380 ZERO_STRUCTP(owner_ace);
381 ZERO_STRUCTP(group_ace);
382 ZERO_STRUCTP(other_ace);
384 owner_ace->type = SMB_ACL_USER_OBJ;
385 owner_ace->sid = *powner;
387 group_ace->type = SMB_ACL_GROUP_OBJ;
388 group_ace->sid = *pgroup;
390 other_ace->type = SMB_ACL_OTHER_OBJ;
391 other_ace->sid = global_sid_World;
393 if (!fsp->is_directory) {
394 owner_ace->perms = unix_perms_to_acl_perms(sbuf.st_mode, S_IRUSR, S_IWUSR, S_IXUSR);
395 group_ace->perms = unix_perms_to_acl_perms(sbuf.st_mode, S_IRGRP, S_IWGRP, S_IXGRP);
396 other_ace->perms = unix_perms_to_acl_perms(sbuf.st_mode, S_IROTH, S_IWOTH, S_IXOTH);
398 mode_t mode = unix_mode( fsp->conn, FILE_ATTRIBUTE_ARCHIVE, fsp->fsp_name);
400 owner_ace->perms = unix_perms_to_acl_perms(mode, S_IRUSR, S_IWUSR, S_IXUSR);
401 group_ace->perms = unix_perms_to_acl_perms(mode, S_IRGRP, S_IWGRP, S_IXGRP);
402 other_ace->perms = unix_perms_to_acl_perms(mode, S_IROTH, S_IWOTH, S_IXOTH);
405 DLIST_ADD(list_head, other_ace);
406 DLIST_ADD(list_head, group_ace);
407 DLIST_ADD(list_head, owner_ace);
413 safe_free(owner_ace);
414 safe_free(group_ace);
415 safe_free(other_ace);
420 /****************************************************************************
421 Create a linked list of canonical ACE entries. This is sorted so that DENY
422 entries are at the front of the list, as NT requires.
423 ****************************************************************************/
425 static canon_ace *canonicalise_acl( SMB_ACL_T posix_acl, SMB_STRUCT_STAT *psbuf)
427 extern DOM_SID global_sid_World;
428 SMB_ACL_PERMSET_T acl_mask = (SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE);
429 canon_ace *list_head = NULL;
430 canon_ace *ace = NULL;
431 canon_ace *next_ace = NULL;
432 int entry_id = SMB_ACL_FIRST_ENTRY;
433 SMB_ACL_ENTRY_T entry;
435 while ( sys_acl_get_entry(posix_acl, entry_id, &entry) == 1) {
436 SMB_ACL_TAG_T tagtype;
437 SMB_ACL_PERMSET_T permset;
441 if (entry_id == SMB_ACL_FIRST_ENTRY)
442 entry_id = SMB_ACL_NEXT_ENTRY;
444 /* Is this a MASK entry ? */
445 if (sys_acl_get_tag_type(entry, &tagtype) == -1)
448 if (sys_acl_get_permset(entry, &permset) == -1)
451 /* Decide which SID to use based on the ACL type. */
454 /* Get the SID from the owner. */
455 uid_to_sid( &sid, psbuf->st_uid );
459 uid_t *puid = (uid_t *)sys_acl_get_qualifier(entry);
461 DEBUG(0,("canonicalise_acl: Failed to get uid.\n"));
464 uid_to_sid( &sid, *puid);
468 /* Get the SID from the owning group. */
469 gid_to_sid( &sid, psbuf->st_gid );
473 gid_t *pgid = (gid_t *)sys_acl_get_qualifier(entry);
475 DEBUG(0,("canonicalise_acl: Failed to get gid.\n"));
478 gid_to_sid( &sid, *pgid);
483 continue; /* Don't count the mask as an entry. */
485 /* Use the Everyone SID */
486 sid = global_sid_World;
489 DEBUG(0,("canonicalise_acl: Unknown tagtype %u\n", (unsigned int)tagtype));
494 * Add this entry to the list.
497 if ((ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL)
502 ace->perms = permset;
505 DLIST_ADD(list_head, ace);
509 * Now go through the list, masking the permissions with the
510 * acl_mask. If the permissions are 0 and the type is ACL_USER
511 * or ACL_GROUP then it's a DENY entry and should be listed
512 * first. If the permissions are 0 and the type is ACL_USER_OBJ,
513 * ACL_GROUP_OBJ or ACL_OTHER_OBJ then remove the entry as they
517 for ( ace = list_head; ace; ace = next_ace) {
519 ace->perms &= acl_mask;
521 if (ace->perms == 0) {
526 DLIST_REMOVE(list_head, ace);
530 DLIST_PROMOTE(list_head, ace);
539 /****************************************************************************
540 Reply to query a security descriptor from an fsp. If it succeeds it allocates
541 the space for the return elements and returns the size needed to return the
542 security descriptor. This should be the only external function needed for
543 the UNIX style get ACL.
544 ****************************************************************************/
546 size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc)
548 extern DOM_SID global_sid_World;
549 SMB_STRUCT_STAT sbuf;
550 SEC_ACE *nt_ace_list;
555 SEC_ACCESS owner_access;
557 SEC_ACCESS group_access;
559 SEC_ACCESS other_access;
562 size_t num_dir_acls = 0;
564 SMB_ACL_T posix_acl = NULL;
565 SMB_ACL_T dir_acl = NULL;
566 canon_ace *file_ace = NULL;
567 canon_ace *dir_ace = NULL;
571 if(fsp->is_directory || fsp->fd == -1) {
573 /* Get the stat struct for the owner info. */
574 if(vfs_stat(fsp,fsp->fsp_name, &sbuf) != 0) {
578 * Get the ACL from the path.
581 posix_acl = sys_acl_get_file( dos_to_unix(fsp->fsp_name, False), SMB_ACL_TYPE_ACCESS);
584 * If it's a directory get the default POSIX ACL.
587 if(fsp->is_directory)
588 dir_acl = sys_acl_get_file( dos_to_unix(fsp->fsp_name, False), SMB_ACL_TYPE_DEFAULT);
592 /* Get the stat struct for the owner info. */
593 if(fsp->conn->vfs_ops.fstat(fsp->fd,&sbuf) != 0) {
597 * Get the ACL from the fd.
599 posix_acl = sys_acl_get_fd(fsp->fd);
603 * Get the owner, group and world SIDs.
606 create_file_sids(&sbuf, &owner_sid, &group_sid);
608 /* Create the canon_ace lists. */
610 file_ace = canonicalise_acl( posix_acl, &sbuf);
612 file_ace = unix_canonicalise_acl(fsp, &sbuf, &owner_sid, &group_sid);
614 num_acls = count_canon_ace_list(file_ace);
616 if (fsp->is_directory) {
618 dir_ace = canonicalise_acl( dir_acl, &sbuf);
620 dir_ace = unix_canonicalise_acl(fsp, &sbuf, &owner_sid, &group_sid);
622 num_dir_acls = count_canon_ace_list(dir_ace);
625 /* Allocate the ace list. */
626 if ((nt_ace_list = (SEC_ACE *)malloc((num_acls + num_dir_acls)* sizeof(SEC_ACE))) == NULL) {
627 DEBUG(0,("get_nt_acl: Unable to malloc space for nt_ace_list.\n"));
631 memset(nt_ace_list, '\0', (num_acls + num_dir_acls) * sizeof(SEC_ACE) );
634 * Create the NT ACE list from the canonical ace lists.
643 for (i = 0; i < num_acls; i++, ace = ace->next) {
644 SEC_ACCESS acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
645 init_sec_ace(&nt_ace_list[num_aces++], &ace->sid, nt_acl_type, acc, 0);
650 for (i = 0; i < num_dir_acls; i++, ace = ace->next) {
651 SEC_ACCESS acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
652 init_sec_ace(&nt_ace_list[num_aces++], &ace->sid, nt_acl_type, acc,
653 SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_INHERIT_ONLY);
658 if((psa = make_sec_acl( ACL_REVISION, num_aces, ace_list)) == NULL) {
659 DEBUG(0,("get_nt_acl: Unable to malloc space for acl.\n"));
664 *ppdesc = make_standard_sec_desc( &owner_sid, &group_sid, psa, &sd_size);
667 DEBUG(0,("get_nt_acl: Unable to malloc space for security descriptor.\n"));
674 sys_acl_free(posix_acl);
676 sys_acl_free(directory_acl);
678 free_canon_ace_list(file_ace);
680 free_canon_ace_list(dir_ace);
689 /****************************************************************************
690 Reply to set a security descriptor on an fsp. security_info_sent is the
691 description of the following NT ACL.
692 This should be the only external function needed for the UNIX style set ACL.
693 ****************************************************************************/
695 BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
697 connection_struct *conn = fsp->conn;
698 uid_t user = (uid_t)-1;
699 gid_t grp = (gid_t)-1;
701 SMB_STRUCT_STAT sbuf;
702 BOOL got_dacl = False;
705 * Get the current state of the file.
708 if(fsp->is_directory) {
709 if(dos_stat(fsp->fsp_name, &sbuf) != 0)
716 ret = conn->vfs_ops.stat(dos_to_unix(fsp->fsp_name,False), &sbuf);
718 ret = conn->vfs_ops.fstat(fsp->fd,&sbuf);
725 * Unpack the user/group/world id's and permissions.
728 if (!unpack_nt_permissions( &sbuf, &user, &grp, &perms, security_info_sent, psd, fsp->is_directory))
731 if (psd->dacl != NULL)
735 * Do we need to chown ?
738 if((user != (uid_t)-1 || grp != (uid_t)-1) && (sbuf.st_uid != user || sbuf.st_gid != grp)) {
740 DEBUG(3,("call_nt_transact_set_security_desc: chown %s. uid = %u, gid = %u.\n",
741 fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
743 if(dos_chown( fsp->fsp_name, user, grp) == -1) {
744 DEBUG(3,("call_nt_transact_set_security_desc: chown %s, %u, %u failed. Error = %s.\n",
745 fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
750 * Recheck the current state of the file, which may have changed.
751 * (suid/sgid bits, for instance)
754 if(fsp->is_directory) {
755 if(dos_stat(fsp->fsp_name, &sbuf) != 0) {
763 ret = conn->vfs_ops.stat(dos_to_unix(fsp->fsp_name,False), &sbuf);
765 ret = conn->vfs_ops.fstat(fsp->fd,&sbuf);
773 * Only change security if we got a DACL.
776 if((security_info_sent & DACL_SECURITY_INFORMATION) && got_dacl) {
779 * Check to see if we need to change anything.
780 * Enforce limits on modified bits *only*. Don't enforce masks
781 * on bits not changed by the user.
784 if(fsp->is_directory) {
786 perms &= (lp_dir_security_mask(SNUM(conn)) | sbuf.st_mode);
787 perms |= (lp_force_dir_security_mode(SNUM(conn)) & ( perms ^ sbuf.st_mode ));
791 perms &= (lp_security_mask(SNUM(conn)) | sbuf.st_mode);
792 perms |= (lp_force_security_mode(SNUM(conn)) & ( perms ^ sbuf.st_mode ));
797 * Preserve special bits.
800 perms |= (sbuf.st_mode & ~0777);
803 * Do we need to chmod ?
806 if(sbuf.st_mode != perms) {
808 DEBUG(3,("call_nt_transact_set_security_desc: chmod %s. perms = 0%o.\n",
809 fsp->fsp_name, (unsigned int)perms ));
811 if(conn->vfs_ops.chmod(dos_to_unix(fsp->fsp_name, False), perms) == -1) {
812 DEBUG(3,("call_nt_transact_set_security_desc: chmod %s, 0%o failed. Error = %s.\n",
813 fsp->fsp_name, (unsigned int)perms, strerror(errno) ));
822 #else /* HAVE_POSIX_ACLS */
823 void dummy_posix_acls(void) {;} /* So some compilers don't complain. */
824 #endif /* HAVE_POSIX_ACLS */