diff options
-rw-r--r-- | proxy/Makefile.am | 1 | ||||
-rw-r--r-- | proxy/man/gssproxy.conf.5.xml | 15 | ||||
-rw-r--r-- | proxy/src/gp_config.c | 12 | ||||
-rw-r--r-- | proxy/src/gp_creds.c | 4 | ||||
-rw-r--r-- | proxy/src/gp_proxy.h | 3 | ||||
-rw-r--r-- | proxy/src/gp_selinux.h | 71 | ||||
-rw-r--r-- | proxy/src/gp_socket.c | 67 |
7 files changed, 160 insertions, 13 deletions
diff --git a/proxy/Makefile.am b/proxy/Makefile.am index a7e9a32..065be6e 100644 --- a/proxy/Makefile.am +++ b/proxy/Makefile.am @@ -134,6 +134,7 @@ dist_noinst_HEADERS = \ src/gp_config_dinglibs.h \ src/gp_debug.h \ src/gp_rpc_creds.h \ + src/gp_selinux.h \ src/mechglue/gss_plugin.h diff --git a/proxy/man/gssproxy.conf.5.xml b/proxy/man/gssproxy.conf.5.xml index 9238aa6..0cbf965 100644 --- a/proxy/man/gssproxy.conf.5.xml +++ b/proxy/man/gssproxy.conf.5.xml @@ -165,6 +165,21 @@ </varlistentry> <varlistentry> + <term>selinux_context (string)</term> + <listitem> + <para>This parameter instructs the proxy to allow map a + request to the service only if the context of the + connecting client matches the one defined here. + </para> + <para>When this parameter is not set any client will be + allowed regardless of their selinux context. + </para> + <para>Example: selinux_context = system_u:system_r:gssd_t + </para> + </listitem> + </varlistentry> + + <varlistentry> <term>socket (string)</term> <listitem> <para>This parameter allows to create a per-service socket file over which gssproxy client and server components communicate. diff --git a/proxy/src/gp_config.c b/proxy/src/gp_config.c index 5051a91..ee218b4 100644 --- a/proxy/src/gp_config.c +++ b/proxy/src/gp_config.c @@ -30,6 +30,7 @@ #include <errno.h> #include "gp_proxy.h" #include "gp_config.h" +#include "gp_selinux.h" static void free_str_array(const char ***a, int *count) { @@ -62,6 +63,7 @@ static void gp_service_free(struct gp_service *svc) &svc->krb5.cred_count); } gp_free_creds_handle(&svc->creds_handle); + SELINUX_context_free(svc->selinux_ctx); memset(svc, 0, sizeof(struct gp_service)); } @@ -252,6 +254,16 @@ static int load_services(struct gp_config *cfg, struct gp_ini_context *ctx) safefree(secname); continue; } + + ret = gp_config_get_string(ctx, secname, + "selinux_context", &value); + if (ret == 0) { + cfg->svcs[n]->selinux_ctx = SELINUX_context_new(value); + if (!cfg->svcs[n]->selinux_ctx) { + ret = EINVAL; + goto done; + } + } } safefree(secname); } diff --git a/proxy/src/gp_creds.c b/proxy/src/gp_creds.c index cd51308..4d68afb 100644 --- a/proxy/src/gp_creds.c +++ b/proxy/src/gp_creds.c @@ -112,6 +112,10 @@ struct gp_service *gp_creds_match_conn(struct gssproxy_ctx *gpctx, continue; } } + if (!gp_conn_check_selinux(conn, + gpctx->config->svcs[i]->selinux_ctx)) { + continue; + } return gpctx->config->svcs[i]; } } diff --git a/proxy/src/gp_proxy.h b/proxy/src/gp_proxy.h index dc7aada..835fcf5 100644 --- a/proxy/src/gp_proxy.h +++ b/proxy/src/gp_proxy.h @@ -31,6 +31,7 @@ #include <stdint.h> #include "verto.h" #include "gp_common.h" +#include "gp_selinux.h" #define _(STRING) gettext(STRING) @@ -52,6 +53,7 @@ struct gp_service { bool trusted; bool kernel_nfsd; char *socket; + SELINUX_CTX selinux_ctx; uint32_t mechs; struct gp_cred_krb5 krb5; @@ -106,6 +108,7 @@ void gp_socket_send_data(verto_ctx *vctx, struct gp_conn *conn, uint8_t *buffer, size_t buflen); struct gp_creds *gp_conn_get_creds(struct gp_conn *conn); const char *gp_conn_get_socket(struct gp_conn *conn); +bool gp_conn_check_selinux(struct gp_conn *conn, SELINUX_CTX ctx); /* from gp_workers.c */ int gp_workers_init(struct gssproxy_ctx *gpctx); diff --git a/proxy/src/gp_selinux.h b/proxy/src/gp_selinux.h new file mode 100644 index 0000000..693a124 --- /dev/null +++ b/proxy/src/gp_selinux.h @@ -0,0 +1,71 @@ +/* + GSS-PROXY + + Copyright (C) 2013 Red Hat, Inc. + Copyright (C) 2013 Simo Sorce <simo.sorce@redhat.com> + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#ifndef _GP_SELINUX_H_ +#define _GP_SELINUX_H_ + +#ifdef HAVE_SELINUX + +#include <selinux/context.h> +#define SELINUX_CTX context_t +#include <selinux/selinux.h> +#define SEC_CTX security_context_t + +#define SELINUX_context_new context_new +#define SELINUX_context_free context_free +#define SELINUX_context_str context_str +#define SELINUX_context_type_get context_type_get +#define SELINUX_context_user_get context_user_get +#define SELINUX_context_role_get context_role_get +#define SELINUX_context_range_get context_range_get +#define SELINUX_getpeercon getpeercon +#define SELINUX_freecon freecon + +#else /* not HAVE_SELINUX */ + +#define SELINUX_CTX void * +#define SEC_CTX void * + +void *SELINUX_context_new(const char *str) { return NULL; } +#define SELINUX_context_free(x) (x) = NULL; +const char *SELINUX_context_dummy_get(void *) { return NULL; } +#define SELINUX_context_str SELINUX_context_dummy_get +#define SELINUX_context_type_get SELINUX_context_dummy_get +#define SELINUX_context_user_get SELINUX_context_dummy_get +#define SELINUX_context_role_get SELINUX_context_dummy_get +#define SELINUX_context_range_get SELINUX_context_dummy_get + +#include <errno.h> +int SELINUX_getpeercon(int fd, SEC_CTX *con) +{ + *con = NULL; + errno = ENOTSUP; + return -1; +} +#define SELINUX_freecon(x) (x) = NULL; + +#endif /* done HAVE_SELINUX */ + +#endif /*_GP_SELINUX_H_ */ diff --git a/proxy/src/gp_socket.c b/proxy/src/gp_socket.c index 02bc882..24eed28 100644 --- a/proxy/src/gp_socket.c +++ b/proxy/src/gp_socket.c @@ -35,13 +35,7 @@ #include <netinet/in.h> #include "gp_proxy.h" #include "gp_creds.h" - -#ifdef HAVE_SELINUX -#include <selinux/selinux.h> -#define SEC_CTX security_context_t -#else -#define SEC_CTX void * -#endif /* HAVE_SELINUX */ +#include "gp_selinux.h" #define FRAGMENT_BIT (1 << 31) @@ -58,7 +52,7 @@ struct gp_conn { struct gp_sock_ctx *sock_ctx; struct unix_sock_conn us; struct gp_creds creds; - SEC_CTX secctx; + SELINUX_CTX selinux_ctx; }; struct gp_buffer { @@ -68,6 +62,40 @@ struct gp_buffer { size_t pos; }; +bool gp_conn_check_selinux(struct gp_conn *conn, SELINUX_CTX ctx) +{ + const char *ra, *rb; + + if (ctx == NULL) { + return true; + } + + if (!(conn->creds.type | CRED_TYPE_SELINUX) || + (conn->selinux_ctx == NULL)) { + return false; + } + + if (strcmp(SELINUX_context_user_get(ctx), + SELINUX_context_user_get(conn->selinux_ctx)) != 0) { + return false; + } + if (strcmp(SELINUX_context_role_get(ctx), + SELINUX_context_role_get(conn->selinux_ctx)) != 0) { + return false; + } + if (strcmp(SELINUX_context_type_get(ctx), + SELINUX_context_type_get(conn->selinux_ctx)) != 0) { + return false; + } + ra = SELINUX_context_range_get(ctx); + rb = SELINUX_context_range_get(conn->selinux_ctx); + if (ra && rb && (strcmp(ra, rb) != 0)) { + return false; + } + + return true; +} + struct gp_creds *gp_conn_get_creds(struct gp_conn *conn) { return &conn->creds; @@ -85,6 +113,7 @@ void gp_conn_free(struct gp_conn *conn) if (conn->us.sd != -1) { close(conn->us.sd); } + SELINUX_context_free(conn->selinux_ctx); free(conn); } @@ -202,6 +231,7 @@ done: static int get_peercred(int fd, struct gp_conn *conn) { + SEC_CTX secctx; socklen_t len; int ret; @@ -219,17 +249,17 @@ static int get_peercred(int fd, struct gp_conn *conn) conn->creds.type |= CRED_TYPE_UNIX; -#ifdef HAVE_SELINUX - ret = getpeercon(fd, &conn->secctx); + ret = SELINUX_getpeercon(fd, &secctx); if (ret == 0) { conn->creds.type |= CRED_TYPE_SELINUX; + conn->selinux_ctx = SELINUX_context_new(secctx); + SELINUX_freecon(secctx); } else { ret = errno; GPDEBUG("Failed to get peer's SELinux context (%d:%s)\n", ret, strerror(ret)); /* consider thisnot fatal, selinux may be disabled */ } -#endif /* HAVE_SELINUX */ return 0; } @@ -507,8 +537,6 @@ void accept_sock_conn(verto_ctx *vctx, verto_ev *ev) } conn->us.sd = fd; - GPDEBUG("Client connected(fd = %d)\n", fd); - ret = set_status_flags(fd, O_NONBLOCK); if (ret) { GPDEBUG("Failed to set O_NONBLOCK on %d!\n", fd); @@ -526,6 +554,19 @@ void accept_sock_conn(verto_ctx *vctx, verto_ev *ev) goto done; } + GPDEBUG("Client connected (fd = %d)", fd); + if (conn->creds.type & CRED_TYPE_UNIX) { + GPDEBUG(" (pid = %d) (uid = %d) (gid = %d)", + conn->creds.ucred.pid, + conn->creds.ucred.uid, + conn->creds.ucred.gid); + } + if (conn->creds.type & CRED_TYPE_SELINUX) { + GPDEBUG(" (context = %s)", + SELINUX_context_str(conn->selinux_ctx)); + } + GPDEBUG("\n"); + gp_setup_reader(vctx, conn); ret = 0; |