summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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;