summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimo Sorce <simo@redhat.com>2013-06-21 20:36:20 -0400
committerGünther Deschner <gdeschner@redhat.com>2013-07-02 16:17:23 +0200
commitacc3b87b655cf7c6c0c7d698f5a5867b6732a69f (patch)
tree97f3d944770bfc78c92f1fff854d66b78df76de7
parentf66a585e042fbb2f313c1cbde329088fac86cea6 (diff)
downloadgss-proxy-acc3b87b655cf7c6c0c7d698f5a5867b6732a69f.tar.gz
gss-proxy-acc3b87b655cf7c6c0c7d698f5a5867b6732a69f.tar.xz
gss-proxy-acc3b87b655cf7c6c0c7d698f5a5867b6732a69f.zip
Add service match using SeLinux Context
Using getpeercon we can know the elinux context of the process talking to gssproxy. Use this information as an optional additional filter to match processes to service definitions. If a selinux_context option with a full user;role;type context is specified into a service section, then the connecting process must also be running under the specified selinux context in order to be allowed to connect. Signed-off-by: Simo Sorce <simo@redhat.com> Reviewed-by: Günther Deschner <gdeschner@redhat.com>
-rw-r--r--proxy/Makefile.am1
-rw-r--r--proxy/man/gssproxy.conf.5.xml15
-rw-r--r--proxy/src/gp_config.c12
-rw-r--r--proxy/src/gp_creds.c4
-rw-r--r--proxy/src/gp_proxy.h3
-rw-r--r--proxy/src/gp_selinux.h71
-rw-r--r--proxy/src/gp_socket.c67
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;