diff options
author | Andrew G. Morgan <morgan@kernel.org> | 2021-09-13 21:08:42 -0700 |
---|---|---|
committer | Andrew G. Morgan <morgan@kernel.org> | 2021-09-13 21:08:42 -0700 |
commit | fc6253b9de68dafae1927b2bcbfcef9e9ec6e05a (patch) | |
tree | 4ff7116780d9bc5ab717f4c4a539e97a5380af17 | |
parent | a3446b5c6e0879b289287c9a87a57cbdc95e99da (diff) | |
download | libcap2-fc6253b9de68dafae1927b2bcbfcef9e9ec6e05a.tar.gz |
Add PAM "session" support to pam_cap.so.
This is an attempt to address:
https://bugzilla.kernel.org/show_bug.cgi?id=214377
The basic structure is you configure PAM with a config like this:
#%PAM-1.0
auth required pam_cap.so use_session keepcaps
auth required pam_unix.so
account required pam_unix.so
password required pam_unix.so
session required pam_unix.so
session optional pam_cap.so
Here the "auth" part prepares the application with "keepcaps", and the
"use_session" instructs the module to apply any IAB tuple for the user
at session open time and not during the setcred (auth) flow.
This has been tested against the contrib/sucap implementation of su.
The "use_session" support should work with more standard PAM enabled
apps too, but I'll wait for some positive feedback (see the bug)
before declaring it stable.
FWIW the contrib/sucap/su app also supports this config for Ambient
vector setting (without a "session" invocation of pam_cap.so):
#%PAM-1.0
auth required pam_cap.so
auth required pam_unix.so
account required pam_unix.so
password required pam_unix.so
session required pam_unix.so
but that is because the sucap/su app is more tightly integrated with
libcap than the standard PAM apps.
Signed-off-by: Andrew G. Morgan <morgan@kernel.org>
-rw-r--r-- | pam_cap/execable.c | 3 | ||||
-rw-r--r-- | pam_cap/pam_cap.c | 77 | ||||
-rw-r--r-- | pam_cap/test_pam_cap.c | 18 |
3 files changed, 79 insertions, 19 deletions
diff --git a/pam_cap/execable.c b/pam_cap/execable.c index 05f18d8..8e5028d 100644 --- a/pam_cap/execable.c +++ b/pam_cap/execable.c @@ -48,6 +48,7 @@ SO_MAIN(int argc, char **argv) "config=<file> - override the default config with file\n" "keepcaps - workaround for apps that setuid without this\n" "autoauth - pam_cap.so to always succeed for the 'auth' phase\n" - "default=<iab> - fallback IAB value if there is no '*' rule\n", + "default=<iab> - fallback IAB value if there is no '*' rule\n" + "use_session - apply IAB value during session open, not setcred\n", cmd); } diff --git a/pam_cap/pam_cap.c b/pam_cap/pam_cap.c index 17ad83e..80eb40b 100644 --- a/pam_cap/pam_cap.c +++ b/pam_cap/pam_cap.c @@ -39,12 +39,17 @@ struct pam_cap_s { int debug; int keepcaps; int autoauth; + int session; const char *user; const char *conf_filename; const char *fallback; }; /* + * pam_cap_iab_s is used to capture any cap_iab_t value if it needs to be applied during pam_sm_ + */ + +/* * load_groups obtains the list all of the groups associated with the * requested user: gid & supplemental groups. */ @@ -252,6 +257,12 @@ static int set_capabilities(struct pam_cap_s *cs) * Best effort to set keep caps - this may help work around * situations where applications are using a capabilities * unaware setuid() call. + * + * It isn't needed unless you want to support Ambient vector + * values in the IAB. In this case, it will likely also + * require you use the "use_session" module argument and + * include a "session" line in your PAM config that points to + * pam_cap.so. */ D(("setting keepcaps")); (void) cap_prctlw(PR_SET_KEEPCAPS, 1, 0, 0, 0, 0); @@ -299,6 +310,8 @@ static void parse_args(int argc, const char **argv, struct pam_cap_s *pcs) pcs->autoauth = 1; } else if (!strncmp(*argv, "default=", 8)) { pcs->fallback = 8 + *argv; + } else if (!strcmp(*argv, "use_session")) { + pcs->session = 1; } else { _pam_log(LOG_ERR, "unknown option; %s", *argv); } @@ -358,23 +371,23 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, _pam_drop(conf_caps); return PAM_SUCCESS; - - } else { - - D(("there are no capabilities restrictions on this user")); - return PAM_IGNORE; - } + + D(("there are no capabilities restrictions on this user")); + return PAM_IGNORE; } /* - * pam_sm_setcred applies inheritable capabilities loaded by the - * pam_sm_authenticate pass for the user. + * pam_sm_setcred optionally applies inheritable capabilities loaded + * by the pam_sm_authenticate pass for the user. If it doesn't apply + * them directly (because of the "use_session" module argument), it + * caches the cap_iab_t value for later use during the + * pam_sm_open_session() call. */ int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) { - int retval; + int retval = 0; struct pam_cap_s pcs; if (!(flags & (PAM_ESTABLISH_CRED | PAM_REINITIALIZE_CRED))) { @@ -390,8 +403,50 @@ int pam_sm_setcred(pam_handle_t *pamh, int flags, return PAM_AUTH_ERR; } - retval = set_capabilities(&pcs); - memset(&pcs, 0, sizeof(pcs)); + if (!pcs.session) { + retval = set_capabilities(&pcs); + memset(&pcs, 0, sizeof(pcs)); + } return (retval ? PAM_SUCCESS:PAM_IGNORE); } + +/* + * pam_sm_open_session supports applying the configured cap_iab_t + * tuple after the user credentials have been fully applied. This is + * for programs where pam_cap.so's auth configuration includes the + * "use_session" and "keepcaps" module arguments. Typically, the + * latter is needed to coax the application into persisting the + * ability to apply the IAB value after a setuid() call by the + * application. + * + * Note, this is only needed in cases where the local system needs to + * support adding Ambient capability vector values. For Inheritable + * capabilities which survive setuid() in all modes, the existing + * module works fine. + */ +int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, + const char **argv) +{ + int retval; + struct pam_cap_s pcs; + + parse_args(argc, argv, &pcs); + + retval = pam_get_item(pamh, PAM_USER, (const void **)&pcs.user); + if ((retval != PAM_SUCCESS) || (pcs.user == NULL) || !(pcs.user[0])) { + D(("user's name is not set")); + return PAM_USER_UNKNOWN; + } + + set_capabilities(&pcs); + memset(&pcs, 0, sizeof(pcs)); + return PAM_SUCCESS; +} + +/* pam_sm_close_session is mostly a no-op; it always returns PAM_SUCCESS. */ +int pam_sm_close_session(pam_handle_t *pamh, int flags, int argc, + const char **argv) +{ + return PAM_SUCCESS; +} diff --git a/pam_cap/test_pam_cap.c b/pam_cap/test_pam_cap.c index 4c67cad..0a58da6 100644 --- a/pam_cap/test_pam_cap.c +++ b/pam_cap/test_pam_cap.c @@ -134,31 +134,35 @@ struct vargs { static int test_arg_parsing(void) { static struct vargs vs[] = { { - { 1, 0, 0, NULL, NULL, NULL }, + { 1, 0, 0, 0, NULL, NULL, NULL }, { "debug", NULL } }, { - { 0, 1, 0, NULL, NULL, NULL }, + { 0, 1, 0, 0, NULL, NULL, NULL }, { "keepcaps", NULL } }, { - { 0, 0, 1, NULL, NULL, NULL }, + { 0, 0, 1, 0, NULL, NULL, NULL }, { "autoauth", NULL } }, { - { 1, 0, 1, NULL, NULL, NULL }, + { 1, 0, 1, 0, NULL, NULL, NULL }, { "autoauth", "debug", NULL } }, { - { 0, 0, 0, NULL, "/over/there", NULL }, + { 0, 0, 0, 0, NULL, "/over/there", NULL }, { "config=/over/there", NULL } }, { - { 0, 0, 0, NULL, NULL, "^cap_setfcap" }, + { 0, 0, 0, 0, NULL, NULL, "^cap_setfcap" }, { "default=^cap_setfcap", NULL } }, { - { 0, 0, 0, NULL, NULL, NULL }, + { 0, 0, 0, 1, NULL, NULL, NULL }, + { "use_session", NULL } + }, + { + { 0, 0, 0, 0, NULL, NULL, NULL }, { NULL } } }; |