This is an automated email from the git hooks/post-receive script.
rharwood pushed a change to branch master in repository gssproxy.
from 69a73d8 Fix memory leak new d31d099 Support matching based on executable name
The 1 revisions listed above as "new" are entirely new to this repository and will be described in separate emails. The revisions listed as "adds" were already present in the repository and have only been added to this reference.
Summary of changes: 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(-) create mode 100644 proxy/tests/t_program.py
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@redhat.com Date: Tue May 16 13:57:04 2017 -0400
Support matching based on executable name
Signed-off-by: Robbie Harwood rharwood@redhat.com Reviewed-by: Simo Sorce simo@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']
gss-proxy@lists.fedorahosted.org