Exemple #1
0
/*
 * remove extended entries
 */
void
remove_ext(acl_t *prev_acl)
{
	acl_t acl_new, acl_old;
	acl_entry_t entry, entry_new;
	acl_permset_t perm;
	acl_tag_t tag;
	int entry_id, have_mask_entry;

	if (acl_type == ACL_TYPE_ACCESS)
		acl_old = acl_dup(prev_acl[ACCESS_ACL]);
	else
		acl_old = acl_dup(prev_acl[DEFAULT_ACL]);

	if (acl_old == NULL)
		err(1, "acl_dup() failed");

	have_mask_entry = 0;
	acl_new = acl_init(ACL_MAX_ENTRIES);
	if (acl_new == NULL)
		err(1, "acl_init() failed");

	tag = ACL_UNDEFINED_TAG;

	/* only save the default user/group/other entries */
	entry_id = ACL_FIRST_ENTRY;
	while (acl_get_entry(acl_old, entry_id, &entry) == 1) {
		entry_id = ACL_NEXT_ENTRY;

		if (acl_get_tag_type(entry, &tag) == -1)
			err(1, "acl_get_tag_type() failed");

		switch(tag) {
		case ACL_USER_OBJ:
		case ACL_GROUP_OBJ:
		case ACL_OTHER:
			if (acl_get_tag_type(entry, &tag) == -1)
				err(1, "acl_get_tag_type() failed");
			if (acl_get_permset(entry, &perm) == -1)
				err(1, "acl_get_permset() failed");
			if (acl_create_entry(&acl_new, &entry_new) == -1)
				err(1, "acl_create_entry() failed");
			if (acl_set_tag_type(entry_new, tag) == -1)
				err(1, "acl_set_tag_type() failed");
			if (acl_set_permset(entry_new, perm) == -1)
				err(1, "acl_get_permset() failed");
			if (acl_copy_entry(entry_new, entry) == -1)
				err(1, "acl_copy_entry() failed");
			break;
		case ACL_MASK:
			have_mask_entry = 1;
			break;
		default:
			break;
		}
	}
	if (have_mask_entry && n_flag == 0) {
		if (acl_calc_mask(&acl_new) == -1)
			err(1, "acl_calc_mask() failed");
	} else {
		have_mask = 1;
	}

	if (acl_type == ACL_TYPE_ACCESS) {
		acl_free(prev_acl[ACCESS_ACL]);
		prev_acl[ACCESS_ACL] = acl_new;
	} else {
		acl_free(prev_acl[DEFAULT_ACL]);
		prev_acl[DEFAULT_ACL] = acl_new;
	}
}
Exemple #2
0
static acl_t
_posix1e_acl_strip_np(const acl_t aclp, int recalculate_mask)
{
	acl_t acl_new, acl_old;
	acl_entry_t entry, entry_new;
	acl_permset_t perm;
	acl_tag_t tag;
	int entry_id, have_mask_entry;

	assert(_acl_brand(aclp) == ACL_BRAND_POSIX);

	acl_old = acl_dup(aclp);
	if (acl_old == NULL)
		return (NULL);

	assert(_acl_brand(acl_old) == ACL_BRAND_POSIX);

	have_mask_entry = 0;
	acl_new = acl_init(ACL_MAX_ENTRIES);
	if (acl_new == NULL)
		return (NULL);
	tag = ACL_UNDEFINED_TAG;

	/* only save the default user/group/other entries */
	entry_id = ACL_FIRST_ENTRY;
	while (acl_get_entry(acl_old, entry_id, &entry) == 1) {
		entry_id = ACL_NEXT_ENTRY;

		assert(_entry_brand(entry) == ACL_BRAND_POSIX);

		if (acl_get_tag_type(entry, &tag) == -1)
			return (NULL);

		switch(tag) {
		case ACL_USER_OBJ:
		case ACL_GROUP_OBJ:
		case ACL_OTHER:
			if (acl_get_tag_type(entry, &tag) == -1)
				return (NULL);
			if (acl_get_permset(entry, &perm) == -1)
				return (NULL);
			if (acl_create_entry(&acl_new, &entry_new) == -1)
				return (NULL);
			if (acl_set_tag_type(entry_new, tag) == -1)
				return (NULL);
			if (acl_set_permset(entry_new, perm) == -1)
				return (NULL);
			if (acl_copy_entry(entry_new, entry) == -1)
				return (NULL);
			assert(_entry_brand(entry_new) == ACL_BRAND_POSIX);
			break;
		case ACL_MASK:
			have_mask_entry = 1;
			break;
		default:
			break;
		}
	}

	assert(_acl_brand(acl_new) == ACL_BRAND_POSIX);

	if (have_mask_entry && recalculate_mask) {
		if (acl_calc_mask(&acl_new) == -1)
			return (NULL);
	}

	return (acl_new);
}
Exemple #3
0
static int CheckPosixLinuxACEs(EvalContext *ctx, Rlist *aces, AclMethod method, const char *file_path, acl_type_t acl_type, Attributes a,
                               const Promise *pp, PromiseResult *result)
{
    acl_t acl_existing;
    acl_t acl_new;
    acl_t acl_tmp;
    acl_entry_t ace_parsed;
    acl_entry_t ace_current;
    acl_permset_t perms;
    char *cf_ace;
    int retv;
    int has_mask;
    Rlist *rp;
    char *acl_type_str;

    acl_new = NULL;
    acl_existing = NULL;
    acl_tmp = NULL;
    has_mask = false;

    acl_type_str = acl_type == ACL_TYPE_ACCESS ? "Access" : "Default";

// read existing acl

    if ((acl_existing = acl_get_file(file_path, acl_type)) == NULL)
    {
        Log(LOG_LEVEL_VERBOSE, "No ACL for '%s' could be read. (acl_get_file: %s)", file_path, GetErrorStr());
        return false;
    }

// allocate memory for temp ace (it needs to reside in a temp acl)

    if ((acl_tmp = acl_init(1)) == NULL)
    {
        Log(LOG_LEVEL_ERR, "New ACL could not be allocated (acl_init: %s)", GetErrorStr());
        acl_free((void *) acl_existing);
        return false;
    }

    if (acl_create_entry(&acl_tmp, &ace_parsed) != 0)
    {
        Log(LOG_LEVEL_ERR, "New ACL could not be allocated (acl_create_entry: %s)", GetErrorStr());
        acl_free((void *) acl_existing);
        acl_free((void *) acl_tmp);
        return false;
    }

// copy existing aces if we are appending

    if (method == ACL_METHOD_APPEND)
    {
        if ((acl_new = acl_dup(acl_existing)) == NULL)
        {
            Log(LOG_LEVEL_ERR, "Error copying existing ACL (acl_dup: %s)", GetErrorStr());
            acl_free((void *) acl_existing);
            acl_free((void *) acl_tmp);
            return false;
        }
    }
    else                        // overwrite existing acl
    {
        if ((acl_new = acl_init(5)) == NULL)    // TODO: Always OK with 5 here ?
        {
            Log(LOG_LEVEL_ERR, "New ACL could not be allocated (acl_init: %s)", GetErrorStr());
            acl_free((void *) acl_existing);
            acl_free((void *) acl_tmp);
            return false;
        }
    }

    for (rp = aces; rp != NULL; rp = rp->next)
    {
        cf_ace = RlistScalarValue(rp);

        if (!ParseEntityPosixLinux(&cf_ace, ace_parsed, &has_mask))
        {
            Log(LOG_LEVEL_ERR, "Error parsing entity in 'cf_ace'.");
            acl_free((void *) acl_existing);
            acl_free((void *) acl_tmp);
            acl_free((void *) acl_new);
            return false;
        }

        // check if an ACE with this entity-type and id already exist in the Posix Linux ACL

        ace_current = FindACE(acl_new, ace_parsed);

        // create new entry in ACL if it did not exist

        if (ace_current == NULL)
        {
            if (acl_create_entry(&acl_new, &ace_current) != 0)
            {
                Log(LOG_LEVEL_ERR, "Failed to allocate ace (acl_create_entry: %s)", GetErrorStr());
                acl_free((void *) acl_existing);
                acl_free((void *) acl_tmp);
                acl_free((void *) acl_new);
                return false;
            }

            // copy parsed entity-type and id

            if (acl_copy_entry(ace_current, ace_parsed) != 0)
            {
                Log(LOG_LEVEL_ERR, "Error copying Linux entry in 'cf_ace' (acl_copy_entry: %s)", GetErrorStr());
                acl_free((void *) acl_existing);
                acl_free((void *) acl_tmp);
                acl_free((void *) acl_new);
                return false;
            }

            // clear ace_current's permissions to avoid ace_parsed from last
            // loop iteration to be taken into account when applying mode below
            if ((acl_get_permset(ace_current, &perms) != 0))
            {
                Log(LOG_LEVEL_ERR, "Error obtaining permset for 'ace_current' (acl_get_permset: %s)", GetErrorStr());
                acl_free((void *) acl_existing);
                acl_free((void *) acl_tmp);
                acl_free((void *) acl_new);
                return false;
            }

            if (acl_clear_perms(perms) != 0)
            {
                Log(LOG_LEVEL_ERR, "Error clearing permset for 'ace_current'. (acl_clear_perms: %s)", GetErrorStr());
                acl_free((void *) acl_existing);
                acl_free((void *) acl_tmp);
                acl_free((void *) acl_new);
                return false;
            }
        }

        // mode string should be prefixed with an entry seperator

        if (*cf_ace != ':')
        {
            Log(LOG_LEVEL_ERR, "No separator before mode-string in 'cf_ace'");
            acl_free((void *) acl_existing);
            acl_free((void *) acl_tmp);
            acl_free((void *) acl_new);
            return false;
        }

        cf_ace += 1;

        if (acl_get_permset(ace_current, &perms) != 0)
        {
            Log(LOG_LEVEL_ERR, "Error obtaining permset for 'cf_ace'");
            acl_free((void *) acl_existing);
            acl_free((void *) acl_tmp);
            acl_free((void *) acl_new);
            return false;
        }

        if (!ParseModePosixLinux(cf_ace, perms))
        {
            Log(LOG_LEVEL_ERR, "Error parsing mode-string in 'cf_ace'");
            acl_free((void *) acl_existing);
            acl_free((void *) acl_tmp);
            acl_free((void *) acl_new);
            return false;
        }

        // only allow permissions exist on posix acls, so we do
        // not check what follows next
    }

// if no mask exists, calculate one (or both?): run acl_calc_mask and add one
    if (!has_mask)
    {
        if (acl_calc_mask(&acl_new) != 0)
        {
            Log(LOG_LEVEL_ERR, "Error calculating new acl mask");
            acl_free((void *) acl_existing);
            acl_free((void *) acl_tmp);
            acl_free((void *) acl_new);
            return false;
        }
    }

    if ((retv = ACLEquals(acl_existing, acl_new)) == -1)
    {
        Log(LOG_LEVEL_ERR, "Error while comparing existing and new ACL, unable to repair.");
        acl_free((void *) acl_existing);
        acl_free((void *) acl_tmp);
        acl_free((void *) acl_new);
        return false;
    }

    if (retv == 1)              // existing and new acl differ, update existing
    {

        switch (a.transaction.action)
        {
        case cfa_warn:

            cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_WARN, pp, a, "%s ACL on file '%s' needs to be updated", acl_type_str, file_path);
            *result = PromiseResultUpdate(*result, PROMISE_RESULT_WARN);
            break;

        case cfa_fix:

            if (!DONTDO)
            {
                if ((retv = acl_set_file(file_path, acl_type, acl_new)) != 0)
                {
                    Log(LOG_LEVEL_ERR, "Error setting new %s ACL on file '%s' (acl_set_file: %s), are required ACEs present ?",
                          acl_type_str, file_path, GetErrorStr());
                    acl_free((void *) acl_existing);
                    acl_free((void *) acl_tmp);
                    acl_free((void *) acl_new);
                    return false;
                }
            }

            cfPS(ctx, LOG_LEVEL_INFO, PROMISE_RESULT_CHANGE, pp, a, "%s ACL on '%s' successfully changed.", acl_type_str, file_path);
            *result = PromiseResultUpdate(*result, PROMISE_RESULT_CHANGE);

            break;

        default:
            ProgrammingError("CFEngine: internal error: illegal file action");
        }

    }
    else
    {
        cfPS(ctx, LOG_LEVEL_INFO, PROMISE_RESULT_NOOP, pp, a, "'%s' ACL on '%s' needs no modification.", acl_type_str, file_path);
    }

    acl_free((void *) acl_existing);
    acl_free((void *) acl_new);
    acl_free((void *) acl_tmp);
    return true;
}
Exemple #4
0
/*
 * merge an ACL into existing file's ACL
 */
int
merge_acl(acl_t acl, acl_t *prev_acl, const char *filename)
{
	acl_entry_t entry, entry_new;
	acl_permset_t permset;
	acl_t acl_new;
	acl_tag_t tag, tag_new;
	acl_entry_type_t entry_type, entry_type_new;
	acl_flagset_t flagset;
	int entry_id, entry_id_new, have_entry, had_entry, entry_number = 0;
	int acl_brand, prev_acl_brand;

	acl_get_brand_np(acl, &acl_brand);
	acl_get_brand_np(*prev_acl, &prev_acl_brand);

	if (branding_mismatch(acl_brand, prev_acl_brand)) {
		warnx("%s: branding mismatch; existing ACL is %s, "
		    "entry to be merged is %s", filename,
		    brand_name(prev_acl_brand), brand_name(acl_brand));
		return (-1);
	}

	acl_new = acl_dup(*prev_acl);
	if (acl_new == NULL)
		err(1, "%s: acl_dup() failed", filename);

	entry_id = ACL_FIRST_ENTRY;

	while (acl_get_entry(acl, entry_id, &entry) == 1) {
		entry_id = ACL_NEXT_ENTRY;
		have_entry = 0;
		had_entry = 0;

		/* keep track of existing ACL_MASK entries */
		if (acl_get_tag_type(entry, &tag) == -1)
			err(1, "%s: acl_get_tag_type() failed - "
			    "invalid ACL entry", filename);
		if (tag == ACL_MASK)
			have_mask = 1;

		/* check against the existing ACL entries */
		entry_id_new = ACL_FIRST_ENTRY;
		while (acl_get_entry(acl_new, entry_id_new, &entry_new) == 1) {
			entry_id_new = ACL_NEXT_ENTRY;

			if (acl_get_tag_type(entry, &tag) == -1)
				err(1, "%s: acl_get_tag_type() failed",
				    filename);
			if (acl_get_tag_type(entry_new, &tag_new) == -1)
				err(1, "%s: acl_get_tag_type() failed",
				    filename);
			if (tag != tag_new)
				continue;

			/*
			 * For NFSv4, in addition to "tag" and "id" we also
			 * compare "entry_type".
			 */
			if (acl_brand == ACL_BRAND_NFS4) {
				if (acl_get_entry_type_np(entry, &entry_type))
					err(1, "%s: acl_get_entry_type_np() "
					    "failed", filename);
				if (acl_get_entry_type_np(entry_new, &entry_type_new))
					err(1, "%s: acl_get_entry_type_np() "
					    "failed", filename);
				if (entry_type != entry_type_new)
					continue;
			}
		
			switch(tag) {
			case ACL_USER:
			case ACL_GROUP:
				have_entry = merge_user_group(&entry,
				    &entry_new, acl_brand);
				if (have_entry == 0)
					break;
				/* FALLTHROUGH */
			case ACL_USER_OBJ:
			case ACL_GROUP_OBJ:
			case ACL_OTHER:
			case ACL_MASK:
			case ACL_EVERYONE:
				if (acl_get_permset(entry, &permset) == -1)
					err(1, "%s: acl_get_permset() failed",
					    filename);
				if (acl_set_permset(entry_new, permset) == -1)
					err(1, "%s: acl_set_permset() failed",
					    filename);

				if (acl_brand == ACL_BRAND_NFS4) {
					if (acl_get_entry_type_np(entry, &entry_type))
						err(1, "%s: acl_get_entry_type_np() failed",
						    filename);
					if (acl_set_entry_type_np(entry_new, entry_type))
						err(1, "%s: acl_set_entry_type_np() failed",
						    filename);
					if (acl_get_flagset_np(entry, &flagset))
						err(1, "%s: acl_get_flagset_np() failed",
						    filename);
					if (acl_set_flagset_np(entry_new, flagset))
						err(1, "%s: acl_set_flagset_np() failed",
						    filename);
				}
				had_entry = have_entry = 1;
				break;
			default:
				/* should never be here */
				errx(1, "%s: invalid tag type: %i", filename, tag);
				break;
			}
		}

		/* if this entry has not been found, it must be new */
		if (had_entry == 0) {

			/*
			 * NFSv4 ACL entries must be prepended to the ACL.
			 * Appending them at the end makes no sense, since
			 * in most cases they wouldn't even get evaluated.
			 */
			if (acl_brand == ACL_BRAND_NFS4) {
				if (acl_create_entry_np(&acl_new, &entry_new, entry_number) == -1) {
					warn("%s: acl_create_entry_np() failed", filename); 
					acl_free(acl_new);
					return (-1);
				}
				/*
				 * Without this increment, adding several
				 * entries at once, for example
				 * "setfacl -m user:1:r:allow,user:2:r:allow",
				 * would make them appear in reverse order.
				 */
				entry_number++;
			} else {
				if (acl_create_entry(&acl_new, &entry_new) == -1) {
					warn("%s: acl_create_entry() failed", filename); 
					acl_free(acl_new);
					return (-1);
				}
			}
			if (acl_copy_entry(entry_new, entry) == -1)
				err(1, "%s: acl_copy_entry() failed", filename);
		}
	}

	acl_free(*prev_acl);
	*prev_acl = acl_new;

	return (0);
}
Exemple #5
0
/* merge 2 acl's together */
static int
merge_acl(acl_t acl, acl_t *prev_acl, const char *path)
{
	acl_t acl_new;
	acl_permset_t permset;
	acl_flagset_t flagset;
	acl_tag_t tag, tag_new;
	acl_entry_t entry, entry_new;
	acl_entry_type_t entry_type, entry_type_new;
	int entry_id, entry_id_new, have_entry, had_entry, entry_number = 0;

	if ((acl_new = acl_dup(*prev_acl)) == NULL)
		err(EX_OSERR, "%s: acl_dup() failed", path);

	entry_id = ACL_FIRST_ENTRY;
	while (acl_get_entry(acl, entry_id, &entry) == 1) {
		entry_id = ACL_NEXT_ENTRY;
		have_entry = had_entry = 0;

		entry_id_new = ACL_FIRST_ENTRY;
		while (acl_get_entry(acl_new, entry_id_new, &entry_new) > 0) {
			entry_id_new = ACL_NEXT_ENTRY;

			if (acl_get_tag_type(entry, &tag) < 0)
				err(EX_OSERR, "%s: acl_get_tag_type() failed", path);
			if (acl_get_tag_type(entry_new, &tag_new) < 0)
				err(EX_OSERR, "%s: acl_get_tag_type() failed", path);
			if (tag != tag_new)
				continue;

			if (acl_get_entry_type_np(entry, &entry_type) < 0)
				err(EX_OSERR, "%s: acl_get_entry_type_np() failed", path);
			if (acl_get_entry_type_np(entry_new, &entry_type_new) < 0)
				err(EX_OSERR, "%s: acl_get_entry_type_np() failed", path);
			if (entry_type != entry_type_new)
				continue;
		
			switch(tag) {
				case ACL_USER:
				case ACL_GROUP:
					have_entry = merge_user_group(&entry, &entry_new);
					if (have_entry == 0)
						break;

				case ACL_USER_OBJ:
				case ACL_GROUP_OBJ:
				case ACL_EVERYONE:
					merge_acl_entries(&entry, &entry_new);
					had_entry = have_entry = 1;
					break;

				default:
					errx(EX_OSERR, "%s: invalid tag type: %i", path, tag);
					break;
			}
		}

		if (had_entry == 0) {
			if (acl_create_entry_np(&acl_new, &entry_new, entry_number) < 0) {
				warn("%s: acl_create_entry_np() failed", path); 
				acl_free(acl_new);
				return (-1);
			}

			entry_number++;
			if (acl_copy_entry(entry_new, entry) < 0)
				err(EX_OSERR, "%s: acl_copy_entry() failed", path);
		}
	}

	acl_free(*prev_acl);
	*prev_acl = acl_new;

	return (0);
}
Exemple #6
0
/* set the appropriate mask the given ACL's */
int
set_acl_mask(acl_t *prev_acl, const char *filename)
{
	acl_entry_t entry;
	acl_t acl;
	acl_tag_t tag;
	int entry_id;

	entry = NULL;

	/*
	 * ... if a mask entry is specified, then the permissions of the mask
	 * entry in the resulting ACL shall be set to the permissions in the
	 * specified ACL mask entry.
	 */
	if (have_mask)
		return (0);

	acl = acl_dup(*prev_acl);
	if (acl == NULL)
		err(1, "%s: acl_dup() failed", filename);

	if (n_flag == 0) {
		/*
		 * If no mask entry is specified and the -n option is not
		 * specified, then the permissions of the resulting ACL mask
		 * entry shall be set to the union of the permissions
		 * associated with all entries which belong to the file group
		 * class in the resulting ACL
		 */
		if (acl_calc_mask(&acl)) {
			warn("%s: acl_calc_mask() failed", filename);
			acl_free(acl);
			return (-1);
		}
	} else {
		/*
		 * If no mask entry is specified and the -n option is
		 * specified, then the permissions of the resulting ACL
		 * mask entry shall remain unchanged ...
		 */

		entry_id = ACL_FIRST_ENTRY;

		while (acl_get_entry(acl, entry_id, &entry) == 1) {
			entry_id = ACL_NEXT_ENTRY;
			if (acl_get_tag_type(entry, &tag) == -1)
				err(1, "%s: acl_get_tag_type() failed",
				    filename);

			if (tag == ACL_MASK) {
				acl_free(acl);
				return (0);
			}
		}

		/*
		 * If no mask entry is specified, the -n option is specified,
		 * and no ACL mask entry exists in the ACL associated with the
		 * file, then write an error message to standard error and
		 * continue with the next file.
		 */
		warnx("%s: warning: no mask entry", filename);
		acl_free(acl);
		return (0);
	}

	acl_free(*prev_acl);
	*prev_acl = acl_dup(acl);
	acl_free(acl);

	return (0);
}
Exemple #7
0
int
modify_file_acl(unsigned int optflags, const char *path, acl_t modifier, int position, int inheritance_level, int follow) {
	
	acl_t oacl = NULL;
	unsigned aindex  = 0, flag_new_acl = 0;
	acl_entry_t newent = NULL;
	acl_entry_t entry = NULL;
	unsigned retval = 0;

	extern int chmod_fflag;

/* XXX acl_get_file() returns a zero entry ACL if an ACL was previously
 * associated with the file, and has had its entries removed.
 * However, POSIX 1003.1e states that a zero entry ACL should be 
 * returned if the caller asks for ACL_TYPE_DEFAULT, and no ACL is 
 * associated with the path; it
 * does not specifically state that a request for ACL_TYPE_EXTENDED
 * should not return a zero entry ACL, however.
 */

/* Determine if we've been given a zero entry ACL, or create an ACL if 
 * none exists. There are some issues to consider here: Should we create
 * a zero-entry ACL for a delete or check canonicity operation?
 */

	if (path == NULL)
		chmod_usage();

	if (optflags & ACL_CLEAR_FLAG) {
		filesec_t fsec = filesec_init();
		if (fsec == NULL) {
			// err(1, "filesec_init() failed");
            fprintf(stderr, "chmod: filesec_init() failed: %s\n", strerror(errno));
            pthread_exit(NULL);
		}
		if (filesec_set_property(fsec, FILESEC_ACL, _FILESEC_REMOVE_ACL) != 0) {
            // err(1, "filesec_set_property() failed");
            fprintf(stderr, "chmod: filesec_set_property() failed: %s\n", strerror(errno));
            pthread_exit(NULL);
                }
		if (follow) {
			if (chmodx_np(path, fsec) != 0) {
                if (!chmod_fflag) {
					// warn("Failed to clear ACL on file %s", path);
                    fprintf(stderr, "chmod: Failed to clear ACL on file %s: %s\n", path, strerror(errno));
				}
				retval = 1;
			}
		} else {
			int fd = open(path, O_SYMLINK);
			if (fd != -1) {
				if (fchmodx_np(fd, fsec) != 0) {
					if (!chmod_fflag) {
                        fprintf(stderr, "chmod: Failed to clear ACL on file %s: %s\n", path, strerror(errno));
                        // warn("Failed to clear ACL on file %s", path);
					}
					retval = 1;
				}
				close(fd);
			} else {
				if (!chmod_fflag) {
					// warn("Failed to open file %s", path);
                    fprintf(stderr, "chmod: Failed to open file %s: %s\n", path, strerror(errno));
				}
				retval = 1;
			}
		}
		filesec_free(fsec);
		return (retval);
	}

	if (optflags & ACL_FROM_STDIN) {
		oacl = acl_dup(modifier);
	} else {
		if (follow) {
			oacl = acl_get_file(path, ACL_TYPE_EXTENDED);
		} else {
			int fd = open(path, O_SYMLINK);
			if (fd != -1) {
				oacl = acl_get_fd_np(fd, ACL_TYPE_EXTENDED);
				close(fd);
			}
		}
		if ((oacl == NULL) ||
		    (acl_get_entry(oacl,ACL_FIRST_ENTRY, &newent) != 0)) {
            if ((oacl = acl_init(1)) == NULL) {
				// err(1, "acl_init() failed");
                fprintf(stderr, "chmod: acl_init() failed: %s\n", strerror(errno));
                pthread_exit(NULL);
            }
			flag_new_acl = 1;
			position = 0;
		}
	
		if ((0 == flag_new_acl) && (optflags & (ACL_REMOVE_INHERIT_FLAG | 
							ACL_REMOVE_INHERITED_ENTRIES))) {
			acl_t facl = NULL;
            if ((facl = acl_init(1)) == NULL) {
				//err(1, "acl_init() failed");
                fprintf(stderr, "chmod: acl_init() failed: %s\n", strerror(errno));
                pthread_exit(NULL);
            }
			for (aindex = 0; 
			     acl_get_entry(oacl, 
					   (entry == NULL ? ACL_FIRST_ENTRY : 
					    ACL_NEXT_ENTRY), &entry) == 0; 
			     aindex++) {
				acl_flagset_t eflags;
				acl_entry_t fent = NULL;
				if (acl_get_flagset_np(entry, &eflags) != 0) {
                    fprintf(stderr,  "chmod: Unable to obtain flagset: %s\n", strerror(errno));
                    pthread_exit(NULL);
                    // err(1, "Unable to obtain flagset");
				}
				
				if (acl_get_flag_np(eflags, ACL_ENTRY_INHERITED)) {
					if (optflags & ACL_REMOVE_INHERIT_FLAG) {
						acl_delete_flag_np(eflags, ACL_ENTRY_INHERITED);
						acl_set_flagset_np(entry, eflags);
						acl_create_entry(&facl, &fent);
						acl_copy_entry(fent, entry);
					}
				}
				else {
					acl_create_entry(&facl, &fent);
					acl_copy_entry(fent, entry);
				}
			}
			if (oacl)
				acl_free(oacl);
			oacl = facl;
		} else if (optflags & ACL_TO_STDOUT) {
			ssize_t len; /* need to get printacl() from ls(1) */
			char *text = acl_to_text(oacl, &len);
			puts(text);
			acl_free(text);
		} else if (optflags & ACL_CHECK_CANONICITY) {
			if (flag_new_acl) {
				// warnx("No ACL currently associated with file '%s'", path);
                fprintf(stderr, "chmod: No ACL currently associated with file '%s'\n", path);
			}
			retval = is_canonical(oacl);
		} else if ((optflags & ACL_SET_FLAG) && (position == -1) && 
		    (!is_canonical(oacl))) {
			// warnx("The specified file '%s' does not have an ACL in canonical order, please specify a position with +a# ", path);
            fprintf(stderr, "chmod: The specified file '%s' does not have an ACL in canonical order, please specify a position with +a# \n", path);
			retval = 1;
		} else if (((optflags & ACL_DELETE_FLAG) && (position != -1))
		    || (optflags & ACL_CHECK_CANONICITY)) {
			retval = modify_acl(&oacl, NULL, optflags, position, 
					    inheritance_level, flag_new_acl, path);
		} else if ((optflags & (ACL_REMOVE_INHERIT_FLAG|ACL_REMOVE_INHERITED_ENTRIES)) && flag_new_acl) {
			// warnx("No ACL currently associated with file '%s'", path);
            fprintf(stderr, "chmod: No ACL currently associated with file '%s'\n", path);
			retval = 1;
		} else {
			if (!modifier) { /* avoid bus error in acl_get_entry */
				// errx(1, "Internal error: modifier should not be NULL");
                fprintf(stderr, "Internal error: modifier should not be NULL\n");
                pthread_exit(NULL);
			}
			for (aindex = 0; 
			     acl_get_entry(modifier, 
					   (entry == NULL ? ACL_FIRST_ENTRY : 
					    ACL_NEXT_ENTRY), &entry) == 0; 
			     aindex++) {

				retval += modify_acl(&oacl, entry, optflags, 
						     position, inheritance_level, 
						     flag_new_acl, path);
			}
		}
	}

/* XXX Potential race here, since someone else could've modified or
 * read the ACL on this file (with the intention of modifying it) in
 * the interval from acl_get_file() to acl_set_file(); we can
 * minimize one aspect of this  window by comparing the original acl
 * to a fresh one from acl_get_file() but we could consider a
 * "changeset" mechanism, common locking  strategy, or kernel
 * supplied reservation mechanism to prevent this race.
 */
	if (!(optflags & (ACL_TO_STDOUT|ACL_CHECK_CANONICITY))) {
		int status = -1;
		if (follow) {
	    		status = acl_set_file(path, ACL_TYPE_EXTENDED, oacl);
		} else {
			int fd = open(path, O_SYMLINK);
			if (fd != -1) {
				status = acl_set_fd_np(fd, oacl,
							ACL_TYPE_EXTENDED);
				close(fd);
			}
		}
		if (status != 0) {
			if (!chmod_fflag)
                fprintf(stderr, "chmod: Failed to set ACL on file '%s': %s\n", path, strerror(errno));
            // warn("Failed to set ACL on file '%s'", path);
			retval = 1;
		}
	}
	
	if (oacl)
		acl_free(oacl);
	
	return retval;
}
Exemple #8
0
static int open_listener(struct listen_config_t *lc)
{
	struct listen_t *l;
	int i;
	
	l = listener_alloc();
	l->id = lc->id;
	l->hidden = lc->hidden;
	l->corepeer = lc->corepeer;
	l->client_flags = lc->client_flags;
	l->clients_max = lc->clients_max;
	
	l->portaccount = port_accounter_alloc();
	
	/* Pick first of the AIs for this listen definition */
	l->addr_s = strsockaddr( lc->ai->ai_addr, lc->ai->ai_addrlen );
	l->name   = hstrdup(lc->name);
	l->portnum = lc->portnum;
	l->ai_protocol = lc->ai->ai_protocol;
	l->listener_id = keyhash(l->addr_s, strlen(l->addr_s), 0);
	l->listener_id = keyhash(&lc->ai->ai_socktype, sizeof(lc->ai->ai_socktype), l->listener_id);
	l->listener_id = keyhash(&lc->ai->ai_protocol, sizeof(lc->ai->ai_protocol), l->listener_id);
	hlog(LOG_DEBUG, "Opening listener %d/%d '%s': %s", lc->id, l->listener_id, lc->name, l->addr_s);
	
	if (lc->ai->ai_socktype == SOCK_DGRAM &&
	    lc->ai->ai_protocol == IPPROTO_UDP) {
		/* UDP listenting is not quite same as TCP listening.. */
		i = open_udp_listener(l, lc->ai);
	} else if (lc->ai->ai_socktype == SOCK_STREAM && lc->ai->ai_protocol == IPPROTO_TCP) {
		/* TCP listenting... */
		i = open_tcp_listener(l, lc->ai, "TCP");
#ifdef USE_SCTP
	} else if (lc->ai->ai_socktype == SOCK_STREAM &&
		   lc->ai->ai_protocol == IPPROTO_SCTP) {
		i = open_tcp_listener(l, lc->ai, "SCTP");
		if (i >= 0)
			i = sctp_set_listen_params(l);
#endif
	} else {
		hlog(LOG_ERR, "Unsupported listener protocol for '%s'", l->name);
		listener_free(l);
		return -1;
	}
	
	if (i < 0) {
		hlog(LOG_DEBUG, "... failed");
		listener_free(l);
		return -1;
	}
	
	hlog(LOG_DEBUG, "... ok, bound");
	
	/* Set up an SSL context if necessary */
#ifdef USE_SSL
	if (lc->keyfile && lc->certfile) {
		l->ssl = ssl_alloc();
		
		if (ssl_create(l->ssl, (void *)l)) {
			hlog(LOG_ERR, "Failed to create SSL context for '%s*': %s", lc->name, l->addr_s);
			listener_free(l);
			return -1;
		}
		
		if (ssl_certificate(l->ssl, lc->certfile, lc->keyfile)) {
			hlog(LOG_ERR, "Failed to load SSL key and certificates for '%s*': %s", lc->name, l->addr_s);
			listener_free(l);
			return -1;
		}
		
		/* optional client cert validation */
		if (lc->cafile) {
			if (ssl_ca_certificate(l->ssl, lc->cafile, 2)) {
				hlog(LOG_ERR, "Failed to load trusted SSL CA certificates for '%s*': %s", lc->name, l->addr_s);
				listener_free(l);
				return -1;
			}
		}
		
		hlog(LOG_INFO, "SSL initialized for '%s': %s%s", lc->name, l->addr_s, (lc->cafile) ? " (client validation enabled)" : "");
	}
#endif
	
	/* Copy access lists */
	if (lc->acl)
		l->acl = acl_dup(lc->acl);
	
	/* Copy filter definitions */
	listener_copy_filters(l, lc);
	
	hlog(LOG_DEBUG, "... adding %s to listened sockets", l->addr_s);
	// put (first) in the list of listening sockets
	l->next = listen_list;
	l->prevp = &listen_list;
	if (listen_list)
		listen_list->prevp = &l->next;
	listen_list = l;
	
	return 0;
}
/*
 * acl_calc_mask() (23.4.2): calculate and set the permissions
 * associated with the ACL_MASK ACL entry.  If the ACL already
 * contains an ACL_MASK entry, its permissions shall be
 * overwritten; if not, one shall be added.
 */
int
acl_calc_mask(acl_t *acl_p)
{
	struct acl	*acl_int, *acl_int_new;
	acl_t		acl_new;
	int		i, mask_mode, mask_num;

	/*
	 * (23.4.2.4) requires acl_p to point to a pointer to a valid ACL.
	 * Since one of the primary reasons to use this function would be
	 * to calculate the appropriate mask to obtain a valid ACL, we only
	 * perform sanity checks here and validate the ACL prior to
	 * returning.
	 */
	if (acl_p == NULL || *acl_p == NULL) {
		errno = EINVAL;
		return (-1);
	}

	if (!_acl_brand_may_be(*acl_p, ACL_BRAND_POSIX)) {
		errno = EINVAL;
		return (-1);
	}
	_acl_brand_as(*acl_p, ACL_BRAND_POSIX);

	acl_int = &(*acl_p)->ats_acl;
	if ((acl_int->acl_cnt < 3) || (acl_int->acl_cnt > ACL_MAX_ENTRIES)) {
		errno = EINVAL;
		return (-1);
	}

	acl_new = acl_dup(*acl_p);
	if (acl_new == NULL)
		return (-1);
	acl_int_new = &acl_new->ats_acl;

	mask_mode = 0;
	mask_num = -1;

	/* gather permissions and find a mask entry */
	for (i = 0; i < acl_int_new->acl_cnt; i++) {
		switch(acl_int_new->acl_entry[i].ae_tag) {
		case ACL_USER:
		case ACL_GROUP:
		case ACL_GROUP_OBJ:
			mask_mode |=
			    acl_int_new->acl_entry[i].ae_perm & ACL_PERM_BITS;
			break;
		case ACL_MASK:
			mask_num = i;
			break;
		}
	}

	/* if a mask entry already exists, overwrite the perms */
	if (mask_num != -1)
		acl_int_new->acl_entry[mask_num].ae_perm = mask_mode;
	else {
		/* if no mask exists, check acl_cnt... */
		if (acl_int_new->acl_cnt == ACL_MAX_ENTRIES) {
			errno = ENOMEM;
			acl_free(acl_new);
			return (-1);
		}
		/* ...and add the mask entry */
		acl_int_new->acl_entry[acl_int_new->acl_cnt].ae_tag = ACL_MASK;
		acl_int_new->acl_entry[acl_int_new->acl_cnt].ae_id =
		    ACL_UNDEFINED_ID;
		acl_int_new->acl_entry[acl_int_new->acl_cnt].ae_perm =
		    mask_mode;
		acl_int_new->acl_cnt++;
	}

	if (acl_valid(acl_new) == -1) {
		errno = EINVAL;
		acl_free(acl_new);
		return (-1);
	}

	**acl_p = *acl_new;
	acl_free(acl_new);

	return (0);
}