aboutsummaryrefslogtreecommitdiffstats
path: root/pam_cap
diff options
context:
space:
mode:
authorAndrew G. Morgan <morgan@kernel.org>2020-02-23 18:23:20 -0800
committerAndrew G. Morgan <morgan@kernel.org>2020-02-23 18:23:20 -0800
commit536cdb941cf3276ae71b969a929a9a92f37dbb57 (patch)
treea980d72b1a04004dff209953e65c7703f8bdd953 /pam_cap
parent6120f3c41354ed56d91a8e89b707b98787f9606f (diff)
downloadplatform_external_libcap-536cdb941cf3276ae71b969a929a9a92f37dbb57.tar.gz
platform_external_libcap-536cdb941cf3276ae71b969a929a9a92f37dbb57.tar.bz2
platform_external_libcap-536cdb941cf3276ae71b969a929a9a92f37dbb57.zip
pam_cap can now use generic parsing for a cap_iab_t.
Delete a lot of redundant code now libcap supports an IAB abstraction. Signed-off-by: Andrew G. Morgan <morgan@kernel.org>
Diffstat (limited to 'pam_cap')
-rw-r--r--pam_cap/pam_cap.c157
1 files changed, 17 insertions, 140 deletions
diff --git a/pam_cap/pam_cap.c b/pam_cap/pam_cap.c
index a800f58..addef87 100644
--- a/pam_cap/pam_cap.c
+++ b/pam_cap/pam_cap.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999,2007,2019 Andrew G. Morgan <morgan@kernel.org>
+ * Copyright (c) 1999,2007,19,20 Andrew G. Morgan <morgan@kernel.org>
*
* The purpose of this module is to enforce inheritable, bounding and
* ambient capability sets for a specified user.
@@ -182,11 +182,7 @@ static int set_capabilities(struct pam_cap_s *cs)
cap_t cap_s;
char *conf_caps;
int ok = 0;
- int has_ambient = 0, has_bound = 0;
- int *bound = NULL, *ambient = NULL;
- cap_flag_value_t had_setpcap = 0;
- cap_value_t max_caps = 0;
- const cap_value_t wanted_caps[] = { CAP_SETPCAP };
+ cap_iab_t iab;
cap_s = cap_get_proc();
if (cap_s == NULL) {
@@ -194,14 +190,6 @@ static int set_capabilities(struct pam_cap_s *cs)
strerror(errno)));
return 0;
}
- if (cap_get_flag(cap_s, CAP_SETPCAP, CAP_EFFECTIVE, &had_setpcap)) {
- D(("failed to read a e capability: %s", strerror(errno)));
- goto cleanup_cap_s;
- }
- if (cap_set_flag(cap_s, CAP_EFFECTIVE, 1, wanted_caps, CAP_SET) != 0) {
- D(("unable to raise CAP_SETPCAP: %s", strerrno(errno)));
- goto cleanup_cap_s;
- }
conf_caps = read_capabilities_for_user(cs->user,
cs->conf_filename
@@ -218,147 +206,36 @@ static int set_capabilities(struct pam_cap_s *cs)
* likely to be the same as none for sensible system defaults.
*/
ok = 1;
- goto cleanup_caps;
- }
-
- if (cap_set_proc(cap_s) != 0) {
- D(("unable to use CAP_SETPCAP: %s", strerrno(errno)));
- goto cleanup_caps;
- }
- if (cap_reset_ambient() == 0) {
- /* Ambient set fully declared by this config. */
- has_ambient = 1;
+ goto cleanup_conf;
}
if (!strcmp(conf_caps, "none")) {
- /* clearing CAP_INHERITABLE will also clear the ambient caps. */
+ /* clearing CAP_INHERITABLE will also clear the ambient caps,
+ * but for legacy reasons we do not alter the bounding set. */
cap_clear_flag(cap_s, CAP_INHERITABLE);
- } else {
- /*
- * we know we have to perform some capability operations and
- * we need to know how many capabilities there are to do it
- * successfully.
- */
- while (cap_get_bound(max_caps) >= 0) {
- max_caps++;
- }
- if (max_caps != cap_max_bits()) {
- D(("this vintage of libcap cannot be trusted; give up"));
- goto cleanup_caps;
- }
- has_bound = (max_caps != 0);
- if (has_bound) {
- bound = calloc(max_caps, sizeof(int));
- if (has_ambient) {
- /* In kernel lineage, bound came first. */
- ambient = calloc(max_caps, sizeof(int));
- }
- }
-
- /*
- * Scan the configured capability string for:
- *
- * cap_name: add to cap_s' inheritable vector
- * ^cap_name: add to cap_s' inheritable vector and ambient set
- * !cap_name: drop from bounding set
- *
- * Setting ambient capabilities requires that we first enable
- * the corresponding inheritable capability to set them. So,
- * there is an order we use: parse the config line, building
- * the inheritable, ambient and bounding sets in three separate
- * arrays. Then, set I set A set B. Finally, at the end, we
- * restore the E value for CAP_SETPCAP.
- */
- char *token = NULL;
- char *next = conf_caps;
- while ((token = strtok_r(next, ",", &next))) {
- if (strlen(token) < 4) {
- D(("bogus cap: [%s] - ignored\n", token));
- goto cleanup_caps;
- }
- int is_a = 0, is_b = 0;
- if (*token == '^') {
- if (!has_ambient) {
- D(("want ambient [%s] but kernel has no support", token));
- goto cleanup_caps;
- }
- is_a = 1;
- token++;
- } else if (*token == '!') {
- if (!has_bound) {
- D(("want bound [%s] dropped - no kernel support", token));
- }
- is_b = 1;
- token++;
- }
-
- cap_value_t c;
- if (cap_from_name(token, &c) != 0) {
- D(("unrecognized name [%s]: %s - ignored", token,
- strerror(errno)));
- goto cleanup_caps;
- }
-
- if (is_b) {
- bound[c] = 1;
- } else {
- if (cap_set_flag(cap_s, CAP_INHERITABLE, 1, &c, CAP_SET)) {
- D(("failed to raise inheritable [%s]: %s", token,
- strerror(errno)));
- goto cleanup_caps;
- }
- if (is_a) {
- ambient[c] = 1;
- }
- }
+ if (!cap_set_proc(cap_s)) {
+ ok = 1;
}
+ goto cleanup_cap_s;
+ }
-#ifdef DEBUG
- {
- char *temp = cap_to_text(cap_s, NULL);
- D(("abbreviated caps for process will be [%s]", temp));
- cap_free(temp);
- }
-#endif /* DEBUG */
+ iab = cap_iab_from_text(conf_caps);
+ if (iab == NULL) {
+ D(("unable to parse the IAB [%s] value", conf_caps));
+ goto cleanup_conf;
}
- if (cap_set_proc(cap_s)) {
- D(("failed to set specified capabilities: %s", strerror(errno)));
- } else {
- cap_value_t c;
- for (c = 0; c < max_caps; c++) {
- if (ambient != NULL && ambient[c]) {
- cap_set_ambient(c, CAP_SET);
- }
- if (bound != NULL && bound[c]) {
- cap_drop_bound(c);
- }
- }
+ if (!cap_iab_set_proc(iab)) {
+ D(("able to set the IAB [%s] value", conf_caps));
ok = 1;
}
+ cap_free(iab);
-cleanup_caps:
- if (has_ambient) {
- memset(ambient, 0, max_caps * sizeof(*ambient));
- _pam_drop(ambient);
- ambient = NULL;
- }
- if (has_bound) {
- memset(bound, 0, max_caps * sizeof(*bound));
- _pam_drop(bound);
- bound = NULL;
- }
+cleanup_conf:
memset(conf_caps, 0, conf_caps_length);
_pam_drop(conf_caps);
cleanup_cap_s:
- if (!had_setpcap) {
- /* Only need to lower if it wasn't raised by caller */
- if (!cap_set_flag(cap_s, CAP_EFFECTIVE, 1, wanted_caps,
- CAP_CLEAR)) {
- cap_set_proc(cap_s);
- }
- }
if (cap_s) {
cap_free(cap_s);
cap_s = NULL;