This is an automated email from the git hooks/post-receive script.
rharwood pushed a commit to branch master
in repository gssproxy.
commit d31d09906dfc35577518a70bc838aeaf80ba25ca
Author: Robbie Harwood <rharwood(a)redhat.com>
Date: Tue May 16 13:57:04 2017 -0400
Support matching based on executable name
Signed-off-by: Robbie Harwood <rharwood(a)redhat.com>
Reviewed-by: Simo Sorce <simo(a)redhat.com>
Resolves: #181
Merges: #187
---
proxy/man/gssproxy.conf.5.xml | 14 +++++++++++
proxy/src/gp_config.c | 30 +++++++++++++++++++----
proxy/src/gp_creds.c | 33 ++++++++++++--------------
proxy/src/gp_proxy.h | 2 ++
proxy/src/gp_socket.c | 55 ++++++++++++++++++++++++++++++++++++++++++-
proxy/tests/Makefile.am | 4 ++--
proxy/tests/t_program.py | 51 +++++++++++++++++++++++++++++++++++++++
proxy/tests/testlib.py | 2 ++
8 files changed, 166 insertions(+), 25 deletions(-)
diff --git a/proxy/man/gssproxy.conf.5.xml b/proxy/man/gssproxy.conf.5.xml
index ed003c1..de846b4 100644
--- a/proxy/man/gssproxy.conf.5.xml
+++ b/proxy/man/gssproxy.conf.5.xml
@@ -349,6 +349,20 @@
</varlistentry>
<varlistentry>
+ <term>program (string)</term>
+ <listitem>
+ <para>If specified, this service will only match when
+ the program being run is the specified string.
+ </para>
+ <para>Programs are assumed to be specified as
+ canonical paths (i.e., no relative paths, no
+ symlinks). Additionally, the '|' character is
+ reserved for future use and therefore forbidden.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term>trusted (boolean)</term>
<listitem><para>Defines whether this service is
considered trusted. Use with caution, this enables impersonation.</para>
<para>Default: trusted = false</para>
diff --git a/proxy/src/gp_config.c b/proxy/src/gp_config.c
index 31c5681..21bf80e 100644
--- a/proxy/src/gp_config.c
+++ b/proxy/src/gp_config.c
@@ -258,6 +258,16 @@ static int check_services(const struct gp_config *cfg)
isock = GP_SOCKET_NAME;
}
+ if (isvc->program) {
+ if (isvc->program[0] != '/') {
+ ret = 1;
+ GPERROR("Program paths must be absolute!\n");
+ } else if (strchr(isvc->program, '|')) {
+ ret = 1;
+ GPERROR("The character '|' is invalid in program
paths!\n");
+ }
+ }
+
for (j = 0; j < i; j++) {
jsvc = cfg->svcs[j];
jsock = jsvc->socket;
@@ -266,18 +276,21 @@ static int check_services(const struct gp_config *cfg)
}
if (!gp_same(isock, jsock) ||
+ !gp_same(isvc->program, jsvc->program) ||
!gp_selinux_ctx_equal(isvc->selinux_ctx, jsvc->selinux_ctx)) {
continue;
}
if (jsvc->any_uid) {
ret = 1;
- GPERROR("%s sets allow_any_uid with the same socket and "
- "selinux_context as %s!\n", jsvc->name,
isvc->name);
+ GPERROR("%s sets allow_any_uid with the same socket, "
+ "selinux_context, and program as %s!\n",
+ jsvc->name, isvc->name);
} else if (jsvc->euid == isvc->euid) {
ret = 1;
- GPERROR("socket, selinux_context, and euid for %s and %s "
- "should not match!\n", isvc->name, jsvc->name);
+ GPERROR("socket, selinux_context, euid, and program for "
+ "%s and %s should not match!\n",
+ isvc->name, jsvc->name);
}
}
}
@@ -514,6 +527,15 @@ static int load_services(struct gp_config *cfg, struct gp_ini_context
*ctx)
ret = parse_flags(value, &cfg->svcs[n]->enforce_flags);
if (ret) goto done;
}
+
+ ret = gp_config_get_string(ctx, secname, "program", &value);
+ if (ret == 0) {
+ cfg->svcs[n]->program = strdup(value);
+ if (!cfg->svcs[n]->program) {
+ ret = ENOMEM;
+ goto done;
+ }
+ }
}
safefree(secname);
}
diff --git a/proxy/src/gp_creds.c b/proxy/src/gp_creds.c
index fdc6bdf..8d2e449 100644
--- a/proxy/src/gp_creds.c
+++ b/proxy/src/gp_creds.c
@@ -77,31 +77,28 @@ struct gp_service *gp_creds_match_conn(struct gssproxy_ctx *gpctx,
{
struct gp_creds *gcs;
const char *socket;
- int i;
+ const char *program;
gcs = gp_conn_get_creds(conn);
socket = gp_conn_get_socket(conn);
+ program = gp_conn_get_program(conn);
- for (i = 0; i < gpctx->config->num_svcs; i++) {
- if (gpctx->config->svcs[i]->any_uid ||
- gpctx->config->svcs[i]->euid == gcs->ucred.uid) {
- if (gpctx->config->svcs[i]->socket) {
- if (!gp_same(socket, gpctx->config->svcs[i]->socket)) {
- continue;
- }
- } else {
- if (!gp_same(socket, gpctx->config->socket_name)) {
- continue;
- }
- }
- if (!gp_conn_check_selinux(conn,
- gpctx->config->svcs[i]->selinux_ctx)) {
- continue;
- }
- return gpctx->config->svcs[i];
+ for (int i = 0; i < gpctx->config->num_svcs; i++) {
+ struct gp_service *svc = gpctx->config->svcs[i];
+
+ if ((!svc->any_uid && svc->euid != gcs->ucred.uid) ||
+ !gp_conn_check_selinux(conn, svc->selinux_ctx) ||
+ (svc->program && !gp_same(program, svc->program)) ||
+ (svc->socket && !gp_same(socket, svc->socket)) ||
+ (!svc->socket && !gp_same(socket,
gpctx->config->socket_name))) {
+ continue;
}
+
+ GPDEBUGN(2, "Connection matched service %s\n", svc->name);
+ return svc;
}
+ GPDEBUGN(2, "No matching service found\n");
return NULL;
}
diff --git a/proxy/src/gp_proxy.h b/proxy/src/gp_proxy.h
index 55ab83c..3e944ab 100644
--- a/proxy/src/gp_proxy.h
+++ b/proxy/src/gp_proxy.h
@@ -41,6 +41,7 @@ struct gp_service {
gss_cred_usage_t cred_usage;
uint32_t filter_flags;
uint32_t enforce_flags;
+ char *program;
uint32_t mechs;
struct gp_cred_krb5 krb5;
@@ -114,6 +115,7 @@ struct gp_creds *gp_conn_get_creds(struct gp_conn *conn);
uid_t gp_conn_get_uid(struct gp_conn *conn);
const char *gp_conn_get_socket(struct gp_conn *conn);
int gp_conn_get_cid(struct gp_conn *conn);
+const char *gp_conn_get_program(struct gp_conn *conn);
bool gp_selinux_ctx_equal(SELINUX_CTX ctx1, SELINUX_CTX ctx2);
bool gp_conn_check_selinux(struct gp_conn *conn, SELINUX_CTX ctx);
diff --git a/proxy/src/gp_socket.c b/proxy/src/gp_socket.c
index 5064e51..2198514 100644
--- a/proxy/src/gp_socket.c
+++ b/proxy/src/gp_socket.c
@@ -33,6 +33,7 @@ struct gp_conn {
struct unix_sock_conn us;
struct gp_creds creds;
SELINUX_CTX selinux_ctx;
+ char *program;
};
struct gp_buffer {
@@ -108,6 +109,11 @@ int gp_conn_get_cid(struct gp_conn *conn)
return conn->us.sd;
}
+const char *gp_conn_get_program(struct gp_conn *conn)
+{
+ return conn->program;
+}
+
void gp_conn_free(struct gp_conn *conn)
{
if (!conn) return;
@@ -115,6 +121,7 @@ void gp_conn_free(struct gp_conn *conn)
if (conn->us.sd != -1) {
close(conn->us.sd);
}
+ free(conn->program);
SELINUX_context_free(conn->selinux_ctx);
free(conn);
}
@@ -273,6 +280,45 @@ static int get_peercred(int fd, struct gp_conn *conn)
return 0;
}
+static char *get_program(pid_t pid)
+{
+ char procfile[21];
+ char *program;
+ int ret, e;
+ struct stat sb;
+
+ ret = snprintf(procfile, 20, "/proc/%u/exe", pid);
+ if (ret < 0) {
+ e = errno;
+ GPERROR("Internal error in snprintf: %d (%s)", e, strerror(e));
+ return NULL;
+ }
+ procfile[ret] = '\0';
+
+ program = realpath(procfile, NULL);
+ if (program) {
+ return program;
+ }
+
+ e = errno;
+ if (e != ENOENT) {
+ GPERROR("Unexpected failure in realpath: %d (%s)", e, strerror(e));
+ return NULL;
+ }
+
+ /* check if /proc is even around */
+ procfile[ret - 4] = '\0';
+ ret = stat(procfile, &sb); /* complains if we give it NULL */
+ e = errno;
+ if (ret == -1 && e == ENOENT) {
+ /* kernel thread */
+ return NULL;
+ }
+
+ GPERROR("Problem with /proc; program name matching won't work: %d
(%s)",
+ e, strerror(e));
+ return NULL;
+}
static void gp_socket_read(verto_ctx *vctx, verto_ev *ev);
@@ -563,7 +609,14 @@ void accept_sock_conn(verto_ctx *vctx, verto_ev *ev)
goto done;
}
- GPDEBUG("Client connected (fd = %d)", fd);
+ conn->program = get_program(conn->creds.ucred.pid);
+
+ GPDEBUG("Client ");
+ if (conn->program) {
+ GPDEBUG("(%s) ", conn->program);
+ }
+ GPDEBUG(" connected (fd = %d)", fd);
+
if (conn->creds.type & CRED_TYPE_UNIX) {
GPDEBUG(" (pid = %d) (uid = %d) (gid = %d)",
conn->creds.ucred.pid,
diff --git a/proxy/tests/Makefile.am b/proxy/tests/Makefile.am
index f6d6e56..bea6a51 100644
--- a/proxy/tests/Makefile.am
+++ b/proxy/tests/Makefile.am
@@ -1,4 +1,3 @@
-
t_acquire_SOURCES = \
t_utils.c \
t_acquire.c
@@ -64,6 +63,7 @@ EXTRA_DIST = \
t_impersonate.py \
t_interpose.py \
t_multi_key.py \
- t_reloading.py
+ t_reloading.py \
+ $(NULL)
all: $(check_PROGRAMS)
diff --git a/proxy/tests/t_program.py b/proxy/tests/t_program.py
new file mode 100644
index 0000000..1f71f07
--- /dev/null
+++ b/proxy/tests/t_program.py
@@ -0,0 +1,51 @@
+#!/usr/bin/python3
+# Copyright (C) 2017 - GSS-Proxy contributors; see COPYING for the license.
+
+from testlib import *
+
+from t_acquire import run as run_acquire_test
+
+import os
+
+GSSPROXY_PROGRAM = '''
+[gssproxy]
+ debug_level = 3
+
+[service/t_acquire]
+ mechs = krb5
+ cred_store = keytab:${GSSPROXY_KEYTAB}
+ cred_store = client_keytab:${GSSPROXY_CLIENT_KEYTAB}
+ trusted = yes
+ euid = ${UIDNUMBER}
+ allow_client_ccache_sync = yes
+ program = ${PROGDIR}/t_acquire
+'''
+
+def run(testdir, env, conf):
+ prefix = conf["prefix"]
+ retval = 0
+
+ print("Testing positive program name matching...", file=sys.stderr)
+ sys.stderr.write(" ")
+ conf["prefix"] = prefix + "_1"
+ update_gssproxy_conf(testdir, conf["keysenv"], GSSPROXY_PROGRAM)
+ os.kill(conf["gpid"], signal.SIGHUP)
+ time.sleep(1)
+ retval |= run_acquire_test(testdir, env, conf)
+
+ print("Testing negative program name matching...", file=sys.stderr)
+ sys.stderr.write(" ")
+ conf["prefix"] = prefix + "_2"
+ bad_progdir = GSSPROXY_PROGRAM.replace("${PROGDIR}",
"//bad/path")
+ update_gssproxy_conf(testdir, conf["keysenv"], bad_progdir)
+ os.kill(conf["gpid"], signal.SIGHUP)
+ time.sleep(1)
+ retval |= run_acquire_test(testdir, env, conf, expected_failure=True)
+
+ # be a good citizen and clean up after ourselves
+ update_gssproxy_conf(testdir, conf["keysenv"], GSSPROXY_CONF_TEMPLATE)
+ os.kill(conf["gpid"], signal.SIGHUP)
+ time.sleep(1)
+
+ print_return(retval, "Program", False)
+ return retval
diff --git a/proxy/tests/testlib.py b/proxy/tests/testlib.py
index 08dfdd6..76dff2d 100755
--- a/proxy/tests/testlib.py
+++ b/proxy/tests/testlib.py
@@ -549,6 +549,7 @@ GSSPROXY_CONF_TEMPLATE = '''
# Contains a garbage service entry
GSSPROXY_CONF_MINIMAL_TEMPLATE = '''
[gssproxy]
+ debug_level = 3
[service/dontuse]
mechs = krb5
@@ -599,6 +600,7 @@ def update_gssproxy_conf(testdir, env, template):
'GSSPROXY_CLIENT_KEYTAB': ckeytab,
'UIDNUMBER': os.getuid(),
'SECOND_SOCKET': socket2,
+ 'PROGDIR': os.path.join(os.getcwd(), "tests"),
'TESTDIR': testdir}
if 'client_name' in env:
subs['GSSPROXY_CLIENT_PRINCIPAL'] = env['client_name']
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.