#endif
};
+/**
+ * Returns TRUE if the current process/user is member of the given group
+ */
+static bool has_group(gid_t group)
+{
+ gid_t *groups;
+ long ngroups, i;
+ bool found = FALSE;
+
+ if (group == getegid())
+ { /* it's unspecified if this is part of the list below or not */
+ return TRUE;
+ }
+ ngroups = sysconf(_SC_NGROUPS_MAX);
+ groups = calloc(ngroups, sizeof(gid_t));
+ ngroups = getgroups(ngroups, groups);
+ if (ngroups == -1)
+ {
+ DBG1(DBG_LIB, "getting groups for current process failed: %s",
+ strerror(errno));
+ return FALSE;
+ }
+ for (i = 0; i < ngroups; i++)
+ {
+ if (group == groups[i])
+ {
+ found = TRUE;
+ break;
+ }
+ }
+ free(groups);
+ return found;
+}
+
/**
* Verify that the current process has the given capability
*/
-static bool has_capability(u_int cap)
+static bool has_capability(private_capabilities_t *this, u_int cap,
+ bool *ignore)
{
+ if (cap == CAP_CHOWN)
+ { /* if new files/UNIX sockets are created they should be owned by the
+ * configured user and group. This requires a call to chown(2). But
+ * CAP_CHOWN is not always required. */
+ if (!this->uid || geteuid() == this->uid)
+ { /* if the owner does not change CAP_CHOWN is not needed */
+ if (!this->gid || has_group(this->gid))
+ { /* the same applies if the owner is a member of the group */
+ if (ignore)
+ { /* we don't have to keep this, if requested */
+ *ignore = TRUE;
+ }
+ return TRUE;
+ }
+ }
+ }
#ifndef CAPABILITIES
/* if we can't check the actual capabilities assume only root has it */
return geteuid() == 0;
*/
static bool keep_capability(private_capabilities_t *this, u_int cap)
{
- if (!has_capability(cap))
- {
- return FALSE;
- }
#ifdef CAPABILITIES_LIBCAP
cap_set_flag(this->caps, CAP_EFFECTIVE, 1, &cap, CAP_SET);
cap_set_flag(this->caps, CAP_INHERITABLE, 1, &cap, CAP_SET);
return TRUE;
}
-/**
- * Returns TRUE if the current process/user is member of the given group
- */
-static bool has_group(gid_t group)
+METHOD(capabilities_t, keep, bool,
+ private_capabilities_t *this, u_int cap)
{
- gid_t *groups;
- long ngroups, i;
- bool found = FALSE;
+ bool ignore = FALSE;
- if (group == getegid())
- { /* it's unspecified if this is part of the list below or not */
- return TRUE;
- }
- ngroups = sysconf(_SC_NGROUPS_MAX);
- groups = calloc(ngroups, sizeof(gid_t));
- ngroups = getgroups(ngroups, groups);
- if (ngroups == -1)
+ if (!has_capability(this, cap, &ignore))
{
- DBG1(DBG_LIB, "getting groups for current process failed: %s",
- strerror(errno));
return FALSE;
}
- for (i = 0; i < ngroups; i++)
- {
- if (group == groups[i])
- {
- found = TRUE;
- break;
- }
+ else if (ignore)
+ { /* don't keep capabilities that are not required */
+ return TRUE;
}
- free(groups);
- return found;
+ return keep_capability(this, cap);
}
-METHOD(capabilities_t, keep, bool,
+METHOD(capabilities_t, check, bool,
private_capabilities_t *this, u_int cap)
{
- if (cap == CAP_CHOWN)
- { /* if new files/UNIX sockets are created they should be owned by the
- * configured user and group. This requires a call to chown(2). But
- * CAP_CHOWN is not always required. */
- if (!this->uid || geteuid() == this->uid)
- { /* if the owner does not change CAP_CHOWN is not needed */
- if (!this->gid || has_group(this->gid))
- { /* the same applies if the owner is a member of the group */
- return TRUE;
- }
- }
- }
- return keep_capability(this, cap);
+ return has_capability(this, cap, NULL);
}
METHOD(capabilities_t, get_uid, uid_t,
INIT(this,
.public = {
.keep = _keep,
+ .check = _check,
.get_uid = _get_uid,
.get_gid = _get_gid,
.set_uid = _set_uid,
* Register a capability to keep while calling drop(). Verifies that the
* capability is currently held.
*
+ * @note CAP_CHOWN is handled specially as it might not be required.
+ *
* @param cap capability to keep
* @return FALSE if the capability is currently not held
*/
bool (*keep)(capabilities_t *this,
u_int cap) __attribute__((warn_unused_result));
+ /**
+ * Check if the given capability is currently held.
+ *
+ * @note CAP_CHOWN is handled specially as it might not be required.
+ *
+ * @param cap capability to check
+ * @return TRUE if the capability is currently held
+ */
+ bool (*check)(capabilities_t *this, u_int cap);
+
/**
* Get the user ID set through set_uid/resolve_uid.
*