SMB_ACL_T aixacl_sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp) { struct acl *file_acl = (struct acl *)NULL; struct smb_acl_t *result = (struct smb_acl_t *)NULL; int rc = 0; uid_t user_id; /* Get the acl using fstatacl */ DEBUG(10,("Entering AIX sys_acl_get_fd\n")); DEBUG(10,("fd is %d\n",fsp->fh->fd)); file_acl = (struct acl *)SMB_MALLOC(BUFSIZ); if(file_acl == NULL) { errno=ENOMEM; DEBUG(0,("Error in AIX sys_acl_get_fd is %d\n",errno)); return(NULL); } memset(file_acl,0,BUFSIZ); rc = fstatacl(fsp->fh->fd,0,file_acl,BUFSIZ); if( (rc == -1) && (errno == ENOSPC)) { struct acl *new_acl = SMB_MALLOC(file_acl->acl_len + sizeof(struct acl)); if( new_acl == NULL) { SAFE_FREE(file_acl); errno = ENOMEM; return NULL; } file_acl = new_acl; rc = fstatacl(fsp->fh->fd,0,file_acl,file_acl->acl_len + sizeof(struct acl)); if( rc == -1) { DEBUG(0,("fstatacl returned %d with errno %d\n",rc,errno)); SAFE_FREE(file_acl); return(NULL); } } DEBUG(10,("Got facl and returned it\n")); result = aixacl_to_smbacl(file_acl); SAFE_FREE(file_acl); return result; /*errno = ENOTSUP; return NULL;*/ }
int qcopy_acl (const char *src_name, int source_desc, const char *dst_name, int dest_desc, mode_t mode) { #if USE_ACL && HAVE_ACL_GET_FILE /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */ /* Linux, FreeBSD, Mac OS X, IRIX, Tru64 */ # if !HAVE_ACL_TYPE_EXTENDED /* Linux, FreeBSD, IRIX, Tru64 */ acl_t acl; int ret; if (HAVE_ACL_GET_FD && source_desc != -1) acl = acl_get_fd (source_desc); else acl = acl_get_file (src_name, ACL_TYPE_ACCESS); if (acl == NULL) { if (! acl_errno_valid (errno)) return qset_acl (dst_name, dest_desc, mode); else return -2; } if (HAVE_ACL_SET_FD && dest_desc != -1) ret = acl_set_fd (dest_desc, acl); else ret = acl_set_file (dst_name, ACL_TYPE_ACCESS, acl); if (ret != 0) { int saved_errno = errno; if (! acl_errno_valid (errno) && !acl_access_nontrivial (acl)) { acl_free (acl); return chmod_or_fchmod (dst_name, dest_desc, mode); } else { acl_free (acl); chmod_or_fchmod (dst_name, dest_desc, mode); errno = saved_errno; return -1; } } else acl_free (acl); if (!MODE_INSIDE_ACL || (mode & (S_ISUID | S_ISGID | S_ISVTX))) { /* We did not call chmod so far, and either the mode and the ACL are separate or special bits are to be set which don't fit into ACLs. */ if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0) return -1; } if (S_ISDIR (mode)) { acl = acl_get_file (src_name, ACL_TYPE_DEFAULT); if (acl == NULL) return -2; if (acl_set_file (dst_name, ACL_TYPE_DEFAULT, acl)) { int saved_errno = errno; acl_free (acl); errno = saved_errno; return -1; } else acl_free (acl); } return 0; # else /* HAVE_ACL_TYPE_EXTENDED */ /* Mac OS X */ /* On Mac OS X, acl_get_file (name, ACL_TYPE_ACCESS) and acl_get_file (name, ACL_TYPE_DEFAULT) always return NULL / EINVAL. You have to use acl_get_file (name, ACL_TYPE_EXTENDED) or acl_get_fd (open (name, ...)) to retrieve an ACL. On the other hand, acl_set_file (name, ACL_TYPE_ACCESS, acl) and acl_set_file (name, ACL_TYPE_DEFAULT, acl) have the same effect as acl_set_file (name, ACL_TYPE_EXTENDED, acl): Each of these calls sets the file's ACL. */ acl_t acl; int ret; if (HAVE_ACL_GET_FD && source_desc != -1) acl = acl_get_fd (source_desc); else acl = acl_get_file (src_name, ACL_TYPE_EXTENDED); if (acl == NULL) { if (!acl_errno_valid (errno)) return qset_acl (dst_name, dest_desc, mode); else return -2; } if (HAVE_ACL_SET_FD && dest_desc != -1) ret = acl_set_fd (dest_desc, acl); else ret = acl_set_file (dst_name, ACL_TYPE_EXTENDED, acl); if (ret != 0) { int saved_errno = errno; if (!acl_errno_valid (saved_errno) && !acl_extended_nontrivial (acl)) { acl_free (acl); return chmod_or_fchmod (dst_name, dest_desc, mode); } else { acl_free (acl); chmod_or_fchmod (dst_name, dest_desc, mode); errno = saved_errno; return -1; } } else acl_free (acl); /* Since !MODE_INSIDE_ACL, we have to call chmod explicitly. */ return chmod_or_fchmod (dst_name, dest_desc, mode); # endif #elif USE_ACL && defined GETACL /* Solaris, Cygwin, not HP-UX */ /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions of Unixware. The acl() call returns the access and default ACL both at once. */ # ifdef ACE_GETACL int ace_count; ace_t *ace_entries; # endif int count; aclent_t *entries; int did_chmod; int saved_errno; int ret; # ifdef ACE_GETACL /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4 file systems (whereas the other ones are used in UFS file systems). There is an API pathconf (name, _PC_ACL_ENABLED) fpathconf (desc, _PC_ACL_ENABLED) that allows to determine which of the two kinds of ACLs is supported for the given file. But some file systems may implement this call incorrectly, so better not use it. When fetching the source ACL, we simply fetch both ACL types. When setting the destination ACL, we try either ACL types, assuming that the kernel will translate the ACL from one form to the other. (See in <http://docs.sun.com/app/docs/doc/819-2241/6n4huc7ia?l=en&a=view> the description of ENOTSUP.) */ for (;;) { ace_count = (source_desc != -1 ? facl (source_desc, ACE_GETACLCNT, 0, NULL) : acl (src_name, ACE_GETACLCNT, 0, NULL)); if (ace_count < 0) { if (errno == ENOSYS || errno == EINVAL) { ace_count = 0; ace_entries = NULL; break; } else return -2; } if (ace_count == 0) { ace_entries = NULL; break; } ace_entries = (ace_t *) malloc (ace_count * sizeof (ace_t)); if (ace_entries == NULL) { errno = ENOMEM; return -2; } ret = (source_desc != -1 ? facl (source_desc, ACE_GETACL, ace_count, ace_entries) : acl (src_name, ACE_GETACL, ace_count, ace_entries)); if (ret < 0) { free (ace_entries); if (errno == ENOSYS || errno == EINVAL) { ace_count = 0; ace_entries = NULL; break; } else return -2; } if (ret == ace_count) break; /* Huh? The number of ACL entries changed since the last call. Repeat. */ } # endif for (;;) { count = (source_desc != -1 ? facl (source_desc, GETACLCNT, 0, NULL) : acl (src_name, GETACLCNT, 0, NULL)); if (count < 0) { if (errno == ENOSYS || errno == ENOTSUP || errno == EOPNOTSUPP) { count = 0; entries = NULL; break; } else return -2; } if (count == 0) { entries = NULL; break; } entries = (aclent_t *) malloc (count * sizeof (aclent_t)); if (entries == NULL) { errno = ENOMEM; return -2; } if ((source_desc != -1 ? facl (source_desc, GETACL, count, entries) : acl (src_name, GETACL, count, entries)) == count) break; /* Huh? The number of ACL entries changed since the last call. Repeat. */ } /* Is there an ACL of either kind? */ # ifdef ACE_GETACL if (ace_count == 0) # endif if (count == 0) return qset_acl (dst_name, dest_desc, mode); did_chmod = 0; /* set to 1 once the mode bits in 0777 have been set */ saved_errno = 0; /* the first non-ignorable error code */ if (!MODE_INSIDE_ACL) { /* On Cygwin, it is necessary to call chmod before acl, because chmod can change the contents of the ACL (in ways that don't change the allowed accesses, but still visible). */ if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0) saved_errno = errno; did_chmod = 1; } /* If both ace_entries and entries are available, try SETACL before ACE_SETACL, because SETACL cannot fail with ENOTSUP whereas ACE_SETACL can. */ if (count > 0) { ret = (dest_desc != -1 ? facl (dest_desc, SETACL, count, entries) : acl (dst_name, SETACL, count, entries)); if (ret < 0 && saved_errno == 0) { saved_errno = errno; if ((errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL) && !acl_nontrivial (count, entries)) saved_errno = 0; } else did_chmod = 1; } free (entries); # ifdef ACE_GETACL if (ace_count > 0) { ret = (dest_desc != -1 ? facl (dest_desc, ACE_SETACL, ace_count, ace_entries) : acl (dst_name, ACE_SETACL, ace_count, ace_entries)); if (ret < 0 && saved_errno == 0) { saved_errno = errno; if ((errno == ENOSYS || errno == EINVAL || errno == ENOTSUP) && !acl_ace_nontrivial (ace_count, ace_entries)) saved_errno = 0; } } free (ace_entries); # endif if (MODE_INSIDE_ACL && did_chmod <= ((mode & (S_ISUID | S_ISGID | S_ISVTX)) ? 1 : 0)) { /* We did not call chmod so far, and either the mode and the ACL are separate or special bits are to be set which don't fit into ACLs. */ if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0) { if (saved_errno == 0) saved_errno = errno; } } if (saved_errno) { errno = saved_errno; return -1; } return 0; #elif USE_ACL && HAVE_GETACL /* HP-UX */ struct acl_entry entries[NACLENTRIES]; int count; # if HAVE_ACLV_H struct acl aclv_entries[NACLVENTRIES]; int aclv_count; # endif int did_chmod; int saved_errno; int ret; count = (source_desc != -1 ? fgetacl (source_desc, NACLENTRIES, entries) : getacl (src_name, NACLENTRIES, entries)); if (count < 0) { if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP) count = 0; else return -2; } else if (count > 0) { if (count > NACLENTRIES) /* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */ abort (); } # if HAVE_ACLV_H aclv_count = acl ((char *) src_name, ACL_GET, NACLVENTRIES, aclv_entries); if (aclv_count < 0) { if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL) count = 0; else return -2; } else if (aclv_count > 0) { if (aclv_count > NACLVENTRIES) /* If NACLVENTRIES cannot be trusted, use dynamic memory allocation. */ abort (); } # endif if (count == 0) # if HAVE_ACLV_H if (aclv_count == 0) # endif return qset_acl (dst_name, dest_desc, mode); did_chmod = 0; /* set to 1 once the mode bits in 0777 have been set */ saved_errno = 0; /* the first non-ignorable error code */ if (count > 0) { ret = (dest_desc != -1 ? fsetacl (dest_desc, count, entries) : setacl (dst_name, count, entries)); if (ret < 0 && saved_errno == 0) { saved_errno = errno; if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP) { struct stat source_statbuf; if ((source_desc != -1 ? fstat (source_desc, &source_statbuf) : stat (src_name, &source_statbuf)) == 0) { if (!acl_nontrivial (count, entries, &source_statbuf)) saved_errno = 0; } else saved_errno = errno; } } else did_chmod = 1; } # if HAVE_ACLV_H if (aclv_count > 0) { ret = acl ((char *) dst_name, ACL_SET, aclv_count, aclv_entries); if (ret < 0 && saved_errno == 0) { saved_errno = errno; if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL) { if (!aclv_nontrivial (aclv_count, aclv_entries)) saved_errno = 0; } } else did_chmod = 1; } # endif if (did_chmod <= ((mode & (S_ISUID | S_ISGID | S_ISVTX)) ? 1 : 0)) { /* We did not call chmod so far, and special bits are to be set which don't fit into ACLs. */ if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0) { if (saved_errno == 0) saved_errno = errno; } } if (saved_errno) { errno = saved_errno; return -1; } return 0; #elif USE_ACL && HAVE_ACLX_GET && 0 /* AIX */ /* TODO */ #elif USE_ACL && HAVE_STATACL /* older AIX */ union { struct acl a; char room[4096]; } u; int ret; if ((source_desc != -1 ? fstatacl (source_desc, STX_NORMAL, &u.a, sizeof (u)) : statacl (src_name, STX_NORMAL, &u.a, sizeof (u))) < 0) return -2; ret = (dest_desc != -1 ? fchacl (dest_desc, &u.a, u.a.acl_len) : chacl (dst_name, &u.a, u.a.acl_len)); if (ret < 0) { int saved_errno = errno; chmod_or_fchmod (dst_name, dest_desc, mode); errno = saved_errno; return -1; } /* No need to call chmod_or_fchmod at this point, since the mode bits S_ISUID, S_ISGID, S_ISVTX are also stored in the ACL. */ return 0; #elif USE_ACL && HAVE_ACLSORT /* NonStop Kernel */ struct acl entries[NACLENTRIES]; int count; int ret; count = acl ((char *) src_name, ACL_GET, NACLENTRIES, entries); if (count < 0) { if (0) count = 0; else return -2; } else if (count > 0) { if (count > NACLENTRIES) /* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */ abort (); } if (count == 0) return qset_acl (dst_name, dest_desc, mode); ret = acl ((char *) dst_name, ACL_SET, count, entries); if (ret < 0) { int saved_errno = errno; if (0) { if (!acl_nontrivial (count, entries)) return chmod_or_fchmod (dst_name, dest_desc, mode); } chmod_or_fchmod (dst_name, dest_desc, mode); errno = saved_errno; return -1; } if (mode & (S_ISUID | S_ISGID | S_ISVTX)) { /* We did not call chmod so far, and either the mode and the ACL are separate or special bits are to be set which don't fit into ACLs. */ return chmod_or_fchmod (dst_name, dest_desc, mode); } return 0; #else return qset_acl (dst_name, dest_desc, mode); #endif }