// // Encode a key into a blob. // We'll have to ask our Database to do this - we don't have its keys. // Note that this returns memory we own and keep. // KeyBlob *KeychainKey::blob() { if (!mValidBlob) { assert(mValidKey); // must have valid key to encode // export Key ACL to blob form CssmData pubAcl, privAcl; acl().exportBlob(pubAcl, privAcl); // assemble external key form CssmKey externalKey = mKey; externalKey.clearAttribute(forcedAttributes); externalKey.setAttribute(mAttributes); // encode the key and replace blob KeyBlob *newBlob = database().encodeKey(externalKey, pubAcl, privAcl); Allocator::standard().free(mBlob); mBlob = newBlob; mValidBlob = true; // clean up and go acl().allocator.free(pubAcl); acl().allocator.free(privAcl); } return mBlob; }
static bool solaris_acl_get_file(const char *name, SOLARIS_ACL_T *solaris_acl, int *count) { bool result = False; DEBUG(10, ("solaris_acl_get_file called for file '%s'\n", name)); /* * The original code tries some INITIAL_ACL_SIZE * and only did the GETACLCNT call upon failure * (for performance reasons). * For the sake of simplicity, I skip this for now. */ *count = acl(name, GETACLCNT, 0, NULL); if (*count < 0) { DEBUG(10, ("acl GETACLCNT failed: %s\n", strerror(errno))); goto done; } *solaris_acl = solaris_acl_init(*count); if (*solaris_acl == NULL) { DEBUG(10, ("error allocating memory for solaris acl...\n")); goto done; } *count = acl(name, GETACL, *count, *solaris_acl); if (*count < 0) { DEBUG(10, ("acl GETACL failed: %s\n", strerror(errno))); goto done; } result = True; done: DEBUG(10, ("solaris_acl_get_file %s.\n", ((result == True) ? "succeeded" : "failed" ))); return result; }
/* * Remove an ACL from a file and create a trivial ACL based * off of the mode argument. After acl has been set owner/group * are updated to match owner,group arguments */ int acl_strip(const char *file, uid_t owner, gid_t group, mode_t mode) { int error = 0; aclent_t min_acl[MIN_ACL_ENTRIES]; ace_t *min_ace_acl; int acl_flavor; int aclcnt; acl_flavor = pathconf(file, _PC_ACL_ENABLED); /* * force it through aclent flavor when file system doesn't * understand question */ if (acl_flavor == 0 || acl_flavor == -1) acl_flavor = _ACL_ACLENT_ENABLED; if (acl_flavor & _ACL_ACLENT_ENABLED) { min_acl[0].a_type = USER_OBJ; min_acl[0].a_id = owner; min_acl[0].a_perm = ((mode & 0700) >> 6); min_acl[1].a_type = GROUP_OBJ; min_acl[1].a_id = group; min_acl[1].a_perm = ((mode & 0070) >> 3); min_acl[2].a_type = CLASS_OBJ; min_acl[2].a_id = (uid_t)-1; min_acl[2].a_perm = ((mode & 0070) >> 3); min_acl[3].a_type = OTHER_OBJ; min_acl[3].a_id = (uid_t)-1; min_acl[3].a_perm = (mode & 0007); aclcnt = 4; error = acl(file, SETACL, aclcnt, min_acl); } else if (acl_flavor & _ACL_ACE_ENABLED) {
/** \brief called to authenticate a x509_cert_t received by the scnx layer * * @return scnx_err_t::OK if the certificate is allowed, any other value mean denied */ scnx_err_t router_peer_t::scnx_auth_ftor_nonesigned_cb(void *userptr, const x509_cert_t &cert) throw() { // log to debug KLOG_ERR("enter remote_cert=" << cert); // NOTE: at this point, it is a authsigned certificate DBG_ASSERT( router_name_t(cert.subject_name()).is_nonesigned_ok() ); // convert the x509_cert_t subject_name into a router_name_t router_name_t remote_dnsname = router_name_t(cert.subject_name()); // NOTE: explicitly no check with the rootca_arr as it is a nonesigned // If this is a authentication for router_itor_t, ensure the cert is the expected one // - if the userptr is non-null, this mean this is an authentication for router_itor_t // - router_resp_t leave it NULL // - this check prevent the following attack // 1. alice and bob are both allowed to connect the local peer // 2. the local peer initiate a connection toward alice // 3. bob intercept the connection and replies its own certificate // 4. the local peer accepts it without noticing it is not alice one if( userptr ){ router_peerid_t remote_peerid = router_peerid_t::from_canonical_string(remote_dnsname.host()); router_itor_t * router_itor = itor_by_remote_peerid(remote_peerid); if( userptr != router_itor ) return scnx_err_t::ACL_REFUSED; } // check if the router_acl_t allows this remote_dnsname if( acl().reject(remote_dnsname.to_string()) ) return scnx_err_t::ACL_REFUSED; // if this point is reached, the certificate is allowed return scnx_err_t::OK; }
QVariantMap FeedHeader::f(Channel *channel) const { QVariantMap json; if (!(acl().match(channel) & Acl::Read)) return json; json[name()] = date(); return json; }
// // Create a Database object from initial parameters (create operation) // KeychainDatabase::KeychainDatabase(const DLDbIdentifier &id, const DBParameters ¶ms, Process &proc, const AccessCredentials *cred, const AclEntryPrototype *owner) : LocalDatabase(proc), mValidData(false), mSecret(Allocator::standard(Allocator::sensitive)), mSaveSecret(false), version(0), mBlob(NULL) { // save a copy of the credentials for later access control mCred = DataWalkers::copy(cred, Allocator::standard()); // create a new random signature to complete the DLDbIdentifier DbBlob::Signature newSig; Server::active().random(newSig.bytes); DbIdentifier ident(id, newSig); // create common block and initialize RefPointer<KeychainDbCommon> newCommon = new KeychainDbCommon(proc.session(), ident); StLock<Mutex> _(*newCommon); parent(*newCommon); // new common is now visible (in ident-map) but we hold its lock // establish the new master secret establishNewSecrets(cred, SecurityAgent::newDatabase); // set initial database parameters common().mParams = params; // the common is "unlocked" now common().makeNewSecrets(); // establish initial ACL if (owner) acl().cssmSetInitial(*owner); else acl().cssmSetInitial(new AnyAclSubject()); mValidData = true; // for now, create the blob immediately encode(); proc.addReference(*this); // this new keychain is unlocked; make it so activity(); SECURITYD_KEYCHAIN_CREATE(&common(), (char*)this->dbName(), this); }
/* Removes all non-trivial ACLs from object. Returns full AFPERR code. */ int remove_acl_vfs(const char *name) { int ret,i, ace_count, trivial_aces, new_aces_count; ace_t *old_aces = NULL; ace_t *new_aces = NULL; LOG(log_debug9, logtype_afpd, "remove_acl: BEGIN"); /* Get existing ACL and count trivial ACEs */ if ((ace_count = get_nfsv4_acl(name, &old_aces)) == -1) return AFPERR_MISC; trivial_aces = 0; for ( i=0; i < ace_count; i++) { if (old_aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE)) trivial_aces++; } /* malloc buffer for new ACL */ if ((new_aces = malloc(trivial_aces * sizeof(ace_t))) == NULL) { LOG(log_error, logtype_afpd, "remove_acl: malloc %s", strerror(errno)); ret = AFPERR_MISC; goto exit; } /* Now copy the trivial ACEs */ new_aces_count = 0; for (i=0; i < ace_count; i++) { if (old_aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE)) { memcpy(&new_aces[new_aces_count], &old_aces[i], sizeof(ace_t)); new_aces_count++; } } if ( (acl(name, ACE_SETACL, trivial_aces, new_aces)) == 0) ret = AFP_OK; else { LOG(log_error, logtype_afpd, "set_acl: error setting acl: %s", strerror(errno)); if (errno == (EACCES | EPERM)) ret = AFPERR_ACCESS; else if (errno == ENOENT) ret = AFPERR_NOITEM; else ret = AFPERR_MISC; } exit: free(old_aces); free(new_aces); LOG(log_debug9, logtype_afpd, "remove_acl: END"); return ret; }
/* * Set an ACL, translates acl to ace_t when appropriate. */ static int cacl_set(acl_inp *acl_inp, acl_t *aclp, int type) { int error = 0; int acl_flavor_target; struct stat64 statbuf; int stat_error; int isdir; if (type == ACL_PATH) { stat_error = stat64(acl_inp->file, &statbuf); if (stat_error) return (-1); acl_flavor_target = pathconf(acl_inp->file, _PC_ACL_ENABLED); } else { stat_error = fstat64(acl_inp->fd, &statbuf); if (stat_error) return (-1); acl_flavor_target = fpathconf(acl_inp->fd, _PC_ACL_ENABLED); } /* * If target returns an error or 0 from pathconf call then * fall back to UFS/POSIX Draft interface. * In the case of 0 we will then fail in either acl(2) or * acl_translate(). We could erroneously get 0 back from * a file system that is using fs_pathconf() and not answering * the _PC_ACL_ENABLED question itself. */ if (acl_flavor_target == 0 || acl_flavor_target == -1) acl_flavor_target = _ACL_ACLENT_ENABLED; isdir = S_ISDIR(statbuf.st_mode); if ((error = acl_translate(aclp, acl_flavor_target, isdir, statbuf.st_uid, statbuf.st_gid)) != 0) { return (error); } if (type == ACL_PATH) { error = acl(acl_inp->file, (aclp->acl_type == ACE_T) ? ACE_SETACL : SETACL, aclp->acl_cnt, aclp->acl_aclp); } else { error = facl(acl_inp->fd, (aclp->acl_type == ACE_T) ? ACE_SETACL : SETACL, aclp->acl_cnt, aclp->acl_aclp); } return (error); }
std::shared_ptr<AudioChannelLayout> AudioConverterX::getOutputChannelLayout() { UInt32 size; Boolean writable; CHECKCA(AudioConverterGetPropertyInfo(m_converter.get(), kAudioConverterOutputChannelLayout, &size, &writable)); std::shared_ptr<AudioChannelLayout> acl( static_cast<AudioChannelLayout*>(std::malloc(size)), std::free); CHECKCA(AudioConverterGetProperty(m_converter.get(), kAudioConverterOutputChannelLayout, &size, acl.get())); return acl; }
/* * Determine whether a file has a trivial ACL * returns: 0 = trivial * 1 = nontrivial * <0 some other system failure, such as ENOENT or EPERM */ int acl_trivial(const char *filename) { int acl_flavor; int aclcnt; int cntcmd; int val = 0; ace_t *acep; acl_flavor = pathconf(filename, _PC_ACL_ENABLED); if (acl_flavor == _ACL_ACE_ENABLED) cntcmd = ACE_GETACLCNT; else cntcmd = GETACLCNT; aclcnt = acl(filename, cntcmd, 0, NULL); if (aclcnt > 0) { if (acl_flavor == _ACL_ACE_ENABLED) { acep = malloc(sizeof (ace_t) * aclcnt); if (acep == NULL) return (-1); if (acl(filename, ACE_GETACL, aclcnt, acep) < 0) { free(acep); return (-1); } val = ace_trivial(acep, aclcnt); free(acep); } else if (aclcnt > MIN_ACL_ENTRIES) val = 1; } return (val); }
// // Given the established master secret, decode the working keys and other // functional secrets for this database. Return false (do NOT throw) if // the decode fails. Call this in low(er) level code once you established // the master key. // bool KeychainDatabase::decode() { assert(mBlob); assert(common().hasMaster()); void *privateAclBlob; if (common().unlockDb(mBlob, &privateAclBlob)) { if (!mValidData) { acl().importBlob(mBlob->publicAclBlob(), privateAclBlob); mValidData = true; } Allocator::standard().free(privateAclBlob); return true; } secdebug("KCdb", "%p decode failed", this); return false; }
/* * routine: * get_acls * * purpose: * to read the ACL (if any) from a file into a fileinfo structure * * parameters: * name of file * pointer to fileinfo structure * * returns: * number of ACL entries */ int get_acls(const char *name, struct fileinfo *ip) { int count; int i; static aclent_t acls[MAX_ACL_ENTRIES]; aclent_t *list; count = acl(name, GETACL, MAX_ACL_ENTRIES, acls); if (count <= 0) return (0); /* with a count of 3 or 4 there may not be any real ones */ if (count > 4) goto gotsome; /* look for anything beyond the normal unix protection */ for (i = 0; i < count; i++) switch (acls[i].a_type) { default: /* weird types are real */ goto gotsome; case USER_OBJ: case GROUP_OBJ: case OTHER_OBJ: case CLASS_OBJ: continue; /* all file have these */ } return (0); /* nothing interesting */ gotsome: /* allocate an array to hold the acls */ list = (aclent_t *) malloc(count * sizeof (*list)); if (list == 0) nomem("Access Control List"); /* copy the acls into the new list */ for (i = 0; i < count; i++) { list[i].a_type = acls[i].a_type; list[i].a_id = acls[i].a_id; list[i].a_perm = acls[i].a_perm; } ip->f_acls = list; ip->f_numacls = count; return (ip->f_numacls); }
int file_has_acl (char const *file, struct stat const *filestat) { /* FIXME: This implementation should work on recent-enough versions of HP-UX, Solaris, and Unixware, but it simply returns 0 with POSIX 1003.1e (draft 17 -- abandoned), AIX, GNU/Linux, Irix, and Tru64. Please see Samba's source/lib/sysacls.c file for fix-related ideas. */ #if HAVE_ACL && defined GETACLCNT if (! S_ISLNK (filestat->st_mode)) { int n = acl (file, GETACLCNT, 0, NULL); return n < 0 ? (errno == ENOSYS ? 0 : -1) : (MIN_ACL_ENTRIES < n); } #endif return 0; }
IpBlockMap::IpBlockMap(Hdf config) { for (Hdf hdf = config.firstChild(); hdf.exists(); hdf = hdf.next()) { AclPtr acl(new Acl()); bool allow = hdf["AllowFirst"].getBool(false); if (allow) { LoadIpList(acl->ips, hdf["Ip.Deny"], false); LoadIpList(acl->ips, hdf["Ip.Allow"], true); } else { LoadIpList(acl->ips, hdf["Ip.Allow"], true); LoadIpList(acl->ips, hdf["Ip.Deny"], false); } string location = hdf["Location"].getString(); if (!location.empty() && location[0] == '/') { location = location.substr(1); } m_acls[location] = acl; } }
/** \brief called to authenticate a x509_cert_t received by the scnx layer * * @return scnx_err_t::OK if the certificate is allowed, any other value mean denied */ scnx_err_t router_peer_t::scnx_auth_ftor_selfsigned_cb(void *userptr, const x509_cert_t &cert) throw() { const std::string & subject_name = cert.subject_name(); // log to debug KLOG_DBG("enter remote_cert=" << cert); // sanity check - the x509_cert_t MUST be one of a selfsigned router_lident_t DBG_ASSERT( !router_peerid_t::from_canonical_string( subject_name ).is_null() ); // convert the cert.subject_name() into a router_peerid_t router_peerid_t remote_peerid = router_peerid_t::from_canonical_string(subject_name); // try to find a router_rident_t for this remote_peerid const router_rident_t * rident = rident_arr().find_by_peerid(remote_peerid); // if the router_rident_t doesnt exists, the certificated is refused if( !rident ) return scnx_err_t::ACL_REFUSED; // if the router_rident_t certificate IS NOT equal, the certificate is refused if( rident->cert() != cert ) return scnx_err_t::ACL_REFUSED; // If this is a authentication for router_itor_t, ensure the cert is the expected one // - if the userptr is non-null, this mean this is an authentication for router_itor_t // - router_resp_t leave it NULL // - this check prevent the following attack // 1. alice and bob are both allowed to connect the local peer // 2. the local peer initiate a connection toward alice // 3. bob intercept the connection and replies its own certificate // 4. the local peer accepts it without noticing it is not alice one if( userptr ){ router_itor_t * router_itor = itor_by_remote_peerid(remote_peerid); if( userptr != router_itor ) return scnx_err_t::ACL_REFUSED; } // get the remote_dnsname from the router_rident_t router_name_t remote_dnsname = rident->dnsfqname(profile); // check if the router_acl_t allows this remote_dnsname if( acl().reject(remote_dnsname.to_string()) ) return scnx_err_t::ACL_REFUSED; // else the certificated is allowed return scnx_err_t::OK; }
/** \brief called to authenticate a x509_cert_t received by the scnx layer * * @return scnx_err_t::OK if the certificate is allowed, any other value mean denied */ scnx_err_t router_peer_t::scnx_auth_ftor_authsigned_cb(void *userptr, const x509_cert_t &cert) throw() { const std::string & subject_name = cert.subject_name(); // log to debug KLOG_ERR("enter remote_cert=" << cert); // NOTE: at this point, it is a authsigned certificate DBG_ASSERT( router_name_t(subject_name).is_authsigned_ok() ); // convert the x509_cert_t subject_name into a router_name_t router_name_t remote_dnsname = router_name_t(subject_name); // try to find a router_rootca_t for the dnsname const router_rootca_t * rootca = rootca_arr().find_by_dnsname(remote_dnsname); // if the router_rootca_t doesnt exists, the certificated is refused if( !rootca ) return scnx_err_t::ACL_REFUSED; // if the router_rootca_t certificate DOES NOT verify the user_cert, the certificate is refused if( rootca->cert().verify_cert(cert).failed() ) return scnx_err_t::ACL_REFUSED; // If this is a authentication for router_itor_t, ensure the cert is the expected one // - if the userptr is non-null, this mean this is an authentication for router_itor_t // - router_resp_t leave it NULL // - this check prevent the following attack // 1. alice and bob are both allowed to connect the local peer // 2. the local peer initiate a connection toward alice // 3. bob intercept the connection and replies its own certificate // 4. the local peer accepts it without noticing it is not alice one if( userptr ){ router_peerid_t remote_peerid = remote_dnsname.to_string(); router_itor_t * router_itor = itor_by_remote_peerid(remote_peerid); if( userptr != router_itor ) return scnx_err_t::ACL_REFUSED; } // check if the router_acl_t allows this remote_dnsname if( acl().reject(remote_dnsname.to_string()) ) return scnx_err_t::ACL_REFUSED; // if this point is reached, the certificate is allowed return scnx_err_t::OK; }
/** \brief return true if fully-qualified router_name_t may be handled by dnsgrab, false otherwise * * - to be dnsgrab_ok, a dnsname MUST be authorized to connect to this peer * - to be dnsgrab_ok, a dnsname MUST NOT be a nonesigned * - nonesigned peer can only itor connection, never resp to it * - and dnsgrab is done to itor connection *toward* this dnsname * - aka the opposite/wrong direction */ bool router_peer_t::dnsname_is_dnsgrab_ok(const router_name_t &remote_name) const throw() { // sanity check - remote_name MUST be fully_qualified DBG_ASSERT( remote_name.is_fully_qualified() ); // if this router_name_t is not allowed by the acl, return false if( acl().reject(remote_name.to_string()) ) return false; // if the remote_name matches a router_rootca_t, return true // - this means it may be a valid authsigned peer if( rootca_arr().find_by_dnsname(remote_name) ) return true; // if remote_name has a selfsigned_domain and has a rident, return true if( remote_name.domain() == profile.selfsigned_domain_str() ){ // if no router_rident_t matches this remote_name, return false if( !rident_arr().find_by_name(remote_name, profile)) return false; // else return true return true; } // if all previous tests passed, the dnsname is NOT handled, so return false return false; }
// // Ensure that a key is fully decoded. // This makes the mKey key value available for use, as well as its ACL. // Caller must hold the key object lock. // void KeychainKey::decode() { if (!mValidKey) { assert(mValidBlob); // must have a blob to decode // decode the key void *publicAcl, *privateAcl; CssmKey key; database().decodeKey(mBlob, key, publicAcl, privateAcl); mKey = CssmClient::Key(Server::csp(), key); acl().importBlob(publicAcl, privateAcl); // publicAcl points into the blob; privateAcl was allocated for us Allocator::standard().free(privateAcl); // extract managed attribute bits mAttributes = mKey.header().attributes() & managedAttributes; mKey.header().clearAttribute(managedAttributes); mKey.header().setAttribute(forcedAttributes); // key is valid now mValidKey = true; } }
/* * delete the default ACL of a directory * * This is achieved by fetching the access ACL and rewriting it * directly, via the solaris system call: the SETACL call on * directories writes both the access and the default ACL as provided. * * XXX: posix acl_delete_def_file returns an error if * the file referred to by path is not a directory. * this function does not complain but the actions * have no effect on a file other than a directory. * But sys_acl_delete_default_file is only called in * smbd/posixacls.c after having checked that the file * is a directory, anyways. So implementing the extra * check is considered unnecessary. --- Agreed? XXX */ int solarisacl_sys_acl_delete_def_file(vfs_handle_struct *handle, const char *path) { SMB_ACL_T smb_acl; int ret = -1; SOLARIS_ACL_T solaris_acl = NULL; int count; DEBUG(10, ("entering solarisacl_sys_acl_delete_def_file.\n")); smb_acl = solarisacl_sys_acl_get_file(handle, path, SMB_ACL_TYPE_ACCESS, talloc_tos()); if (smb_acl == NULL) { DEBUG(10, ("getting file acl failed!\n")); goto done; } if (!smb_acl_to_solaris_acl(smb_acl, &solaris_acl, &count, SMB_ACL_TYPE_ACCESS)) { DEBUG(10, ("conversion smb_acl -> solaris_acl failed.\n")); goto done; } if (!solaris_acl_sort(solaris_acl, count)) { DEBUG(10, ("resulting acl is not valid!\n")); goto done; } ret = acl(path, SETACL, count, solaris_acl); if (ret != 0) { DEBUG(10, ("settinge file acl failed!\n")); } done: DEBUG(10, ("solarisacl_sys_acl_delete_def_file %s.\n", ((ret != 0) ? "failed" : "succeeded" ))); TALLOC_FREE(smb_acl); return ret; }
int file_has_acl (char const *name, struct stat const *sb) { #if USE_ACL if (! S_ISLNK (sb->st_mode)) { # if HAVE_ACL_GET_FILE /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */ /* Linux, FreeBSD, MacOS X, IRIX, Tru64 */ int ret; if (HAVE_ACL_EXTENDED_FILE) /* Linux */ { /* On Linux, acl_extended_file is an optimized function: It only makes two calls to getxattr(), one for ACL_TYPE_ACCESS, one for ACL_TYPE_DEFAULT. */ ret = acl_extended_file (name); } else /* FreeBSD, MacOS X, IRIX, Tru64 */ { # if HAVE_ACL_TYPE_EXTENDED /* MacOS X */ /* On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS) and acl_get_file (name, ACL_TYPE_DEFAULT) always return NULL / EINVAL. There is no point in making these two useless calls. The real ACL is retrieved through acl_get_file (name, ACL_TYPE_EXTENDED). */ acl_t acl = acl_get_file (name, ACL_TYPE_EXTENDED); if (acl) { ret = acl_extended_nontrivial (acl); acl_free (acl); } else ret = -1; # else /* FreeBSD, IRIX, Tru64 */ acl_t acl = acl_get_file (name, ACL_TYPE_ACCESS); if (acl) { int saved_errno; ret = acl_access_nontrivial (acl); saved_errno = errno; acl_free (acl); errno = saved_errno; # if HAVE_ACL_FREE_TEXT /* Tru64 */ /* On OSF/1, acl_get_file (name, ACL_TYPE_DEFAULT) always returns NULL with errno not set. There is no point in making this call. */ # else /* FreeBSD, IRIX */ /* On Linux, FreeBSD, IRIX, acl_get_file (name, ACL_TYPE_ACCESS) and acl_get_file (name, ACL_TYPE_DEFAULT) on a directory either both succeed or both fail; it depends on the file system. Therefore there is no point in making the second call if the first one already failed. */ if (ret == 0 && S_ISDIR (sb->st_mode)) { acl = acl_get_file (name, ACL_TYPE_DEFAULT); if (acl) { ret = (0 < acl_entries (acl)); acl_free (acl); } else ret = -1; } # endif } else ret = -1; # endif } if (ret < 0) return ACL_NOT_WELL_SUPPORTED (errno) ? 0 : -1; return ret; # elif HAVE_FACL && defined GETACLCNT /* Solaris, Cygwin, not HP-UX */ # if defined ACL_NO_TRIVIAL /* Solaris 10 (newer version), which has additional API declared in <sys/acl.h> (acl_t) and implemented in libsec (acl_set, acl_trivial, acl_fromtext, ...). */ return acl_trivial (name); # else /* Solaris, Cygwin, general case */ /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions of Unixware. The acl() call returns the access and default ACL both at once. */ int count; { aclent_t *entries; for (;;) { count = acl (name, GETACLCNT, 0, NULL); if (count < 0) { if (errno == ENOSYS || errno == ENOTSUP) break; else return -1; } if (count == 0) break; /* Don't use MIN_ACL_ENTRIES: It's set to 4 on Cygwin, but Cygwin returns only 3 entries for files with no ACL. But this is safe: If there are more than 4 entries, there cannot be only the "user::", "group::", "other:", and "mask:" entries. */ if (count > 4) return 1; entries = (aclent_t *) malloc (count * sizeof (aclent_t)); if (entries == NULL) { errno = ENOMEM; return -1; } if (acl (name, GETACL, count, entries) == count) { if (acl_nontrivial (count, entries)) { free (entries); return 1; } free (entries); break; } /* Huh? The number of ACL entries changed since the last call. Repeat. */ free (entries); } } # 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). */ { ace_t *entries; for (;;) { count = acl (name, ACE_GETACLCNT, 0, NULL); if (count < 0) { if (errno == ENOSYS || errno == EINVAL) break; else return -1; } if (count == 0) break; /* In the old (original Solaris 10) convention: If there are more than 3 entries, there cannot be only the ACE_OWNER, ACE_GROUP, ACE_OTHER entries. In the newer Solaris 10 and Solaris 11 convention: If there are more than 6 entries, there cannot be only the ACE_OWNER, ACE_GROUP, ACE_EVERYONE entries, each once with NEW_ACE_ACCESS_ALLOWED_ACE_TYPE and once with NEW_ACE_ACCESS_DENIED_ACE_TYPE. */ if (count > 6) return 1; entries = (ace_t *) malloc (count * sizeof (ace_t)); if (entries == NULL) { errno = ENOMEM; return -1; } if (acl (name, ACE_GETACL, count, entries) == count) { if (acl_ace_nontrivial (count, entries)) { free (entries); return 1; } free (entries); break; } /* Huh? The number of ACL entries changed since the last call. Repeat. */ free (entries); } } # endif return 0; # endif # elif HAVE_GETACL /* HP-UX */ for (;;) { int count; struct acl_entry entries[NACLENTRIES]; count = getacl (name, 0, NULL); if (count < 0) { /* ENOSYS is seen on newer HP-UX versions. EOPNOTSUPP is typically seen on NFS mounts. ENOTSUP was seen on Quantum StorNext file systems (cvfs). */ if (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP) break; else return -1; } if (count == 0) return 0; if (count > NACLENTRIES) /* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */ abort (); /* If there are more than 3 entries, there cannot be only the (uid,%), (%,gid), (%,%) entries. */ if (count > 3) return 1; if (getacl (name, count, entries) == count) { struct stat statbuf; if (stat (name, &statbuf) < 0) return -1; return acl_nontrivial (count, entries, &statbuf); } /* Huh? The number of ACL entries changed since the last call. Repeat. */ } # if HAVE_ACLV_H /* HP-UX >= 11.11 */ for (;;) { int count; struct acl entries[NACLVENTRIES]; count = acl ((char *) name, ACL_CNT, NACLVENTRIES, entries); if (count < 0) { /* EOPNOTSUPP is seen on NFS in HP-UX 11.11, 11.23. EINVAL is seen on NFS in HP-UX 11.31. */ if (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL) break; else return -1; } if (count == 0) return 0; if (count > NACLVENTRIES) /* If NACLVENTRIES cannot be trusted, use dynamic memory allocation. */ abort (); /* If there are more than 4 entries, there cannot be only the four base ACL entries. */ if (count > 4) return 1; if (acl ((char *) name, ACL_GET, count, entries) == count) return aclv_nontrivial (count, entries); /* Huh? The number of ACL entries changed since the last call. Repeat. */ } # endif # elif HAVE_ACLX_GET && defined ACL_AIX_WIP /* AIX */ acl_type_t type; char aclbuf[1024]; void *acl = aclbuf; size_t aclsize = sizeof (aclbuf); mode_t mode; for (;;) { /* The docs say that type being 0 is equivalent to ACL_ANY, but it is not true, in AIX 5.3. */ type.u64 = ACL_ANY; if (aclx_get (name, 0, &type, aclbuf, &aclsize, &mode) >= 0) break; if (errno == ENOSYS) return 0; if (errno != ENOSPC) { if (acl != aclbuf) { int saved_errno = errno; free (acl); errno = saved_errno; } return -1; } aclsize = 2 * aclsize; if (acl != aclbuf) free (acl); acl = malloc (aclsize); if (acl == NULL) { errno = ENOMEM; return -1; } } if (type.u64 == ACL_AIXC) { int result = acl_nontrivial ((struct acl *) acl); if (acl != aclbuf) free (acl); return result; } else if (type.u64 == ACL_NFS4) { int result = acl_nfs4_nontrivial ((nfs4_acl_int_t *) acl); if (acl != aclbuf) free (acl); return result; } else { /* A newer type of ACL has been introduced in the system. We should better support it. */ if (acl != aclbuf) free (acl); errno = EINVAL; return -1; } # elif HAVE_STATACL /* older AIX */ union { struct acl a; char room[4096]; } u; if (statacl (name, STX_NORMAL, &u.a, sizeof (u)) < 0) return -1; return acl_nontrivial (&u.a); # elif HAVE_ACLSORT /* NonStop Kernel */ int count; struct acl entries[NACLENTRIES]; for (;;) { count = acl ((char *) name, ACL_CNT, NACLENTRIES, NULL); if (count < 0) { if (errno == ENOSYS || errno == ENOTSUP) break; else return -1; } if (count == 0) return 0; if (count > NACLENTRIES) /* If NACLENTRIES cannot be trusted, use dynamic memory allocation. */ abort (); /* If there are more than 4 entries, there cannot be only the four base ACL entries. */ if (count > 4) return 1; if (acl ((char *) name, ACL_GET, count, entries) == count) return acl_nontrivial (count, entries); /* Huh? The number of ACL entries changed since the last call. Repeat. */ } # endif } #endif return 0; }
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 }
/* Set permissions of a file. -*- coding: utf-8 -*- Copyright (C) 2002-2003, 2005-2017 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. Written by Paul Eggert, Andreas Grünbacher, and Bruno Haible. */ #include <config.h> #include "acl.h" #include "acl-internal.h" #if USE_ACL # if ! defined HAVE_ACL_FROM_MODE && defined HAVE_ACL_FROM_TEXT /* FreeBSD, IRIX, Tru64 */ # if HAVE_ACL_GET_FILE && !HAVE_ACL_TYPE_EXTENDED static acl_t acl_from_mode (mode_t mode) { # if HAVE_ACL_FREE_TEXT /* Tru64 */ char acl_text[] = "u::---,g::---,o::---,"; # else /* FreeBSD, IRIX */ char acl_text[] = "u::---,g::---,o::---"; # endif if (mode & S_IRUSR) acl_text[ 3] = 'r'; if (mode & S_IWUSR) acl_text[ 4] = 'w'; if (mode & S_IXUSR) acl_text[ 5] = 'x'; if (mode & S_IRGRP) acl_text[10] = 'r'; if (mode & S_IWGRP) acl_text[11] = 'w'; if (mode & S_IXGRP) acl_text[12] = 'x'; if (mode & S_IROTH) acl_text[17] = 'r'; if (mode & S_IWOTH) acl_text[18] = 'w'; if (mode & S_IXOTH) acl_text[19] = 'x'; return acl_from_text (acl_text); } # endif # endif # if HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */ static int set_acls_from_mode (const char *name, int desc, mode_t mode, bool *must_chmod) { # 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). */ /* The flags in the ace_t structure changed in a binary incompatible way when ACL_NO_TRIVIAL etc. were introduced in <sys/acl.h> version 1.15. How to distinguish the two conventions at runtime? We fetch the existing ACL. In the old convention, usually three ACEs have a_flags = ACE_OWNER / ACE_GROUP / ACE_OTHER, in the range 0x0100..0x0400. In the new convention, these values are not used. */ int convention; { /* Initially, try to read the entries into a stack-allocated buffer. Use malloc if it does not fit. */ enum { alloc_init = 4000 / sizeof (ace_t), /* >= 3 */ alloc_max = MIN (INT_MAX, SIZE_MAX / sizeof (ace_t)) }; ace_t buf[alloc_init]; size_t alloc = alloc_init; ace_t *entries = buf; ace_t *malloced = NULL; int count; for (;;) { count = (desc != -1 ? facl (desc, ACE_GETACL, alloc, entries) : acl (name, ACE_GETACL, alloc, entries)); if (count < 0 && errno == ENOSPC) { /* Increase the size of the buffer. */ free (malloced); if (alloc > alloc_max / 2) { errno = ENOMEM; return -1; } alloc = 2 * alloc; /* <= alloc_max */ entries = malloced = (ace_t *) malloc (alloc * sizeof (ace_t)); if (entries == NULL) { errno = ENOMEM; return -1; } continue; } break; } if (count <= 0) convention = -1; else { int i; convention = 0; for (i = 0; i < count; i++) if (entries[i].a_flags & (OLD_ACE_OWNER | OLD_ACE_GROUP | OLD_ACE_OTHER)) { convention = 1; break; } } free (malloced); } if (convention >= 0) { ace_t entries[6]; int count; int ret; if (convention) { /* Running on Solaris 10. */ entries[0].a_type = OLD_ALLOW; entries[0].a_flags = OLD_ACE_OWNER; entries[0].a_who = 0; /* irrelevant */ entries[0].a_access_mask = (mode >> 6) & 7; entries[1].a_type = OLD_ALLOW; entries[1].a_flags = OLD_ACE_GROUP; entries[1].a_who = 0; /* irrelevant */ entries[1].a_access_mask = (mode >> 3) & 7; entries[2].a_type = OLD_ALLOW; entries[2].a_flags = OLD_ACE_OTHER; entries[2].a_who = 0; entries[2].a_access_mask = mode & 7; count = 3; } else {
int solarisacl_sys_acl_set_file(vfs_handle_struct *handle, const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T theacl) { int ret = -1; struct stat_ex s; SOLARIS_ACL_T solaris_acl = NULL; int count; DEBUG(10, ("solarisacl_sys_acl_set_file called for file '%s'\n", name)); if ((type != SMB_ACL_TYPE_ACCESS) && (type != SMB_ACL_TYPE_DEFAULT)) { errno = EINVAL; DEBUG(10, ("invalid smb acl type given (%d).\n", type)); goto done; } DEBUGADD(10, ("setting %s acl\n", ((type == SMB_ACL_TYPE_ACCESS) ? "access" : "default"))); if(!smb_acl_to_solaris_acl(theacl, &solaris_acl, &count, type)) { DEBUG(10, ("conversion smb_acl -> solaris_acl failed (%s).\n", strerror(errno))); goto done; } /* * if the file is a directory, there is extra work to do: * since the solaris acl call stores both the access acl and * the default acl as provided, we have to get the acl part * that has not been specified in "type" from the file first * and concatenate it with the acl provided. */ if (vfs_stat_smb_basename(handle->conn, name, &s) != 0) { DEBUG(10, ("Error in stat call: %s\n", strerror(errno))); goto done; } if (S_ISDIR(s.st_ex_mode)) { SOLARIS_ACL_T other_acl; int other_count; SMB_ACL_TYPE_T other_type; other_type = (type == SMB_ACL_TYPE_ACCESS) ? SMB_ACL_TYPE_DEFAULT : SMB_ACL_TYPE_ACCESS; DEBUGADD(10, ("getting acl from filesystem\n")); if (!solaris_acl_get_file(name, &other_acl, &other_count)) { DEBUG(10, ("error getting acl from directory\n")); goto done; } DEBUG(10, ("adding %s part of fs acl to given acl\n", ((other_type == SMB_ACL_TYPE_ACCESS) ? "access" : "default"))); if (!solaris_add_to_acl(&solaris_acl, &count, other_acl, other_count, other_type)) { DEBUG(10, ("error adding other acl.\n")); SAFE_FREE(other_acl); goto done; } SAFE_FREE(other_acl); } else if (type != SMB_ACL_TYPE_ACCESS) { errno = EINVAL; goto done; } if (!solaris_acl_sort(solaris_acl, count)) { DEBUG(10, ("resulting acl is not valid!\n")); goto done; } ret = acl(name, SETACL, count, solaris_acl); done: DEBUG(10, ("solarisacl_sys_acl_set_file %s.\n", ((ret != 0) ? "failed" : "succeeded"))); SAFE_FREE(solaris_acl); return ret; }
void file_mode(t_stat st) { ft_file_type(st); ft_long_permissions(st); acl(st); }
int main (int argc, char *argv[]) { const char *file1; const char *file2; set_program_name (argv[0]); ASSERT (argc == 3); file1 = argv[1]; file2 = argv[2]; /* Compare the contents of the two files. */ { size_t size1; char *contents1; size_t size2; char *contents2; contents1 = read_file (file1, &size1); if (contents1 == NULL) { fprintf (stderr, "error reading file %s: errno = %d\n", file1, errno); fflush (stderr); abort (); } contents2 = read_file (file2, &size2); if (contents2 == NULL) { fprintf (stderr, "error reading file %s: errno = %d\n", file2, errno); fflush (stderr); abort (); } if (size2 != size1) { fprintf (stderr, "files %s and %s have different sizes\n", file1, file2); fflush (stderr); abort (); } if (memcmp (contents1, contents2, size1) != 0) { fprintf (stderr, "files %s and %s have different contents\n", file1, file2); fflush (stderr); abort (); } } /* Compare the access permissions of the two files, including ACLs. */ { struct stat statbuf1; struct stat statbuf2; if (stat (file1, &statbuf1) < 0) { fprintf (stderr, "error accessing file %s: errno = %d\n", file1, errno); fflush (stderr); abort (); } if (stat (file2, &statbuf2) < 0) { fprintf (stderr, "error accessing file %s: errno = %d\n", file2, errno); fflush (stderr); abort (); } if (statbuf1.st_mode != statbuf2.st_mode) { fprintf (stderr, "files %s and %s have different access modes: %03o and %03o\n", file1, file2, (unsigned int) statbuf1.st_mode, (unsigned int) statbuf2.st_mode); return 1; } } { #if HAVE_ACL_GET_FILE /* Linux, FreeBSD, MacOS X, IRIX, Tru64 */ static const int types[] = { ACL_TYPE_ACCESS # if HAVE_ACL_TYPE_EXTENDED /* MacOS X */ , ACL_TYPE_EXTENDED # endif }; int t; for (t = 0; t < sizeof (types) / sizeof (types[0]); t++) { int type = types[t]; acl_t acl1; char *text1; int errno1; acl_t acl2; char *text2; int errno2; acl1 = acl_get_file (file1, type); if (acl1 == (acl_t)NULL) { text1 = NULL; errno1 = errno; } else { text1 = acl_to_text (acl1, NULL); if (text1 == NULL) errno1 = errno; else errno1 = 0; } acl2 = acl_get_file (file2, type); if (acl2 == (acl_t)NULL) { text2 = NULL; errno2 = errno; } else { text2 = acl_to_text (acl2, NULL); if (text2 == NULL) errno2 = errno; else errno2 = 0; } if (acl1 != (acl_t)NULL) { if (acl2 != (acl_t)NULL) { if (text1 != NULL) { if (text2 != NULL) { if (strcmp (text1, text2) != 0) { fprintf (stderr, "files %s and %s have different ACLs:\n%s\n%s\n", file1, file2, text1, text2); return 1; } } else { fprintf (stderr, "file %s has a valid ACL, but file %s has an invalid ACL\n", file1, file2); return 1; } } else { if (text2 != NULL) { fprintf (stderr, "file %s has an invalid ACL, but file %s has a valid ACL\n", file1, file2); return 1; } else { if (errno1 != errno2) { fprintf (stderr, "files %s and %s have differently invalid ACLs, errno = %d vs. %d\n", file1, file2, errno1, errno2); return 1; } } } } else { fprintf (stderr, "file %s has an ACL, but file %s has no ACL\n", file1, file2); return 1; } } else { if (acl2 != (acl_t)NULL) { fprintf (stderr, "file %s has no ACL, but file %s has an ACL\n", file1, file2); return 1; } } } #elif HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */ int count1; int count2; count1 = acl (file1, GETACLCNT, 0, NULL); if (count1 < 0 && errno == ENOSYS) /* Can happen on Solaris 10 with ZFS */ count1 = 0; count2 = acl (file2, GETACLCNT, 0, NULL); if (count2 < 0 && errno == ENOSYS) /* Can happen on Solaris 10 with ZFS */ count2 = 0; if (count1 < 0) { fprintf (stderr, "error accessing the ACLs of file %s\n", file1); fflush (stderr); abort (); } if (count2 < 0) { fprintf (stderr, "error accessing the ACLs of file %s\n", file2); fflush (stderr); abort (); } if (count1 != count2) { fprintf (stderr, "files %s and %s have different number of ACLs: %d and %d\n", file1, file2, count1, count2); return 1; } else { aclent_t *entries1 = XNMALLOC (count1, aclent_t); aclent_t *entries2 = XNMALLOC (count2, aclent_t); int i; if (count1 > 0 && acl (file1, GETACL, count1, entries1) < count1) { fprintf (stderr, "error retrieving the ACLs of file %s\n", file1); fflush (stderr); abort (); } if (count2 > 0 && acl (file2, GETACL, count2, entries2) < count1) { fprintf (stderr, "error retrieving the ACLs of file %s\n", file2); fflush (stderr); abort (); } for (i = 0; i < count1; i++) { if (entries1[i].a_type != entries2[i].a_type) { fprintf (stderr, "files %s and %s: different ACL entry #%d: different types %d and %d\n", file1, file2, i, entries1[i].a_type, entries2[i].a_type); return 1; } if (entries1[i].a_id != entries2[i].a_id) { fprintf (stderr, "files %s and %s: different ACL entry #%d: different ids %d and %d\n", file1, file2, i, (int)entries1[i].a_id, (int)entries2[i].a_id); return 1; } if (entries1[i].a_perm != entries2[i].a_perm) { fprintf (stderr, "files %s and %s: different ACL entry #%d: different permissions %03o and %03o\n", file1, file2, i, (unsigned int) entries1[i].a_perm, (unsigned int) entries2[i].a_perm); return 1; } } } # ifdef ACE_GETACL count1 = acl (file1, ACE_GETACLCNT, 0, NULL); if (count1 < 0 && errno == EINVAL) count1 = 0; count2 = acl (file2, ACE_GETACLCNT, 0, NULL); if (count2 < 0 && errno == EINVAL) count2 = 0; if (count1 < 0) { fprintf (stderr, "error accessing the ACE-ACLs of file %s\n", file1); fflush (stderr); abort (); } if (count2 < 0) { fprintf (stderr, "error accessing the ACE-ACLs of file %s\n", file2); fflush (stderr); abort (); } if (count1 != count2) { fprintf (stderr, "files %s and %s have different number of ACE-ACLs: %d and %d\n", file1, file2, count1, count2); return 1; } else if (count1 > 0) { ace_t *entries1 = XNMALLOC (count1, ace_t); ace_t *entries2 = XNMALLOC (count2, ace_t); int i; if (acl (file1, ACE_GETACL, count1, entries1) < count1) { fprintf (stderr, "error retrieving the ACE-ACLs of file %s\n", file1); fflush (stderr); abort (); } if (acl (file2, ACE_GETACL, count2, entries2) < count1) { fprintf (stderr, "error retrieving the ACE-ACLs of file %s\n", file2); fflush (stderr); abort (); } for (i = 0; i < count1; i++) { if (entries1[i].a_type != entries2[i].a_type) { fprintf (stderr, "files %s and %s: different ACE-ACL entry #%d: different types %d and %d\n", file1, file2, i, entries1[i].a_type, entries2[i].a_type); return 1; } if (entries1[i].a_who != entries2[i].a_who) { fprintf (stderr, "files %s and %s: different ACE-ACL entry #%d: different ids %d and %d\n", file1, file2, i, (int)entries1[i].a_who, (int)entries2[i].a_who); return 1; } if (entries1[i].a_access_mask != entries2[i].a_access_mask) { fprintf (stderr, "files %s and %s: different ACE-ACL entry #%d: different access masks %03o and %03o\n", file1, file2, i, (unsigned int) entries1[i].a_access_mask, (unsigned int) entries2[i].a_access_mask); return 1; } if (entries1[i].a_flags != entries2[i].a_flags) { fprintf (stderr, "files %s and %s: different ACE-ACL entry #%d: different flags 0x%x and 0x%x\n", file1, file2, i, (unsigned int) entries1[i].a_flags, (unsigned int) entries2[i].a_flags); return 1; } } } # endif #elif HAVE_GETACL /* HP-UX */ int count1; int count2; count1 = getacl (file1, 0, NULL); if (count1 < 0 && (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)) count1 = 0; count2 = getacl (file2, 0, NULL); if (count2 < 0 && (errno == ENOSYS || errno == EOPNOTSUPP || errno == ENOTSUP)) count2 = 0; if (count1 < 0) { fprintf (stderr, "error accessing the ACLs of file %s\n", file1); fflush (stderr); abort (); } if (count2 < 0) { fprintf (stderr, "error accessing the ACLs of file %s\n", file2); fflush (stderr); abort (); } if (count1 != count2) { fprintf (stderr, "files %s and %s have different number of ACLs: %d and %d\n", file1, file2, count1, count2); return 1; } else if (count1 > 0) { struct acl_entry *entries1 = XNMALLOC (count1, struct acl_entry); struct acl_entry *entries2 = XNMALLOC (count2, struct acl_entry); int i; if (getacl (file1, count1, entries1) < count1) { fprintf (stderr, "error retrieving the ACLs of file %s\n", file1); fflush (stderr); abort (); } if (getacl (file2, count2, entries2) < count1) { fprintf (stderr, "error retrieving the ACLs of file %s\n", file2); fflush (stderr); abort (); } for (i = 0; i < count1; i++) { if (entries1[i].uid != entries2[i].uid) { fprintf (stderr, "files %s and %s: different ACL entry #%d: different uids %d and %d\n", file1, file2, i, (int)entries1[i].uid, (int)entries2[i].uid); return 1; } if (entries1[i].gid != entries2[i].gid) { fprintf (stderr, "files %s and %s: different ACL entry #%d: different gids %d and %d\n", file1, file2, i, (int)entries1[i].gid, (int)entries2[i].gid); return 1; } if (entries1[i].mode != entries2[i].mode) { fprintf (stderr, "files %s and %s: different ACL entry #%d: different permissions %03o and %03o\n", file1, file2, i, (unsigned int) entries1[i].mode, (unsigned int) entries2[i].mode); return 1; } } } # if HAVE_ACLV_H /* HP-UX >= 11.11 */ { struct acl dummy_entries[NACLVENTRIES]; count1 = acl ((char *) file1, ACL_CNT, NACLVENTRIES, dummy_entries); if (count1 < 0 && (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)) count1 = 0; count2 = acl ((char *) file2, ACL_CNT, NACLVENTRIES, dummy_entries); if (count2 < 0 && (errno == ENOSYS || errno == EOPNOTSUPP || errno == EINVAL)) count2 = 0; } if (count1 < 0) { fprintf (stderr, "error accessing the ACLs of file %s\n", file1); fflush (stderr); abort (); } if (count2 < 0) { fprintf (stderr, "error accessing the ACLs of file %s\n", file2); fflush (stderr); abort (); } if (count1 != count2) { fprintf (stderr, "files %s and %s have different number of ACLs: %d and %d\n", file1, file2, count1, count2); return 1; } else if (count1 > 0) { struct acl *entries1 = XNMALLOC (count1, struct acl); struct acl *entries2 = XNMALLOC (count2, struct acl); int i; if (acl ((char *) file1, ACL_GET, count1, entries1) < count1) { fprintf (stderr, "error retrieving the ACLs of file %s\n", file1); fflush (stderr); abort (); } if (acl ((char *) file2, ACL_GET, count2, entries2) < count1) { fprintf (stderr, "error retrieving the ACLs of file %s\n", file2); fflush (stderr); abort (); } for (i = 0; i < count1; i++) { if (entries1[i].a_type != entries2[i].a_type) { fprintf (stderr, "files %s and %s: different ACL entry #%d: different types %d and %d\n", file1, file2, i, entries1[i].a_type, entries2[i].a_type); return 1; } if (entries1[i].a_id != entries2[i].a_id) { fprintf (stderr, "files %s and %s: different ACL entry #%d: different ids %d and %d\n", file1, file2, i, (int)entries1[i].a_id, (int)entries2[i].a_id); return 1; } if (entries1[i].a_perm != entries2[i].a_perm) { fprintf (stderr, "files %s and %s: different ACL entry #%d: different permissions %03o and %03o\n", file1, file2, i, (unsigned int) entries1[i].a_perm, (unsigned int) entries2[i].a_perm); return 1; } } } # endif #elif HAVE_ACLX_GET /* AIX */ acl_type_t type1; char acl1[1000]; size_t aclsize1 = sizeof (acl1); mode_t mode1; char text1[1000]; size_t textsize1 = sizeof (text1); acl_type_t type2; char acl2[1000]; size_t aclsize2 = sizeof (acl2); mode_t mode2; char text2[1000]; size_t textsize2 = sizeof (text2); /* The docs say that type1 being 0 is equivalent to ACL_ANY, but it is not true, in AIX 5.3. */ type1.u64 = ACL_ANY; if (aclx_get (file1, 0, &type1, acl1, &aclsize1, &mode1) < 0) { if (errno == ENOSYS) text1[0] = '\0'; else { fprintf (stderr, "error accessing the ACLs of file %s\n", file1); fflush (stderr); abort (); } } else if (aclx_printStr (text1, &textsize1, acl1, aclsize1, type1, file1, 0) < 0) { fprintf (stderr, "cannot convert the ACLs of file %s to text\n", file1); fflush (stderr); abort (); } /* The docs say that type2 being 0 is equivalent to ACL_ANY, but it is not true, in AIX 5.3. */ type2.u64 = ACL_ANY; if (aclx_get (file2, 0, &type2, acl2, &aclsize2, &mode2) < 0) { if (errno == ENOSYS) text2[0] = '\0'; else { fprintf (stderr, "error accessing the ACLs of file %s\n", file2); fflush (stderr); abort (); } } else if (aclx_printStr (text2, &textsize2, acl2, aclsize2, type2, file2, 0) < 0) { fprintf (stderr, "cannot convert the ACLs of file %s to text\n", file2); fflush (stderr); abort (); } if (strcmp (text1, text2) != 0) { fprintf (stderr, "files %s and %s have different ACLs:\n%s\n%s\n", file1, file2, text1, text2); return 1; } #elif HAVE_STATACL /* older AIX */ union { struct acl a; char room[4096]; } acl1; union { struct acl a; char room[4096]; } acl2; unsigned int i; if (statacl (file1, STX_NORMAL, &acl1.a, sizeof (acl1)) < 0) { fprintf (stderr, "error accessing the ACLs of file %s\n", file1); fflush (stderr); abort (); } if (statacl (file2, STX_NORMAL, &acl2.a, sizeof (acl2)) < 0) { fprintf (stderr, "error accessing the ACLs of file %s\n", file2); fflush (stderr); abort (); } if (acl1.a.acl_len != acl2.a.acl_len) { fprintf (stderr, "files %s and %s have different ACL lengths: %u and %u\n", file1, file2, acl1.a.acl_len, acl2.a.acl_len); return 1; } if (acl1.a.acl_mode != acl2.a.acl_mode) { fprintf (stderr, "files %s and %s have different ACL modes: %03o and %03o\n", file1, file2, acl1.a.acl_mode, acl2.a.acl_mode); return 1; } if (acl1.a.u_access != acl2.a.u_access || acl1.a.g_access != acl2.a.g_access || acl1.a.o_access != acl2.a.o_access) { fprintf (stderr, "files %s and %s have different ACL access masks: %03o %03o %03o and %03o %03o %03o\n", file1, file2, acl1.a.u_access, acl1.a.g_access, acl1.a.o_access, acl2.a.u_access, acl2.a.g_access, acl2.a.o_access); return 1; } if (memcmp (acl1.a.acl_ext, acl2.a.acl_ext, acl1.a.acl_len) != 0) { fprintf (stderr, "files %s and %s have different ACL entries\n", file1, file2); return 1; } #elif HAVE_ACLSORT /* NonStop Kernel */ int count1; int count2; count1 = acl ((char *) file1, ACL_CNT, NACLENTRIES, NULL); count2 = acl ((char *) file2, ACL_CNT, NACLENTRIES, NULL); if (count1 < 0) { fprintf (stderr, "error accessing the ACLs of file %s\n", file1); fflush (stderr); abort (); } if (count2 < 0) { fprintf (stderr, "error accessing the ACLs of file %s\n", file2); fflush (stderr); abort (); } if (count1 != count2) { fprintf (stderr, "files %s and %s have different number of ACLs: %d and %d\n", file1, file2, count1, count2); return 1; } else if (count1 > 0) { struct acl *entries1 = XNMALLOC (count1, struct acl); struct acl *entries2 = XNMALLOC (count2, struct acl); int i; if (acl ((char *) file1, ACL_GET, count1, entries1) < count1) { fprintf (stderr, "error retrieving the ACLs of file %s\n", file1); fflush (stderr); abort (); } if (acl ((char *) file2, ACL_GET, count2, entries2) < count1) { fprintf (stderr, "error retrieving the ACLs of file %s\n", file2); fflush (stderr); abort (); } for (i = 0; i < count1; i++) { if (entries1[i].a_type != entries2[i].a_type) { fprintf (stderr, "files %s and %s: different ACL entry #%d: different types %d and %d\n", file1, file2, i, entries1[i].a_type, entries2[i].a_type); return 1; } if (entries1[i].a_id != entries2[i].a_id) { fprintf (stderr, "files %s and %s: different ACL entry #%d: different ids %d and %d\n", file1, file2, i, (int)entries1[i].a_id, (int)entries2[i].a_id); return 1; } if (entries1[i].a_perm != entries2[i].a_perm) { fprintf (stderr, "files %s and %s: different ACL entry #%d: different permissions %03o and %03o\n", file1, file2, i, (unsigned int) entries1[i].a_perm, (unsigned int) entries2[i].a_perm); return 1; } } } #endif } return 0; }
int main (int argc, char **argv) { int c; int ret = 0; int aopt = 0; int copt = 0; int eopt = 0; int dopt = 0; int nopt = 0; int istty = isatty (fileno (stdout)); struct stat st; aclent_t acls[MAX_ACL_ENTRIES]; prog_name = program_invocation_short_name; while ((c = getopt_long (argc, argv, opts, longopts, NULL)) != EOF) switch (c) { case 'a': aopt = 1; break; case 'c': copt = 1; break; case 'd': dopt = 1; break; case 'e': eopt = 1; break; case 'E': eopt = -1; break; case 'h': usage (stdout); return 0; case 'n': nopt = 1; break; case 'V': print_version (); return 0; default: fprintf (stderr, "Try `%s --help' for more information.\n", prog_name); return 1; } if (optind > argc - 1) { usage (stderr); return 1; } for (; optind < argc; ++optind) { int i, num_acls; mode_t mask = S_IRWXO, def_mask = S_IRWXO; if (stat (argv[optind], &st) || (num_acls = acl (argv[optind], GETACL, MAX_ACL_ENTRIES, acls)) < 0) { fprintf (stderr, "%s: %s: %s\n", prog_name, argv[optind], strerror (errno)); ret = 2; continue; } if (!copt) { printf ("# file: %s\n", argv[optind]); if (nopt) { printf ("# owner: %lu\n", (unsigned long)st.st_uid); printf ("# group: %lu\n", (unsigned long)st.st_gid); } else { printf ("# owner: %s\n", username (st.st_uid)); printf ("# group: %s\n", groupname (st.st_gid)); } if (st.st_mode & (S_ISUID | S_ISGID | S_ISVTX)) printf ("# flags: %c%c%c\n", (st.st_mode & S_ISUID) ? 's' : '-', (st.st_mode & S_ISGID) ? 's' : '-', (st.st_mode & S_ISVTX) ? 't' : '-'); } for (i = 0; i < num_acls; ++i) { if (acls[i].a_type == CLASS_OBJ) mask = acls[i].a_perm; else if (acls[i].a_type == DEF_CLASS_OBJ) def_mask = acls[i].a_perm; } for (i = 0; i < num_acls; ++i) { int n = 0; int print_effective = 0; mode_t effective = acls[i].a_perm; if (acls[i].a_type & ACL_DEFAULT) { if (aopt) continue; n += printf ("default:"); } else if (dopt) continue; switch (acls[i].a_type & ~ACL_DEFAULT) { case USER_OBJ: printf ("user::"); break; case USER: if (nopt) n += printf ("user:%lu:", (unsigned long)acls[i].a_id); else n += printf ("user:%s:", username (acls[i].a_id)); break; case GROUP_OBJ: n += printf ("group::"); break; case GROUP: if (nopt) n += printf ("group:%lu:", (unsigned long)acls[i].a_id); else n += printf ("group:%s:", groupname (acls[i].a_id)); break; case CLASS_OBJ: printf ("mask:"); break; case OTHER_OBJ: printf ("other:"); break; } n += printf ("%s", permstr (acls[i].a_perm)); switch (acls[i].a_type) { case USER: case GROUP_OBJ: effective = acls[i].a_perm & mask; print_effective = 1; break; case GROUP: /* Special case SYSTEM and Admins group: The mask only applies to them as far as the execute bit is concerned. */ if (acls[i].a_id == 18 || acls[i].a_id == 544) effective = acls[i].a_perm & (mask | S_IROTH | S_IWOTH); else effective = acls[i].a_perm & mask; print_effective = 1; break; case DEF_USER: case DEF_GROUP_OBJ: effective = acls[i].a_perm & def_mask; print_effective = 1; break; case DEF_GROUP: /* Special case SYSTEM and Admins group: The mask only applies to them as far as the execute bit is concerned. */ if (acls[i].a_id == 18 || acls[i].a_id == 544) effective = acls[i].a_perm & (def_mask | S_IROTH | S_IWOTH); else effective = acls[i].a_perm & def_mask; print_effective = 1; break; } if (print_effective && eopt >= 0 && (eopt > 0 || effective != acls[i].a_perm)) { if (istty) { n = 40 - n; if (n <= 0) n = 1; printf ("%*s", n, " "); } else putchar ('\t'); printf ("#effective:%s", permstr (effective)); } putchar ('\n'); } putchar ('\n'); } return ret; }
static int check_facl(pool *p, const char *path, int mode, void *acl, int nents, struct stat *st, uid_t uid, gid_t gid, array_header *suppl_gids) { # if defined(HAVE_BSD_POSIX_ACL) || defined(HAVE_LINUX_POSIX_ACL) register unsigned int i; int have_access_entry = FALSE, res = -1; pool *acl_pool; acl_t facl = acl; acl_entry_t ae; acl_tag_t ae_type; acl_entry_t acl_user_entry = NULL; acl_entry_t acl_group_entry = NULL; acl_entry_t acl_other_entry = NULL; acl_entry_t acl_mask_entry = NULL; array_header *acl_groups; array_header *acl_users; /* Iterate through all of the ACL entries, sorting them for later * checking. */ res = acl_get_entry(facl, ACL_FIRST_ENTRY, &ae); if (res < 0) { pr_log_debug(DEBUG10, "FS: unable to retrieve first ACL entry for '%s': %s", path, strerror(errno)); errno = EACCES; return -1; } if (res == 0) { pr_log_debug(DEBUG3, "FS: ill-formed ACL for '%s' has no entries!", path); errno = EACCES; return -1; } acl_pool = make_sub_pool(p); acl_groups = make_array(acl_pool, 1, sizeof(acl_entry_t)); acl_users = make_array(acl_pool, 1, sizeof(acl_entry_t)); while (res > 0) { if (acl_get_tag_type(ae, &ae_type) < 0) { pr_log_debug(DEBUG5, "FS: error retrieving type of ACL entry for '%s': %s", path, strerror(errno)); res = acl_get_entry(facl, ACL_NEXT_ENTRY, &ae); continue; } if (ae_type & ACL_USER_OBJ) { acl_copy_entry(acl_user_entry, ae); } else if (ae_type & ACL_USER) { acl_entry_t *ae_dup = push_array(acl_users); acl_copy_entry(*ae_dup, ae); } else if (ae_type & ACL_GROUP_OBJ) { acl_copy_entry(acl_group_entry, ae); } else if (ae_type & ACL_GROUP) { acl_entry_t *ae_dup = push_array(acl_groups); acl_copy_entry(*ae_dup, ae); } else if (ae_type & ACL_OTHER) { acl_copy_entry(acl_other_entry, ae); } else if (ae_type & ACL_MASK) { acl_copy_entry(acl_mask_entry, ae); } res = acl_get_entry(facl, ACL_NEXT_ENTRY, &ae); } /* Select the ACL entry that determines access. */ res = -1; /* 1. If the given user ID matches the file owner, use that entry for * access. */ if (uid == st->st_uid) { /* Check the acl_user_entry for access. */ acl_copy_entry(ae, acl_user_entry); ae_type = ACL_USER_OBJ; have_access_entry = TRUE; } /* 2. If not matched above, and f the given user ID matches one of the * named user entries, use that entry for access. */ for (i = 0; !have_access_entry && i < acl_users->nelts; i++) { acl_entry_t e = ((acl_entry_t *) acl_users->elts)[i]; if (uid == *((uid_t *) acl_get_qualifier(e))) { /* Check this entry for access. Note that it'll need to * be modified by the mask, if any, later. */ acl_copy_entry(ae, e); ae_type = ACL_USER; have_access_entry = TRUE; break; } } /* 3. If not matched above, and if one of the group IDs matches the * group owner entry, and the group owner entry contains the * requested permissions, use that entry for access. */ if (!have_access_entry && gid == st->st_gid) { /* Check the acl_group_entry for access. First though, we need to * see if the acl_group_entry contains the requested permissions. */ acl_permset_t perms; acl_get_permset(acl_group_entry, &perms); # if defined(HAVE_BSD_POSIX_ACL) if (acl_get_perm_np(perms, mode) == 1) { # elif defined(HAVE_LINUX_POSIX_ACL) if (acl_get_perm(perms, mode) == 1) { # endif acl_copy_entry(ae, acl_group_entry); ae_type = ACL_GROUP_OBJ; have_access_entry = TRUE; } } if (suppl_gids) { for (i = 0; !have_access_entry && i < suppl_gids->nelts; i++) { gid_t suppl_gid = ((gid_t *) suppl_gids->elts)[i]; if (suppl_gid == st->st_gid) { /* Check the acl_group_entry for access. First though, we need to * see if the acl_group_entry contains the requested permissions. */ acl_permset_t perms; acl_get_permset(acl_group_entry, &perms); # if defined(HAVE_BSD_POSIX_ACL) if (acl_get_perm_np(perms, mode) == 1) { # elif defined(HAVE_LINUX_POSIX_ACL) if (acl_get_perm(perms, mode) == 1) { # endif acl_copy_entry(ae, acl_group_entry); ae_type = ACL_GROUP_OBJ; have_access_entry = TRUE; break; } } } } /* 5. If not matched above, and if one of the group IDs matches one * of the named group entries, and that entry contains the requested * permissions, use that entry for access. */ for (i = 0; !have_access_entry && i < acl_groups->nelts; i++) { acl_entry_t e = ((acl_entry_t *) acl_groups->elts)[i]; if (gid == *((gid_t *) acl_get_qualifier(e))) { /* Check this entry for access. Note that it'll need to * be modified by the mask, if any, later. */ acl_permset_t perms; acl_get_permset(e, &perms); # if defined(HAVE_BSD_POSIX_ACL) if (acl_get_perm_np(perms, mode) == 1) { # elif defined(HAVE_LINUX_POSIX_ACL) if (acl_get_perm(perms, mode) == 1) { # endif acl_copy_entry(ae, e); ae_type = ACL_GROUP; have_access_entry = TRUE; break; } } if (suppl_gids) { register unsigned int j; for (j = 0; !have_access_entry && j < suppl_gids->nelts; j++) { gid_t suppl_gid = ((gid_t *) suppl_gids->elts)[j]; if (suppl_gid == *((gid_t *) acl_get_qualifier(e))) { /* Check this entry for access. Note that it'll need to * be modified by the mask, if any, later. */ acl_permset_t perms; acl_get_permset(e, &perms); # if defined(HAVE_BSD_POSIX_ACL) if (acl_get_perm_np(perms, mode) == 1) { # elif defined(HAVE_LINUX_POSIX_ACL) if (acl_get_perm(perms, mode) == 1) { # endif acl_copy_entry(ae, e); ae_type = ACL_GROUP; have_access_entry = TRUE; break; } } } } } /* 6. If not matched above, and if one of the group IDs matches * the group owner or any of the named group entries, but neither * the group owner entry nor any of the named group entries contains * the requested permissions, access is denied. */ /* 7. If not matched above, the other entry determines access. */ if (!have_access_entry) { acl_copy_entry(ae, acl_other_entry); ae_type = ACL_OTHER; have_access_entry = TRUE; } /* Access determination: * * If either the user owner entry or other entry were used, and the * entry contains the requested permissions, access is permitted. * * Otherwise, if the selected entry and the mask entry both contain * the requested permissions, access is permitted. * * Otherwise, access is denied. */ switch (ae_type) { case ACL_USER_OBJ: case ACL_OTHER: { acl_permset_t perms; acl_get_permset(ae, &perms); # if defined(HAVE_BSD_POSIX_ACL) if (acl_get_perm_np(perms, mode) == 1) { # elif defined(HAVE_LINUX_POSIX_ACL) if (acl_get_perm(perms, mode) == 1) { # endif res = 0; } break; } default: { acl_permset_t ent_perms, mask_perms; acl_get_permset(ae, &ent_perms); acl_get_permset(acl_mask_entry, &mask_perms); # if defined(HAVE_BSD_POSIX_ACL) if (acl_get_perm_np(ent_perms, mode) == 1 && acl_get_perm_np(mask_perms, mode) == 1) { # elif defined(HAVE_LINUX_POSIX_ACL) if (acl_get_perm(ent_perms, mode) == 1 && acl_get_perm(mask_perms, mode) == 1) { # endif res = 0; } break; } } destroy_pool(acl_pool); if (res < 0) errno = EACCES; return res; # elif defined(HAVE_SOLARIS_POSIX_ACL) register unsigned int i; int have_access_entry = FALSE, idx, res = -1; pool *acl_pool; aclent_t *acls = acl; aclent_t ae; int ae_type = 0; aclent_t acl_user_entry; aclent_t acl_group_entry; aclent_t acl_other_entry; aclent_t acl_mask_entry; array_header *acl_groups; array_header *acl_users; /* In the absence of any clear documentation, I'll assume that * Solaris ACLs follow the same selection and checking algorithm * as do BSD and Linux. */ res = aclcheck(acls, nents, &idx); switch (res) { case 0: break; case GRP_ERROR: pr_log_debug(DEBUG3, "FS: ill-formed ACL for '%s': %s", path, "too many GROUP entries"); errno = EACCES; return -1; case USER_ERROR: pr_log_debug(DEBUG3, "FS: ill-formed ACL for '%s': %s", path, "too many USER entries"); errno = EACCES; return -1; case OTHER_ERROR: pr_log_debug(DEBUG3, "FS: ill-formed ACL for '%s': %s", path, "too many OTHER entries"); errno = EACCES; return -1; case CLASS_ERROR: pr_log_debug(DEBUG3, "FS: ill-formed ACL for '%s': %s", path, "too many CLASS entries"); errno = EACCES; return -1; case DUPLICATE_ERROR: pr_log_debug(DEBUG3, "FS: ill-formed ACL for '%s': %s", path, "duplicate entries"); errno = EACCES; return -1; case MISS_ERROR: pr_log_debug(DEBUG3, "FS: ill-formed ACL for '%s': %s", path, "missing required entry"); errno = EACCES; return -1; case MEM_ERROR: pr_log_debug(DEBUG3, "FS: ill-formed ACL for '%s': %s", path, "Out of memory!"); errno = EACCES; return -1; case ENTRY_ERROR: pr_log_debug(DEBUG3, "FS: ill-formed ACL for '%s': %s", path, "invalid entry type"); errno = EACCES; return -1; } /* Iterate through all of the ACL entries, sorting them for later * checking. */ acl_pool = make_sub_pool(p); acl_groups = make_array(acl_pool, 1, sizeof(aclent_t)); acl_users = make_array(acl_pool, 1, sizeof(aclent_t)); for (i = 0; i < nents; i++) { if (acls[i].a_type & USER_OBJ) { memcpy(&acl_user_entry, &(acls[i]), sizeof(aclent_t)); } else if (acls[i].a_type & USER) { aclent_t *ae_dup = push_array(acl_users); memcpy(ae_dup, &(acls[i]), sizeof(aclent_t)); } else if (acls[i].a_type & GROUP_OBJ) { memcpy(&acl_group_entry, &(acls[i]), sizeof(aclent_t)); } else if (acls[i].a_type & GROUP) { aclent_t *ae_dup = push_array(acl_groups); memcpy(ae_dup, &(acls[i]), sizeof(aclent_t)); } else if (acls[i].a_type & OTHER_OBJ) { memcpy(&acl_other_entry, &(acls[i]), sizeof(aclent_t)); } else if (acls[i].a_type & CLASS_OBJ) { memcpy(&acl_mask_entry, &(acls[i]), sizeof(aclent_t)); } } /* Select the ACL entry that determines access. */ res = -1; /* 1. If the given user ID matches the file owner, use that entry for * access. */ if (uid == st->st_uid) { /* Check the acl_user_entry for access. */ memcpy(&ae, &acl_user_entry, sizeof(aclent_t)); ae_type = USER_OBJ; have_access_entry = TRUE; } /* 2. If not matched above, and f the given user ID matches one of the * named user entries, use that entry for access. */ for (i = 0; !have_access_entry && i < acl_users->nelts; i++) { aclent_t e; memcpy(&e, &(((aclent_t *) acl_users->elts)[i]), sizeof(aclent_t)); if (uid == e.a_id) { /* Check this entry for access. Note that it'll need to * be modified by the mask, if any, later. */ memcpy(&ae, &e, sizeof(aclent_t)); ae_type = USER; have_access_entry = TRUE; break; } } /* 3. If not matched above, and if one of the group IDs matches the * group owner entry, and the group owner entry contains the * requested permissions, use that entry for access. */ if (!have_access_entry && gid == st->st_gid) { /* Check the acl_group_entry for access. First though, we need to * see if the acl_group_entry contains the requested permissions. */ if (acl_group_entry.a_perm & mode) { memcpy(&ae, &acl_group_entry, sizeof(aclent_t)); ae_type = GROUP_OBJ; have_access_entry = TRUE; } } if (suppl_gids) { for (i = 0; !have_access_entry && i < suppl_gids->nelts; i++) { gid_t suppl_gid = ((gid_t *) suppl_gids->elts)[i]; if (suppl_gid == st->st_gid) { /* Check the acl_group_entry for access. First though, we need to * see if the acl_group_entry contains the requested permissions. */ if (acl_group_entry.a_perm & mode) { memcpy(&ae, &acl_group_entry, sizeof(aclent_t)); ae_type = GROUP_OBJ; have_access_entry = TRUE; break; } } } } /* 5. If not matched above, and if one of the group IDs matches one * of the named group entries, and that entry contains the requested * permissions, use that entry for access. */ for (i = 0; !have_access_entry && i < acl_groups->nelts; i++) { aclent_t e; memcpy(&e, &(((aclent_t *) acl_groups->elts)[i]), sizeof(aclent_t)); if (gid == e.a_id) { /* Check this entry for access. Note that it'll need to * be modified by the mask, if any, later. */ if (e.a_perm & mode) { memcpy(&ae, &e, sizeof(aclent_t)); ae_type = GROUP; have_access_entry = TRUE; break; } } if (suppl_gids) { register unsigned int j; for (j = 0; !have_access_entry && j < suppl_gids->nelts; j++) { gid_t suppl_gid = ((gid_t *) suppl_gids->elts)[j]; if (suppl_gid == e.a_id) { /* Check this entry for access. Note that it'll need to * be modified by the mask, if any, later. */ if (e.a_perm & mode) { memcpy(&ae, &e, sizeof(aclent_t)); ae_type = GROUP; have_access_entry = TRUE; break; } } } } } /* 6. If not matched above, and if one of the group IDs matches * the group owner or any of the named group entries, but neither * the group owner entry nor any of the named group entries contains * the requested permissions, access is denied. */ /* 7. If not matched above, the other entry determines access. */ if (!have_access_entry) { memcpy(&ae, &acl_other_entry, sizeof(aclent_t)); ae_type = OTHER_OBJ; have_access_entry = TRUE; } /* Access determination: * * If either the user owner entry or other entry were used, and the * entry contains the requested permissions, access is permitted. * * Otherwise, if the selected entry and the mask entry both contain * the requested permissions, access is permitted. * * Otherwise, access is denied. */ switch (ae_type) { case USER_OBJ: case OTHER_OBJ: if (ae.a_perm & mode) res = 0; break; default: if ((ae.a_perm & mode) && (acl_mask_entry.a_perm & mode)) res = 0; break; } destroy_pool(acl_pool); if (res < 0) errno = EACCES; return res; # endif /* HAVE_SOLARIS_POSIX_ACL */ } /* FSIO handlers */ static int facl_fsio_access(pr_fs_t *fs, const char *path, int mode, uid_t uid, gid_t gid, array_header *suppl_gids) { int nents = 0; struct stat st; void *acls; pr_fs_clear_cache(); if (pr_fsio_stat(path, &st) < 0) return -1; /* Look up the acl for this path. */ # if defined(HAVE_BSD_POSIX_ACL) || defined(HAVE_LINUX_POSIX_ACL) acls = acl_get_file(path, ACL_TYPE_ACCESS); if (!acls) { pr_log_debug(DEBUG10, "FS: unable to retrieve ACL for '%s': %s", path, strerror(errno)); return -1; } # elif defined(HAVE_SOLARIS_POSIX_ACL) nents = acl(path, GETACLCNT, 0, NULL); if (nents < 0) { pr_log_debug(DEBUG10, "FS: unable to retrieve ACL count for '%s': %s", path, strerror(errno)); return -1; } acls = pcalloc(fs->fs_pool, nents * sizeof(aclent_t)); nents = acl(path, GETACL, nents, acls); if (nents < 0) { pr_log_debug(DEBUG10, "FS: unable to retrieve ACL for '%s': %s", path, strerror(errno)); return -1; } # endif return check_facl(fs->fs_pool, path, mode, acls, nents, &st, uid, gid, suppl_gids); } static int facl_fsio_faccess(pr_fh_t *fh, int mode, uid_t uid, gid_t gid, array_header *suppl_gids) { int nents = 0; struct stat st; void *acls; pr_fs_clear_cache(); if (pr_fsio_fstat(fh, &st) < 0) return -1; /* Look up the acl for this fd. */ # if defined(HAVE_BSD_POSIX_ACL) || defined(HAVE_LINUX_POSIX_ACL) acls = acl_get_fd(PR_FH_FD(fh)); if (!acls) { pr_log_debug(DEBUG10, "FS: unable to retrieve ACL for '%s': %s", fh->fh_path, strerror(errno)); return -1; } # elif defined(HAVE_SOLARIS_POSIX_ACL) nents = facl(PR_FH_FD(fh), GETACLCNT, 0, NULL); if (nents < 0) { pr_log_debug(DEBUG10, "FS: unable to retrieve ACL count for '%s': %s", fh->fh_path, strerror(errno)); return -1; } acls = pcalloc(fh->fh_fs->fs_pool, nents * sizeof(aclent_t)); nents = facl(PR_FH_FD(fh), GETACL, nents, acls); if (nents < 0) { pr_log_debug(DEBUG10, "FS: unable to retrieve ACL for '%s': %s", fh->fh_path, strerror(errno)); return -1; } # endif return check_facl(fh->fh_fs->fs_pool, fh->fh_path, mode, acls, nents, &st, uid, gid, suppl_gids); } #endif /* HAVE_POSIX_ACL */ /* Initialization routines */ static int facl_init(void) { #if defined(PR_USE_FACL) && defined(HAVE_POSIX_ACL) pr_fs_t *fs = pr_register_fs(permanent_pool, "facl", "/"); if (!fs) { pr_log_pri(PR_LOG_ERR, MOD_FACL_VERSION ": error registering fs: %s", strerror(errno)); return -1; } /* Ensure that our ACL-checking handlers are used. */ fs->access = facl_fsio_access; fs->faccess = facl_fsio_faccess; #endif /* PR_USE_FACL and HAVE_POSIX_ACL */ return 0; } /* Module Tables */ module facl_module = { /* Always NULL */ NULL, NULL, /* Module API version */ 0x20, /* Module name */ "facl", /* Module configuration directive handlers */ NULL, /* Module command handlers */ NULL, /* Module authentication handlers */ NULL, /* Module initialization */ facl_init, /* Session initialization */ NULL, /* Module version */ MOD_FACL_VERSION };
PHPCPP_EXPORT void *get_module() { static Php::Extension extension("Phalcon++", "0.0.1"); Php::Ini ini("phalcon.debug.enable_debug", false); extension.add(std::move(ini)); /** * Define Phalcon namespace */ Php::Namespace phalconNamespace("Phalcon"); /* Class Phalcon\Di\Injectable */ Php::Class<Phalcon::Injectable> injectable("Injectable", Php::Abstract); phalconNamespace.add(injectable); /* Class Phalcon\Version */ Php::Class<Phalcon::Version> version("Version"); phalconNamespace.add(std::move(version)); /* Class Phalcon\Debug */ Php::Class<Phalcon::Debug> debug("Debug"); phalconNamespace.add(std::move(debug)); /* Class Phalcon\Acl */ Php::Class<Phalcon::Acl> acl("Acl", Php::Abstract); phalconNamespace.add(std::move(acl)); /* Class Phalcon\Application */ Php::Class<Phalcon::Application> application("Application", Php::Abstract); phalconNamespace.add(std::move(application)); /* Class Phalcon\Arr */ Php::Class<Phalcon::Arr> arr("Arr"); phalconNamespace.add(std::move(arr)); /* Class Phalcon\Config */ Php::Class<Phalcon::Config> config("Config"); phalconNamespace.add(std::move(config)); /* Class Phalcon\Loader */ Php::Class<Phalcon::Loader> loader("Loader", injectable); phalconNamespace.add(std::move(loader)); /* Interface Phalcon\DiInterface */ Phalcon::DiInterface diInterface("DiInterface"); phalconNamespace.add(std::move(diInterface)); /* Class Phalcon\Di */ Php::Class<Phalcon::Di> di("Di", diInterface); phalconNamespace.add(std::move(di)); /* Interface Phalcon\DiInterface */ Phalcon::DispatcherInterface dispatcherInterface("DispatcherInterface"); phalconNamespace.add(std::move(dispatcherInterface)); /* Class Phalcon\Dispatcher */ Php::Class<Phalcon::Dispatcher> dispatcher("Dispatcher", dispatcherInterface); phalconNamespace.add(std::move(dispatcher)); /* Class Phalcon\Db */ Php::Class<Phalcon::Db> db("Db"); phalconNamespace.add(std::move(db)); /** * Define Di namespace */ Php::Namespace diNamespace("Di"); /* Interface Phalcon\Di\ServiceInterface */ Phalcon::Di_ServiceInterface diServiceInterface("ServiceInterface"); diNamespace.add(std::move(diServiceInterface)); /* Class Phalcon\Di\Service */ Php::Class<Phalcon::Di_Service> di_service("Service", diServiceInterface); diNamespace.add(std::move(di_service)); phalconNamespace.add(std::move(diNamespace)); extension.add(std::move(phalconNamespace)); return extension; }
int qset_acl (char const *name, int desc, mode_t mode) { #if USE_ACL # if HAVE_ACL_GET_FILE /* POSIX 1003.1e draft 17 (abandoned) specific version. */ /* Linux, FreeBSD, MacOS X, IRIX, Tru64 */ # if !HAVE_ACL_TYPE_EXTENDED /* Linux, FreeBSD, IRIX, Tru64 */ /* We must also have acl_from_text and acl_delete_def_file. (acl_delete_def_file could be emulated with acl_init followed by acl_set_file, but acl_set_file with an empty acl is unspecified.) */ # ifndef HAVE_ACL_FROM_TEXT # error Must have acl_from_text (see POSIX 1003.1e draft 17). # endif # ifndef HAVE_ACL_DELETE_DEF_FILE # error Must have acl_delete_def_file (see POSIX 1003.1e draft 17). # endif acl_t acl; int ret; if (HAVE_ACL_FROM_MODE) /* Linux */ { acl = acl_from_mode (mode); if (!acl) return -1; } else /* FreeBSD, IRIX, Tru64 */ { /* If we were to create the ACL using the functions acl_init(), acl_create_entry(), acl_set_tag_type(), acl_set_qualifier(), acl_get_permset(), acl_clear_perm[s](), acl_add_perm(), we would need to create a qualifier. I don't know how to do this. So create it using acl_from_text(). */ # if HAVE_ACL_FREE_TEXT /* Tru64 */ char acl_text[] = "u::---,g::---,o::---,"; # else /* FreeBSD, IRIX */ char acl_text[] = "u::---,g::---,o::---"; # endif if (mode & S_IRUSR) acl_text[ 3] = 'r'; if (mode & S_IWUSR) acl_text[ 4] = 'w'; if (mode & S_IXUSR) acl_text[ 5] = 'x'; if (mode & S_IRGRP) acl_text[10] = 'r'; if (mode & S_IWGRP) acl_text[11] = 'w'; if (mode & S_IXGRP) acl_text[12] = 'x'; if (mode & S_IROTH) acl_text[17] = 'r'; if (mode & S_IWOTH) acl_text[18] = 'w'; if (mode & S_IXOTH) acl_text[19] = 'x'; acl = acl_from_text (acl_text); if (!acl) return -1; } if (HAVE_ACL_SET_FD && desc != -1) ret = acl_set_fd (desc, acl); else ret = acl_set_file (name, ACL_TYPE_ACCESS, acl); if (ret != 0) { int saved_errno = errno; acl_free (acl); if (ACL_NOT_WELL_SUPPORTED (errno)) return chmod_or_fchmod (name, desc, mode); else { errno = saved_errno; return -1; } } else acl_free (acl); if (S_ISDIR (mode) && acl_delete_def_file (name)) return -1; 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. */ return chmod_or_fchmod (name, desc, mode); } return 0; # else /* HAVE_ACL_TYPE_EXTENDED */ /* MacOS X */ /* On MacOS 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; /* Remove the ACL if the file has ACLs. */ if (HAVE_ACL_GET_FD && desc != -1) acl = acl_get_fd (desc); else acl = acl_get_file (name, ACL_TYPE_EXTENDED); if (acl) { acl_free (acl); acl = acl_init (0); if (acl) { if (HAVE_ACL_SET_FD && desc != -1) ret = acl_set_fd (desc, acl); else ret = acl_set_file (name, ACL_TYPE_EXTENDED, acl); if (ret != 0) { int saved_errno = errno; acl_free (acl); if (ACL_NOT_WELL_SUPPORTED (saved_errno)) return chmod_or_fchmod (name, desc, mode); else { errno = saved_errno; return -1; } } acl_free (acl); } } /* Since !MODE_INSIDE_ACL, we have to call chmod explicitly. */ return chmod_or_fchmod (name, desc, mode); # endif # elif HAVE_FACL && defined GETACLCNT /* Solaris, Cygwin, not HP-UX */ int done_setacl = 0; # 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). */ /* The flags in the ace_t structure changed in a binary incompatible way when ACL_NO_TRIVIAL etc. were introduced in <sys/acl.h> version 1.15. How to distinguish the two conventions at runtime? We fetch the existing ACL. In the old convention, usually three ACEs have a_flags = ACE_OWNER / ACE_GROUP / ACE_OTHER, in the range 0x0100..0x0400. In the new convention, these values are not used. */ int convention; { int count; ace_t *entries; for (;;) { if (desc != -1) count = facl (desc, ACE_GETACLCNT, 0, NULL); else count = acl (name, ACE_GETACLCNT, 0, NULL); if (count <= 0) { convention = -1; break; } entries = (ace_t *) malloc (count * sizeof (ace_t)); if (entries == NULL) { errno = ENOMEM; return -1; } if ((desc != -1 ? facl (desc, ACE_GETACL, count, entries) : acl (name, ACE_GETACL, count, entries)) == count) { int i; convention = 0; for (i = 0; i < count; i++) if (entries[i].a_flags & (OLD_ACE_OWNER | OLD_ACE_GROUP | OLD_ACE_OTHER)) { convention = 1; break; } free (entries); break; } /* Huh? The number of ACL entries changed since the last call. Repeat. */ free (entries); } } if (convention >= 0) { ace_t entries[6]; int count; int ret; if (convention) { /* Running on Solaris 10. */ entries[0].a_type = OLD_ALLOW; entries[0].a_flags = OLD_ACE_OWNER; entries[0].a_who = 0; /* irrelevant */ entries[0].a_access_mask = (mode >> 6) & 7; entries[1].a_type = OLD_ALLOW; entries[1].a_flags = OLD_ACE_GROUP; entries[1].a_who = 0; /* irrelevant */ entries[1].a_access_mask = (mode >> 3) & 7; entries[2].a_type = OLD_ALLOW; entries[2].a_flags = OLD_ACE_OTHER; entries[2].a_who = 0; entries[2].a_access_mask = mode & 7; count = 3; } else {
/** \brief dnsgrab callback to received request by name * * @return a tokeep for the dnsgrab_t */ bool router_peer_t::dnsgrab_byname_cb(dnsgrab_request_t &request) throw() { router_name_t request_dnsname = router_name_t(request.get_request_name()); // log to debug KLOG_ERR("enter request_name=" << request.get_request_name()); // sanity check - here the dnsgrab_request MUST be AF_INET DBG_ASSERT( request.get_addr_family() == "AF_INET" ); // sanity check - here the dnsgrab_request MUST be by_name() DBG_ASSERT( request.is_request_by_name() ); // if request_dnsname is not is_fully_qualified, notify a not_found // - NOTE: in theory, it should not happen but "be tolerant with what you receive" if( !request_dnsname.is_fully_qualified() ){ set_dnsreq_reply_notfound(request); return true; } // if the dnsgrab_request_t is NOT one for this router_peer_t, notify a not_found if( !dnsname_is_dnsgrab_ok(request_dnsname) ){ set_dnsreq_reply_notfound(request); return true; } // if the dnsgrab_request_t is for the lident peername, reply the lident if( lident().dnsfqname(profile) == request_dnsname ){ set_dnsreq_reply_lident(request); return true; } // NOTE: here the request name MAY NOT be a router_lident_t one // if router_acl_t reject it, reply a notfound if( acl().reject(request_dnsname.to_string()) ){ set_dnsreq_reply_notfound(request); return true; } // try to get a remote_peerid matching the request name router_peerid_t remote_peerid = dnsname2peerid(request_dnsname); // if no remote_peerid matches, reply notfound if( remote_peerid.is_null() ){ set_dnsreq_reply_notfound(request); return true; } // if there are already a router_full_t for this remote_peerid, reply its matching rident router_full_t * router_full = full_by_remote_peerid(remote_peerid); if( router_full ){ set_dnsreq_reply_cnxfull(request, router_full); return true; } // if an router_itor_t is already running for the requested hostname, add this request to it router_itor_t * router_itor; router_itor = itor_by_remote_peerid(remote_peerid); if( router_itor ){ router_itor->queue_dnsgrab_request(request); return true; } // if the remote_peerid is in the itor_negcache, reply notfound if( itor_negcache.contain(remote_peerid) ){ set_dnsreq_reply_notfound(request); return true; } // launch a new router_itor_t based on this dnsgrab_request_t router_err_t router_err; router_itor = nipmem_new router_itor_t(this); router_err = router_itor->queue_dnsgrab_request(request).start(remote_peerid, request_dnsname); // if the router_itor start failed, delete the router_itor_t and reply notfound if( router_err.failed() ){ nipmem_delete router_itor; set_dnsreq_reply_notfound(request); return true; } // return tokeep return true; }